diff options
| author | Fuwn <[email protected]> | 2024-01-11 18:45:31 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-01-11 18:45:31 -0800 |
| commit | 1b71b6a1197967271528fd0d5b9ff5fc9a1f3c26 (patch) | |
| tree | 5261f5d00e22b53e89420c3c1b5fa97d60253d6e | |
| parent | refactor(routes): move shortcuts to hooks (diff) | |
| download | due.moe-1b71b6a1197967271528fd0d5b9ff5fc9a1f3c26.tar.xz due.moe-1b71b6a1197967271528fd0d5b9ff5fc9a1f3c26.zip | |
feat: notifications
| -rwxr-xr-x | bun.lockb | bin | 146196 -> 146577 bytes | |||
| -rw-r--r-- | package.json | 89 | ||||
| -rw-r--r-- | src/lib/Notification/Notification.svelte | 112 | ||||
| -rw-r--r-- | src/lib/Notification/options.ts | 19 | ||||
| -rw-r--r-- | src/lib/Settings/Categories/Debug.svelte | 26 | ||||
| -rw-r--r-- | src/routes/+layout.svelte | 28 |
6 files changed, 216 insertions, 58 deletions
| Binary files differ diff --git a/package.json b/package.json index f5282881..764d1209 100644 --- a/package.json +++ b/package.json @@ -1,46 +1,47 @@ { - "name": "due.moe", - "version": "0.0.0", - "private": true, - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "lint": "prettier --plugin-search-dir . --check . && eslint .", - "format": "prettier --plugin-search-dir . --write ." - }, - "devDependencies": { - "@sveltejs/adapter-vercel": "next", - "@sveltejs/kit": "^1.20.4", - "@types/fast-levenshtein": "^0.0.4", - "@types/jsdom": "^21.1.6", - "@types/string-similarity": "^4.0.2", - "@typescript-eslint/eslint-plugin": "^5.45.0", - "@typescript-eslint/parser": "^5.45.0", - "eslint": "^8.28.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-svelte": "^2.30.0", - "prettier": "^2.8.0", - "prettier-plugin-svelte": "^2.10.1", - "sass": "^1.69.7", - "svelte": "^4.0.5", - "svelte-check": "^3.4.3", - "sveltekit-rate-limiter": "^0.4.2", - "tslib": "^2.4.1", - "typescript": "^5.0.0", - "vite": "^4.4.2" - }, - "type": "module", - "dependencies": { - "@vercel/postgres": "^0.5.1", - "dexie": "^4.0.1-alpha.25", - "jsdom": "^23.0.1", - "lz-string": "^1.5.0", - "modern-screenshot": "^4.4.33", - "rss-parser": "^3.13.0", - "string-similarity": "^4.0.4", - "wanakana": "^5.3.1" - } + "name": "due.moe", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --plugin-search-dir . --check . && eslint .", + "format": "prettier --plugin-search-dir . --write ." + }, + "devDependencies": { + "@sveltejs/adapter-vercel": "next", + "@sveltejs/kit": "^1.20.4", + "@types/fast-levenshtein": "^0.0.4", + "@types/jsdom": "^21.1.6", + "@types/string-similarity": "^4.0.2", + "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/parser": "^5.45.0", + "eslint": "^8.28.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-svelte": "^2.30.0", + "prettier": "^2.8.0", + "prettier-plugin-svelte": "^2.10.1", + "sass": "^1.69.7", + "svelte": "^4.0.5", + "svelte-check": "^3.4.3", + "sveltekit-rate-limiter": "^0.4.2", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "vite": "^4.4.2" + }, + "type": "module", + "dependencies": { + "@vercel/postgres": "^0.5.1", + "dexie": "^4.0.1-alpha.25", + "jsdom": "^23.0.1", + "lz-string": "^1.5.0", + "modern-screenshot": "^4.4.33", + "rss-parser": "^3.13.0", + "string-similarity": "^4.0.4", + "svelte-notifications": "^0.9.98", + "wanakana": "^5.3.1" + } } diff --git a/src/lib/Notification/Notification.svelte b/src/lib/Notification/Notification.svelte new file mode 100644 index 00000000..9612d526 --- /dev/null +++ b/src/lib/Notification/Notification.svelte @@ -0,0 +1,112 @@ +<script lang="ts"> + import { onMount } from 'svelte'; + + export let notification: { [key: string]: any } = {}; + export let onRemove: () => void = () => { + return; + }; + export let removed = false; + + onMount(() => setTimeout(remove, notification.duration)); + + const remove = () => { + removed = true; + + setTimeout(onRemove, 150); + }; +</script> + +<div id="notification-container" class={removed ? 'fade-out' : 'fade-in'}> + {#if notification.description} + <details open id="notification"> + <summary>{@html notification.heading}</summary> + + {@html notification.description} + + <br /> + + <div class="button-container"> + <button on:click={remove} class="button-hide">Hide</button> + </div> + </details> + {:else} + <div class="card" id="notification"> + {@html notification.heading} + + + + <div class="button-container"> + <button on:click={remove} class="button-hide">Hide</button> + </div> + </div> + {/if} +</div> + +<style> + #notification-container { + margin: 1rem 1rem 0 0; + float: right; + } + + #notification { + background-color: var(--base001); + box-shadow: rgba(0, 0, 11, 0.2) 0px 7px 29px 0px, 0 0 0 4px var(--base0E); + + widows: 100%; + } + + .button-container { + display: flex; + justify-content: flex-end; + } + + #notification > div { + display: inline; + } + + .button-hide { + float: right; + } + + .button-container::after { + content: ''; + clear: both; + display: table; + } + + .fade-in { + animation: fadeInAnimation ease 300ms; + animation-iteration-count: 1; + animation-fill-mode: forwards; + } + + .fade-out { + animation: fadeOutAnimation ease 150ms; + animation-iteration-count: 1; + animation-fill-mode: forwards; + } + + @keyframes fadeInAnimation { + 100% { + opacity: 1; + } + 1% { + opacity: 0.01; + } + 0% { + opacity: 0; + } + } + + @keyframes fadeOutAnimation { + 0% { + opacity: 1; + } + 99% { + opacity: 0.01; + } + 100% { + opacity: 0; + } + } +</style> diff --git a/src/lib/Notification/options.ts b/src/lib/Notification/options.ts new file mode 100644 index 00000000..f14e0d25 --- /dev/null +++ b/src/lib/Notification/options.ts @@ -0,0 +1,19 @@ +type Position = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'; + +interface Options { + heading: string | number; + description: string | number | undefined; + position: Position; + duration: number; + id: string; +} + +export const options = (preferences: { [key: string]: number | string }): Options => { + return { + position: (preferences.position || 'top-right') as Position, + duration: Number(preferences.duration || 3000), + heading: preferences.heading || 'Notification', + description: preferences.description || undefined, + id: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + }; +}; diff --git a/src/lib/Settings/Categories/Debug.svelte b/src/lib/Settings/Categories/Debug.svelte index 5f6be96b..c21b6dd7 100644 --- a/src/lib/Settings/Categories/Debug.svelte +++ b/src/lib/Settings/Categories/Debug.svelte @@ -1,16 +1,38 @@ <script lang="ts"> import settings from '$stores/settings'; + import { getNotificationsContext } from 'svelte-notifications'; import SettingHint from '../SettingHint.svelte'; + import { options } from '$lib/Notification/options'; + + const { addNotification } = getNotificationsContext(); </script> -<button on:click={settings.reset}>Reset <b>ALL</b> settings</button> +<button + on:click={() => { + settings.reset(); + addNotification( + options({ + heading: 'All settings successfully reset' + }) + ); + }}>Reset <b>ALL</b> settings</button +> <SettingHint lineBreak> Resets all settings present on this page to their default values </SettingHint> <p /> -<button on:click={() => localStorage.clear()}>Clear <code>localStorage</code></button> +<button + on:click={() => { + localStorage.clear(); + addNotification( + options({ + heading: '<code>localStorage</code> successfully cleared' + }) + ); + }}>Clear <code>localStorage</code></button +> <SettingHint lineBreak> Resets all of your settings to their default values and clears both AniList media list and manga data caches diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index e1df9c9d..52d1b8ba 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -10,6 +10,8 @@ import { fly } from 'svelte/transition'; import { readable, type Readable } from 'svelte/store'; import { navigating } from '$app/stores'; + import Notifications from 'svelte-notifications'; + import Notification from '$lib/Notification/Notification.svelte'; export let data; @@ -99,18 +101,20 @@ <p /> - {#key data.url} - <div - in:fly={{ - x: way, - duration: animationDelay, - delay: animationDelay - }} - out:fly={{ x: -way, duration: animationDelay }} - > - <slot /> - </div> - {/key} + <Notifications item={Notification} zIndex={5000}> + {#key data.url} + <div + in:fly={{ + x: way, + duration: animationDelay, + delay: animationDelay + }} + out:fly={{ x: -way, duration: animationDelay }} + > + <slot /> + </div> + {/key} + </Notifications> </div> <style> |