yaxa-svelte 1.0.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/LICENSE +21 -0
- package/README.md +163 -0
- package/dist/assets/favicon.svg +15 -0
- package/dist/components/elements/Avatar.svelte +106 -0
- package/dist/components/elements/Avatar.svelte.d.ts +40 -0
- package/dist/components/elements/AvatarGroup.svelte +18 -0
- package/dist/components/elements/AvatarGroup.svelte.d.ts +8 -0
- package/dist/components/elements/Badge.svelte +202 -0
- package/dist/components/elements/Badge.svelte.d.ts +75 -0
- package/dist/components/elements/Button.svelte +300 -0
- package/dist/components/elements/Button.svelte.d.ts +109 -0
- package/dist/components/elements/ButtonGroup.svelte +22 -0
- package/dist/components/elements/ButtonGroup.svelte.d.ts +9 -0
- package/dist/components/elements/Chip.svelte +117 -0
- package/dist/components/elements/Chip.svelte.d.ts +15 -0
- package/dist/components/elements/DataTable.svelte +222 -0
- package/dist/components/elements/DataTable.svelte.d.ts +43 -0
- package/dist/components/elements/Icon.svelte +87 -0
- package/dist/components/elements/Icon.svelte.d.ts +10 -0
- package/dist/components/elements/Kbd.svelte +37 -0
- package/dist/components/elements/Kbd.svelte.d.ts +32 -0
- package/dist/components/elements/Link.svelte +63 -0
- package/dist/components/elements/Link.svelte.d.ts +15 -0
- package/dist/components/elements/Logo.svelte +77 -0
- package/dist/components/elements/Logo.svelte.d.ts +9 -0
- package/dist/components/elements/Meter.svelte +87 -0
- package/dist/components/elements/Meter.svelte.d.ts +14 -0
- package/dist/components/elements/Progress.svelte +63 -0
- package/dist/components/elements/Progress.svelte.d.ts +49 -0
- package/dist/components/elements/Skeleton.svelte +12 -0
- package/dist/components/elements/Skeleton.svelte.d.ts +6 -0
- package/dist/components/elements/Spinner.svelte +39 -0
- package/dist/components/elements/Spinner.svelte.d.ts +7 -0
- package/dist/components/forms/Checkbox.svelte +77 -0
- package/dist/components/forms/Checkbox.svelte.d.ts +17 -0
- package/dist/components/forms/ColorPicker.svelte +142 -0
- package/dist/components/forms/ColorPicker.svelte.d.ts +10 -0
- package/dist/components/forms/Form.svelte +84 -0
- package/dist/components/forms/Form.svelte.d.ts +14 -0
- package/dist/components/forms/FormField.svelte +56 -0
- package/dist/components/forms/FormField.svelte.d.ts +14 -0
- package/dist/components/forms/Input.svelte +138 -0
- package/dist/components/forms/Input.svelte.d.ts +58 -0
- package/dist/components/forms/RadioGroup.svelte +74 -0
- package/dist/components/forms/RadioGroup.svelte.d.ts +17 -0
- package/dist/components/forms/Select.svelte +91 -0
- package/dist/components/forms/Select.svelte.d.ts +50 -0
- package/dist/components/forms/Slider.svelte +37 -0
- package/dist/components/forms/Slider.svelte.d.ts +12 -0
- package/dist/components/forms/Switch.svelte +81 -0
- package/dist/components/forms/Switch.svelte.d.ts +53 -0
- package/dist/components/forms/Textarea.svelte +73 -0
- package/dist/components/forms/Textarea.svelte.d.ts +64 -0
- package/dist/components/layout/Card.svelte +89 -0
- package/dist/components/layout/Card.svelte.d.ts +64 -0
- package/dist/components/layout/Container.svelte +36 -0
- package/dist/components/layout/Container.svelte.d.ts +37 -0
- package/dist/components/layout/Divider.svelte +45 -0
- package/dist/components/layout/Divider.svelte.d.ts +11 -0
- package/dist/components/layout/Footer.svelte +96 -0
- package/dist/components/layout/Footer.svelte.d.ts +10 -0
- package/dist/components/layout/Header.svelte +175 -0
- package/dist/components/layout/Header.svelte.d.ts +12 -0
- package/dist/components/layout/Section.svelte +62 -0
- package/dist/components/layout/Section.svelte.d.ts +14 -0
- package/dist/components/layout/YaxaApp.svelte +48 -0
- package/dist/components/layout/YaxaApp.svelte.d.ts +12 -0
- package/dist/components/navigation/Breadcrumb.svelte +58 -0
- package/dist/components/navigation/Breadcrumb.svelte.d.ts +13 -0
- package/dist/components/navigation/CommandPalette.svelte +201 -0
- package/dist/components/navigation/CommandPalette.svelte.d.ts +19 -0
- package/dist/components/navigation/DropdownMenu.svelte +75 -0
- package/dist/components/navigation/DropdownMenu.svelte.d.ts +20 -0
- package/dist/components/navigation/Pagination.svelte +106 -0
- package/dist/components/navigation/Pagination.svelte.d.ts +10 -0
- package/dist/components/navigation/Tabs.svelte +91 -0
- package/dist/components/navigation/Tabs.svelte.d.ts +18 -0
- package/dist/components/overlays/Accordion.svelte +54 -0
- package/dist/components/overlays/Accordion.svelte.d.ts +16 -0
- package/dist/components/overlays/Alert.svelte +110 -0
- package/dist/components/overlays/Alert.svelte.d.ts +37 -0
- package/dist/components/overlays/ContextMenu.svelte +67 -0
- package/dist/components/overlays/ContextMenu.svelte.d.ts +21 -0
- package/dist/components/overlays/Modal.svelte +99 -0
- package/dist/components/overlays/Modal.svelte.d.ts +40 -0
- package/dist/components/overlays/Popover.svelte +33 -0
- package/dist/components/overlays/Popover.svelte.d.ts +11 -0
- package/dist/components/overlays/Slideover.svelte +102 -0
- package/dist/components/overlays/Slideover.svelte.d.ts +37 -0
- package/dist/components/overlays/Tooltip.svelte +39 -0
- package/dist/components/overlays/Tooltip.svelte.d.ts +12 -0
- package/dist/components/saas/AuthCard.svelte +273 -0
- package/dist/components/saas/AuthCard.svelte.d.ts +16 -0
- package/dist/components/saas/PricingCard.svelte +166 -0
- package/dist/components/saas/PricingCard.svelte.d.ts +19 -0
- package/dist/components/saas/PricingTable.svelte +139 -0
- package/dist/components/saas/PricingTable.svelte.d.ts +11 -0
- package/dist/components/saas/SubscriptionCard.svelte +162 -0
- package/dist/components/saas/SubscriptionCard.svelte.d.ts +16 -0
- package/dist/components/saas/UserMenu.svelte +137 -0
- package/dist/components/saas/UserMenu.svelte.d.ts +19 -0
- package/dist/components/seo/Favicons.svelte +22 -0
- package/dist/components/seo/Favicons.svelte.d.ts +8 -0
- package/dist/components/seo/OgImage.svelte +61 -0
- package/dist/components/seo/OgImage.svelte.d.ts +12 -0
- package/dist/components/seo/Seo.svelte +170 -0
- package/dist/components/seo/Seo.svelte.d.ts +21 -0
- package/dist/composables/useAuth.svelte.d.ts +23 -0
- package/dist/composables/useAuth.svelte.js +157 -0
- package/dist/composables/useClipboard.svelte.d.ts +9 -0
- package/dist/composables/useClipboard.svelte.js +36 -0
- package/dist/composables/useColorMode.svelte.d.ts +8 -0
- package/dist/composables/useColorMode.svelte.js +20 -0
- package/dist/composables/useDebounce.svelte.d.ts +3 -0
- package/dist/composables/useDebounce.svelte.js +17 -0
- package/dist/composables/useMediaQuery.svelte.d.ts +3 -0
- package/dist/composables/useMediaQuery.svelte.js +17 -0
- package/dist/composables/useShortcuts.svelte.d.ts +10 -0
- package/dist/composables/useShortcuts.svelte.js +50 -0
- package/dist/composables/useToast.d.ts +19 -0
- package/dist/composables/useToast.js +34 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +92 -0
- package/dist/server/auth/hook.d.ts +14 -0
- package/dist/server/auth/hook.js +36 -0
- package/dist/server/auth/index.d.ts +39 -0
- package/dist/server/auth/index.js +69 -0
- package/dist/server/db/index.d.ts +18 -0
- package/dist/server/db/index.js +43 -0
- package/dist/server/db/schema-pg.d.ts +977 -0
- package/dist/server/db/schema-pg.js +83 -0
- package/dist/server/db/schema-sqlite.d.ts +1045 -0
- package/dist/server/db/schema-sqlite.js +83 -0
- package/dist/server/db/types.d.ts +44 -0
- package/dist/server/db/types.js +1 -0
- package/dist/server/email/index.d.ts +27 -0
- package/dist/server/email/index.js +79 -0
- package/dist/server/polar/index.d.ts +29 -0
- package/dist/server/polar/index.js +49 -0
- package/dist/server/polar/webhook.d.ts +16 -0
- package/dist/server/polar/webhook.js +118 -0
- package/dist/site/config.d.ts +63 -0
- package/dist/site/config.js +48 -0
- package/dist/site/context.d.ts +11 -0
- package/dist/site/context.js +23 -0
- package/dist/site/hook.d.ts +15 -0
- package/dist/site/hook.js +38 -0
- package/dist/site/manifest.d.ts +6 -0
- package/dist/site/manifest.js +32 -0
- package/dist/site/og.d.ts +14 -0
- package/dist/site/og.js +116 -0
- package/dist/site/robots.d.ts +10 -0
- package/dist/site/robots.js +54 -0
- package/dist/site/schema.d.ts +67 -0
- package/dist/site/schema.js +67 -0
- package/dist/site/seo-helpers.d.ts +36 -0
- package/dist/site/seo-helpers.js +21 -0
- package/dist/site/sitemap-xsl.d.ts +6 -0
- package/dist/site/sitemap-xsl.js +164 -0
- package/dist/site/sitemap.d.ts +20 -0
- package/dist/site/sitemap.js +61 -0
- package/dist/styles/yaxa.css +84 -0
- package/dist/theme/theme.svelte.d.ts +74 -0
- package/dist/theme/theme.svelte.js +421 -0
- package/dist/utils/cn.d.ts +3 -0
- package/dist/utils/cn.js +3 -0
- package/dist/vite/index.d.ts +20 -0
- package/dist/vite/index.js +29 -0
- package/package.json +108 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
value: number;
|
|
4
|
+
min?: number;
|
|
5
|
+
max?: number;
|
|
6
|
+
label?: string;
|
|
7
|
+
valueLabel?: string;
|
|
8
|
+
color?: 'primary' | 'success' | 'warning' | 'error' | 'neutral';
|
|
9
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
10
|
+
showValue?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
value,
|
|
16
|
+
min = 0,
|
|
17
|
+
max = 100,
|
|
18
|
+
label,
|
|
19
|
+
valueLabel,
|
|
20
|
+
color = 'primary',
|
|
21
|
+
size = 'md',
|
|
22
|
+
showValue = true,
|
|
23
|
+
class: className = ''
|
|
24
|
+
}: Props = $props();
|
|
25
|
+
|
|
26
|
+
let percentage = $derived(
|
|
27
|
+
Math.min(100, Math.max(0, Math.round(((value - min) / (max - min)) * 100)))
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
let formattedValue = $derived(valueLabel || `${percentage}%`);
|
|
31
|
+
|
|
32
|
+
let heightClass = $derived.by(() => {
|
|
33
|
+
switch (size) {
|
|
34
|
+
case 'xs':
|
|
35
|
+
return 'h-1';
|
|
36
|
+
case 'sm':
|
|
37
|
+
return 'h-1.5';
|
|
38
|
+
case 'lg':
|
|
39
|
+
return 'h-3.5';
|
|
40
|
+
case 'md':
|
|
41
|
+
default:
|
|
42
|
+
return 'h-2.5';
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
let colorClass = $derived.by(() => {
|
|
47
|
+
switch (color) {
|
|
48
|
+
case 'success':
|
|
49
|
+
return 'bg-emerald-500';
|
|
50
|
+
case 'warning':
|
|
51
|
+
return 'bg-amber-500';
|
|
52
|
+
case 'error':
|
|
53
|
+
return 'bg-red-500';
|
|
54
|
+
case 'neutral':
|
|
55
|
+
return 'bg-neutral-600';
|
|
56
|
+
case 'primary':
|
|
57
|
+
default:
|
|
58
|
+
return 'bg-primary-600';
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<div class="w-full space-y-1.5 {className}">
|
|
64
|
+
{#if label || showValue}
|
|
65
|
+
<div class="flex items-center justify-between text-sm">
|
|
66
|
+
{#if label}
|
|
67
|
+
<span class="font-medium text-neutral-700 dark:text-neutral-300">{label}</span>
|
|
68
|
+
{/if}
|
|
69
|
+
{#if showValue}
|
|
70
|
+
<span class="font-mono text-neutral-500 dark:text-neutral-400">{formattedValue}</span>
|
|
71
|
+
{/if}
|
|
72
|
+
</div>
|
|
73
|
+
{/if}
|
|
74
|
+
|
|
75
|
+
<div
|
|
76
|
+
class="relative w-full overflow-hidden rounded-full bg-neutral-200 dark:bg-neutral-800 {heightClass}"
|
|
77
|
+
role="meter"
|
|
78
|
+
aria-valuenow={value}
|
|
79
|
+
aria-valuemin={min}
|
|
80
|
+
aria-valuemax={max}
|
|
81
|
+
>
|
|
82
|
+
<div
|
|
83
|
+
class="h-full rounded-full transition-all duration-500 ease-out {colorClass}"
|
|
84
|
+
style="width: {percentage}%;"
|
|
85
|
+
></div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
value: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
valueLabel?: string;
|
|
7
|
+
color?: 'primary' | 'success' | 'warning' | 'error' | 'neutral';
|
|
8
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
9
|
+
showValue?: boolean;
|
|
10
|
+
class?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const Meter: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type Meter = ReturnType<typeof Meter>;
|
|
14
|
+
export default Meter;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { tv, type VariantProps } from '../../utils/cn';
|
|
3
|
+
|
|
4
|
+
export const progressVariants = tv({
|
|
5
|
+
base: 'relative w-full overflow-hidden rounded-full bg-neutral-200 dark:bg-neutral-800',
|
|
6
|
+
variants: {
|
|
7
|
+
size: {
|
|
8
|
+
xs: 'h-1',
|
|
9
|
+
sm: 'h-1.5',
|
|
10
|
+
md: 'h-2.5',
|
|
11
|
+
lg: 'h-4'
|
|
12
|
+
},
|
|
13
|
+
color: {
|
|
14
|
+
primary: '[&>div]:bg-primary-600',
|
|
15
|
+
success: '[&>div]:bg-emerald-600',
|
|
16
|
+
warning: '[&>div]:bg-amber-600',
|
|
17
|
+
error: '[&>div]:bg-rose-600'
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
size: 'md',
|
|
22
|
+
color: 'primary'
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export type ProgressProps = VariantProps<typeof progressVariants> & {
|
|
27
|
+
value?: number;
|
|
28
|
+
max?: number;
|
|
29
|
+
class?: string;
|
|
30
|
+
};
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<script lang="ts">
|
|
34
|
+
let {
|
|
35
|
+
value,
|
|
36
|
+
max = 100,
|
|
37
|
+
size = 'md',
|
|
38
|
+
color = 'primary',
|
|
39
|
+
class: className = ''
|
|
40
|
+
}: ProgressProps = $props();
|
|
41
|
+
|
|
42
|
+
let percentage = $derived.by(() => {
|
|
43
|
+
if (value === undefined) return undefined;
|
|
44
|
+
return Math.min(100, Math.max(0, (value / max) * 100));
|
|
45
|
+
});
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<div
|
|
49
|
+
class={progressVariants({ size, color, class: className })}
|
|
50
|
+
role="progressbar"
|
|
51
|
+
aria-valuenow={value}
|
|
52
|
+
aria-valuemin={0}
|
|
53
|
+
aria-valuemax={max}
|
|
54
|
+
>
|
|
55
|
+
{#if percentage !== undefined}
|
|
56
|
+
<div
|
|
57
|
+
class="h-full rounded-full transition-all duration-300 ease-in-out"
|
|
58
|
+
style="width: {percentage}%"
|
|
59
|
+
></div>
|
|
60
|
+
{:else}
|
|
61
|
+
<div class="h-full w-1/3 animate-pulse rounded-full"></div>
|
|
62
|
+
{/if}
|
|
63
|
+
</div>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type VariantProps } from '../../utils/cn';
|
|
2
|
+
export declare const progressVariants: import("tailwind-variants").TVReturnType<{
|
|
3
|
+
size: {
|
|
4
|
+
xs: "h-1";
|
|
5
|
+
sm: "h-1.5";
|
|
6
|
+
md: "h-2.5";
|
|
7
|
+
lg: "h-4";
|
|
8
|
+
};
|
|
9
|
+
color: {
|
|
10
|
+
primary: "[&>div]:bg-primary-600";
|
|
11
|
+
success: "[&>div]:bg-emerald-600";
|
|
12
|
+
warning: "[&>div]:bg-amber-600";
|
|
13
|
+
error: "[&>div]:bg-rose-600";
|
|
14
|
+
};
|
|
15
|
+
}, undefined, "relative w-full overflow-hidden rounded-full bg-neutral-200 dark:bg-neutral-800", {
|
|
16
|
+
size: {
|
|
17
|
+
xs: "h-1";
|
|
18
|
+
sm: "h-1.5";
|
|
19
|
+
md: "h-2.5";
|
|
20
|
+
lg: "h-4";
|
|
21
|
+
};
|
|
22
|
+
color: {
|
|
23
|
+
primary: "[&>div]:bg-primary-600";
|
|
24
|
+
success: "[&>div]:bg-emerald-600";
|
|
25
|
+
warning: "[&>div]:bg-amber-600";
|
|
26
|
+
error: "[&>div]:bg-rose-600";
|
|
27
|
+
};
|
|
28
|
+
}, undefined, import("tailwind-variants").TVReturnTypeLike<{
|
|
29
|
+
size: {
|
|
30
|
+
xs: "h-1";
|
|
31
|
+
sm: "h-1.5";
|
|
32
|
+
md: "h-2.5";
|
|
33
|
+
lg: "h-4";
|
|
34
|
+
};
|
|
35
|
+
color: {
|
|
36
|
+
primary: "[&>div]:bg-primary-600";
|
|
37
|
+
success: "[&>div]:bg-emerald-600";
|
|
38
|
+
warning: "[&>div]:bg-amber-600";
|
|
39
|
+
error: "[&>div]:bg-rose-600";
|
|
40
|
+
};
|
|
41
|
+
}, undefined>>;
|
|
42
|
+
export type ProgressProps = VariantProps<typeof progressVariants> & {
|
|
43
|
+
value?: number;
|
|
44
|
+
max?: number;
|
|
45
|
+
class?: string;
|
|
46
|
+
};
|
|
47
|
+
declare const Progress: import("svelte").Component<ProgressProps, {}, "">;
|
|
48
|
+
type Progress = ReturnType<typeof Progress>;
|
|
49
|
+
export default Progress;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
4
|
+
class?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let { size = 'md', class: className = '' }: Props = $props();
|
|
8
|
+
|
|
9
|
+
let sizeClasses = $derived.by(() => {
|
|
10
|
+
switch (size) {
|
|
11
|
+
case 'xs':
|
|
12
|
+
return 'w-3.5 h-3.5';
|
|
13
|
+
case 'sm':
|
|
14
|
+
return 'w-4 h-4';
|
|
15
|
+
case 'lg':
|
|
16
|
+
return 'w-6 h-6';
|
|
17
|
+
case 'xl':
|
|
18
|
+
return 'w-8 h-8';
|
|
19
|
+
case 'md':
|
|
20
|
+
default:
|
|
21
|
+
return 'w-5 h-5';
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<svg
|
|
27
|
+
class="animate-spin text-current {sizeClasses} {className}"
|
|
28
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
29
|
+
fill="none"
|
|
30
|
+
viewBox="0 0 24 24"
|
|
31
|
+
aria-hidden="true"
|
|
32
|
+
>
|
|
33
|
+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
34
|
+
<path
|
|
35
|
+
class="opacity-75"
|
|
36
|
+
fill="currentColor"
|
|
37
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
38
|
+
></path>
|
|
39
|
+
</svg>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import Icon from '../elements/Icon.svelte';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
checked?: boolean;
|
|
7
|
+
label?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
name?: string;
|
|
11
|
+
value?: string;
|
|
12
|
+
'aria-label'?: string;
|
|
13
|
+
ariaLabel?: string;
|
|
14
|
+
class?: string;
|
|
15
|
+
onchange?: (checked: boolean) => void;
|
|
16
|
+
children?: Snippet;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
checked = $bindable(false),
|
|
21
|
+
label,
|
|
22
|
+
description,
|
|
23
|
+
disabled = false,
|
|
24
|
+
name,
|
|
25
|
+
value,
|
|
26
|
+
'aria-label': ariaLabelAttr,
|
|
27
|
+
ariaLabel,
|
|
28
|
+
class: className = '',
|
|
29
|
+
onchange,
|
|
30
|
+
children
|
|
31
|
+
}: Props = $props();
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<label
|
|
35
|
+
class="relative flex items-start gap-3 select-none {disabled
|
|
36
|
+
? 'cursor-not-allowed opacity-60'
|
|
37
|
+
: 'cursor-pointer'} {className}"
|
|
38
|
+
>
|
|
39
|
+
<div class="flex h-5 items-center">
|
|
40
|
+
<input
|
|
41
|
+
type="checkbox"
|
|
42
|
+
bind:checked
|
|
43
|
+
aria-label={ariaLabelAttr || ariaLabel || label}
|
|
44
|
+
onchange={(e) => {
|
|
45
|
+
const isChecked = (e.currentTarget as HTMLInputElement).checked;
|
|
46
|
+
if (onchange) onchange(isChecked);
|
|
47
|
+
}}
|
|
48
|
+
{disabled}
|
|
49
|
+
{name}
|
|
50
|
+
{value}
|
|
51
|
+
class="sr-only"
|
|
52
|
+
/>
|
|
53
|
+
<div
|
|
54
|
+
class="flex h-4.5 w-4.5 items-center justify-center rounded border transition-all duration-150 {checked
|
|
55
|
+
? 'border-primary-600 bg-primary-600 text-white shadow-xs'
|
|
56
|
+
: 'border-neutral-300 bg-white hover:border-neutral-400 dark:border-neutral-700 dark:bg-neutral-900'}"
|
|
57
|
+
>
|
|
58
|
+
{#if checked}
|
|
59
|
+
<Icon name="check" size="xs" />
|
|
60
|
+
{/if}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
{#if label || description || children}
|
|
65
|
+
<div class="text-sm leading-5">
|
|
66
|
+
{#if label}
|
|
67
|
+
<span class="font-medium text-neutral-800 dark:text-neutral-200">{label}</span>
|
|
68
|
+
{/if}
|
|
69
|
+
{#if children}
|
|
70
|
+
{@render children()}
|
|
71
|
+
{/if}
|
|
72
|
+
{#if description}
|
|
73
|
+
<p class="text-sm text-neutral-500 dark:text-neutral-400">{description}</p>
|
|
74
|
+
{/if}
|
|
75
|
+
</div>
|
|
76
|
+
{/if}
|
|
77
|
+
</label>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
checked?: boolean;
|
|
4
|
+
label?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
name?: string;
|
|
8
|
+
value?: string;
|
|
9
|
+
'aria-label'?: string;
|
|
10
|
+
ariaLabel?: string;
|
|
11
|
+
class?: string;
|
|
12
|
+
onchange?: (checked: boolean) => void;
|
|
13
|
+
children?: Snippet;
|
|
14
|
+
}
|
|
15
|
+
declare const Checkbox: import("svelte").Component<Props, {}, "checked">;
|
|
16
|
+
type Checkbox = ReturnType<typeof Checkbox>;
|
|
17
|
+
export default Checkbox;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Popover from '../overlays/Popover.svelte';
|
|
3
|
+
import Icon from '../elements/Icon.svelte';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
value?: string;
|
|
7
|
+
presets?: string[];
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
inline?: boolean;
|
|
10
|
+
class?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const defaultPresets = [
|
|
14
|
+
'#ff3e00', // Svelte Flame
|
|
15
|
+
'#f59e0b', // Amber
|
|
16
|
+
'#10b981', // Emerald
|
|
17
|
+
'#0ea5e9', // Sky
|
|
18
|
+
'#8b5cf6', // Violet
|
|
19
|
+
'#f43f5e', // Rose
|
|
20
|
+
'#64748b', // Slate
|
|
21
|
+
'#18181b', // Dark
|
|
22
|
+
'#ffffff' // White
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
value = $bindable('#ff3e00'),
|
|
27
|
+
presets = defaultPresets,
|
|
28
|
+
disabled = false,
|
|
29
|
+
inline = false,
|
|
30
|
+
class: className = ''
|
|
31
|
+
}: Props = $props();
|
|
32
|
+
|
|
33
|
+
let popoverOpen = $state(false);
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
{#if inline}
|
|
37
|
+
<div
|
|
38
|
+
class="inline-flex flex-col gap-3 rounded-xl border border-neutral-200 bg-white p-3 shadow-xs dark:border-neutral-800 dark:bg-neutral-900 {className}"
|
|
39
|
+
>
|
|
40
|
+
<!-- Swatches Grid -->
|
|
41
|
+
<div class="grid grid-cols-5 gap-1.5">
|
|
42
|
+
{#each presets as hex}
|
|
43
|
+
<button
|
|
44
|
+
type="button"
|
|
45
|
+
{disabled}
|
|
46
|
+
onclick={() => (value = hex)}
|
|
47
|
+
class="h-6 w-6 rounded-md border border-neutral-300/40 transition-transform hover:scale-110 {value.toLowerCase() ===
|
|
48
|
+
hex.toLowerCase()
|
|
49
|
+
? 'scale-105 ring-2 ring-primary-500 ring-offset-2 ring-offset-white dark:ring-offset-neutral-900'
|
|
50
|
+
: ''}"
|
|
51
|
+
style="background-color: {hex};"
|
|
52
|
+
title={hex}
|
|
53
|
+
aria-label="Select color {hex}"
|
|
54
|
+
></button>
|
|
55
|
+
{/each}
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!-- Custom Hex & Native Color input -->
|
|
59
|
+
<div class="flex items-center gap-2 border-t border-neutral-200 pt-2 dark:border-neutral-800">
|
|
60
|
+
<label
|
|
61
|
+
class="relative flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-md border border-neutral-300 dark:border-neutral-700"
|
|
62
|
+
style="background-color: {value};"
|
|
63
|
+
>
|
|
64
|
+
<input
|
|
65
|
+
type="color"
|
|
66
|
+
bind:value
|
|
67
|
+
{disabled}
|
|
68
|
+
class="absolute inset-0 h-full w-full cursor-pointer opacity-0"
|
|
69
|
+
aria-label="Pick color"
|
|
70
|
+
/>
|
|
71
|
+
</label>
|
|
72
|
+
<input
|
|
73
|
+
type="text"
|
|
74
|
+
bind:value
|
|
75
|
+
{disabled}
|
|
76
|
+
placeholder="#ff3e00"
|
|
77
|
+
class="h-8 w-full rounded-md border border-neutral-200 bg-neutral-50 px-2.5 font-mono text-sm text-neutral-800 focus:border-primary-500 focus:outline-none dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-200"
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
{:else}
|
|
82
|
+
<Popover bind:open={popoverOpen}>
|
|
83
|
+
{#snippet trigger()}
|
|
84
|
+
<button
|
|
85
|
+
type="button"
|
|
86
|
+
{disabled}
|
|
87
|
+
class="inline-flex items-center gap-2 rounded-lg border border-neutral-200 bg-white px-3 py-1.5 text-sm font-medium text-neutral-700 transition hover:border-neutral-300 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-300 dark:hover:border-neutral-700 {className}"
|
|
88
|
+
>
|
|
89
|
+
<span
|
|
90
|
+
class="h-4 w-4 rounded border border-neutral-300/40"
|
|
91
|
+
style="background-color: {value};"
|
|
92
|
+
></span>
|
|
93
|
+
<span class="font-mono">{value}</span>
|
|
94
|
+
<Icon name="chevron-down" size="xs" class="text-neutral-400" />
|
|
95
|
+
</button>
|
|
96
|
+
{/snippet}
|
|
97
|
+
|
|
98
|
+
<div class="w-48 space-y-3 p-3">
|
|
99
|
+
<div class="text-xs font-semibold text-neutral-500 dark:text-neutral-400">Color Swatches</div>
|
|
100
|
+
<!-- Swatches Grid -->
|
|
101
|
+
<div class="grid grid-cols-5 gap-1.5">
|
|
102
|
+
{#each presets as hex}
|
|
103
|
+
<button
|
|
104
|
+
type="button"
|
|
105
|
+
onclick={() => {
|
|
106
|
+
value = hex;
|
|
107
|
+
popoverOpen = false;
|
|
108
|
+
}}
|
|
109
|
+
class="h-6 w-6 rounded-md border border-neutral-300/40 transition-transform hover:scale-110 {value.toLowerCase() ===
|
|
110
|
+
hex.toLowerCase()
|
|
111
|
+
? 'scale-105 ring-2 ring-primary-500 ring-offset-2 ring-offset-white dark:ring-offset-neutral-900'
|
|
112
|
+
: ''}"
|
|
113
|
+
style="background-color: {hex};"
|
|
114
|
+
title={hex}
|
|
115
|
+
aria-label="Select color {hex}"
|
|
116
|
+
></button>
|
|
117
|
+
{/each}
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<!-- Custom Hex & Native Color input -->
|
|
121
|
+
<div class="flex items-center gap-2 border-t border-neutral-200 pt-2 dark:border-neutral-800">
|
|
122
|
+
<label
|
|
123
|
+
class="relative flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-md border border-neutral-300 dark:border-neutral-700"
|
|
124
|
+
style="background-color: {value};"
|
|
125
|
+
>
|
|
126
|
+
<input
|
|
127
|
+
type="color"
|
|
128
|
+
bind:value
|
|
129
|
+
class="absolute inset-0 h-full w-full cursor-pointer opacity-0"
|
|
130
|
+
aria-label="Pick color"
|
|
131
|
+
/>
|
|
132
|
+
</label>
|
|
133
|
+
<input
|
|
134
|
+
type="text"
|
|
135
|
+
bind:value
|
|
136
|
+
placeholder="#ff3e00"
|
|
137
|
+
class="h-8 w-full rounded-md border border-neutral-200 bg-neutral-50 px-2.5 font-mono text-sm text-neutral-800 focus:border-primary-500 focus:outline-none dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-200"
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</Popover>
|
|
142
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
value?: string;
|
|
3
|
+
presets?: string[];
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
inline?: boolean;
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const ColorPicker: import("svelte").Component<Props, {}, "value">;
|
|
9
|
+
type ColorPicker = ReturnType<typeof ColorPicker>;
|
|
10
|
+
export default ColorPicker;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { ZodSchema } from 'zod';
|
|
4
|
+
import Alert from '../overlays/Alert.svelte';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
schema?: ZodSchema;
|
|
8
|
+
values?: Record<string, any>;
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
errorSummary?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
onsubmit?: (e: SubmitEvent, values: Record<string, any>) => void | Promise<void>;
|
|
13
|
+
children?: Snippet;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
schema,
|
|
18
|
+
values = {},
|
|
19
|
+
loading = false,
|
|
20
|
+
errorSummary = false,
|
|
21
|
+
class: className = '',
|
|
22
|
+
onsubmit,
|
|
23
|
+
children
|
|
24
|
+
}: Props = $props();
|
|
25
|
+
|
|
26
|
+
let errors = $state<Record<string, string>>({});
|
|
27
|
+
let isSubmitting = $state(false);
|
|
28
|
+
let isBusy = $derived(loading || isSubmitting);
|
|
29
|
+
|
|
30
|
+
function validate() {
|
|
31
|
+
if (!schema) return true;
|
|
32
|
+
try {
|
|
33
|
+
schema.parse(values);
|
|
34
|
+
errors = {};
|
|
35
|
+
return true;
|
|
36
|
+
} catch (err: any) {
|
|
37
|
+
const fieldErrors: Record<string, string> = {};
|
|
38
|
+
const issues = err?.issues || err?.errors || [];
|
|
39
|
+
for (const e of issues) {
|
|
40
|
+
const field = Array.isArray(e.path) ? e.path.join('.') : String(e.path || 'form');
|
|
41
|
+
if (!fieldErrors[field]) {
|
|
42
|
+
fieldErrors[field] = e.message;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
errors = fieldErrors;
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function handleSubmit(e: SubmitEvent) {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
if (!validate()) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (onsubmit) {
|
|
57
|
+
isSubmitting = true;
|
|
58
|
+
try {
|
|
59
|
+
await onsubmit(e, values);
|
|
60
|
+
} finally {
|
|
61
|
+
isSubmitting = false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<form
|
|
68
|
+
onsubmit={handleSubmit}
|
|
69
|
+
aria-busy={isBusy}
|
|
70
|
+
class="space-y-4 {className} {isBusy ? 'pointer-events-none opacity-80' : ''}"
|
|
71
|
+
novalidate
|
|
72
|
+
>
|
|
73
|
+
{#if errorSummary && Object.keys(errors).length > 0}
|
|
74
|
+
<Alert
|
|
75
|
+
color="error"
|
|
76
|
+
title="Please correct the following errors:"
|
|
77
|
+
description={Object.values(errors).join(' · ')}
|
|
78
|
+
/>
|
|
79
|
+
{/if}
|
|
80
|
+
|
|
81
|
+
{#if children}
|
|
82
|
+
{@render children()}
|
|
83
|
+
{/if}
|
|
84
|
+
</form>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ZodSchema } from 'zod';
|
|
3
|
+
interface Props {
|
|
4
|
+
schema?: ZodSchema;
|
|
5
|
+
values?: Record<string, any>;
|
|
6
|
+
loading?: boolean;
|
|
7
|
+
errorSummary?: boolean;
|
|
8
|
+
class?: string;
|
|
9
|
+
onsubmit?: (e: SubmitEvent, values: Record<string, any>) => void | Promise<void>;
|
|
10
|
+
children?: Snippet;
|
|
11
|
+
}
|
|
12
|
+
declare const Form: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type Form = ReturnType<typeof Form>;
|
|
14
|
+
export default Form;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
label?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
hint?: string;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
name?: string;
|
|
11
|
+
class?: string;
|
|
12
|
+
children?: Snippet;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
label,
|
|
17
|
+
description,
|
|
18
|
+
error,
|
|
19
|
+
hint,
|
|
20
|
+
required = false,
|
|
21
|
+
name,
|
|
22
|
+
class: className = '',
|
|
23
|
+
children
|
|
24
|
+
}: Props = $props();
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<div class="space-y-1.5 {className}">
|
|
28
|
+
{#if label || hint}
|
|
29
|
+
<div class="flex items-center justify-between">
|
|
30
|
+
{#if label}
|
|
31
|
+
<label for={name} class="block text-sm font-medium text-neutral-700 dark:text-neutral-300">
|
|
32
|
+
{label}
|
|
33
|
+
{#if required}
|
|
34
|
+
<span class="ml-0.5 text-rose-500">*</span>
|
|
35
|
+
{/if}
|
|
36
|
+
</label>
|
|
37
|
+
{/if}
|
|
38
|
+
|
|
39
|
+
{#if hint}
|
|
40
|
+
<span class="text-sm text-neutral-500 dark:text-neutral-400">{hint}</span>
|
|
41
|
+
{/if}
|
|
42
|
+
</div>
|
|
43
|
+
{/if}
|
|
44
|
+
|
|
45
|
+
{#if description}
|
|
46
|
+
<p class="text-sm text-neutral-500 dark:text-neutral-400">{description}</p>
|
|
47
|
+
{/if}
|
|
48
|
+
|
|
49
|
+
{#if children}
|
|
50
|
+
{@render children()}
|
|
51
|
+
{/if}
|
|
52
|
+
|
|
53
|
+
{#if error}
|
|
54
|
+
<p class="text-sm font-medium text-rose-600 dark:text-rose-400">{error}</p>
|
|
55
|
+
{/if}
|
|
56
|
+
</div>
|