@classic-homes/theme-svelte 0.1.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 +305 -0
- package/dist/lib/components/Alert.svelte +51 -0
- package/dist/lib/components/Alert.svelte.d.ts +9 -0
- package/dist/lib/components/AlertDescription.svelte +16 -0
- package/dist/lib/components/AlertDescription.svelte.d.ts +9 -0
- package/dist/lib/components/AlertDialog.svelte +136 -0
- package/dist/lib/components/AlertDialog.svelte.d.ts +79 -0
- package/dist/lib/components/AlertTitle.svelte +16 -0
- package/dist/lib/components/AlertTitle.svelte.d.ts +9 -0
- package/dist/lib/components/Avatar.svelte +56 -0
- package/dist/lib/components/Avatar.svelte.d.ts +26 -0
- package/dist/lib/components/AvatarFallback.svelte +31 -0
- package/dist/lib/components/AvatarFallback.svelte.d.ts +17 -0
- package/dist/lib/components/AvatarImage.svelte +29 -0
- package/dist/lib/components/AvatarImage.svelte.d.ts +12 -0
- package/dist/lib/components/Badge.svelte +73 -0
- package/dist/lib/components/Badge.svelte.d.ts +11 -0
- package/dist/lib/components/Button.svelte +130 -0
- package/dist/lib/components/Button.svelte.d.ts +17 -0
- package/dist/lib/components/Card.svelte +58 -0
- package/dist/lib/components/Card.svelte.d.ts +26 -0
- package/dist/lib/components/CardContent.svelte +16 -0
- package/dist/lib/components/CardContent.svelte.d.ts +9 -0
- package/dist/lib/components/CardDescription.svelte +16 -0
- package/dist/lib/components/CardDescription.svelte.d.ts +9 -0
- package/dist/lib/components/CardFooter.svelte +16 -0
- package/dist/lib/components/CardFooter.svelte.d.ts +9 -0
- package/dist/lib/components/CardHeader.svelte +16 -0
- package/dist/lib/components/CardHeader.svelte.d.ts +9 -0
- package/dist/lib/components/CardTitle.svelte +16 -0
- package/dist/lib/components/CardTitle.svelte.d.ts +9 -0
- package/dist/lib/components/Checkbox.svelte +65 -0
- package/dist/lib/components/Checkbox.svelte.d.ts +14 -0
- package/dist/lib/components/DataTable.svelte +334 -0
- package/dist/lib/components/DataTable.svelte.d.ts +103 -0
- package/dist/lib/components/Dialog.svelte +111 -0
- package/dist/lib/components/Dialog.svelte.d.ts +22 -0
- package/dist/lib/components/DropdownMenu.svelte +135 -0
- package/dist/lib/components/DropdownMenu.svelte.d.ts +33 -0
- package/dist/lib/components/FileUpload.svelte +448 -0
- package/dist/lib/components/FileUpload.svelte.d.ts +42 -0
- package/dist/lib/components/FormField.svelte +134 -0
- package/dist/lib/components/FormField.svelte.d.ts +37 -0
- package/dist/lib/components/Input.svelte +61 -0
- package/dist/lib/components/Input.svelte.d.ts +19 -0
- package/dist/lib/components/Label.svelte +33 -0
- package/dist/lib/components/Label.svelte.d.ts +11 -0
- package/dist/lib/components/LoadingLogo.svelte +124 -0
- package/dist/lib/components/LoadingLogo.svelte.d.ts +16 -0
- package/dist/lib/components/LogoMain.svelte +237 -0
- package/dist/lib/components/LogoMain.svelte.d.ts +20 -0
- package/dist/lib/components/PageHeader.svelte +90 -0
- package/dist/lib/components/PageHeader.svelte.d.ts +28 -0
- package/dist/lib/components/Section.svelte +44 -0
- package/dist/lib/components/Section.svelte.d.ts +28 -0
- package/dist/lib/components/Select.svelte +174 -0
- package/dist/lib/components/Select.svelte.d.ts +32 -0
- package/dist/lib/components/Separator.svelte +29 -0
- package/dist/lib/components/Separator.svelte.d.ts +9 -0
- package/dist/lib/components/Skeleton.svelte +35 -0
- package/dist/lib/components/Skeleton.svelte.d.ts +7 -0
- package/dist/lib/components/Spinner.svelte +50 -0
- package/dist/lib/components/Spinner.svelte.d.ts +8 -0
- package/dist/lib/components/Switch.svelte +56 -0
- package/dist/lib/components/Switch.svelte.d.ts +14 -0
- package/dist/lib/components/TabPanel.svelte +44 -0
- package/dist/lib/components/TabPanel.svelte.d.ts +12 -0
- package/dist/lib/components/Tabs.svelte +125 -0
- package/dist/lib/components/Tabs.svelte.d.ts +19 -0
- package/dist/lib/components/Textarea.svelte +54 -0
- package/dist/lib/components/Textarea.svelte.d.ts +16 -0
- package/dist/lib/components/Toast.svelte +116 -0
- package/dist/lib/components/Toast.svelte.d.ts +12 -0
- package/dist/lib/components/ToastContainer.svelte +56 -0
- package/dist/lib/components/ToastContainer.svelte.d.ts +8 -0
- package/dist/lib/components/Tooltip.svelte +55 -0
- package/dist/lib/components/Tooltip.svelte.d.ts +18 -0
- package/dist/lib/components/layout/AppShell.svelte +82 -0
- package/dist/lib/components/layout/AppShell.svelte.d.ts +44 -0
- package/dist/lib/components/layout/DashboardLayout.svelte +248 -0
- package/dist/lib/components/layout/DashboardLayout.svelte.d.ts +62 -0
- package/dist/lib/components/layout/Footer.svelte +130 -0
- package/dist/lib/components/layout/Footer.svelte.d.ts +32 -0
- package/dist/lib/components/layout/FormPageLayout.svelte +92 -0
- package/dist/lib/components/layout/FormPageLayout.svelte.d.ts +33 -0
- package/dist/lib/components/layout/Header.svelte +94 -0
- package/dist/lib/components/layout/Header.svelte.d.ts +30 -0
- package/dist/lib/components/layout/PublicLayout.svelte +180 -0
- package/dist/lib/components/layout/PublicLayout.svelte.d.ts +39 -0
- package/dist/lib/components/layout/QuickLinks.svelte +112 -0
- package/dist/lib/components/layout/QuickLinks.svelte.d.ts +27 -0
- package/dist/lib/components/layout/Sidebar.svelte +243 -0
- package/dist/lib/components/layout/Sidebar.svelte.d.ts +48 -0
- package/dist/lib/composables/index.d.ts +8 -0
- package/dist/lib/composables/index.js +10 -0
- package/dist/lib/composables/useAsync.svelte.d.ts +102 -0
- package/dist/lib/composables/useAsync.svelte.js +210 -0
- package/dist/lib/composables/useForm.svelte.d.ts +123 -0
- package/dist/lib/composables/useForm.svelte.js +245 -0
- package/dist/lib/index.d.ts +65 -0
- package/dist/lib/index.js +83 -0
- package/dist/lib/performance.d.ts +79 -0
- package/dist/lib/performance.js +170 -0
- package/dist/lib/schemas/auth.d.ts +410 -0
- package/dist/lib/schemas/auth.js +216 -0
- package/dist/lib/schemas/common.d.ts +267 -0
- package/dist/lib/schemas/common.js +268 -0
- package/dist/lib/schemas/index.d.ts +24 -0
- package/dist/lib/schemas/index.js +32 -0
- package/dist/lib/stores/sidebar.svelte.d.ts +25 -0
- package/dist/lib/stores/sidebar.svelte.js +38 -0
- package/dist/lib/stores/theme.svelte.d.ts +72 -0
- package/dist/lib/stores/theme.svelte.js +150 -0
- package/dist/lib/stores/toast.svelte.d.ts +62 -0
- package/dist/lib/stores/toast.svelte.js +93 -0
- package/dist/lib/types/components.d.ts +85 -0
- package/dist/lib/types/components.js +7 -0
- package/dist/lib/types/layout.d.ts +258 -0
- package/dist/lib/types/layout.js +7 -0
- package/dist/lib/utils.d.ts +6 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/validation.d.ts +101 -0
- package/dist/lib/validation.js +170 -0
- package/package.json +56 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* PageHeader - Comprehensive hero/page header component
|
|
4
|
+
*
|
|
5
|
+
* A flexible page header component for hero sections and page titles.
|
|
6
|
+
* Supports multiple layout variants and optional action buttons.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Multiple variants: default, hero, centered
|
|
10
|
+
* - Optional subtitle with branded styling
|
|
11
|
+
* - Optional actions slot for CTA buttons
|
|
12
|
+
* - Consistent typography using design tokens
|
|
13
|
+
*/
|
|
14
|
+
import type { Snippet } from 'svelte';
|
|
15
|
+
import { cn } from '../utils.js';
|
|
16
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
17
|
+
|
|
18
|
+
const pageHeaderVariants = tv({
|
|
19
|
+
slots: {
|
|
20
|
+
container: '',
|
|
21
|
+
title: 'text-foreground',
|
|
22
|
+
subtitle: 'text-muted-foreground',
|
|
23
|
+
actionsWrapper: 'flex gap-4',
|
|
24
|
+
},
|
|
25
|
+
variants: {
|
|
26
|
+
variant: {
|
|
27
|
+
default: {
|
|
28
|
+
container: '',
|
|
29
|
+
title: 'text-3xl font-bold mb-2',
|
|
30
|
+
subtitle: 'text-lg',
|
|
31
|
+
actionsWrapper: 'mt-4',
|
|
32
|
+
},
|
|
33
|
+
hero: {
|
|
34
|
+
container: '',
|
|
35
|
+
title: 'text-5xl font-black uppercase tracking-tight mb-2',
|
|
36
|
+
subtitle: 'text-lg font-serif italic',
|
|
37
|
+
actionsWrapper: 'mt-6',
|
|
38
|
+
},
|
|
39
|
+
centered: {
|
|
40
|
+
container: 'text-center',
|
|
41
|
+
title: 'text-4xl font-bold mb-3',
|
|
42
|
+
subtitle: 'text-xl max-w-2xl mx-auto',
|
|
43
|
+
actionsWrapper: 'mt-6 justify-center',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
defaultVariants: {
|
|
48
|
+
variant: 'default',
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
type PageHeaderVariants = VariantProps<typeof pageHeaderVariants>;
|
|
53
|
+
|
|
54
|
+
interface Props {
|
|
55
|
+
/** Main title text */
|
|
56
|
+
title: string;
|
|
57
|
+
/** Optional subtitle text */
|
|
58
|
+
subtitle?: string;
|
|
59
|
+
/** Visual variant */
|
|
60
|
+
variant?: PageHeaderVariants['variant'];
|
|
61
|
+
/** Additional classes for the container */
|
|
62
|
+
class?: string;
|
|
63
|
+
/** Optional action buttons/content */
|
|
64
|
+
actions?: Snippet;
|
|
65
|
+
[key: string]: unknown;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let {
|
|
69
|
+
title,
|
|
70
|
+
subtitle,
|
|
71
|
+
variant = 'default',
|
|
72
|
+
class: className,
|
|
73
|
+
actions,
|
|
74
|
+
...restProps
|
|
75
|
+
}: Props = $props();
|
|
76
|
+
|
|
77
|
+
const styles = $derived(pageHeaderVariants({ variant }));
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<header class={cn(styles.container(), className)} {...restProps}>
|
|
81
|
+
<h1 class={styles.title()}>{title}</h1>
|
|
82
|
+
{#if subtitle}
|
|
83
|
+
<p class={styles.subtitle()}>{subtitle}</p>
|
|
84
|
+
{/if}
|
|
85
|
+
{#if actions}
|
|
86
|
+
<div class={styles.actionsWrapper()}>
|
|
87
|
+
{@render actions()}
|
|
88
|
+
</div>
|
|
89
|
+
{/if}
|
|
90
|
+
</header>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PageHeader - Comprehensive hero/page header component
|
|
3
|
+
*
|
|
4
|
+
* A flexible page header component for hero sections and page titles.
|
|
5
|
+
* Supports multiple layout variants and optional action buttons.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Multiple variants: default, hero, centered
|
|
9
|
+
* - Optional subtitle with branded styling
|
|
10
|
+
* - Optional actions slot for CTA buttons
|
|
11
|
+
* - Consistent typography using design tokens
|
|
12
|
+
*/
|
|
13
|
+
import type { Snippet } from 'svelte';
|
|
14
|
+
declare const PageHeader: import("svelte").Component<{
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
/** Main title text */
|
|
17
|
+
title: string;
|
|
18
|
+
/** Optional subtitle text */
|
|
19
|
+
subtitle?: string;
|
|
20
|
+
/** Visual variant */
|
|
21
|
+
variant?: "default" | "hero" | "centered" | undefined;
|
|
22
|
+
/** Additional classes for the container */
|
|
23
|
+
class?: string;
|
|
24
|
+
/** Optional action buttons/content */
|
|
25
|
+
actions?: Snippet;
|
|
26
|
+
}, {}, "">;
|
|
27
|
+
type PageHeader = ReturnType<typeof PageHeader>;
|
|
28
|
+
export default PageHeader;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Section - Content section container component
|
|
4
|
+
*
|
|
5
|
+
* A full-width content container with optional title and description.
|
|
6
|
+
* Different from Card in that Sections are meant for page-level content
|
|
7
|
+
* organization, while Cards are for individual content panels.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Optional title (renders as h2)
|
|
11
|
+
* - Optional description
|
|
12
|
+
* - Consistent styling with shadow and border
|
|
13
|
+
* - Flexible content area via children snippet
|
|
14
|
+
*/
|
|
15
|
+
import type { Snippet } from 'svelte';
|
|
16
|
+
import { cn } from '../utils.js';
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
/** Section title (rendered as h2) */
|
|
20
|
+
title?: string;
|
|
21
|
+
/** Optional description text below the title */
|
|
22
|
+
description?: string;
|
|
23
|
+
/** Additional classes for the section container */
|
|
24
|
+
class?: string;
|
|
25
|
+
/** Section content */
|
|
26
|
+
children: Snippet;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let { title, description, class: className, children, ...restProps }: Props = $props();
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<section
|
|
34
|
+
class={cn('bg-card rounded-lg shadow-md p-6 border border-border', className)}
|
|
35
|
+
{...restProps}
|
|
36
|
+
>
|
|
37
|
+
{#if title}
|
|
38
|
+
<h2 class="text-2xl font-bold text-card-foreground mb-4">{title}</h2>
|
|
39
|
+
{/if}
|
|
40
|
+
{#if description}
|
|
41
|
+
<p class="text-sm text-muted-foreground mb-4">{description}</p>
|
|
42
|
+
{/if}
|
|
43
|
+
{@render children()}
|
|
44
|
+
</section>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section - Content section container component
|
|
3
|
+
*
|
|
4
|
+
* A full-width content container with optional title and description.
|
|
5
|
+
* Different from Card in that Sections are meant for page-level content
|
|
6
|
+
* organization, while Cards are for individual content panels.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Optional title (renders as h2)
|
|
10
|
+
* - Optional description
|
|
11
|
+
* - Consistent styling with shadow and border
|
|
12
|
+
* - Flexible content area via children snippet
|
|
13
|
+
*/
|
|
14
|
+
import type { Snippet } from 'svelte';
|
|
15
|
+
interface Props {
|
|
16
|
+
/** Section title (rendered as h2) */
|
|
17
|
+
title?: string;
|
|
18
|
+
/** Optional description text below the title */
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Additional classes for the section container */
|
|
21
|
+
class?: string;
|
|
22
|
+
/** Section content */
|
|
23
|
+
children: Snippet;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
declare const Section: import("svelte").Component<Props, {}, "">;
|
|
27
|
+
type Section = ReturnType<typeof Section>;
|
|
28
|
+
export default Section;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Select as SelectPrimitive } from 'bits-ui';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
import { validateNonEmptyArray } from '../validation.js';
|
|
5
|
+
|
|
6
|
+
export interface SelectOption {
|
|
7
|
+
value: string;
|
|
8
|
+
label: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SelectGroup {
|
|
13
|
+
label: string;
|
|
14
|
+
options: SelectOption[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
/** Current value */
|
|
19
|
+
value?: string;
|
|
20
|
+
/** Callback when value changes */
|
|
21
|
+
onValueChange?: (value: string) => void;
|
|
22
|
+
/** Placeholder text when no value selected */
|
|
23
|
+
placeholder?: string;
|
|
24
|
+
/** Array of options or grouped options */
|
|
25
|
+
options: (SelectOption | SelectGroup)[];
|
|
26
|
+
/** Whether the select is disabled */
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
/** Name attribute for form submission */
|
|
29
|
+
name?: string;
|
|
30
|
+
/** Whether this field is required */
|
|
31
|
+
required?: boolean;
|
|
32
|
+
/** Additional class for the trigger */
|
|
33
|
+
class?: string;
|
|
34
|
+
/** Optional label */
|
|
35
|
+
label?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let {
|
|
39
|
+
value = $bindable(''),
|
|
40
|
+
onValueChange,
|
|
41
|
+
placeholder = 'Select an option...',
|
|
42
|
+
options,
|
|
43
|
+
disabled = false,
|
|
44
|
+
name,
|
|
45
|
+
required = false,
|
|
46
|
+
class: className,
|
|
47
|
+
label,
|
|
48
|
+
}: Props = $props();
|
|
49
|
+
|
|
50
|
+
// Validate props in development
|
|
51
|
+
$effect(() => {
|
|
52
|
+
validateNonEmptyArray(options, 'options', 'Select');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
function isGroup(item: SelectOption | SelectGroup): item is SelectGroup {
|
|
56
|
+
return 'options' in item;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Find the label for the current value
|
|
60
|
+
const selectedLabel = $derived.by(() => {
|
|
61
|
+
for (const item of options) {
|
|
62
|
+
if (isGroup(item)) {
|
|
63
|
+
const found = item.options.find((opt) => opt.value === value);
|
|
64
|
+
if (found) return found.label;
|
|
65
|
+
} else if (item.value === value) {
|
|
66
|
+
return item.label;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Build items array for typeahead support
|
|
73
|
+
const flatItems = $derived.by(() => {
|
|
74
|
+
const items: { value: string; label: string; disabled?: boolean }[] = [];
|
|
75
|
+
for (const item of options) {
|
|
76
|
+
if (isGroup(item)) {
|
|
77
|
+
for (const opt of item.options) {
|
|
78
|
+
items.push(opt);
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
items.push(item);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return items;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
function handleValueChange(newValue: string) {
|
|
88
|
+
value = newValue;
|
|
89
|
+
onValueChange?.(newValue);
|
|
90
|
+
}
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
{#if label}
|
|
94
|
+
<span
|
|
95
|
+
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-1.5 block"
|
|
96
|
+
>
|
|
97
|
+
{label}
|
|
98
|
+
{#if required}
|
|
99
|
+
<span class="text-destructive">*</span>
|
|
100
|
+
{/if}
|
|
101
|
+
</span>
|
|
102
|
+
{/if}
|
|
103
|
+
|
|
104
|
+
<SelectPrimitive.Root
|
|
105
|
+
type="single"
|
|
106
|
+
{name}
|
|
107
|
+
{disabled}
|
|
108
|
+
{required}
|
|
109
|
+
{value}
|
|
110
|
+
items={flatItems}
|
|
111
|
+
onValueChange={handleValueChange}
|
|
112
|
+
>
|
|
113
|
+
<SelectPrimitive.Trigger
|
|
114
|
+
class={cn(
|
|
115
|
+
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
|
116
|
+
className
|
|
117
|
+
)}
|
|
118
|
+
aria-label={label || placeholder}
|
|
119
|
+
>
|
|
120
|
+
<span class={value ? '' : 'text-muted-foreground'}>
|
|
121
|
+
{selectedLabel || placeholder}
|
|
122
|
+
</span>
|
|
123
|
+
<svg
|
|
124
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
125
|
+
width="24"
|
|
126
|
+
height="24"
|
|
127
|
+
viewBox="0 0 24 24"
|
|
128
|
+
fill="none"
|
|
129
|
+
stroke="currentColor"
|
|
130
|
+
stroke-width="2"
|
|
131
|
+
stroke-linecap="round"
|
|
132
|
+
stroke-linejoin="round"
|
|
133
|
+
class="h-4 w-4 opacity-50"
|
|
134
|
+
>
|
|
135
|
+
<path d="m6 9 6 6 6-6" />
|
|
136
|
+
</svg>
|
|
137
|
+
</SelectPrimitive.Trigger>
|
|
138
|
+
|
|
139
|
+
<SelectPrimitive.Content
|
|
140
|
+
class="relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
|
|
141
|
+
sideOffset={4}
|
|
142
|
+
>
|
|
143
|
+
<div class="p-1">
|
|
144
|
+
{#each options as item}
|
|
145
|
+
{#if isGroup(item)}
|
|
146
|
+
<SelectPrimitive.Group>
|
|
147
|
+
<div class="py-1.5 pl-8 pr-2 text-sm font-semibold">
|
|
148
|
+
{item.label}
|
|
149
|
+
</div>
|
|
150
|
+
{#each item.options as option}
|
|
151
|
+
<SelectPrimitive.Item
|
|
152
|
+
value={option.value}
|
|
153
|
+
label={option.label}
|
|
154
|
+
disabled={option.disabled}
|
|
155
|
+
class="relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
|
|
156
|
+
>
|
|
157
|
+
{option.label}
|
|
158
|
+
</SelectPrimitive.Item>
|
|
159
|
+
{/each}
|
|
160
|
+
</SelectPrimitive.Group>
|
|
161
|
+
{:else}
|
|
162
|
+
<SelectPrimitive.Item
|
|
163
|
+
value={item.value}
|
|
164
|
+
label={item.label}
|
|
165
|
+
disabled={item.disabled}
|
|
166
|
+
class="relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
|
|
167
|
+
>
|
|
168
|
+
{item.label}
|
|
169
|
+
</SelectPrimitive.Item>
|
|
170
|
+
{/if}
|
|
171
|
+
{/each}
|
|
172
|
+
</div>
|
|
173
|
+
</SelectPrimitive.Content>
|
|
174
|
+
</SelectPrimitive.Root>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface SelectOption {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface SelectGroup {
|
|
7
|
+
label: string;
|
|
8
|
+
options: SelectOption[];
|
|
9
|
+
}
|
|
10
|
+
interface Props {
|
|
11
|
+
/** Current value */
|
|
12
|
+
value?: string;
|
|
13
|
+
/** Callback when value changes */
|
|
14
|
+
onValueChange?: (value: string) => void;
|
|
15
|
+
/** Placeholder text when no value selected */
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
/** Array of options or grouped options */
|
|
18
|
+
options: (SelectOption | SelectGroup)[];
|
|
19
|
+
/** Whether the select is disabled */
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/** Name attribute for form submission */
|
|
22
|
+
name?: string;
|
|
23
|
+
/** Whether this field is required */
|
|
24
|
+
required?: boolean;
|
|
25
|
+
/** Additional class for the trigger */
|
|
26
|
+
class?: string;
|
|
27
|
+
/** Optional label */
|
|
28
|
+
label?: string;
|
|
29
|
+
}
|
|
30
|
+
declare const Select: import("svelte").Component<Props, {}, "value">;
|
|
31
|
+
type Select = ReturnType<typeof Select>;
|
|
32
|
+
export default Select;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Separator as SeparatorPrimitive } from 'bits-ui';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
orientation?: 'horizontal' | 'vertical';
|
|
7
|
+
decorative?: boolean;
|
|
8
|
+
class?: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
orientation = 'horizontal',
|
|
14
|
+
decorative = true,
|
|
15
|
+
class: className,
|
|
16
|
+
...restProps
|
|
17
|
+
}: Props = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<SeparatorPrimitive.Root
|
|
21
|
+
{orientation}
|
|
22
|
+
{decorative}
|
|
23
|
+
class={cn(
|
|
24
|
+
'shrink-0 bg-black',
|
|
25
|
+
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
{...restProps}
|
|
29
|
+
/>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
orientation?: 'horizontal' | 'vertical';
|
|
3
|
+
decorative?: boolean;
|
|
4
|
+
class?: string;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
declare const Separator: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type Separator = ReturnType<typeof Separator>;
|
|
9
|
+
export default Separator;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../utils.js';
|
|
3
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
4
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
5
|
+
|
|
6
|
+
const skeletonVariants = tv({
|
|
7
|
+
base: 'animate-pulse rounded-md bg-muted',
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: '',
|
|
11
|
+
text: 'h-4 w-full',
|
|
12
|
+
avatar: 'h-12 w-12 rounded-full',
|
|
13
|
+
card: 'h-32 w-full',
|
|
14
|
+
button: 'h-10 w-24',
|
|
15
|
+
title: 'h-6 w-3/4',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
variant: 'default',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
type SkeletonVariants = VariantProps<typeof skeletonVariants>;
|
|
24
|
+
|
|
25
|
+
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
26
|
+
variant?: SkeletonVariants['variant'];
|
|
27
|
+
class?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let { variant = 'default', class: className, ...restProps }: Props = $props();
|
|
31
|
+
|
|
32
|
+
const classes = $derived(cn(skeletonVariants({ variant }), className));
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<div class={classes} {...restProps}></div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
declare const Skeleton: import("svelte").Component<HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
variant?: "default" | "button" | "text" | "title" | "avatar" | "card" | undefined;
|
|
4
|
+
class?: string;
|
|
5
|
+
}, {}, "">;
|
|
6
|
+
type Skeleton = ReturnType<typeof Skeleton>;
|
|
7
|
+
export default Skeleton;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../utils.js';
|
|
3
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
4
|
+
|
|
5
|
+
const spinnerVariants = tv({
|
|
6
|
+
base: 'animate-spin text-current',
|
|
7
|
+
variants: {
|
|
8
|
+
size: {
|
|
9
|
+
sm: 'h-4 w-4',
|
|
10
|
+
md: 'h-6 w-6',
|
|
11
|
+
lg: 'h-8 w-8',
|
|
12
|
+
xl: 'h-12 w-12',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultVariants: {
|
|
16
|
+
size: 'md',
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
type SpinnerVariants = VariantProps<typeof spinnerVariants>;
|
|
21
|
+
|
|
22
|
+
interface Props {
|
|
23
|
+
size?: SpinnerVariants['size'];
|
|
24
|
+
class?: string;
|
|
25
|
+
label?: string;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let { size = 'md', class: className, label = 'Loading...', ...restProps }: Props = $props();
|
|
30
|
+
|
|
31
|
+
const classes = $derived(cn(spinnerVariants({ size }), className));
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<svg
|
|
35
|
+
class={classes}
|
|
36
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
37
|
+
fill="none"
|
|
38
|
+
viewBox="0 0 24 24"
|
|
39
|
+
aria-label={label}
|
|
40
|
+
role="status"
|
|
41
|
+
{...restProps}
|
|
42
|
+
>
|
|
43
|
+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
44
|
+
<path
|
|
45
|
+
class="opacity-75"
|
|
46
|
+
fill="currentColor"
|
|
47
|
+
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"
|
|
48
|
+
></path>
|
|
49
|
+
<title>{label}</title>
|
|
50
|
+
</svg>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Switch as SwitchPrimitive } from 'bits-ui';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
checked?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
name?: string;
|
|
10
|
+
value?: string;
|
|
11
|
+
id?: string;
|
|
12
|
+
class?: string;
|
|
13
|
+
onchange?: (checked: boolean) => void;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let {
|
|
18
|
+
checked = $bindable(false),
|
|
19
|
+
disabled = false,
|
|
20
|
+
required = false,
|
|
21
|
+
name,
|
|
22
|
+
value,
|
|
23
|
+
id,
|
|
24
|
+
class: className,
|
|
25
|
+
onchange,
|
|
26
|
+
...restProps
|
|
27
|
+
}: Props = $props();
|
|
28
|
+
|
|
29
|
+
function handleCheckedChange(newChecked: boolean) {
|
|
30
|
+
checked = newChecked;
|
|
31
|
+
onchange?.(newChecked);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<SwitchPrimitive.Root
|
|
36
|
+
bind:checked
|
|
37
|
+
{disabled}
|
|
38
|
+
{required}
|
|
39
|
+
{name}
|
|
40
|
+
{value}
|
|
41
|
+
{id}
|
|
42
|
+
onCheckedChange={handleCheckedChange}
|
|
43
|
+
class={cn(
|
|
44
|
+
'peer relative inline-flex h-7 w-12 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
|
|
45
|
+
className
|
|
46
|
+
)}
|
|
47
|
+
{...restProps}
|
|
48
|
+
>
|
|
49
|
+
<!-- Touch target expansion (invisible, extends clickable area) -->
|
|
50
|
+
<span class="absolute inset-0 -m-2" aria-hidden="true"></span>
|
|
51
|
+
<SwitchPrimitive.Thumb
|
|
52
|
+
class={cn(
|
|
53
|
+
'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-0.5'
|
|
54
|
+
)}
|
|
55
|
+
/>
|
|
56
|
+
</SwitchPrimitive.Root>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
checked?: boolean;
|
|
3
|
+
disabled?: boolean;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
name?: string;
|
|
6
|
+
value?: string;
|
|
7
|
+
id?: string;
|
|
8
|
+
class?: string;
|
|
9
|
+
onchange?: (checked: boolean) => void;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
declare const Switch: import("svelte").Component<Props, {}, "checked">;
|
|
13
|
+
type Switch = ReturnType<typeof Switch>;
|
|
14
|
+
export default Switch;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { getContext } from 'svelte';
|
|
4
|
+
import { cn } from '../utils.js';
|
|
5
|
+
|
|
6
|
+
interface TabsContext {
|
|
7
|
+
activeTab: string;
|
|
8
|
+
tabsId: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
/** Tab ID this panel belongs to */
|
|
13
|
+
value: string;
|
|
14
|
+
/** Additional classes */
|
|
15
|
+
class?: string;
|
|
16
|
+
/** Panel content */
|
|
17
|
+
children?: Snippet;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let { value, class: className, children }: Props = $props();
|
|
21
|
+
|
|
22
|
+
// Get context from parent Tabs
|
|
23
|
+
const context = getContext<TabsContext>('tabs');
|
|
24
|
+
const isActive = $derived(context?.activeTab === value);
|
|
25
|
+
const panelId = $derived(context ? `${context.tabsId}-panel-${value}` : `panel-${value}`);
|
|
26
|
+
const tabId = $derived(context ? `${context.tabsId}-tab-${value}` : `tab-${value}`);
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
{#if isActive}
|
|
30
|
+
<div
|
|
31
|
+
id={panelId}
|
|
32
|
+
role="tabpanel"
|
|
33
|
+
aria-labelledby={tabId}
|
|
34
|
+
tabindex="0"
|
|
35
|
+
class={cn(
|
|
36
|
+
'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
|
37
|
+
className
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
{#if children}
|
|
41
|
+
{@render children()}
|
|
42
|
+
{/if}
|
|
43
|
+
</div>
|
|
44
|
+
{/if}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Tab ID this panel belongs to */
|
|
4
|
+
value: string;
|
|
5
|
+
/** Additional classes */
|
|
6
|
+
class?: string;
|
|
7
|
+
/** Panel content */
|
|
8
|
+
children?: Snippet;
|
|
9
|
+
}
|
|
10
|
+
declare const TabPanel: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type TabPanel = ReturnType<typeof TabPanel>;
|
|
12
|
+
export default TabPanel;
|