generateur_v3/frontend/src/context/Notification.svelte

161 lines
3.1 KiB
Svelte

<script lang="ts">
import { setContext } from 'svelte';
import { writable } from 'svelte/store';
import SvelteMarkdown from 'svelte-markdown'
type Notif = {
title: string;
description: string;
type: 'alert' | 'info' | 'success' | 'error';
};
type Notification = {
title: string;
description: string;
type: 'alert' | 'info' | 'success' | 'error';
id: number;
deleted: boolean;
};
const notifications = writable<Notification[]>([]);
const getId = () => {
return Math.round(Date.now() * Math.random());
};
const toast = (notif: Notif) => {
let id = getId();
notifications.update((n) => {
return [...n, { ...notif, id, deleted: false }];
});
setTimeout(() => {
notifications.update((n) => {
return n.map((o) => {
if (o.id == id) {
return { ...o, deleted: true };
}
return o;
});
});
setTimeout(() => {
notifications.update((n) => {
return n.filter((o) => o.id != id);
});
}, 500);
}, 3000);
};
const alert = (title: string, description: string) => {
toast({ title, description, type: 'alert' });
};
const info = (title: string, description: string) => {
toast({ title, description, type: 'info' });
};
const success = (title: string, description: string) => {
toast({ title, description, type: 'success' });
};
const error = (title: string, description: string) => {
toast({ title, description, type: 'error' });
};
setContext('notif', { toast, alert, info, success, error });
</script>
<slot />
<div class="notifs" class:empty ={$notifications.length == 0}>
{#each $notifications as n}
<div
on:click={() => {
n.deleted = true;
setTimeout(() => {
notifications.update((o) => o.filter((i) => i.id != n.id));
}, 500);
}}
class={n.type}
on:keydown={() => {}}
class:deleted={n.deleted}
>
<h1>{n.title}</h1>
<p><SvelteMarkdown source={n.description} /></p>
</div>
{/each}
</div>
<style lang="scss">
.notifs {
position: absolute;
right: 0;
top: 0;
padding: 30px;
gap: 10px;
display: flex;
flex-direction: column;
width: 500px;
z-index: 1000;
div {
background-color: $background;
z-index: 1000;
padding: 10px;
cursor: pointer;
position: relative;
overflow: hidden;
word-wrap: break-word;
h1 {
font-size: 1.1em;
}
p {
font-size: 0.9em;
}
&::before,
&::after {
content: '';
display: block;
height: 3px;
position: absolute;
bottom: 0;
right: 0;
left: 0;
}
&::before {
z-index: 3;
background-color: $background-light;
transition: 3s;
width: 0%;
animation: slide 3s forwards ease-in-out;
}
&::after {
width: 100%;
z-index: 2;
}
&.deleted {
transition: 0.5s;
opacity: 0;
}
}
}
.empty{
z-index: -20;
}
.alert::after{
background-color: $orange;
}
.info::after{
background-color: $bleu;
}
.error::after{
background-color: $red;
}
.success::after{
background-color: $green;
}
@keyframes slide {
from {
width: 0%;
}
to {
width: 100%;
}
}
</style>