yaxa-svelte 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/components/ai/AiChat.svelte +1 -1
- package/dist/components/elements/Button.svelte +1 -1
- package/dist/components/elements/Button.svelte.d.ts +1 -1
- package/dist/components/elements/CodeBlock.svelte +1 -1
- package/dist/components/elements/CodeDiff.svelte +1 -1
- package/dist/components/elements/Icon.svelte +116 -40
- package/dist/components/elements/Icon.svelte.d.ts +25 -0
- package/dist/components/elements/Icon.test.d.ts +1 -0
- package/dist/components/elements/Icon.test.js +91 -0
- package/dist/components/layout/Footer.svelte +29 -9
- package/dist/components/layout/Header.svelte +2 -2
- package/dist/components/layout/YaxaApp.svelte +4 -4
- package/dist/components/legal/LegalDocument.svelte +98 -13
- package/dist/components/overlays/Toast.svelte +283 -0
- package/dist/components/overlays/Toast.svelte.d.ts +62 -0
- package/dist/components/overlays/Toast.test.d.ts +1 -0
- package/dist/components/overlays/Toast.test.js +122 -0
- package/dist/components/overlays/Toaster.svelte +72 -0
- package/dist/components/overlays/Toaster.svelte.d.ts +13 -0
- package/dist/components/saas/PricingCard.svelte +3 -3
- package/dist/components/theme/ThemeStudio.svelte +154 -69
- package/dist/components/theme/ThemeStudio.svelte.d.ts +1 -0
- package/dist/composables/useFormAction.svelte.js +1 -1
- package/dist/composables/useToast.svelte.d.ts +64 -0
- package/dist/composables/useToast.svelte.js +172 -0
- package/dist/composables/useToast.test.js +109 -40
- package/dist/index.d.ts +7 -4
- package/dist/index.js +4 -4
- package/dist/styles/yaxa.css +12 -17
- package/dist/theme/theme.svelte.d.ts +6 -0
- package/dist/theme/theme.svelte.js +25 -2
- package/dist/vite/index.js +2 -9
- package/dist/vite/index.test.js +1 -6
- package/package.json +1 -6
- package/dist/composables/useToast.d.ts +0 -19
- package/dist/composables/useToast.js +0 -34
package/README.md
CHANGED
|
@@ -31,8 +31,8 @@ _Nuxt UI v4 & Nuxt UI Pro Equivalent for SvelteKit 2.7+ & Svelte 5 with Built-in
|
|
|
31
31
|
- ♿ **Accessible by Default**: Headless primitives powered by **Bits UI**.
|
|
32
32
|
- 🚀 **100% DRY SEO Parity**: Automate dynamic Open Graph cards (`/api/og`), environment-aware `robots.txt`, XML sitemaps with human-readable `sitemap.xsl` stylesheets, PWA manifests, and Schema.org JSON-LD from a single `src/site.config.ts`.
|
|
33
33
|
- 🔐 **Batteries-Included SaaS Suite**: Pre-integrated **Better-Auth**, multi-dialect **Drizzle ORM** (Neon PostgreSQL & Turso LibSQL/SQLite), **Polar.sh** payments & webhook sync, and **Resend** transactional emails.
|
|
34
|
-
- 🧩 **
|
|
35
|
-
- 🛠️ **Composable Runes**: `useAuth`, `useShortcuts`, `useClipboard`, `useColorMode`, `useToast`, `useMediaQuery`, `useDebounce`, `useIdle`.
|
|
34
|
+
- 🧩 **50+ Production Components**: Elements, AI primitives, charts, advanced forms (`<RichTextEditor>`, `<PhoneInput>`, `<CreditCardInput>`), layout, overlays, native `<Toast>` / `<Toaster>`, and drop-in SaaS widgets (`<AuthCard>`, `<UserMenu>`, `<PricingTable>`, `<SubscriptionCard>`).
|
|
35
|
+
- 🛠️ **Composable Runes**: `useAuth`, `useShortcuts`, `useClipboard`, `useColorMode`, `useToast`, `useMediaQuery`, `useDebounce`, `useIdle`, `useGate`.
|
|
36
36
|
|
|
37
37
|
---
|
|
38
38
|
|
|
@@ -40,7 +40,7 @@ _Nuxt UI v4 & Nuxt UI Pro Equivalent for SvelteKit 2.7+ & Svelte 5 with Built-in
|
|
|
40
40
|
|
|
41
41
|
### 1. Install Dependencies
|
|
42
42
|
|
|
43
|
-
Install `yaxa-svelte` along with Tailwind CSS v4
|
|
43
|
+
Install `yaxa-svelte` along with Tailwind CSS v4:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
46
|
# Core package & icons
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
import PromptBar from './PromptBar.svelte';
|
|
50
50
|
import AiThought from './AiThought.svelte';
|
|
51
51
|
import AiToolCall from './AiToolCall.svelte';
|
|
52
|
-
import { useToast } from '../../composables/useToast';
|
|
52
|
+
import { useToast } from '../../composables/useToast.svelte';
|
|
53
53
|
|
|
54
54
|
let {
|
|
55
55
|
messages = [],
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import type { IconSource } from './Icon.svelte';
|
|
6
6
|
|
|
7
7
|
export const buttonVariants = tv({
|
|
8
|
-
base: 'inline-flex items-center justify-center font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 select-none active:scale-[0.98]',
|
|
8
|
+
base: 'inline-flex items-center justify-center font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 select-none active:scale-[0.98] whitespace-nowrap max-w-full overflow-hidden text-ellipsis shrink-0 [&>svg]:shrink-0',
|
|
9
9
|
variants: {
|
|
10
10
|
variant: {
|
|
11
11
|
solid: 'shadow-xs text-white',
|
|
@@ -30,7 +30,7 @@ export declare const buttonVariants: import("tailwind-variants").TVReturnType<{
|
|
|
30
30
|
square: {
|
|
31
31
|
true: "aspect-square p-0";
|
|
32
32
|
};
|
|
33
|
-
}, undefined, "inline-flex items-center justify-center font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 select-none active:scale-[0.98]", {
|
|
33
|
+
}, undefined, "inline-flex items-center justify-center font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 select-none active:scale-[0.98] whitespace-nowrap max-w-full overflow-hidden text-ellipsis shrink-0 [&>svg]:shrink-0", {
|
|
34
34
|
variant: {
|
|
35
35
|
solid: "shadow-xs text-white";
|
|
36
36
|
outline: "border bg-transparent shadow-xs";
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
import Button from './Button.svelte';
|
|
157
157
|
import Icon from './Icon.svelte';
|
|
158
158
|
import Badge from './Badge.svelte';
|
|
159
|
-
import { useToast } from '../../composables/useToast';
|
|
159
|
+
import { useToast } from '../../composables/useToast.svelte';
|
|
160
160
|
|
|
161
161
|
let {
|
|
162
162
|
original = '',
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
+
import { tv } from '../../utils/cn';
|
|
2
3
|
import type { Component, Snippet } from 'svelte';
|
|
3
4
|
|
|
5
|
+
export const iconVariants = tv({
|
|
6
|
+
base: 'inline-flex shrink-0 items-center justify-center',
|
|
7
|
+
variants: {
|
|
8
|
+
size: {
|
|
9
|
+
xs: 'w-3.5 h-3.5',
|
|
10
|
+
sm: 'w-4 h-4',
|
|
11
|
+
md: 'w-5 h-5',
|
|
12
|
+
lg: 'w-6 h-6',
|
|
13
|
+
xl: 'w-8 h-8'
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
size: 'md'
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
4
21
|
export type IconSource =
|
|
5
22
|
string | Component<{ class?: string; size?: string | number; [key: string]: any }>;
|
|
6
23
|
|
|
@@ -24,22 +41,11 @@
|
|
|
24
41
|
...restProps
|
|
25
42
|
}: IconProps = $props();
|
|
26
43
|
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
case 'sm':
|
|
33
|
-
return 'w-4 h-4';
|
|
34
|
-
case 'lg':
|
|
35
|
-
return 'w-6 h-6';
|
|
36
|
-
case 'xl':
|
|
37
|
-
return 'w-8 h-8';
|
|
38
|
-
case 'md':
|
|
39
|
-
default:
|
|
40
|
-
return 'w-5 h-5';
|
|
41
|
-
}
|
|
42
|
-
});
|
|
44
|
+
let classes = $derived(
|
|
45
|
+
typeof size === 'number'
|
|
46
|
+
? `inline-flex shrink-0 items-center justify-center w-[${size}px] h-[${size}px] ${className}`
|
|
47
|
+
: iconVariants({ size: size as 'xs' | 'sm' | 'md' | 'lg' | 'xl', class: className })
|
|
48
|
+
);
|
|
43
49
|
|
|
44
50
|
let IconComponent = $derived.by(() => {
|
|
45
51
|
if (icon && typeof icon !== 'string') return icon;
|
|
@@ -53,6 +59,43 @@
|
|
|
53
59
|
return null;
|
|
54
60
|
});
|
|
55
61
|
|
|
62
|
+
const iconAliases: Record<string, string> = {
|
|
63
|
+
close: 'cross',
|
|
64
|
+
x: 'cross',
|
|
65
|
+
'x-mark': 'cross',
|
|
66
|
+
pencil: 'edit',
|
|
67
|
+
lightning: 'bolt',
|
|
68
|
+
zap: 'bolt',
|
|
69
|
+
'arrow-right-on-rectangle': 'log-out',
|
|
70
|
+
logout: 'log-out',
|
|
71
|
+
document: 'file',
|
|
72
|
+
envelope: 'mail',
|
|
73
|
+
email: 'mail',
|
|
74
|
+
'shield-check': 'shield',
|
|
75
|
+
security: 'shield',
|
|
76
|
+
paintbrush: 'paint-brush',
|
|
77
|
+
swatches: 'swatch',
|
|
78
|
+
laptop: 'computer',
|
|
79
|
+
desktop: 'computer',
|
|
80
|
+
monitor: 'computer',
|
|
81
|
+
menu: 'bars-3',
|
|
82
|
+
adjustments: 'sliders',
|
|
83
|
+
'adjustments-horizontal': 'sliders',
|
|
84
|
+
'adjustments-vertical': 'sliders',
|
|
85
|
+
'square-3-stack-3d': 'layers',
|
|
86
|
+
'chart-bar': 'chart',
|
|
87
|
+
'bar-chart': 'chart',
|
|
88
|
+
book: 'book-open',
|
|
89
|
+
building: 'building-office-2',
|
|
90
|
+
'cursor-arrow-rays': 'cursor',
|
|
91
|
+
receipt: 'receipt-percent'
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
let resolvedIconName = $derived.by(() => {
|
|
95
|
+
if (!stringIconName) return null;
|
|
96
|
+
return iconAliases[stringIconName] || stringIconName;
|
|
97
|
+
});
|
|
98
|
+
|
|
56
99
|
// Common built-in SVGs for immediate zero-config use
|
|
57
100
|
const builtInIcons: Record<string, string> = {
|
|
58
101
|
check:
|
|
@@ -134,7 +177,7 @@
|
|
|
134
177
|
bolt: '<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
135
178
|
cube: '<path d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="3.27 6.96 12 12.01 20.73 6.96" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><line x1="12" y1="22.08" x2="12" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>',
|
|
136
179
|
swatch:
|
|
137
|
-
'<path d="
|
|
180
|
+
'<path d="M11 17a4 4 0 0 1-8 0V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M16.7 13H19a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><circle cx="7" cy="17" r="1.5" fill="currentColor"/><path d="m11 8 2.3-2.3a2.4 2.4 0 0 1 3.4.004L18.6 7.6a2.4 2.4 0 0 1 .002 3.4L13 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
138
181
|
star: '<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
139
182
|
photo:
|
|
140
183
|
'<rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" stroke-width="2" fill="none"/><circle cx="8.5" cy="8.5" r="1.5" fill="currentColor"/><polyline points="21 15 16 10 5 21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
@@ -142,8 +185,14 @@
|
|
|
142
185
|
'<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="14 2 14 8 20 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><line x1="8" y1="13" x2="16" y2="13" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="8" y1="17" x2="13" y2="17" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',
|
|
143
186
|
'clipboard-document':
|
|
144
187
|
'<path d="M16 4h2a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2h2" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/><rect x="8" y="2" width="8" height="4" rx="1" stroke="currentColor" stroke-width="2" fill="none"/><line x1="9" y1="12" x2="15" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="9" y1="16" x2="13" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',
|
|
188
|
+
'rotate-ccw':
|
|
189
|
+
'<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="3 3 3 8 8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
190
|
+
'rotate-cw':
|
|
191
|
+
'<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="21 3 21 8 16 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
145
192
|
'arrow-path':
|
|
146
|
-
'<path d="M21
|
|
193
|
+
'<path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="3 3 3 8 8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="16 16 21 16 21 21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
194
|
+
'refresh-cw':
|
|
195
|
+
'<path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="3 3 3 8 8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="16 16 21 16 21 21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
147
196
|
'code-bracket':
|
|
148
197
|
'<polyline points="16 18 22 12 16 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="8 6 2 12 8 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
149
198
|
'squares-2x2':
|
|
@@ -157,38 +206,65 @@
|
|
|
157
206
|
'layout-top':
|
|
158
207
|
'<rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" stroke-width="2" fill="none"/><line x1="3" y1="9" x2="21" y2="9" stroke="currentColor" stroke-width="2"/>',
|
|
159
208
|
'panel-right':
|
|
160
|
-
'<rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" stroke-width="2" fill="none"/><line x1="15" y1="3" x2="15" y2="21" stroke="currentColor" stroke-width="2"/>'
|
|
209
|
+
'<rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" stroke-width="2" fill="none"/><line x1="15" y1="3" x2="15" y2="21" stroke="currentColor" stroke-width="2"/>',
|
|
210
|
+
bell: '<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M13.73 21a2 2 0 0 1-3.46 0" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
211
|
+
fingerprint:
|
|
212
|
+
'<path d="M12 10a2 2 0 0 0-2 2c0 1.02-.1 2.51-.26 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/><path d="M14 13.12c0 2.38 0 6.38-1 8.88" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/><path d="M2 16h.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/><path d="M21.8 16c.2-2 .131-5.354 0-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/><path d="M5 19.5C5.5 18 6 15 6 12a6 6 0 0 1 .34-2" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/><path d="M8.65 22c.21-.66.45-1.32.57-2" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/><path d="M9 6.8a6 6 0 0 1 9 5.2v2" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/>',
|
|
213
|
+
key: '<path d="M21 2l-2 2m-1.5 1.5L14 9l-3-3L2 15l7 7 9-9 3.5-3.5z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><circle cx="7.5" cy="16.5" r="1.5" fill="currentColor"/>',
|
|
214
|
+
'credit-card':
|
|
215
|
+
'<rect x="2" y="5" width="20" height="14" rx="2" stroke="currentColor" stroke-width="2" fill="none"/><line x1="2" y1="10" x2="22" y2="10" stroke="currentColor" stroke-width="2"/><line x1="6" y1="15" x2="10" y2="15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',
|
|
216
|
+
home: '<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="9 22 9 12 15 12 15 22" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
217
|
+
settings:
|
|
218
|
+
'<circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2" fill="none"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
219
|
+
'log-out':
|
|
220
|
+
'<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="16 17 21 12 16 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><line x1="21" y1="12" x2="9" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>',
|
|
221
|
+
mail: '<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" stroke="currentColor" stroke-width="2" fill="none"/><polyline points="22,6 12,13 2,6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
222
|
+
inbox:
|
|
223
|
+
'<polyline points="22 12 16 12 14 15 10 15 8 12 2 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
224
|
+
palette:
|
|
225
|
+
'<circle cx="13.5" cy="6.5" r="1.5" fill="currentColor"/><circle cx="17.5" cy="10.5" r="1.5" fill="currentColor"/><circle cx="8.5" cy="7.5" r="1.5" fill="currentColor"/><circle cx="6.5" cy="12.5" r="1.5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
226
|
+
'paint-brush':
|
|
227
|
+
'<path d="m9.53 16.122 9.72-9.72a.75.75 0 0 0-.01-1.06l-4.58-4.58a.75.75 0 0 0-1.06 0l-9.72 9.72a3.75 3.75 0 0 0-1.1 2.652v2.368a.75.75 0 0 0 .75.75h2.368a3.75 3.75 0 0 0 2.652-1.12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
228
|
+
layers:
|
|
229
|
+
'<path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
230
|
+
sliders:
|
|
231
|
+
'<line x1="4" y1="21" x2="4" y2="14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="4" y1="10" x2="4" y2="3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="12" y1="21" x2="12" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="12" y1="8" x2="12" y2="3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="20" y1="21" x2="20" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="20" y1="12" x2="20" y2="3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="1" y1="14" x2="7" y2="14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="9" y1="8" x2="15" y2="8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="17" y1="16" x2="23" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',
|
|
232
|
+
shield:
|
|
233
|
+
'<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
234
|
+
chart:
|
|
235
|
+
'<line x1="12" y1="20" x2="12" y2="10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="18" y1="20" x2="18" y2="4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="6" y1="20" x2="6" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',
|
|
236
|
+
'building-office-2':
|
|
237
|
+
'<path d="M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M6 12H4a2 2 0 0 0-2 2v8h20v-8a2 2 0 0 0-2-2h-2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><line x1="10" y1="6" x2="10" y2="6.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="14" y1="6" x2="14" y2="6.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="10" y1="10" x2="10" y2="10.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="14" y1="10" x2="14" y2="10.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="10" y1="14" x2="10" y2="14.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="14" y1="14" x2="14" y2="14.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="10" y1="18" x2="14" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',
|
|
238
|
+
table:
|
|
239
|
+
'<rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" stroke-width="2" fill="none"/><line x1="3" y1="9" x2="21" y2="9" stroke="currentColor" stroke-width="2"/><line x1="3" y1="15" x2="21" y2="15" stroke="currentColor" stroke-width="2"/><line x1="9" y1="3" x2="9" y2="21" stroke="currentColor" stroke-width="2"/><line x1="15" y1="3" x2="15" y2="21" stroke="currentColor" stroke-width="2"/>',
|
|
240
|
+
window:
|
|
241
|
+
'<rect x="2" y="3" width="20" height="18" rx="2" stroke="currentColor" stroke-width="2" fill="none"/><line x1="2" y1="8" x2="22" y2="8" stroke="currentColor" stroke-width="2"/><circle cx="5" cy="5.5" r="1" fill="currentColor"/><circle cx="8" cy="5.5" r="1" fill="currentColor"/><circle cx="11" cy="5.5" r="1" fill="currentColor"/>',
|
|
242
|
+
'bars-3-bottom-right':
|
|
243
|
+
'<line x1="3" y1="6" x2="21" y2="6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="3" y1="12" x2="21" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><line x1="9" y1="18" x2="21" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',
|
|
244
|
+
cursor:
|
|
245
|
+
'<path d="m4 4 7 17 2.5-6.5L20 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
246
|
+
'book-open':
|
|
247
|
+
'<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>',
|
|
248
|
+
'receipt-percent':
|
|
249
|
+
'<path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><line x1="9" y1="9" x2="15" y2="15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><circle cx="9.5" cy="9.5" r=".75" fill="currentColor"/><circle cx="14.5" cy="14.5" r=".75" fill="currentColor"/>',
|
|
250
|
+
'document-magnifying-glass':
|
|
251
|
+
'<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><polyline points="14 2 14 8 20 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/><circle cx="11" cy="14" r="3" stroke="currentColor" stroke-width="2" fill="none"/><line x1="13.2" y1="16.2" x2="16.5" y2="19.5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>'
|
|
161
252
|
};
|
|
162
253
|
</script>
|
|
163
254
|
|
|
164
255
|
{#if children}
|
|
165
|
-
<span class=
|
|
256
|
+
<span class={classes}>
|
|
166
257
|
{@render children()}
|
|
167
258
|
</span>
|
|
168
259
|
{:else if IconComponent}
|
|
169
260
|
{@const RenderIcon = IconComponent}
|
|
170
|
-
<RenderIcon
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
{:else if stringIconName && builtInIcons[stringIconName]}
|
|
175
|
-
<svg
|
|
176
|
-
class="inline-flex shrink-0 items-center justify-center {sizeClass} {className}"
|
|
177
|
-
viewBox="0 0 24 24"
|
|
178
|
-
fill="none"
|
|
179
|
-
aria-hidden="true"
|
|
180
|
-
{...restProps}
|
|
181
|
-
>
|
|
182
|
-
{@html builtInIcons[stringIconName]}
|
|
261
|
+
<RenderIcon class={classes} {...restProps} />
|
|
262
|
+
{:else if resolvedIconName && builtInIcons[resolvedIconName]}
|
|
263
|
+
<svg class={classes} viewBox="0 0 24 24" fill="none" aria-hidden="true" {...restProps}>
|
|
264
|
+
{@html builtInIcons[resolvedIconName]}
|
|
183
265
|
</svg>
|
|
184
266
|
{:else}
|
|
185
|
-
<svg
|
|
186
|
-
class="inline-flex shrink-0 items-center justify-center {sizeClass} {className}"
|
|
187
|
-
viewBox="0 0 24 24"
|
|
188
|
-
fill="none"
|
|
189
|
-
aria-hidden="true"
|
|
190
|
-
{...restProps}
|
|
191
|
-
>
|
|
267
|
+
<svg class={classes} viewBox="0 0 24 24" fill="none" aria-hidden="true" {...restProps}>
|
|
192
268
|
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2" stroke-dasharray="4 4" />
|
|
193
269
|
</svg>
|
|
194
270
|
{/if}
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
import type { Component, Snippet } from 'svelte';
|
|
2
|
+
export declare const iconVariants: import("tailwind-variants").TVReturnType<{
|
|
3
|
+
size: {
|
|
4
|
+
xs: "w-3.5 h-3.5";
|
|
5
|
+
sm: "w-4 h-4";
|
|
6
|
+
md: "w-5 h-5";
|
|
7
|
+
lg: "w-6 h-6";
|
|
8
|
+
xl: "w-8 h-8";
|
|
9
|
+
};
|
|
10
|
+
}, undefined, "inline-flex shrink-0 items-center justify-center", {
|
|
11
|
+
size: {
|
|
12
|
+
xs: "w-3.5 h-3.5";
|
|
13
|
+
sm: "w-4 h-4";
|
|
14
|
+
md: "w-5 h-5";
|
|
15
|
+
lg: "w-6 h-6";
|
|
16
|
+
xl: "w-8 h-8";
|
|
17
|
+
};
|
|
18
|
+
}, undefined, import("tailwind-variants").TVReturnTypeLike<{
|
|
19
|
+
size: {
|
|
20
|
+
xs: "w-3.5 h-3.5";
|
|
21
|
+
sm: "w-4 h-4";
|
|
22
|
+
md: "w-5 h-5";
|
|
23
|
+
lg: "w-6 h-6";
|
|
24
|
+
xl: "w-8 h-8";
|
|
25
|
+
};
|
|
26
|
+
}, undefined>>;
|
|
2
27
|
export type IconSource = string | Component<{
|
|
3
28
|
class?: string;
|
|
4
29
|
size?: string | number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { renderComponent } from '../../testing';
|
|
3
|
+
import Icon from './Icon.svelte';
|
|
4
|
+
describe('Icon Component', () => {
|
|
5
|
+
it('renders built-in SVG icons by string name', () => {
|
|
6
|
+
const { target, cleanup } = renderComponent(Icon, {
|
|
7
|
+
name: 'check'
|
|
8
|
+
});
|
|
9
|
+
const svg = target.querySelector('svg');
|
|
10
|
+
expect(svg).toBeDefined();
|
|
11
|
+
expect(svg?.getAttribute('aria-hidden')).toBe('true');
|
|
12
|
+
expect(svg?.innerHTML).toContain('<path');
|
|
13
|
+
expect(svg?.getAttribute('class')).toContain('w-5 h-5');
|
|
14
|
+
cleanup();
|
|
15
|
+
});
|
|
16
|
+
it('resolves icon aliases correctly', () => {
|
|
17
|
+
const { target: t1, cleanup: c1 } = renderComponent(Icon, {
|
|
18
|
+
name: 'close'
|
|
19
|
+
});
|
|
20
|
+
expect(t1.querySelector('svg')?.innerHTML).toContain('18 6L6 18');
|
|
21
|
+
c1();
|
|
22
|
+
const { target: t2, cleanup: c2 } = renderComponent(Icon, {
|
|
23
|
+
name: 'zap'
|
|
24
|
+
});
|
|
25
|
+
expect(t2.querySelector('svg')?.innerHTML).toContain('13 2L3 14');
|
|
26
|
+
c2();
|
|
27
|
+
});
|
|
28
|
+
it('renders newly added common icons: bell, home, settings, credit-card, fingerprint, key, swatch, paint-brush', () => {
|
|
29
|
+
const names = [
|
|
30
|
+
'bell',
|
|
31
|
+
'home',
|
|
32
|
+
'settings',
|
|
33
|
+
'credit-card',
|
|
34
|
+
'fingerprint',
|
|
35
|
+
'key',
|
|
36
|
+
'mail',
|
|
37
|
+
'inbox',
|
|
38
|
+
'palette',
|
|
39
|
+
'shield',
|
|
40
|
+
'swatch',
|
|
41
|
+
'swatches',
|
|
42
|
+
'paint-brush',
|
|
43
|
+
'paintbrush',
|
|
44
|
+
'layers'
|
|
45
|
+
];
|
|
46
|
+
for (const name of names) {
|
|
47
|
+
const { target, cleanup } = renderComponent(Icon, { name });
|
|
48
|
+
const svg = target.querySelector('svg');
|
|
49
|
+
expect(svg).toBeDefined();
|
|
50
|
+
expect(svg?.innerHTML).not.toContain('stroke-dasharray="4 4"');
|
|
51
|
+
cleanup();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
it('renders fallback dashed circle for unknown icon name', () => {
|
|
55
|
+
const { target, cleanup } = renderComponent(Icon, {
|
|
56
|
+
name: 'non-existent-icon-xyz'
|
|
57
|
+
});
|
|
58
|
+
const svg = target.querySelector('svg');
|
|
59
|
+
expect(svg).toBeDefined();
|
|
60
|
+
expect(svg?.innerHTML).toContain('stroke-dasharray="4 4"');
|
|
61
|
+
cleanup();
|
|
62
|
+
});
|
|
63
|
+
it('supports all size variants and custom numeric size', () => {
|
|
64
|
+
const sizeMap = {
|
|
65
|
+
xs: 'w-3.5 h-3.5',
|
|
66
|
+
sm: 'w-4 h-4',
|
|
67
|
+
md: 'w-5 h-5',
|
|
68
|
+
lg: 'w-6 h-6',
|
|
69
|
+
xl: 'w-8 h-8'
|
|
70
|
+
};
|
|
71
|
+
for (const [size, expectedClass] of Object.entries(sizeMap)) {
|
|
72
|
+
const { target, cleanup } = renderComponent(Icon, {
|
|
73
|
+
name: 'sparkles',
|
|
74
|
+
size: size
|
|
75
|
+
});
|
|
76
|
+
const svg = target.querySelector('svg');
|
|
77
|
+
expect(svg?.getAttribute('class')).toContain(expectedClass);
|
|
78
|
+
cleanup();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
it('merges custom classes', () => {
|
|
82
|
+
const { target, cleanup } = renderComponent(Icon, {
|
|
83
|
+
name: 'sparkles',
|
|
84
|
+
class: 'text-primary-500 animate-spin'
|
|
85
|
+
});
|
|
86
|
+
const svg = target.querySelector('svg');
|
|
87
|
+
expect(svg?.getAttribute('class')).toContain('text-primary-500');
|
|
88
|
+
expect(svg?.getAttribute('class')).toContain('animate-spin');
|
|
89
|
+
cleanup();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -31,6 +31,18 @@
|
|
|
31
31
|
legalLinks?.privacy || legalLinks?.terms || legalLinks?.refunds || legalLinks?.impressum
|
|
32
32
|
)
|
|
33
33
|
);
|
|
34
|
+
|
|
35
|
+
let copiedEmail = $state(false);
|
|
36
|
+
|
|
37
|
+
function copyEmail(email: string) {
|
|
38
|
+
if (typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
39
|
+
navigator.clipboard.writeText(email);
|
|
40
|
+
copiedEmail = true;
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
copiedEmail = false;
|
|
43
|
+
}, 2000);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
34
46
|
</script>
|
|
35
47
|
|
|
36
48
|
<footer
|
|
@@ -56,20 +68,28 @@
|
|
|
56
68
|
{currentConfig.description}
|
|
57
69
|
</p>
|
|
58
70
|
{#if currentConfig.email}
|
|
59
|
-
<
|
|
60
|
-
Contact
|
|
71
|
+
<div class="flex items-center gap-2 text-xs text-neutral-500 dark:text-neutral-400">
|
|
72
|
+
<span>Contact:</span>
|
|
61
73
|
<a
|
|
62
74
|
href="mailto:{currentConfig.email}"
|
|
63
|
-
class="font-medium text-neutral-700 hover:underline dark:text-neutral-300"
|
|
75
|
+
class="font-medium text-neutral-700 transition-colors hover:text-primary-600 hover:underline dark:text-neutral-300 dark:hover:text-primary-400"
|
|
64
76
|
>
|
|
65
77
|
{currentConfig.email}
|
|
66
78
|
</a>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
79
|
+
<button
|
|
80
|
+
type="button"
|
|
81
|
+
onclick={() => copyEmail(currentConfig.email!)}
|
|
82
|
+
class="inline-flex items-center justify-center rounded p-1 text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-neutral-700 dark:hover:bg-neutral-800 dark:hover:text-neutral-200"
|
|
83
|
+
aria-label="Copy email address"
|
|
84
|
+
title={copiedEmail ? 'Copied to clipboard!' : 'Copy email address'}
|
|
85
|
+
>
|
|
86
|
+
{#if copiedEmail}
|
|
87
|
+
<Icon name="check" size="xs" class="text-emerald-500" />
|
|
88
|
+
{:else}
|
|
89
|
+
<Icon name="clipboard" size="xs" />
|
|
90
|
+
{/if}
|
|
91
|
+
</button>
|
|
92
|
+
</div>
|
|
73
93
|
{/if}
|
|
74
94
|
|
|
75
95
|
<div class="pt-2 text-xs text-neutral-500 dark:text-neutral-400">
|
|
@@ -104,9 +104,9 @@
|
|
|
104
104
|
aria-label="Toggle color mode"
|
|
105
105
|
>
|
|
106
106
|
{#if theme.resolvedTheme === 'dark'}
|
|
107
|
-
<Icon name="
|
|
107
|
+
<Icon name="moon" size="sm" class="text-primary-400" />
|
|
108
108
|
{:else}
|
|
109
|
-
<Icon name="
|
|
109
|
+
<Icon name="sun" size="sm" class="text-amber-500" />
|
|
110
110
|
{/if}
|
|
111
111
|
</Button>
|
|
112
112
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
-
import
|
|
3
|
+
import Toaster from '../overlays/Toaster.svelte';
|
|
4
4
|
import { Tooltip } from 'bits-ui';
|
|
5
5
|
import { type SiteConfig, DEFAULT_SITE_CONFIG } from '../../site/config';
|
|
6
|
-
import {
|
|
6
|
+
import { themeInitScript } from '../../theme/theme.svelte';
|
|
7
7
|
import Favicons from '../seo/Favicons.svelte';
|
|
8
8
|
import Seo from '../seo/Seo.svelte';
|
|
9
9
|
import { initYaxaState, type AuthUserContext } from '../../site/context';
|
|
@@ -53,5 +53,5 @@
|
|
|
53
53
|
</div>
|
|
54
54
|
</Tooltip.Provider>
|
|
55
55
|
|
|
56
|
-
<!-- Global Toast Container
|
|
57
|
-
<Toaster richColors
|
|
56
|
+
<!-- Global Toast Container -->
|
|
57
|
+
<Toaster richColors position="top-right" closeButton />
|