Skip to content

Commit

Permalink
update notification design + new animation
Browse files Browse the repository at this point in the history
  • Loading branch information
icepick4 committed Jul 30, 2023
1 parent 210f687 commit d15dfe6
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 210 deletions.
85 changes: 0 additions & 85 deletions src/components/Notification/Notification.v2.vue

This file was deleted.

141 changes: 63 additions & 78 deletions src/components/Notification/Notification.vue
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
<script setup lang="ts">
import { IconCircleCheckFilled, IconX } from '@tabler/icons-vue';
import { onMounted, ref } from 'vue';
import type { Notification, NotificationType } from '@/plugins/notifications';
import {
IconCircleCheckFilled,
IconExclamationCircle,
IconX
} from '@tabler/icons-vue';
import { computed, onMounted, ref } from 'vue';
import Badge from '../Badge.vue';
export interface Properties {
title: string;
message?: string;
type: 'success' | 'error' | 'warning';
flag?: string;
score?: number;
timeout?: number;
}
const props = defineProps<{ notification: Notification }>();
const timeoutMapping: Record<NotificationType, number | undefined> = {
success: 5000,
warning: 7500,
error: undefined
};
const props = defineProps<Properties>();
const emit = defineEmits(['close']);
const close = () => emit('close');
const enabled = ref(true);
const timeout = props.timeout || 5000;
const close = () => {
enabled.value = false;
};
const timeout = computed(() => timeoutMapping[props.notification.type]);
const progress = ref(0);
const intervalDuration = 10;
onMounted(() => {
if (!timeout.value) return;
const interval = setInterval(() => {
progress.value = ((Date.now() - startTime) / timeout) * 100;
progress.value = ((Date.now() - startTime) / timeout.value!) * 100;
if (progress.value >= 100) {
close();
clearInterval(interval);
Expand All @@ -36,76 +37,60 @@ const startTime = Date.now();
</script>

<template>
<div class="fixed bottom-0 right-0 m-6 z-50">
<transition name="fade-slide">
<div v-if="enabled" class="m-auto">
<div class="relative mt-3">
<div
class="absolute top-0 left-0 h-[4px] bg-green-300 rounded"
:style="{ width: `${progress}%` }"
></div>
</div>
<div
class="bg-white border-gray-300 border p-3 shadow-lg rounded-md"
>
<div class="flex flex-row">
<div class="w-full">
<div class="relative">
<div
class="absolute top-0 left-0 h-[4px] rounded"
:class="{
'bg-green-300': notification.type === 'success',
'bg-yellow-300': notification.type === 'warning'
}"
:style="{ width: `${progress}%` }"
></div>
</div>
<div class="bg-white border-gray-300 border p-3 shadow-lg rounded-md">
<div class="flex flex-col gap-2">
<div class="flex flex-row justify-between">
<div class="flex flex-row gap-3 items-center">
<div
class="px-2 flex gap-3 items-center"
v-if="!flag && !score"
v-if="!notification.flag && !notification.score"
>
<IconCircleCheckFilled
v-if="notification.type === 'success'"
class="w-8 h-8 text-green-500"
/>
<IconExclamationCircle
v-else-if="notification.type === 'error'"
class="w-8 h-8 text-red-500"
/>
</div>
<div class="ml-3 mr-3">
<div
class="flex flex-row justify-between items-center mb-2"
>
<span>{{ title }}</span>
<template v-if="flag && score">
<Badge :score="score" />
<img
v-if="flag"
class="w-12 h-8 border-[1px] border-gray-700 rounded"
:src="flag"
:alt="title"
/>
</template>
</div>
<span class="block text-gray-500">{{
message
}}</span>
<slot name="badge"></slot>
</div>
<div class="px-2">
<button @click="close">
<IconX
class="w-6 h-6 text-gray-500 hover:text-gray-700 transition-all duration-300"
/>
</button>
</div>
<img
v-else
class="w-12 h-8 border-[1px] border-gray-700 rounded"
:src="notification.flag"
:alt="notification.title"
/>
<span class="text-lg">{{ notification.title }}</span>
</div>
<div class="px-2">
<button @click="close">
<IconX
class="w-6 h-6 text-gray-500 hover:text-gray-700 transition-all duration-300"
/>
</button>
</div>
</div>
<div class="flex flex-row justify-start items-center gap-3">
<span class="block text-gray-500">{{
notification.message
}}</span>
<Badge
v-if="notification.score"
:score="notification.score"
/>
</div>
</div>
</transition>
</div>
</div>
</template>

<style scoped>
.fade-slide-enter-active,
.fade-slide-leave-active {
transition: all 0.5s ease;
}
.fade-slide-enter-from,
.fade-slide-leave-to {
opacity: 0;
transform: translateX(100px);
}
.fade-slide-enter-to,
.fade-slide-leave-from {
opacity: 1;
transform: translateX(0px);
}
</style>
49 changes: 29 additions & 20 deletions src/components/Notification/NotificationsWrapper.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
<script setup lang="ts">
import type { Notification } from '@/plugins/notifications';
import { Ref, inject } from 'vue';
import NotificationComponent from './Notification.v2.vue';
import NotificationComponent from './Notification.vue';
const notifications = inject<Ref<Notification[]>>('notifications') as Ref<Notification[]>;
const notifications = inject<Ref<Notification[]>>('notifications') as Ref<
Notification[]
>;
function removeNotification(id: string) {
console.log("Delete " + id);
console.log(
notifications.value.map((n) => n.id).join(', ')
)
notifications.value = notifications.value.filter(n => n.id !== id);
notifications.value = notifications.value.filter((n) => n.id !== id);
}
</script>

<template>
<transition-group
name="fade-slide"
name="slide-fade"
enter-active-class="slide-fade-enter-active"
leave-active-class="slide-fade-leave-active"
tag="div"
class="absolute bottom-0 right-0 z-50 p-6 w-full max-w-md flex flex-col gap-y-3 overflow-hidden"
class="absolute bottom-0 right-0 z-50 p-6 w-full max-w-md flex flex-col gap-y-4 overflow-hidden"
>
<NotificationComponent
v-for="notification in notifications"
Expand All @@ -29,20 +29,29 @@ function removeNotification(id: string) {
</template>

<style scoped>
.fade-slide-enter-active,
.fade-slide-leave-active {
transition: all 0.5s ease;
.slide-fade-enter-active {
animation: slide-up 0.5s ease-out;
}
.fade-slide-enter-from,
.fade-slide-leave-to {
opacity: 0;
transform: translateX(100px);
.slide-fade-leave-active {
animation: slide-right 0.5s ease-out;
}
.fade-slide-enter-to,
.fade-slide-leave-from {
opacity: 1;
transform: translateY(0);
@keyframes slide-up {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
@keyframes slide-right {
from {
transform: translateX(0);
}
to {
transform: translateX(100%);
}
}
</style>
7 changes: 3 additions & 4 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,9 @@
"deleteAccountConfirmation": "Are you sure you want to delete your account ?",
"signedUpSuccessfully": "Signed up successfully, now you can log in",
"world": "World",
"congratulations": "Congratulations",
"tooBad": "Too bad",
"levelUp": "You've reached the next level ! 🚀🎉",
"levelDown": "You've lost a level ! 😔",
"congratulations": "Congratulations! 🚀🎉",
"tooBad": "Too bad! 😔",
"levelUp": "You've reached the level",
"confirmDialog": {
"cancel": "Cancel",
"confirm": "Confirm"
Expand Down
7 changes: 3 additions & 4 deletions src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,9 @@
"deleteAccountConfirmation": "¿Estás seguro de que quieres eliminar tu cuenta?",
"signedUpSuccessfully": "¡Te has registrado con éxito!",
"world": "Mundo",
"congratulations": "¡Felicidades!",
"tooBad": "¡Qué pena!",
"levelUp": "¡Has pasado al siguiente nivel! 🚀🎉",
"levelDown": "¡Has bajado de nivel! 😔",
"congratulations": "¡Felicidades! 🚀🎉",
"tooBad": "¡Qué pena! 😔",
"levelUp": "Has pasado al nivel ",
"confirmDialog": {
"cancel": "Cancelar",
"confirm": "Confirmar"
Expand Down
7 changes: 3 additions & 4 deletions src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,9 @@
"deleteAccountConfirmation": "Êtes-vous sûr de vouloir supprimer votre compte ?",
"signedUpSuccessfully": "Inscription réussie ! Veuillez vous connecter pour continuer.",
"world": "Monde",
"congratulations": "Félicitations !",
"tooBad": "Dommage !",
"levelUp": "Vous êtes passé au niveau supérieur ! 🚀🎉",
"levelDown": "Vous êtes redescendu d'un niveau ! 😔",
"congratulations": "Félicitations ! 🚀🎉",
"tooBad": "Dommage ! 😔",
"levelUp": "Vous êtes passé au niveau",
"confirmDialog": {
"cancel": "Annuler",
"confirm": "Confirmer"
Expand Down
7 changes: 3 additions & 4 deletions src/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,9 @@
"deleteAccountConfirmation": "Sei sicuro di voler eliminare il tuo account?",
"signedUpSuccessfully": "Registrazione avvenuta con successo!",
"world": "Mondo",
"congratulations": "Congratulazioni!",
"tooBad": "Peccato!",
"levelUp": "Siete passati al livello successivo ! 🚀🎉",
"levelDown": "Siete tornati al livello precedente ! 😔",
"congratulations": "Congratulazioni! 🚀🎉",
"tooBad": "Peccato! 😔",
"levelUp": "Siete passati al livello",
"confirmDialog": {
"cancel": "Cancella",
"confirm": "Conferma"
Expand Down
Loading

0 comments on commit d15dfe6

Please sign in to comment.