@mrintel/villain-ui 0.2.2 → 0.6.3
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 -21
- package/README.md +3490 -1296
- package/dist/components/buttons/Button.svelte +27 -0
- package/dist/components/buttons/Button.svelte.d.ts +14 -0
- package/dist/components/buttons/ButtonGroup.svelte +17 -0
- package/dist/components/buttons/ButtonGroup.svelte.d.ts +8 -0
- package/dist/components/buttons/FloatingActionButton.svelte +20 -0
- package/dist/components/buttons/FloatingActionButton.svelte.d.ts +12 -0
- package/dist/components/buttons/IconButton.svelte +23 -0
- package/dist/components/buttons/IconButton.svelte.d.ts +14 -0
- package/dist/components/buttons/LinkButton.svelte +24 -0
- package/dist/components/buttons/LinkButton.svelte.d.ts +15 -0
- package/dist/components/buttons/buttonClasses.d.ts +15 -0
- package/dist/components/buttons/buttonClasses.js +15 -0
- package/dist/components/buttons/index.d.ts +5 -0
- package/dist/components/buttons/index.js +5 -0
- package/dist/components/cards/Card.svelte +60 -0
- package/dist/components/cards/Card.svelte.d.ts +15 -0
- package/dist/components/cards/Container.svelte +17 -0
- package/dist/components/cards/Container.svelte.d.ts +10 -0
- package/dist/components/cards/Divider.svelte +36 -0
- package/dist/components/cards/Divider.svelte.d.ts +11 -0
- package/dist/components/cards/Grid.svelte +55 -0
- package/dist/components/cards/Grid.svelte.d.ts +10 -0
- package/dist/components/cards/Panel.svelte +18 -0
- package/dist/components/cards/Panel.svelte.d.ts +11 -0
- package/dist/components/cards/SectionHeader.svelte +24 -0
- package/dist/components/cards/SectionHeader.svelte.d.ts +12 -0
- package/dist/components/cards/index.d.ts +6 -0
- package/dist/components/cards/index.js +6 -0
- package/dist/components/data/Avatar.svelte +48 -0
- package/dist/components/data/Avatar.svelte.d.ts +10 -0
- package/dist/components/data/Badge.svelte +45 -0
- package/dist/components/data/Badge.svelte.d.ts +14 -0
- package/dist/components/data/CalendarGrid.svelte +433 -0
- package/dist/components/data/CalendarGrid.svelte.d.ts +25 -0
- package/dist/components/data/CalendarGrid.types.d.ts +7 -0
- package/dist/components/data/CalendarGrid.types.js +1 -0
- package/dist/components/data/CodeBlock.svelte +119 -0
- package/dist/components/data/CodeBlock.svelte.d.ts +40 -0
- package/dist/components/data/List.svelte +87 -0
- package/dist/components/data/List.svelte.d.ts +15 -0
- package/dist/components/data/Pagination.svelte +121 -0
- package/dist/components/data/Pagination.svelte.d.ts +14 -0
- package/dist/components/data/Sparkline.svelte +117 -0
- package/dist/components/data/Sparkline.svelte.d.ts +43 -0
- package/dist/components/data/Stat.svelte +92 -0
- package/dist/components/data/Stat.svelte.d.ts +11 -0
- package/dist/components/data/Table.svelte +443 -0
- package/dist/components/data/Table.svelte.d.ts +30 -0
- package/dist/components/data/Table.types.d.ts +14 -0
- package/dist/components/data/Table.types.js +1 -0
- package/dist/components/data/Tag.svelte +51 -0
- package/dist/components/data/Tag.svelte.d.ts +13 -0
- package/dist/components/data/index.d.ts +12 -0
- package/dist/components/data/index.js +10 -0
- package/dist/components/forms/Checkbox.svelte +39 -0
- package/dist/components/forms/Checkbox.svelte.d.ts +12 -0
- package/dist/components/forms/DatePicker.svelte +61 -0
- package/dist/components/forms/DatePicker.svelte.d.ts +15 -0
- package/dist/components/forms/DateTimePicker.svelte +63 -0
- package/dist/components/forms/DateTimePicker.svelte.d.ts +16 -0
- package/dist/components/forms/FileUpload.svelte +136 -0
- package/dist/components/forms/FileUpload.svelte.d.ts +23 -0
- package/dist/components/forms/Input.svelte +282 -0
- package/dist/components/forms/Input.svelte.d.ts +19 -0
- package/dist/components/forms/InputGroup.svelte +7 -0
- package/dist/components/forms/InputGroup.svelte.d.ts +20 -0
- package/dist/components/forms/RadioGroup.svelte +77 -0
- package/dist/components/forms/RadioGroup.svelte.d.ts +17 -0
- package/dist/components/forms/RangeSlider.svelte +90 -0
- package/dist/components/forms/RangeSlider.svelte.d.ts +14 -0
- package/dist/components/forms/Select.svelte +106 -0
- package/dist/components/forms/Select.svelte.d.ts +18 -0
- package/dist/components/forms/Switch.svelte +44 -0
- package/dist/components/forms/Switch.svelte.d.ts +12 -0
- package/dist/components/forms/Textarea.svelte +52 -0
- package/dist/components/forms/Textarea.svelte.d.ts +15 -0
- package/dist/components/forms/TimePicker.svelte +63 -0
- package/dist/components/forms/TimePicker.svelte.d.ts +16 -0
- package/dist/components/forms/formClasses.d.ts +3 -0
- package/dist/components/forms/formClasses.js +3 -0
- package/dist/components/forms/index.d.ts +12 -0
- package/dist/components/forms/index.js +12 -0
- package/dist/components/navigation/Breadcrumbs.svelte +56 -0
- package/dist/components/navigation/Breadcrumbs.svelte.d.ts +15 -0
- package/dist/components/navigation/ContextMenu.svelte +133 -0
- package/dist/components/navigation/ContextMenu.svelte.d.ts +18 -0
- package/dist/components/navigation/DropdownMenu.svelte +139 -0
- package/dist/components/navigation/DropdownMenu.svelte.d.ts +17 -0
- package/dist/components/navigation/Menu.svelte +72 -0
- package/dist/components/navigation/Menu.svelte.d.ts +15 -0
- package/dist/components/navigation/Navbar.svelte +111 -0
- package/dist/components/navigation/Navbar.svelte.d.ts +15 -0
- package/dist/components/navigation/Sidebar.svelte +236 -0
- package/dist/components/navigation/Sidebar.svelte.d.ts +12 -0
- package/dist/components/navigation/Tabs.svelte +86 -0
- package/dist/components/navigation/Tabs.svelte.d.ts +19 -0
- package/dist/components/navigation/index.d.ts +7 -0
- package/dist/components/navigation/index.js +7 -0
- package/dist/components/overlays/Alert.svelte +81 -0
- package/dist/components/overlays/Alert.svelte.d.ts +15 -0
- package/dist/components/overlays/CommandPalette.svelte +182 -0
- package/dist/components/overlays/CommandPalette.svelte.d.ts +16 -0
- package/dist/components/overlays/Drawer.svelte +158 -0
- package/dist/components/overlays/Drawer.svelte.d.ts +16 -0
- package/dist/components/overlays/Dropdown.svelte +62 -0
- package/dist/components/overlays/Dropdown.svelte.d.ts +11 -0
- package/dist/components/overlays/Modal.svelte +125 -0
- package/dist/components/overlays/Modal.svelte.d.ts +15 -0
- package/dist/components/overlays/Popover.svelte +106 -0
- package/dist/components/overlays/Popover.svelte.d.ts +11 -0
- package/dist/components/overlays/ProgressBar.svelte +29 -0
- package/dist/components/overlays/ProgressBar.svelte.d.ts +10 -0
- package/dist/components/overlays/SkeletonLoader.svelte +66 -0
- package/dist/components/overlays/SkeletonLoader.svelte.d.ts +9 -0
- package/dist/components/overlays/Spinner.svelte +33 -0
- package/dist/components/overlays/Spinner.svelte.d.ts +7 -0
- package/dist/components/overlays/Toast.svelte +111 -0
- package/dist/components/overlays/Toast.svelte.d.ts +16 -0
- package/dist/components/overlays/Tooltip.svelte +94 -0
- package/dist/components/overlays/Tooltip.svelte.d.ts +12 -0
- package/dist/components/overlays/index.d.ts +11 -0
- package/dist/components/overlays/index.js +11 -0
- package/dist/components/typography/Code.svelte +10 -0
- package/dist/components/typography/Code.svelte.d.ts +6 -0
- package/dist/components/typography/Heading.svelte +15 -0
- package/dist/components/typography/Heading.svelte.d.ts +10 -0
- package/dist/components/typography/Text.svelte +21 -0
- package/dist/components/typography/Text.svelte.d.ts +10 -0
- package/dist/components/typography/index.d.ts +3 -0
- package/dist/components/typography/index.js +3 -0
- package/dist/components/utilities/Accordion.svelte +54 -0
- package/dist/components/utilities/Accordion.svelte.d.ts +17 -0
- package/dist/components/utilities/Carousel.svelte +124 -0
- package/dist/components/utilities/Carousel.svelte.d.ts +16 -0
- package/dist/components/utilities/Collapse.svelte +46 -0
- package/dist/components/utilities/Collapse.svelte.d.ts +10 -0
- package/dist/components/utilities/Hero.svelte +42 -0
- package/dist/components/utilities/Hero.svelte.d.ts +10 -0
- package/dist/components/utilities/Portal.svelte +47 -0
- package/dist/components/utilities/Portal.svelte.d.ts +21 -0
- package/dist/components/utilities/ScrollArea.svelte +33 -0
- package/dist/components/utilities/ScrollArea.svelte.d.ts +8 -0
- package/dist/components/utilities/SystemConsole.svelte +310 -0
- package/dist/components/utilities/SystemConsole.svelte.d.ts +20 -0
- package/dist/components/utilities/SystemInterface.svelte +726 -0
- package/dist/components/utilities/SystemInterface.svelte.d.ts +19 -0
- package/dist/components/utilities/index.d.ts +9 -0
- package/dist/components/utilities/index.js +8 -0
- package/dist/components/utilities/utilities.types.d.ts +46 -0
- package/dist/components/utilities/utilities.types.js +4 -0
- package/dist/index.d.ts +60 -175
- package/dist/index.js +24 -4560
- package/dist/lib/internal/id.d.ts +12 -0
- package/dist/lib/internal/id.js +15 -0
- package/dist/theme.css +2821 -0
- package/package.json +83 -75
- package/dist/index.css +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { default as Modal } from './Modal.svelte';
|
|
2
|
+
export { default as Alert } from './Alert.svelte';
|
|
3
|
+
export { default as Spinner } from './Spinner.svelte';
|
|
4
|
+
export { default as Tooltip } from './Tooltip.svelte';
|
|
5
|
+
export { default as ProgressBar } from './ProgressBar.svelte';
|
|
6
|
+
export { default as SkeletonLoader } from './SkeletonLoader.svelte';
|
|
7
|
+
export { default as Toast } from './Toast.svelte';
|
|
8
|
+
export { default as Drawer } from './Drawer.svelte';
|
|
9
|
+
export { default as Popover } from './Popover.svelte';
|
|
10
|
+
export { default as Dropdown } from './Dropdown.svelte';
|
|
11
|
+
export { default as CommandPalette } from './CommandPalette.svelte';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<script lang="ts">"use strict";
|
|
2
|
+
let { children } = $props();
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<code
|
|
6
|
+
class="inline-flex items-center transition-all duration-300 hover:shadow-[0_0_12px_var(--color-accent-overlay-30)]"
|
|
7
|
+
style="background: var(--color-accent-overlay-10); border: 1px solid var(--color-border); padding: 0.125rem 0.375rem; border-radius: var(--radius-sm); font-family: var(--font-mono); color: var(--color-accent-soft); font-size: 0.9em;"
|
|
8
|
+
>
|
|
9
|
+
{@render children?.()}
|
|
10
|
+
</code>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts">"use strict";
|
|
2
|
+
let { level = 1, glow = false, variant = 'default', as, children } = $props();
|
|
3
|
+
const element = $derived(as ?? `h${level}`);
|
|
4
|
+
const variantClasses = {
|
|
5
|
+
default: '',
|
|
6
|
+
accent: 'text-accent',
|
|
7
|
+
gradient: 'text-gradient'
|
|
8
|
+
};
|
|
9
|
+
const baseClasses = $derived(`transition-all duration-300 ${glow ? 'text-glow' : ''} ${variantClasses[variant]}`);
|
|
10
|
+
const styles = $derived(`font-size: var(--text-h${level}-size); line-height: var(--text-h${level}-line-height); font-weight: var(--text-h${level}-weight); letter-spacing: var(--text-h${level}-letter-spacing); font-family: var(--font-heading); color: var(--color-text);`);
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<svelte:element this={element} class={baseClasses} style={styles}>
|
|
14
|
+
{@render children?.()}
|
|
15
|
+
</svelte:element>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
3
|
+
glow?: boolean;
|
|
4
|
+
variant?: 'default' | 'accent' | 'gradient';
|
|
5
|
+
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
6
|
+
children?: import('svelte').Snippet;
|
|
7
|
+
}
|
|
8
|
+
declare const Heading: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type Heading = ReturnType<typeof Heading>;
|
|
10
|
+
export default Heading;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">"use strict";
|
|
2
|
+
let { variant = 'body', color = 'default', weight = 'normal', as = 'p', children } = $props();
|
|
3
|
+
const colorMap = {
|
|
4
|
+
default: 'var(--color-text)',
|
|
5
|
+
soft: 'var(--color-text-soft)',
|
|
6
|
+
muted: 'var(--color-text-muted)',
|
|
7
|
+
success: 'var(--color-success)',
|
|
8
|
+
warning: 'var(--color-warning)',
|
|
9
|
+
error: 'var(--color-error)',
|
|
10
|
+
};
|
|
11
|
+
const weightMap = {
|
|
12
|
+
normal: '400',
|
|
13
|
+
semibold: '600',
|
|
14
|
+
bold: '700',
|
|
15
|
+
};
|
|
16
|
+
const styles = $derived(`font-size: var(--text-${variant}-size); line-height: var(--text-${variant}-line-height); font-weight: ${weightMap[weight] || '400'}; letter-spacing: var(--text-${variant}-letter-spacing); font-family: var(--font-body); color: ${colorMap[color]};`);
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<svelte:element this={as} class="transition-colors duration-300" style={styles}>
|
|
20
|
+
{@render children?.()}
|
|
21
|
+
</svelte:element>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
variant?: 'body' | 'caption';
|
|
3
|
+
color?: 'default' | 'soft' | 'muted' | 'success' | 'warning' | 'error';
|
|
4
|
+
weight?: 'normal' | 'bold' | 'semibold';
|
|
5
|
+
as?: 'p' | 'span' | 'div';
|
|
6
|
+
children?: import('svelte').Snippet;
|
|
7
|
+
}
|
|
8
|
+
declare const Text: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type Text = ReturnType<typeof Text>;
|
|
10
|
+
export default Text;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script lang="ts">import Collapse from './Collapse.svelte';
|
|
2
|
+
let { items, openItems = $bindable([]), mode = 'single', onToggle, ontoggle } = $props();
|
|
3
|
+
const onToggleCallback = $derived(onToggle ?? ontoggle);
|
|
4
|
+
// Normalize openItems to array
|
|
5
|
+
let openItemsArray = $derived(mode === 'single'
|
|
6
|
+
? typeof openItems === 'string'
|
|
7
|
+
? [openItems]
|
|
8
|
+
: []
|
|
9
|
+
: Array.isArray(openItems)
|
|
10
|
+
? openItems
|
|
11
|
+
: []);
|
|
12
|
+
function isItemOpen(id) {
|
|
13
|
+
return openItemsArray.includes(id);
|
|
14
|
+
}
|
|
15
|
+
function toggleItem(id) {
|
|
16
|
+
const wasOpen = isItemOpen(id);
|
|
17
|
+
if (mode === 'single') {
|
|
18
|
+
// Single mode: only one item open at a time
|
|
19
|
+
if (wasOpen) {
|
|
20
|
+
openItems = '';
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
openItems = id;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Multiple mode: toggle independently
|
|
28
|
+
if (wasOpen) {
|
|
29
|
+
openItems = openItemsArray.filter(itemId => itemId !== id);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
openItems = [...openItemsArray, id];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Call onToggle callback if provided
|
|
36
|
+
onToggleCallback?.(id, !wasOpen);
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<div class="space-y-2">
|
|
41
|
+
{#each items as item (item.id)}
|
|
42
|
+
<Collapse
|
|
43
|
+
title={item.title}
|
|
44
|
+
open={isItemOpen(item.id)}
|
|
45
|
+
onToggle={() => toggleItem(item.id)}
|
|
46
|
+
>
|
|
47
|
+
{#if typeof item.content === 'string'}
|
|
48
|
+
{item.content}
|
|
49
|
+
{:else}
|
|
50
|
+
{@render item.content()}
|
|
51
|
+
{/if}
|
|
52
|
+
</Collapse>
|
|
53
|
+
{/each}
|
|
54
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface AccordionItem {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
content: string | Snippet;
|
|
6
|
+
}
|
|
7
|
+
export interface Props {
|
|
8
|
+
items: AccordionItem[];
|
|
9
|
+
openItems?: string | string[];
|
|
10
|
+
mode?: 'single' | 'multiple';
|
|
11
|
+
onToggle?: (itemId: string, isOpen: boolean) => void;
|
|
12
|
+
/** @deprecated Use onToggle */
|
|
13
|
+
ontoggle?: (itemId: string, isOpen: boolean) => void;
|
|
14
|
+
}
|
|
15
|
+
declare const Accordion: import("svelte").Component<Props, {}, "openItems">;
|
|
16
|
+
type Accordion = ReturnType<typeof Accordion>;
|
|
17
|
+
export default Accordion;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script lang="ts">let { items, currentIndex = $bindable(0), autoplay = false, autoplayInterval = 3000, showDots = true, showArrows = true } = $props();
|
|
2
|
+
let startX = $state(0);
|
|
3
|
+
let currentX = $state(0);
|
|
4
|
+
let isDragging = $state(false);
|
|
5
|
+
function goToNext() {
|
|
6
|
+
if (!items.length)
|
|
7
|
+
return;
|
|
8
|
+
currentIndex = (currentIndex + 1) % items.length;
|
|
9
|
+
}
|
|
10
|
+
function goToPrev() {
|
|
11
|
+
if (!items.length)
|
|
12
|
+
return;
|
|
13
|
+
currentIndex = (currentIndex - 1 + items.length) % items.length;
|
|
14
|
+
}
|
|
15
|
+
function goToIndex(index) {
|
|
16
|
+
if (items.length === 0 || index < 0 || index >= items.length)
|
|
17
|
+
return;
|
|
18
|
+
currentIndex = index;
|
|
19
|
+
}
|
|
20
|
+
function handleTouchStart(event) {
|
|
21
|
+
isDragging = true;
|
|
22
|
+
startX = event.touches[0].clientX;
|
|
23
|
+
currentX = startX;
|
|
24
|
+
}
|
|
25
|
+
function handleTouchMove(event) {
|
|
26
|
+
if (!isDragging)
|
|
27
|
+
return;
|
|
28
|
+
currentX = event.touches[0].clientX;
|
|
29
|
+
}
|
|
30
|
+
function handleTouchEnd() {
|
|
31
|
+
if (!isDragging)
|
|
32
|
+
return;
|
|
33
|
+
if (!items.length) {
|
|
34
|
+
isDragging = false;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
isDragging = false;
|
|
38
|
+
const diff = startX - currentX;
|
|
39
|
+
const threshold = 50;
|
|
40
|
+
if (diff > threshold) {
|
|
41
|
+
goToNext();
|
|
42
|
+
}
|
|
43
|
+
else if (diff < -threshold) {
|
|
44
|
+
goToPrev();
|
|
45
|
+
}
|
|
46
|
+
startX = 0;
|
|
47
|
+
currentX = 0;
|
|
48
|
+
}
|
|
49
|
+
$effect(() => {
|
|
50
|
+
if (!autoplay || items.length < 2)
|
|
51
|
+
return;
|
|
52
|
+
const interval = setInterval(goToNext, autoplayInterval);
|
|
53
|
+
return () => {
|
|
54
|
+
clearInterval(interval);
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
// Clamp currentIndex when items change
|
|
58
|
+
$effect(() => {
|
|
59
|
+
if (items.length && (currentIndex < 0 || currentIndex >= items.length)) {
|
|
60
|
+
currentIndex = 0;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
export {};
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<div class="relative">
|
|
67
|
+
<div class="panel-raised rounded-[var(--radius-lg)] overflow-hidden">
|
|
68
|
+
<div
|
|
69
|
+
class="flex transition-transform duration-300 ease-luxe"
|
|
70
|
+
style="transform: translateX(-{currentIndex * 100}%);"
|
|
71
|
+
ontouchstart={handleTouchStart}
|
|
72
|
+
ontouchmove={handleTouchMove}
|
|
73
|
+
ontouchend={handleTouchEnd}
|
|
74
|
+
>
|
|
75
|
+
{#each items as item (item.id)}
|
|
76
|
+
<div class="min-w-full flex items-center justify-center p-8">
|
|
77
|
+
{#if typeof item.content === 'string'}
|
|
78
|
+
<div class="text-text">{item.content}</div>
|
|
79
|
+
{:else}
|
|
80
|
+
{@render item.content()}
|
|
81
|
+
{/if}
|
|
82
|
+
</div>
|
|
83
|
+
{/each}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
{#if showArrows && items.length}
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
onclick={goToPrev}
|
|
91
|
+
class="absolute left-2 top-1/2 -translate-y-1/2 obsidian-surface metal-edge rounded-full p-2 text-text hover:accent-glow transition-all"
|
|
92
|
+
aria-label="Previous item"
|
|
93
|
+
>
|
|
94
|
+
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
95
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
|
96
|
+
</svg>
|
|
97
|
+
</button>
|
|
98
|
+
|
|
99
|
+
<button
|
|
100
|
+
type="button"
|
|
101
|
+
onclick={goToNext}
|
|
102
|
+
class="absolute right-2 top-1/2 -translate-y-1/2 obsidian-surface metal-edge rounded-full p-2 text-text hover:accent-glow transition-all"
|
|
103
|
+
aria-label="Next item"
|
|
104
|
+
>
|
|
105
|
+
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
106
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
107
|
+
</svg>
|
|
108
|
+
</button>
|
|
109
|
+
{/if}
|
|
110
|
+
|
|
111
|
+
{#if showDots && items.length}
|
|
112
|
+
<div class="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2">
|
|
113
|
+
{#each items as item, index (item.id)}
|
|
114
|
+
<button
|
|
115
|
+
type="button"
|
|
116
|
+
onclick={() => goToIndex(index)}
|
|
117
|
+
class="w-2 h-2 rounded-full transition-all {index === currentIndex ? 'accent-glow bg-accent w-8' : 'bg-text-muted'}"
|
|
118
|
+
aria-label="Go to item {index + 1}"
|
|
119
|
+
>
|
|
120
|
+
</button>
|
|
121
|
+
{/each}
|
|
122
|
+
</div>
|
|
123
|
+
{/if}
|
|
124
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface CarouselItem {
|
|
3
|
+
id: string;
|
|
4
|
+
content: Snippet | string;
|
|
5
|
+
}
|
|
6
|
+
interface Props {
|
|
7
|
+
items: CarouselItem[];
|
|
8
|
+
currentIndex?: number;
|
|
9
|
+
autoplay?: boolean;
|
|
10
|
+
autoplayInterval?: number;
|
|
11
|
+
showDots?: boolean;
|
|
12
|
+
showArrows?: boolean;
|
|
13
|
+
}
|
|
14
|
+
declare const Carousel: import("svelte").Component<Props, {}, "currentIndex">;
|
|
15
|
+
type Carousel = ReturnType<typeof Carousel>;
|
|
16
|
+
export default Carousel;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script lang="ts">import { createId } from '../../lib/internal/id.js';
|
|
2
|
+
let { open, title, children, onToggle } = $props();
|
|
3
|
+
let contentElement = $state();
|
|
4
|
+
let openLocal = $state(open);
|
|
5
|
+
const headerId = createId('collapse-header');
|
|
6
|
+
const contentId = createId('collapse-content');
|
|
7
|
+
function toggleLocal() {
|
|
8
|
+
openLocal = !openLocal;
|
|
9
|
+
}
|
|
10
|
+
let effectiveOpen = $derived(onToggle ? open : openLocal);
|
|
11
|
+
let maxHeight = $derived(effectiveOpen && contentElement ? `${contentElement.scrollHeight}px` : '0px');
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<div class="border border-border rounded-md overflow-hidden {effectiveOpen ? 'panel-raised' : ''}">
|
|
15
|
+
<button
|
|
16
|
+
id={headerId}
|
|
17
|
+
type="button"
|
|
18
|
+
onclick={onToggle ?? toggleLocal}
|
|
19
|
+
class="w-full flex items-center justify-between p-4 text-left text-text font-medium hover:bg-base-3 transition-colors"
|
|
20
|
+
aria-expanded={effectiveOpen}
|
|
21
|
+
aria-controls={contentId}
|
|
22
|
+
>
|
|
23
|
+
<span>{title}</span>
|
|
24
|
+
<svg
|
|
25
|
+
class="w-5 h-5 transition-transform duration-300 ease-luxe {effectiveOpen ? 'rotate-180' : ''}"
|
|
26
|
+
fill="none"
|
|
27
|
+
stroke="currentColor"
|
|
28
|
+
viewBox="0 0 24 24"
|
|
29
|
+
>
|
|
30
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
|
31
|
+
</svg>
|
|
32
|
+
</button>
|
|
33
|
+
|
|
34
|
+
<div
|
|
35
|
+
bind:this={contentElement}
|
|
36
|
+
id={contentId}
|
|
37
|
+
class="overflow-hidden transition-[max-height] duration-300 ease-luxe"
|
|
38
|
+
style="max-height: {maxHeight};"
|
|
39
|
+
role="region"
|
|
40
|
+
aria-labelledby={headerId}
|
|
41
|
+
>
|
|
42
|
+
<div class="p-4 text-text-soft border-t border-border">
|
|
43
|
+
{@render children?.()}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
open: boolean;
|
|
4
|
+
title: string;
|
|
5
|
+
children?: Snippet;
|
|
6
|
+
onToggle?: () => void;
|
|
7
|
+
}
|
|
8
|
+
declare const Collapse: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type Collapse = ReturnType<typeof Collapse>;
|
|
10
|
+
export default Collapse;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts">"use strict";
|
|
2
|
+
let { title, text, features, children, class: className = '', ...restProps } = $props();
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<div class="hero-section {className}" {...restProps}>
|
|
6
|
+
{#if title}
|
|
7
|
+
<div class="mb-4">
|
|
8
|
+
{@render title()}
|
|
9
|
+
</div>
|
|
10
|
+
{/if}
|
|
11
|
+
|
|
12
|
+
{#if text}
|
|
13
|
+
<div class="mb-8 mx-auto max-w-3xl">
|
|
14
|
+
{@render text()}
|
|
15
|
+
</div>
|
|
16
|
+
{/if}
|
|
17
|
+
|
|
18
|
+
{#if features}
|
|
19
|
+
<div class="feature-tags">
|
|
20
|
+
{@render features()}
|
|
21
|
+
</div>
|
|
22
|
+
{/if}
|
|
23
|
+
|
|
24
|
+
{#if children}
|
|
25
|
+
{@render children()}
|
|
26
|
+
{/if}
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<style>
|
|
30
|
+
.feature-tags {
|
|
31
|
+
display: flex;
|
|
32
|
+
gap: 1rem;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
flex-wrap: wrap;
|
|
35
|
+
margin-top: 2rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.hero-section {
|
|
39
|
+
text-align: center;
|
|
40
|
+
padding-bottom: 3rem;
|
|
41
|
+
margin-bottom: 3rem;
|
|
42
|
+
}</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
title?: import('svelte').Snippet;
|
|
3
|
+
text?: import('svelte').Snippet;
|
|
4
|
+
features?: import('svelte').Snippet;
|
|
5
|
+
children?: import('svelte').Snippet;
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const Hero: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type Hero = ReturnType<typeof Hero>;
|
|
10
|
+
export default Hero;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">let { target = 'body', children } = $props();
|
|
2
|
+
let mountElement = $state(null);
|
|
3
|
+
function portal(node, currentTarget) {
|
|
4
|
+
currentTarget.appendChild(node);
|
|
5
|
+
return {
|
|
6
|
+
update(newTarget) {
|
|
7
|
+
// Handle target prop changes by moving node to new parent
|
|
8
|
+
if (newTarget !== currentTarget) {
|
|
9
|
+
newTarget.appendChild(node);
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
destroy() {
|
|
13
|
+
if (node.parentNode) {
|
|
14
|
+
node.parentNode.removeChild(node);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
$effect(() => {
|
|
20
|
+
if (typeof document === 'undefined')
|
|
21
|
+
return;
|
|
22
|
+
// Resolve target element
|
|
23
|
+
const targetElement = typeof target === 'string'
|
|
24
|
+
? document.querySelector(target)
|
|
25
|
+
: target;
|
|
26
|
+
if (!targetElement)
|
|
27
|
+
return;
|
|
28
|
+
// Create container div
|
|
29
|
+
const container = document.createElement('div');
|
|
30
|
+
targetElement.appendChild(container);
|
|
31
|
+
mountElement = container;
|
|
32
|
+
return () => {
|
|
33
|
+
// Cleanup: remove container from DOM
|
|
34
|
+
container.remove();
|
|
35
|
+
mountElement = null;
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
export {};
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
{#if mountElement}
|
|
42
|
+
{#if children}
|
|
43
|
+
<div use:portal={mountElement}>
|
|
44
|
+
{@render children()}
|
|
45
|
+
</div>
|
|
46
|
+
{/if}
|
|
47
|
+
{/if}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* Portal component - teleports content to a different DOM location.
|
|
4
|
+
*
|
|
5
|
+
* **Focus Management**: This component handles DOM manipulation only.
|
|
6
|
+
* For focus-sensitive content (modals, drawers, toasts), the parent component
|
|
7
|
+
* should manage focus using the patterns from Modal.svelte and Drawer.svelte:
|
|
8
|
+
* - Store previousFocus before opening
|
|
9
|
+
* - Focus appropriate element after mount
|
|
10
|
+
* - Restore focus on cleanup
|
|
11
|
+
*
|
|
12
|
+
* **Stacking Coordination**: Multiple portals can coexist. For z-index stacking,
|
|
13
|
+
* manage via CSS classes on the portal children or implement a portal manager.
|
|
14
|
+
*/
|
|
15
|
+
interface Props {
|
|
16
|
+
target?: HTMLElement | string;
|
|
17
|
+
children?: Snippet;
|
|
18
|
+
}
|
|
19
|
+
declare const Portal: import("svelte").Component<Props, {}, "">;
|
|
20
|
+
type Portal = ReturnType<typeof Portal>;
|
|
21
|
+
export default Portal;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script lang="ts">let { height = '400px', children } = $props();
|
|
2
|
+
export {};
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<div
|
|
6
|
+
class="overflow-y-auto"
|
|
7
|
+
style="
|
|
8
|
+
height: {height};
|
|
9
|
+
scrollbar-width: thin;
|
|
10
|
+
scrollbar-color: var(--color-accent) var(--color-base-3);
|
|
11
|
+
"
|
|
12
|
+
>
|
|
13
|
+
{@render children?.()}
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<style>
|
|
17
|
+
div::-webkit-scrollbar {
|
|
18
|
+
width: 8px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
div::-webkit-scrollbar-track {
|
|
22
|
+
background: var(--color-base-3);
|
|
23
|
+
border-radius: var(--radius-sm);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
div::-webkit-scrollbar-thumb {
|
|
27
|
+
background: var(--color-accent);
|
|
28
|
+
border-radius: var(--radius-sm);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
div::-webkit-scrollbar-thumb:hover {
|
|
32
|
+
background: var(--color-accent-soft);
|
|
33
|
+
}</style>
|