diff options
Diffstat (limited to 'assets')
| -rw-r--r-- | assets/src/components/RequestPage.svelte | 3 | ||||
| -rw-r--r-- | assets/src/components/SharePage.svelte | 3 | ||||
| -rw-r--r-- | assets/src/components/Toasts.svelte | 77 | ||||
| -rw-r--r-- | assets/src/components/icons/FlashIcon.svelte | 13 | ||||
| -rw-r--r-- | assets/src/components/icons/LightbulbIcon.svelte | 16 | ||||
| -rw-r--r-- | assets/src/state/toast.ts | 42 | ||||
| -rw-r--r-- | assets/src/utils/generateId.ts | 10 |
7 files changed, 162 insertions, 2 deletions
diff --git a/assets/src/components/RequestPage.svelte b/assets/src/components/RequestPage.svelte index 1297891..69981b4 100644 --- a/assets/src/components/RequestPage.svelte +++ b/assets/src/components/RequestPage.svelte @@ -1,10 +1,11 @@ <script lang="ts"> import Header from "./Header.svelte"; import RequestStatus from "./request/RequestStatus.svelte"; + import Toasts from "./Toasts.svelte"; </script> <Header color="white" /> - +<Toasts /> <main> <div class="left-segment"> <RequestStatus /> diff --git a/assets/src/components/SharePage.svelte b/assets/src/components/SharePage.svelte index 826f70e..9c40c67 100644 --- a/assets/src/components/SharePage.svelte +++ b/assets/src/components/SharePage.svelte @@ -3,12 +3,13 @@ import ShareStatus from "./share/ShareStatus.svelte"; import RequestList from "./share/RequestList.svelte"; import { getShareState, ShareStateType } from "../state/share"; + import Toasts from "./Toasts.svelte"; const state = getShareState().type; </script> <Header color="black" /> - +<Toasts /> <main> <div class="left-segment"> <ShareStatus /> diff --git a/assets/src/components/Toasts.svelte b/assets/src/components/Toasts.svelte new file mode 100644 index 0000000..f909831 --- /dev/null +++ b/assets/src/components/Toasts.svelte @@ -0,0 +1,77 @@ +<script lang="ts"> + import { dismissToast, toasts, ToastType } from "../state/toast"; + import { scale } from "svelte/transition"; + import CloseIcon from "./icons/CloseIcon.svelte"; + import FlashIcon from "./icons/FlashIcon.svelte"; + import LightbulbIcon from "./icons/LightbulbIcon.svelte"; + + function trim(str: string) { + return str.slice(0, 100) + (str.length > 100 ? "..." : ""); + } +</script> + +<div class="toasts"> + {#each $toasts as toast (toast.id)} + <ul class="toast" in:scale out:scale> + <div class="button" on:click={() => dismissToast(toast)}> + <CloseIcon color="white" /> + </div> + + <li> + {#if toast.type === ToastType.INFO} + <LightbulbIcon color="white" /> + {:else} + <FlashIcon color="white" /> + {/if} + </li> + + {#if toast.title} + <li class="title">{toast.title}</li> + {/if} + + <li class="message">{trim(toast.message)}</li> + </ul> + {/each} +</div> + +<style> + .toasts { + position: fixed; + bottom: 0; + display: flex; + align-items: center; + width: 100%; + z-index: 1; + flex-direction: column-reverse; + } + + .toast { + width: 300px; + background-color: black; + border: solid 1px #626262; + padding: 17px 20px; + font-size: 12px; + line-height: 1.5rem; + position: relative; + } + + .title { + font-size: 16px; + } + + .message { + color: #626262; + font-size: 12px; + line-height: 1.2rem; + word-wrap: anywhere; + } + + ul { + list-style-type: none; + } + + .button { + position: absolute; + right: 20px; + } +</style> diff --git a/assets/src/components/icons/FlashIcon.svelte b/assets/src/components/icons/FlashIcon.svelte new file mode 100644 index 0000000..57525f2 --- /dev/null +++ b/assets/src/components/icons/FlashIcon.svelte @@ -0,0 +1,13 @@ +<script lang="ts"> + export let color: "white" | "black"; +</script> + +<svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + width="16" + height="16" +> + <path fill="none" d="M0 0h24v24H0z" /> + <path d="M13 10h7l-9 13v-9H4l9-13z" fill={color} /> +</svg> diff --git a/assets/src/components/icons/LightbulbIcon.svelte b/assets/src/components/icons/LightbulbIcon.svelte new file mode 100644 index 0000000..fbaef1d --- /dev/null +++ b/assets/src/components/icons/LightbulbIcon.svelte @@ -0,0 +1,16 @@ +<script lang="ts"> + export let color: "white" | "black"; +</script> + +<svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + width="16" + height="16" +> + <path fill="none" d="M0 0h24v24H0z" /> + <path + d="M9.973 18H11v-5h2v5h1.027c.132-1.202.745-2.194 1.74-3.277.113-.122.832-.867.917-.973a6 6 0 1 0-9.37-.002c.086.107.807.853.918.974.996 1.084 1.609 2.076 1.741 3.278zM10 20v1h4v-1h-4zm-4.246-5a8 8 0 1 1 12.49.002C17.624 15.774 16 17 16 18.5V21a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-2.5C8 17 6.375 15.774 5.754 15z" + fill={color} + /> +</svg> diff --git a/assets/src/state/toast.ts b/assets/src/state/toast.ts new file mode 100644 index 0000000..8eba306 --- /dev/null +++ b/assets/src/state/toast.ts @@ -0,0 +1,42 @@ +import { writable } from "svelte/store"; +import generateId from "../utils/generateId"; + +export enum ToastType { + INFO, + ERROR, +} + +export type ToastData = { + type: ToastType; + message: string; + title?: string; +}; + +export type Toast = { + id: string; +} & ToastData; + +export const toasts = writable<Toast[]>([]); + +export function toast(toast: ToastData): Toast { + const toastWithId: Toast = { + ...toast, + id: generateId(8), + }; + + toasts.update(toasts => [...toasts, toastWithId]); + + // Dissmiss toast after 5 seconds. + setTimeout(() => { + dismissToast(toastWithId); + }, 5000); + + return toastWithId; +} + +// @ts-ignore +window.toast = toast; + +export function dismissToast(toast: Toast) { + toasts.update(toasts => toasts.filter(t => t.id !== toast.id)); +} diff --git a/assets/src/utils/generateId.ts b/assets/src/utils/generateId.ts new file mode 100644 index 0000000..51119a8 --- /dev/null +++ b/assets/src/utils/generateId.ts @@ -0,0 +1,10 @@ +// Returns a fairly random id string, which can +// then be used for keys in each blocks. +export default function (length: number): string { + const chars = "0123456789abcdef"; + + return Array(length) + .fill(0) + .map(() => chars[Math.floor(Math.random() * chars.length)]) + .join(""); +} |
