add svelte-sonner for toast notifications
This commit is contained in:
parent
1933f3d8e9
commit
513c7660f5
6 changed files with 91 additions and 33 deletions
|
|
@ -79,6 +79,7 @@
|
|||
"modern-normalize": "^3.0.1",
|
||||
"runed": "^0.31.1",
|
||||
"svelecte": "^5.3.0",
|
||||
"svelte-sonner": "^1.0.7",
|
||||
"wx-grid-data-provider": "^2.2.0",
|
||||
"wx-svelte-grid": "^2.0.0",
|
||||
"zod": "^4.1.5"
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ importers:
|
|||
svelecte:
|
||||
specifier: ^5.3.0
|
||||
version: 5.3.0(svelte@5.38.7)
|
||||
svelte-sonner:
|
||||
specifier: ^1.0.7
|
||||
version: 1.0.7(svelte@5.38.7)
|
||||
wx-grid-data-provider:
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
|
|
@ -2390,6 +2393,11 @@ packages:
|
|||
run-parallel@1.2.0:
|
||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||
|
||||
runed@0.28.0:
|
||||
resolution: {integrity: sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ==}
|
||||
peerDependencies:
|
||||
svelte: ^5.7.0
|
||||
|
||||
runed@0.29.2:
|
||||
resolution: {integrity: sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA==}
|
||||
peerDependencies:
|
||||
|
|
@ -2557,6 +2565,11 @@ packages:
|
|||
typescript:
|
||||
optional: true
|
||||
|
||||
svelte-sonner@1.0.7:
|
||||
resolution: {integrity: sha512-1EUFYmd7q/xfs2qCHwJzGPh9n5VJ3X6QjBN10fof2vxgy8fYE7kVfZ7uGnd7i6fQaWIr5KvXcwYXE/cmTEjk5A==}
|
||||
peerDependencies:
|
||||
svelte: ^5.0.0
|
||||
|
||||
svelte-toolbelt@0.9.3:
|
||||
resolution: {integrity: sha512-HCSWxCtVmv+c6g1ACb8LTwHVbDqLKJvHpo6J8TaqwUme2hj9ATJCpjCPNISR1OCq2Q4U1KT41if9ON0isINQZw==}
|
||||
engines: {node: '>=18', pnpm: '>=8.7.0'}
|
||||
|
|
@ -5279,6 +5292,11 @@ snapshots:
|
|||
dependencies:
|
||||
queue-microtask: 1.2.3
|
||||
|
||||
runed@0.28.0(svelte@5.38.7):
|
||||
dependencies:
|
||||
esm-env: 1.2.2
|
||||
svelte: 5.38.7
|
||||
|
||||
runed@0.29.2(svelte@5.38.7):
|
||||
dependencies:
|
||||
esm-env: 1.2.2
|
||||
|
|
@ -5424,6 +5442,11 @@ snapshots:
|
|||
sass: 1.92.1
|
||||
typescript: 5.9.2
|
||||
|
||||
svelte-sonner@1.0.7(svelte@5.38.7):
|
||||
dependencies:
|
||||
runed: 0.28.0(svelte@5.38.7)
|
||||
svelte: 5.38.7
|
||||
|
||||
svelte-toolbelt@0.9.3(svelte@5.38.7):
|
||||
dependencies:
|
||||
clsx: 2.1.1
|
||||
|
|
|
|||
32
src/app.scss
32
src/app.scss
|
|
@ -78,3 +78,35 @@ $font-size-base: 16px;
|
|||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// Toast notification overrides (svelte-sonner)
|
||||
[data-sonner-toaster] {
|
||||
--normal-bg: var(--toast-bg);
|
||||
--normal-text: var(--toast-text);
|
||||
--normal-border: var(--toast-border);
|
||||
|
||||
--success-bg: var(--toast-success-bg);
|
||||
--success-text: var(--toast-success-text);
|
||||
--success-border: var(--toast-success-text);
|
||||
|
||||
--error-bg: var(--toast-error-bg);
|
||||
--error-text: var(--toast-error-text);
|
||||
--error-border: var(--toast-error-text);
|
||||
|
||||
--warning-bg: var(--toast-warning-bg);
|
||||
--warning-text: var(--toast-warning-text);
|
||||
--warning-border: var(--toast-warning-text);
|
||||
|
||||
--info-bg: var(--toast-info-bg);
|
||||
--info-text: var(--toast-info-text);
|
||||
--info-border: var(--toast-info-text);
|
||||
|
||||
font-family: var(--font-family);
|
||||
z-index: 102; // Above dialogs (101)
|
||||
}
|
||||
|
||||
[data-sonner-toast] {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,35 @@
|
|||
<svelte:options runes={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import { toast } from 'svelte-sonner'
|
||||
|
||||
interface Props {
|
||||
value: string | number
|
||||
}
|
||||
|
||||
let { value }: Props = $props()
|
||||
|
||||
let copied = $state(false)
|
||||
|
||||
async function copyToClipboard() {
|
||||
if (!value) return
|
||||
try {
|
||||
await navigator.clipboard.writeText(String(value))
|
||||
copied = true
|
||||
setTimeout(() => {
|
||||
copied = false
|
||||
}, 1500)
|
||||
toast.success('Copied to clipboard')
|
||||
} catch (err) {
|
||||
console.error('Failed to copy:', err)
|
||||
toast.error('Failed to copy')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button class="copyable-text" class:copied onclick={copyToClipboard} title="Click to copy">
|
||||
<button class="copyable-text" onclick={copyToClipboard} title="Click to copy">
|
||||
<span class="text">{value}</span>
|
||||
{#if copied}
|
||||
<span class="copied-indicator">Copied!</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$src/themes/colors' as colors;
|
||||
@use '$src/themes/spacing' as spacing;
|
||||
@use '$src/themes/typography' as typography;
|
||||
|
||||
.copyable-text {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: spacing.$unit;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
|
|
@ -52,10 +43,6 @@
|
|||
&:hover {
|
||||
color: colors.$grey-10;
|
||||
}
|
||||
|
||||
&.copied .text {
|
||||
color: colors.$grey-50;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
|
|
@ -63,19 +50,4 @@
|
|||
text-decoration-style: dotted;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
.copied-indicator {
|
||||
font-size: typography.$font-small;
|
||||
color: colors.$grey-50;
|
||||
animation: fadeIn 0.15s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { browser } from '$app/environment'
|
||||
import { QueryClientProvider } from '@tanstack/svelte-query'
|
||||
import { Toaster } from 'svelte-sonner'
|
||||
import type { LayoutData } from './$types'
|
||||
|
||||
const { data, children } = $props<{
|
||||
|
|
@ -18,5 +19,6 @@
|
|||
</svelte:head>
|
||||
|
||||
<QueryClientProvider client={data.queryClient}>
|
||||
<Toaster position="bottom-right" richColors toastOptions={{ duration: 4000 }} />
|
||||
{@render children?.()}
|
||||
</QueryClientProvider>
|
||||
|
|
|
|||
|
|
@ -376,6 +376,20 @@
|
|||
--light-shadow-hover: #{colors.$light--shadow--light--hover};
|
||||
--light-accent: #{colors.$light--bg--light};
|
||||
|
||||
// Toast notifications
|
||||
--toast-bg: #{colors.$grey-100};
|
||||
--toast-text: #{colors.$text--primary--color--light};
|
||||
--toast-text-secondary: #{colors.$text--secondary--color--light};
|
||||
--toast-border: #{colors.$border--subtle--light};
|
||||
--toast-success-bg: #e8f5e9;
|
||||
--toast-success-text: #2e7d32;
|
||||
--toast-error-bg: #{colors.$error--bg--light};
|
||||
--toast-error-text: #{colors.$error};
|
||||
--toast-warning-bg: #{colors.$notice--bg--light};
|
||||
--toast-warning-text: #{colors.$notice--text--light};
|
||||
--toast-info-bg: #e3f2fd;
|
||||
--toast-info-text: #1565c0;
|
||||
|
||||
// Gradients
|
||||
--hero-gradient: #{effects.$hero--gradient--light};
|
||||
--hero-gradient-overlay: #{effects.$hero--gradient--light--overlay};
|
||||
|
|
@ -728,6 +742,20 @@
|
|||
--light-shadow-hover: #{colors.$light--shadow--dark--hover};
|
||||
--light-accent: #{colors.$light--bg--dark};
|
||||
|
||||
// Toast notifications
|
||||
--toast-bg: #{colors.$grey-20};
|
||||
--toast-text: #{colors.$text--primary--color--dark};
|
||||
--toast-text-secondary: #{colors.$text--secondary--color--dark};
|
||||
--toast-border: #{colors.$border--subtle--dark};
|
||||
--toast-success-bg: #1b3d1f;
|
||||
--toast-success-text: #66bb6a;
|
||||
--toast-error-bg: #{colors.$error--bg--dark};
|
||||
--toast-error-text: #{colors.$error};
|
||||
--toast-warning-bg: #{colors.$notice--bg--dark};
|
||||
--toast-warning-text: #{colors.$notice--text--dark};
|
||||
--toast-info-bg: #0d2744;
|
||||
--toast-info-text: #64b5f6;
|
||||
|
||||
// Gradients
|
||||
--hero-gradient: #{effects.$hero--gradient--dark};
|
||||
--hero-gradient-overlay: #{effects.$hero--gradient--dark--overlay};
|
||||
|
|
|
|||
Loading…
Reference in a new issue