Fixed toasts not working.
This commit is contained in:
parent
8b9a2ac8d5
commit
f31f180687
@ -1,6 +1,7 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { fade } from "svelte/transition";
|
import { fade } from "svelte/transition";
|
||||||
|
import { Toast, ToastType } from "$lib/toast";
|
||||||
import SuccessIcon from "./SuccessIcon.svelte";
|
import SuccessIcon from "./SuccessIcon.svelte";
|
||||||
import ErrorIcon from "./ErrorIcon.svelte";
|
import ErrorIcon from "./ErrorIcon.svelte";
|
||||||
import InfoIcon from "./InfoIcon.svelte";
|
import InfoIcon from "./InfoIcon.svelte";
|
||||||
@ -8,24 +9,23 @@
|
|||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
export let type = "error";
|
export let toastData: Toast;
|
||||||
export let dismissible = true;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<article class={type} role="alert" transition:fade>
|
<article class={toastData.type.toString().toLowerCase()} role="alert" transition:fade>
|
||||||
{#if type === "success"}
|
{#if toastData.type === ToastType.Success}
|
||||||
<SuccessIcon width="1.1em" />
|
<SuccessIcon width="1.1em" />
|
||||||
{:else if type === "error"}
|
{:else if toastData.type === ToastType.Error}
|
||||||
<ErrorIcon width="1.1em" />
|
<ErrorIcon width="1.1em" />
|
||||||
{:else}
|
{:else}
|
||||||
<InfoIcon width="1.1em" />
|
<InfoIcon width="1.1em" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<slot />
|
{toastData.text}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if dismissible}
|
{#if toastData.dismissable}
|
||||||
<button class="close" on:click={() => dispatch("dismiss")}>
|
<button class="close" on:click={() => dispatch("dismiss")}>
|
||||||
<CloseIcon width="0.8em" />
|
<CloseIcon width="0.8em" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -7,11 +7,7 @@
|
|||||||
{#if $toasts}
|
{#if $toasts}
|
||||||
<section>
|
<section>
|
||||||
{#each $toasts as toast (toast.id)}
|
{#each $toasts as toast (toast.id)}
|
||||||
<Toast
|
<Toast toastData = {toast} on:dismiss={() => dismissToast(toast.id)} />
|
||||||
type={toast.type}
|
|
||||||
dismissible={toast.dismissible}
|
|
||||||
on:dismiss={() => dismissToast(toast.id)}>{toast.message}</Toast
|
|
||||||
>
|
|
||||||
{/each}
|
{/each}
|
||||||
</section>
|
</section>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,10 +1,26 @@
|
|||||||
class Toast {
|
/**
|
||||||
constructor(text: String, type: String, dismissable: boolean, timeout: number ) {
|
* @enum Used to refer to the type of toast being displayed
|
||||||
id = text
|
*/
|
||||||
|
export enum ToastType {
|
||||||
|
Info = "info",
|
||||||
|
Success = "success",
|
||||||
|
Error = "error"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Toast Notification
|
||||||
|
*/
|
||||||
|
export class Toast {
|
||||||
|
constructor(text: String, type: ToastType, dismissable: boolean, timeout: number ) {
|
||||||
|
this.text = text;
|
||||||
|
this.type = type;
|
||||||
|
this.dismissable = dismissable;
|
||||||
|
this.timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
id: String;
|
id: number = 0;
|
||||||
type: String;
|
text: String;
|
||||||
dismissible: boolean;
|
type: ToastType;
|
||||||
|
dismissable: Boolean;
|
||||||
timeout: number;
|
timeout: number;
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { getJson } from "$lib/data";
|
import { getJson } from "$lib/data";
|
||||||
import { removeMessage } from "$lib/snackbar"
|
import { Toast, ToastType } from "$lib/toast";
|
||||||
|
import { addToast } from "./store";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -79,4 +80,5 @@
|
|||||||
<h1>Unable to load portfolio overview data</h1>
|
<h1>Unable to load portfolio overview data</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{addToast(new Toast("Unable to load me.json", ToastType.Error, true, 3000))}
|
||||||
{/await}
|
{/await}
|
@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import Snackbar from '../snackbar.svelte';
|
import Toasts from "../Toasts.svelte";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -52,5 +52,6 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="main-container fade">
|
<div class="main-container fade">
|
||||||
|
<Toasts></Toasts>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import Main from '../main.svelte';
|
import Main from '../main.svelte';
|
||||||
import Snackbar from '../snackbar.svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Main></Main>
|
<Main></Main>
|
||||||
<Snackbar></Snackbar>
|
|
@ -1,73 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
let messages: string[] = [];
|
|
||||||
|
|
||||||
export function addMessage(text: string) {
|
|
||||||
messages = [...messages, text];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeMessage() {
|
|
||||||
if(messages.length == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
messages = messages.splice(1, messages.length-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
/* Flex container for all of the elements waiting to be shown*/
|
|
||||||
.snackbar-container {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
margin: 1rem;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1em;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The snackbar - position it at the bottom and in the middle of the screen */
|
|
||||||
.snackbar-item {
|
|
||||||
background-color: var(--bg-2);
|
|
||||||
color: var(--green);
|
|
||||||
width: 10em;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 1em;
|
|
||||||
padding: 16px;
|
|
||||||
left: 50%;
|
|
||||||
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
|
||||||
animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Animations to fade the snackbar in and out */
|
|
||||||
@-webkit-keyframes fadein {
|
|
||||||
from {bottom: 0; opacity: 0;}
|
|
||||||
to {bottom: 30px; opacity: 1;}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadein {
|
|
||||||
from {bottom: 0; opacity: 0;}
|
|
||||||
to {bottom: 30px; opacity: 1;}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes fadeout {
|
|
||||||
from {bottom: 30px; opacity: 1;}
|
|
||||||
to {bottom: 0; opacity: 0;}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeout {
|
|
||||||
from {bottom: 30px; opacity: 1;}
|
|
||||||
to {bottom: 0; opacity: 0;}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<button on:click={() => addMessage("Hello")}>Hello</button>
|
|
||||||
|
|
||||||
<div class="snackbar-container">
|
|
||||||
{#each messages as message}
|
|
||||||
<div class="snackbar-item" on:click={removeMessage}>{message}</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
17
src/store.ts
17
src/store.ts
@ -1,16 +1,17 @@
|
|||||||
import { writable } from "svelte/store";
|
import { ToastType, type Toast } from "$lib/toast";
|
||||||
|
import { writable, type Writable } from "svelte/store";
|
||||||
|
|
||||||
export const toasts = writable([]);
|
export const toasts: Writable<Toast[]> = writable([]);
|
||||||
|
|
||||||
export const addToast = (toast: ) => {
|
export const addToast = (toast: Toast) => {
|
||||||
// Create a unique ID so we can easily find/remove it
|
// Create a unique ID so we can easily find/remove it
|
||||||
// if it is dismissible/has a timeout.
|
// if it is dismissible/has a timeout.
|
||||||
const id = Math.floor(Math.random() * 10000);
|
toast.id = Math.floor(Math.random() * 10000);
|
||||||
|
|
||||||
// Setup some sensible defaults for a toast.
|
// Setup some sensible defaults for a toast.
|
||||||
const defaults = {
|
const defaults = {
|
||||||
id,
|
id: toast.id,
|
||||||
type: "info",
|
type: ToastType.Info,
|
||||||
dismissible: true,
|
dismissible: true,
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
};
|
};
|
||||||
@ -19,9 +20,9 @@ export const addToast = (toast: ) => {
|
|||||||
toasts.update((all) => [{ ...defaults, ...toast }, ...all]);
|
toasts.update((all) => [{ ...defaults, ...toast }, ...all]);
|
||||||
|
|
||||||
// If toast is dismissible, dismiss it after "timeout" amount of time.
|
// If toast is dismissible, dismiss it after "timeout" amount of time.
|
||||||
if (toast.timeout) setTimeout(() => dismissToast(id), toast.timeout);
|
if (toast.timeout) setTimeout(() => dismissToast(toast.id), toast.timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const dismissToast = (id) => {
|
export const dismissToast = (id: number) => {
|
||||||
toasts.update((all) => all.filter((t) => t.id !== id));
|
toasts.update((all) => all.filter((t) => t.id !== id));
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user