add basic notifications

This commit is contained in:
Torsten Dittmann
2022-02-02 00:26:22 +01:00
parent 8e09aeedbe
commit 6b91f81941
8 changed files with 216 additions and 73 deletions
+52
View File
@@ -0,0 +1,52 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition';
import type { Notification } from '../notifications';
const dispatch = createEventDispatcher();
export let type: Notification['type'] = 'info';
export let dismissible = true;
</script>
<article class={type} role="alert" transition:fade>
<div class="text">
<slot />
</div>
{#if dismissible}
<button class="close" on:click={() => dispatch('dismiss')}> x </button>
{/if}
</article>
<style lang="scss">
article {
color: white;
padding: 0.75rem 1.5rem;
border-radius: 0.2rem;
display: flex;
align-items: center;
margin: 0 auto 0.5rem auto;
width: 20rem;
}
.error {
background: IndianRed;
}
.success {
background: MediumSeaGreen;
}
.info {
background: SkyBlue;
}
.text {
margin-left: 1rem;
}
button {
color: white;
background: transparent;
border: 0 none;
padding: 0;
margin: 0 0 0 auto;
line-height: 1;
font-size: 1rem;
}
</style>
+34
View File
@@ -0,0 +1,34 @@
<script lang="ts">
import Notification from './notification.svelte';
import { dismissToast, toasts } from '../notifications';
</script>
{#if $toasts}
<section>
{#each $toasts as toast (toast.id)}
<Notification
type={toast.type}
dismissible={toast.dismissible}
on:dismiss={() => dismissToast(toast.id)}
>
{toast.message}
</Notification>
{/each}
</section>
{/if}
<style lang="postcss">
section {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
display: flex;
margin-top: 1rem;
justify-content: center;
flex-direction: column;
z-index: 1000;
}
</style>
+31
View File
@@ -0,0 +1,31 @@
import { writable } from 'svelte/store';
export type Notification = {
id: number;
type: 'success' | 'error' | 'info';
dismissible: boolean;
timeout: number;
message: string;
};
let counter = 0;
export const toasts = writable<Notification[]>([]);
export const dismissToast = (id: number) => {
toasts.update((all) => all.filter((t) => t.id !== id));
};
export const addToast = (notification: Omit<Notification, 'id'>) => {
const defaults = {
id: counter++,
type: 'info',
dismissible: true,
timeout: 3000
};
const n = { ...defaults, ...notification };
toasts.update((all) => [n, ...all]);
if (n.timeout) setTimeout(() => dismissToast(n.id), n.timeout);
};
+2
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import Notifications from '$lib/layout/notifications.svelte';
import { sdkForConsole } from '$lib/stores/sdk';
import { user } from '$lib/stores/user';
import { onMount } from 'svelte';
@@ -20,6 +21,7 @@
});
</script>
<Notifications />
<main class="container">
<slot />
</main>
@@ -24,7 +24,7 @@
<h1>Overview</h1>
<article class="overview">
<p><img src={getAvatar(user.name)} alt={user.name} class="avatar" /></p>
<p class="id" data-tooltip="Click to copy.">{user.$id}</p>
<p>{user.$id}</p>
<p>Member since {user.registration}</p>
<p>{user.emailVerification ? 'Verified' : 'Unverified'}</p>
<p>{user.email}</p>
@@ -54,10 +54,6 @@
flex-direction: column;
align-items: center;
.id {
cursor: pointer;
}
.avatar {
border-radius: 50%;
}
@@ -1,10 +1,34 @@
<script lang="ts">
import { page } from '$app/stores';
import { Pagination, Table, TableCell, TableHeader, TableBody, TableRow } from '$lib/components';
import {
Pagination,
Table,
TableCell,
TableHeader,
TableBody,
TableRow,
Button
} from '$lib/components';
import { sdkForProject } from '$lib/stores/sdk';
const getSessions = () => sdkForProject.users.getSessions($page.params.user);
const deleteSession = async (id: string) => {
try {
await sdkForProject.users.deleteSession($page.params.user, id);
request = getSessions();
} catch (error) {
alert(error.message);
}
};
const deleteAllSessions = async () => {
try {
if (confirm('You really want to delete all sessions?')) {
await sdkForProject.users.deleteSessions($page.params.user);
}
} catch (error) {
alert(error.message);
}
};
let offset = 0;
const limit = 25;
@@ -19,6 +43,7 @@
<TableCell>Country</TableCell>
<TableCell>OS</TableCell>
<TableCell>IP</TableCell>
<TableCell />
</TableHeader>
<TableBody>
{#each response.sessions as session}
@@ -26,10 +51,12 @@
<TableCell>{session.countryName}</TableCell>
<TableCell>{session.osName}</TableCell>
<TableCell>{session.ip}</TableCell>
<TableCell><Button on:click={() => deleteSession(session.$id)}>Logout</Button></TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
<Pagination {limit} bind:offset sum={response.sum} on:change={() => (request = getSessions())} />
<Button on:click={deleteAllSessions}>Logout from all sessions</Button>
{/await}