Add initialization error toasts (#24)

* Add error, success, info, and warning styles

* Add Toast component

* Add initialization error toast

* Add device store and toast placement

* Set device on window resize events


Co-authored-by: Brian Ginsburg <gins@brianginsburg.com>
Co-authored-by: Jess Martin <jessmartin@gmail.com>
This commit is contained in:
Brian Ginsburg 2022-08-02 10:57:36 -07:00 committed by GitHub
parent 046c80be44
commit 2d25466f93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 143 additions and 16 deletions

14
package-lock.json generated
View File

@ -8,7 +8,7 @@
"name": "svelte-elemetary-template",
"version": "0.1.0",
"dependencies": {
"webnative": "0.33.0-alpha-3"
"webnative": "0.33.0-alpha-4"
},
"devDependencies": {
"@sveltejs/adapter-static": "1.0.0-next.36",
@ -4679,9 +4679,9 @@
}
},
"node_modules/webnative": {
"version": "0.33.0-alpha-3",
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.33.0-alpha-3.tgz",
"integrity": "sha512-fx7ZNk1eKdt88RHG90fKg99xhBKsPIizOEgggr0HYrbM9G9O4vXGabt48QQF6K9pTuZmrrSW/RyqR/bxCHRc6A==",
"version": "0.33.0-alpha-4",
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.33.0-alpha-4.tgz",
"integrity": "sha512-P7TH9uwh31IS8PjHaRD74wQRjmVu1qiHnMwkjr2x0FiUixUwbrkvumL4qergeCIKQj//ZrrnkCZhebJ1efaylQ==",
"dependencies": {
"@ipld/dag-cbor": "^7.0.0",
"@ipld/dag-pb": "^2.1.15",
@ -8069,9 +8069,9 @@
"peer": true
},
"webnative": {
"version": "0.33.0-alpha-3",
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.33.0-alpha-3.tgz",
"integrity": "sha512-fx7ZNk1eKdt88RHG90fKg99xhBKsPIizOEgggr0HYrbM9G9O4vXGabt48QQF6K9pTuZmrrSW/RyqR/bxCHRc6A==",
"version": "0.33.0-alpha-4",
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.33.0-alpha-4.tgz",
"integrity": "sha512-P7TH9uwh31IS8PjHaRD74wQRjmVu1qiHnMwkjr2x0FiUixUwbrkvumL4qergeCIKQj//ZrrnkCZhebJ1efaylQ==",
"requires": {
"@ipld/dag-cbor": "^7.0.0",
"@ipld/dag-pb": "^2.1.15",

View File

@ -50,6 +50,6 @@
]
},
"dependencies": {
"webnative": "0.33.0-alpha-3"
"webnative": "0.33.0-alpha-4"
}
}

View File

@ -88,12 +88,12 @@
/>
{/if}
{#if !(username.length === 0) && usernameAvailable && usernameValid && !checkingUsername}
<span class="w-4 h-4 block absolute top-4 right-4">
<span class="w-4 h-4 block absolute top-5 right-4">
<CheckIcon />
</span>
{/if}
{#if !(username.length === 0) && !checkingUsername && !(usernameAvailable && usernameValid)}
<span class="w-4 h-4 block absolute top-4 right-4">
<span class="w-4 h-4 block absolute top-5 right-4">
<XIcon />
</span>
{/if}

View File

@ -0,0 +1,17 @@
<svg
width="28px"
height="28px"
viewBox="0 0 28 28"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g fill="none" fill-rule="nonzero">
<path
d="M4.03033009,13.4696699 C3.73743687,13.1767767 3.26256313,13.1767767 2.96966991,13.4696699 C2.6767767,13.7625631 2.6767767,14.2374369 2.96966991,14.5303301 L9.96966991,21.5303301 C10.2625631,21.8232233 10.7374369,21.8232233 11.0303301,21.5303301 L25.0303301,7.53033009 C25.3232233,7.23743687 25.3232233,6.76256313 25.0303301,6.46966991 C24.7374369,6.1767767 24.2625631,6.1767767 23.9696699,6.46966991 L10.5,19.9393398 L4.03033009,13.4696699 Z"
fill="#14532d"
/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 788 B

View File

@ -0,0 +1,14 @@
<svg
width="15px"
height="15px"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M6.7929 7.49998L1.14645 1.85353L1.85356 1.14642L7.50001 6.79287L13.1465 1.14642L13.8536 1.85353L8.20711 7.49998L13.8536 13.1464L13.1465 13.8535L7.50001 8.20708L1.85356 13.8535L1.14645 13.1464L6.7929 7.49998Z"
fill="#7f1d1d"
/>
</svg>

After

Width:  |  Height:  |  Size: 414 B

View File

@ -0,0 +1,36 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { quintOut } from 'svelte/easing'
import { fade } from 'svelte/transition'
import CheckThinIcon from '$components/icons/CheckThinIcon.svelte'
import XThinIcon from '$components/icons/XThinIcon.svelte'
export let kind: 'success' | 'error'
export let message: string
const dispatch = createEventDispatcher()
const clearNotification = () => {
dispatch('clear')
}
</script>
<div
class="toast"
on:click={clearNotification}
out:fade={{ duration: 800, easing: quintOut }}
>
<div
class="alert {kind === 'success' ? 'alert-success' : 'alert-error'} text-sm"
>
<div>
{#if kind === 'success'}
<CheckThinIcon />
{:else if kind === 'error'}
<XThinIcon />
{/if}
<span class="pl-1">{message}</span>
</div>
</div>
</div>

3
src/lib/device.ts Normal file
View File

@ -0,0 +1,3 @@
export type Device = {
isMobile: boolean
}

View File

@ -2,5 +2,17 @@ export type Session = {
username: string
authed: boolean
loading: boolean
error?: 'Insecure Context' | 'Unsupported Browser'
}
error?: SessionError
}
type SessionError = 'Insecure Context' | 'Unsupported Browser'
export const errorToMessage = (error: SessionError): string => {
switch (error) {
case 'Insecure Context':
return 'This application requires a secure context (HTTPS)'
case 'Unsupported Browser':
return 'Your browser does not support this application'
}
}

View File

@ -1,29 +1,63 @@
<script lang="ts">
import { get } from 'svelte/store'
import { onMount } from 'svelte'
import '../global.css'
import { initialize } from '$lib/common/webnative'
import { sessionStore, theme } from '../stores'
import { deviceStore, sessionStore, theme } from '../stores'
import { storeTheme } from '$lib/theme'
import { errorToMessage, type Session } from '$lib/session'
import Toast from '$components/notifications/Toast.svelte'
import Header from '$components/Header.svelte'
let session: Session = null
theme.subscribe(val => {
storeTheme(val)
})
sessionStore.subscribe(val => {
session = val
})
onMount(() => { setDevice() })
const setDevice = () => {
if (window.innerWidth <= 768) {
deviceStore.set({ isMobile: true })
} else {
deviceStore.set({ isMobile: false })
}
}
const init = async () => {
await initialize()
// TODO: Remove this debugging statement
const session = get(sessionStore)
console.log('session at init', session)
}
const clearNotification = () => {
sessionStore.update(session => ({
...session,
error: null
}))
}
init()
</script>
<svelte:window on:resize={setDevice} />
<div data-theme={$theme}>
<Header />
{#if session.error}
<Toast
kind="error"
message={errorToMessage(session.error)}
on:clear={clearNotification}
/>
{/if}
<slot />
</div>

View File

@ -3,6 +3,7 @@ import type { Writable } from 'svelte/store'
import type FileSystem from 'webnative/fs/index'
import { loadTheme } from '$lib/theme'
import type { Device } from '$lib/device'
import type { Session } from '$lib/session'
import type { Theme } from '$lib/theme'
@ -14,4 +15,6 @@ export const sessionStore: Writable<Session> = writable({
loading: true
})
export const filesystemStore: Writable<FileSystem | null> = writable(null)
export const filesystemStore: Writable<FileSystem | null> = writable(null)
export const deviceStore: Writable<Device> = writable({ isMobile: true })

View File

@ -11,6 +11,10 @@ module.exports = {
secondary: "#30aadd",
accent: "#00ffc6",
neutral: "#282828",
info: "#bfdbfe",
success: "#bbf7d0",
warning: "#fdba74",
error: "#fecaca",
"base-content": "#ffffff",
"base-100": "#111111",
"--rounded-box": "16px",
@ -24,6 +28,10 @@ module.exports = {
secondary: "#30aadd",
accent: "#00ffc6",
neutral: "#e5e5e5",
info: "#bfdbfe",
success: "#bbf7d0",
warning: "#fdba74",
error: "#fecaca",
"base-content": "#000000",
"base-100": "#ffffff",
"--rounded-box": "16px",