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:
parent
046c80be44
commit
2d25466f93
|
|
@ -8,7 +8,7 @@
|
||||||
"name": "svelte-elemetary-template",
|
"name": "svelte-elemetary-template",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"webnative": "0.33.0-alpha-3"
|
"webnative": "0.33.0-alpha-4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/adapter-static": "1.0.0-next.36",
|
"@sveltejs/adapter-static": "1.0.0-next.36",
|
||||||
|
|
@ -4679,9 +4679,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webnative": {
|
"node_modules/webnative": {
|
||||||
"version": "0.33.0-alpha-3",
|
"version": "0.33.0-alpha-4",
|
||||||
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.33.0-alpha-3.tgz",
|
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.33.0-alpha-4.tgz",
|
||||||
"integrity": "sha512-fx7ZNk1eKdt88RHG90fKg99xhBKsPIizOEgggr0HYrbM9G9O4vXGabt48QQF6K9pTuZmrrSW/RyqR/bxCHRc6A==",
|
"integrity": "sha512-P7TH9uwh31IS8PjHaRD74wQRjmVu1qiHnMwkjr2x0FiUixUwbrkvumL4qergeCIKQj//ZrrnkCZhebJ1efaylQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ipld/dag-cbor": "^7.0.0",
|
"@ipld/dag-cbor": "^7.0.0",
|
||||||
"@ipld/dag-pb": "^2.1.15",
|
"@ipld/dag-pb": "^2.1.15",
|
||||||
|
|
@ -8069,9 +8069,9 @@
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"webnative": {
|
"webnative": {
|
||||||
"version": "0.33.0-alpha-3",
|
"version": "0.33.0-alpha-4",
|
||||||
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.33.0-alpha-3.tgz",
|
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.33.0-alpha-4.tgz",
|
||||||
"integrity": "sha512-fx7ZNk1eKdt88RHG90fKg99xhBKsPIizOEgggr0HYrbM9G9O4vXGabt48QQF6K9pTuZmrrSW/RyqR/bxCHRc6A==",
|
"integrity": "sha512-P7TH9uwh31IS8PjHaRD74wQRjmVu1qiHnMwkjr2x0FiUixUwbrkvumL4qergeCIKQj//ZrrnkCZhebJ1efaylQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ipld/dag-cbor": "^7.0.0",
|
"@ipld/dag-cbor": "^7.0.0",
|
||||||
"@ipld/dag-pb": "^2.1.15",
|
"@ipld/dag-pb": "^2.1.15",
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"webnative": "0.33.0-alpha-3"
|
"webnative": "0.33.0-alpha-4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,12 +88,12 @@
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if !(username.length === 0) && usernameAvailable && usernameValid && !checkingUsername}
|
{#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 />
|
<CheckIcon />
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
{#if !(username.length === 0) && !checkingUsername && !(usernameAvailable && usernameValid)}
|
{#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 />
|
<XIcon />
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
export type Device = {
|
||||||
|
isMobile: boolean
|
||||||
|
}
|
||||||
|
|
@ -2,5 +2,17 @@ export type Session = {
|
||||||
username: string
|
username: string
|
||||||
authed: boolean
|
authed: boolean
|
||||||
loading: 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'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,29 +1,63 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { get } from 'svelte/store'
|
import { onMount } from 'svelte'
|
||||||
|
|
||||||
import '../global.css'
|
import '../global.css'
|
||||||
import { initialize } from '$lib/common/webnative'
|
import { initialize } from '$lib/common/webnative'
|
||||||
import { sessionStore, theme } from '../stores'
|
import { deviceStore, sessionStore, theme } from '../stores'
|
||||||
import { storeTheme } from '$lib/theme'
|
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'
|
import Header from '$components/Header.svelte'
|
||||||
|
|
||||||
|
let session: Session = null
|
||||||
|
|
||||||
theme.subscribe(val => {
|
theme.subscribe(val => {
|
||||||
storeTheme(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 () => {
|
const init = async () => {
|
||||||
await initialize()
|
await initialize()
|
||||||
|
|
||||||
// TODO: Remove this debugging statement
|
// TODO: Remove this debugging statement
|
||||||
const session = get(sessionStore)
|
|
||||||
console.log('session at init', session)
|
console.log('session at init', session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clearNotification = () => {
|
||||||
|
sessionStore.update(session => ({
|
||||||
|
...session,
|
||||||
|
error: null
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
init()
|
init()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:resize={setDevice} />
|
||||||
|
|
||||||
<div data-theme={$theme}>
|
<div data-theme={$theme}>
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
|
{#if session.error}
|
||||||
|
<Toast
|
||||||
|
kind="error"
|
||||||
|
message={errorToMessage(session.error)}
|
||||||
|
on:clear={clearNotification}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import type { Writable } from 'svelte/store'
|
||||||
import type FileSystem from 'webnative/fs/index'
|
import type FileSystem from 'webnative/fs/index'
|
||||||
|
|
||||||
import { loadTheme } from '$lib/theme'
|
import { loadTheme } from '$lib/theme'
|
||||||
|
import type { Device } from '$lib/device'
|
||||||
import type { Session } from '$lib/session'
|
import type { Session } from '$lib/session'
|
||||||
import type { Theme } from '$lib/theme'
|
import type { Theme } from '$lib/theme'
|
||||||
|
|
||||||
|
|
@ -15,3 +16,5 @@ export const sessionStore: Writable<Session> = writable({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const filesystemStore: Writable<FileSystem | null> = writable(null)
|
export const filesystemStore: Writable<FileSystem | null> = writable(null)
|
||||||
|
|
||||||
|
export const deviceStore: Writable<Device> = writable({ isMobile: true })
|
||||||
|
|
@ -11,6 +11,10 @@ module.exports = {
|
||||||
secondary: "#30aadd",
|
secondary: "#30aadd",
|
||||||
accent: "#00ffc6",
|
accent: "#00ffc6",
|
||||||
neutral: "#282828",
|
neutral: "#282828",
|
||||||
|
info: "#bfdbfe",
|
||||||
|
success: "#bbf7d0",
|
||||||
|
warning: "#fdba74",
|
||||||
|
error: "#fecaca",
|
||||||
"base-content": "#ffffff",
|
"base-content": "#ffffff",
|
||||||
"base-100": "#111111",
|
"base-100": "#111111",
|
||||||
"--rounded-box": "16px",
|
"--rounded-box": "16px",
|
||||||
|
|
@ -24,6 +28,10 @@ module.exports = {
|
||||||
secondary: "#30aadd",
|
secondary: "#30aadd",
|
||||||
accent: "#00ffc6",
|
accent: "#00ffc6",
|
||||||
neutral: "#e5e5e5",
|
neutral: "#e5e5e5",
|
||||||
|
info: "#bfdbfe",
|
||||||
|
success: "#bbf7d0",
|
||||||
|
warning: "#fdba74",
|
||||||
|
error: "#fecaca",
|
||||||
"base-content": "#000000",
|
"base-content": "#000000",
|
||||||
"base-100": "#ffffff",
|
"base-100": "#ffffff",
|
||||||
"--rounded-box": "16px",
|
"--rounded-box": "16px",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue