@delightstack/components 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/LICENSE +21 -0
- package/README.md +136 -0
- package/SKILL.md +149 -0
- package/bin/agents.js +63 -0
- package/dist/actions/Alert.svelte +202 -0
- package/dist/actions/Alert.svelte.d.ts +36 -0
- package/dist/actions/Alert.svelte.d.ts.map +1 -0
- package/dist/actions/Button.svelte +1450 -0
- package/dist/actions/Button.svelte.d.ts +56 -0
- package/dist/actions/Button.svelte.d.ts.map +1 -0
- package/dist/actions/ButtonGroup.svelte +111 -0
- package/dist/actions/ButtonGroup.svelte.d.ts +41 -0
- package/dist/actions/ButtonGroup.svelte.d.ts.map +1 -0
- package/dist/actions/CommandPalette.svelte +939 -0
- package/dist/actions/CommandPalette.svelte.d.ts +37 -0
- package/dist/actions/CommandPalette.svelte.d.ts.map +1 -0
- package/dist/actions/ContextMenu.svelte +138 -0
- package/dist/actions/ContextMenu.svelte.d.ts +54 -0
- package/dist/actions/ContextMenu.svelte.d.ts.map +1 -0
- package/dist/actions/Modal.svelte +474 -0
- package/dist/actions/Modal.svelte.d.ts +28 -0
- package/dist/actions/Modal.svelte.d.ts.map +1 -0
- package/dist/actions/Popover.svelte +1214 -0
- package/dist/actions/Popover.svelte.d.ts +31 -0
- package/dist/actions/Popover.svelte.d.ts.map +1 -0
- package/dist/actions/Portal.svelte +80 -0
- package/dist/actions/Portal.svelte.d.ts +17 -0
- package/dist/actions/Portal.svelte.d.ts.map +1 -0
- package/dist/actions/ThemeToggle.svelte +345 -0
- package/dist/actions/ThemeToggle.svelte.d.ts +15 -0
- package/dist/actions/ThemeToggle.svelte.d.ts.map +1 -0
- package/dist/actions/index.d.ts +13 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +10 -0
- package/dist/actions/scrollbar.d.ts +48 -0
- package/dist/actions/scrollbar.d.ts.map +1 -0
- package/dist/actions/scrollbar.js +404 -0
- package/dist/display/Accordion.svelte +586 -0
- package/dist/display/Accordion.svelte.d.ts +41 -0
- package/dist/display/Accordion.svelte.d.ts.map +1 -0
- package/dist/display/Avatar.svelte +527 -0
- package/dist/display/Avatar.svelte.d.ts +22 -0
- package/dist/display/Avatar.svelte.d.ts.map +1 -0
- package/dist/display/AvatarGroup.svelte +298 -0
- package/dist/display/AvatarGroup.svelte.d.ts +31 -0
- package/dist/display/AvatarGroup.svelte.d.ts.map +1 -0
- package/dist/display/Calendar.svelte +1366 -0
- package/dist/display/Calendar.svelte.d.ts +58 -0
- package/dist/display/Calendar.svelte.d.ts.map +1 -0
- package/dist/display/Chart.svelte +1426 -0
- package/dist/display/Chart.svelte.d.ts +35 -0
- package/dist/display/Chart.svelte.d.ts.map +1 -0
- package/dist/display/Code.svelte +780 -0
- package/dist/display/Code.svelte.d.ts +19 -0
- package/dist/display/Code.svelte.d.ts.map +1 -0
- package/dist/display/Comparison.svelte +686 -0
- package/dist/display/Comparison.svelte.d.ts +22 -0
- package/dist/display/Comparison.svelte.d.ts.map +1 -0
- package/dist/display/Counter.svelte +285 -0
- package/dist/display/Counter.svelte.d.ts +21 -0
- package/dist/display/Counter.svelte.d.ts.map +1 -0
- package/dist/display/Expand.svelte +48 -0
- package/dist/display/Expand.svelte.d.ts +9 -0
- package/dist/display/Expand.svelte.d.ts.map +1 -0
- package/dist/display/List.svelte +294 -0
- package/dist/display/List.svelte.d.ts +40 -0
- package/dist/display/List.svelte.d.ts.map +1 -0
- package/dist/display/ListContextReset.svelte +19 -0
- package/dist/display/ListContextReset.svelte.d.ts +7 -0
- package/dist/display/ListContextReset.svelte.d.ts.map +1 -0
- package/dist/display/ListItem.svelte +834 -0
- package/dist/display/ListItem.svelte.d.ts +22 -0
- package/dist/display/ListItem.svelte.d.ts.map +1 -0
- package/dist/display/QR.svelte +1193 -0
- package/dist/display/QR.svelte.d.ts +23 -0
- package/dist/display/QR.svelte.d.ts.map +1 -0
- package/dist/display/SplitPane.svelte +744 -0
- package/dist/display/SplitPane.svelte.d.ts +25 -0
- package/dist/display/SplitPane.svelte.d.ts.map +1 -0
- package/dist/display/Stat.svelte +439 -0
- package/dist/display/Stat.svelte.d.ts +24 -0
- package/dist/display/Stat.svelte.d.ts.map +1 -0
- package/dist/display/Table.svelte +4654 -0
- package/dist/display/Table.svelte.d.ts +249 -0
- package/dist/display/Table.svelte.d.ts.map +1 -0
- package/dist/display/TableCellEditor.svelte +935 -0
- package/dist/display/TableCellEditor.svelte.d.ts +58 -0
- package/dist/display/TableCellEditor.svelte.d.ts.map +1 -0
- package/dist/display/Timeline.svelte +1258 -0
- package/dist/display/Timeline.svelte.d.ts +43 -0
- package/dist/display/Timeline.svelte.d.ts.map +1 -0
- package/dist/display/Tree.svelte +1740 -0
- package/dist/display/Tree.svelte.d.ts +74 -0
- package/dist/display/Tree.svelte.d.ts.map +1 -0
- package/dist/display/Typewriter.svelte +338 -0
- package/dist/display/Typewriter.svelte.d.ts +22 -0
- package/dist/display/Typewriter.svelte.d.ts.map +1 -0
- package/dist/display/index.d.ts +24 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +18 -0
- package/dist/feedback/Callout.svelte +529 -0
- package/dist/feedback/Callout.svelte.d.ts +24 -0
- package/dist/feedback/Callout.svelte.d.ts.map +1 -0
- package/dist/feedback/Confetti.svelte +631 -0
- package/dist/feedback/Confetti.svelte.d.ts +90 -0
- package/dist/feedback/Confetti.svelte.d.ts.map +1 -0
- package/dist/feedback/Progress.svelte +382 -0
- package/dist/feedback/Progress.svelte.d.ts +25 -0
- package/dist/feedback/Progress.svelte.d.ts.map +1 -0
- package/dist/feedback/Toast.svelte +967 -0
- package/dist/feedback/Toast.svelte.d.ts +54 -0
- package/dist/feedback/Toast.svelte.d.ts.map +1 -0
- package/dist/feedback/index.d.ts +7 -0
- package/dist/feedback/index.d.ts.map +1 -0
- package/dist/feedback/index.js +4 -0
- package/dist/form/Checkbox.svelte +449 -0
- package/dist/form/Checkbox.svelte.d.ts +27 -0
- package/dist/form/Checkbox.svelte.d.ts.map +1 -0
- package/dist/form/Fieldset.svelte +410 -0
- package/dist/form/Fieldset.svelte.d.ts +22 -0
- package/dist/form/Fieldset.svelte.d.ts.map +1 -0
- package/dist/form/FileUpload.svelte +934 -0
- package/dist/form/FileUpload.svelte.d.ts +41 -0
- package/dist/form/FileUpload.svelte.d.ts.map +1 -0
- package/dist/form/Form.svelte +530 -0
- package/dist/form/Form.svelte.d.ts +120 -0
- package/dist/form/Form.svelte.d.ts.map +1 -0
- package/dist/form/Input.svelte +2858 -0
- package/dist/form/Input.svelte.d.ts +66 -0
- package/dist/form/Input.svelte.d.ts.map +1 -0
- package/dist/form/Radio.svelte +507 -0
- package/dist/form/Radio.svelte.d.ts +39 -0
- package/dist/form/Radio.svelte.d.ts.map +1 -0
- package/dist/form/Range.svelte +912 -0
- package/dist/form/Range.svelte.d.ts +33 -0
- package/dist/form/Range.svelte.d.ts.map +1 -0
- package/dist/form/Rating.svelte +429 -0
- package/dist/form/Rating.svelte.d.ts +28 -0
- package/dist/form/Rating.svelte.d.ts.map +1 -0
- package/dist/form/Select.svelte +1933 -0
- package/dist/form/Select.svelte.d.ts +54 -0
- package/dist/form/Select.svelte.d.ts.map +1 -0
- package/dist/form/Toggle.svelte +645 -0
- package/dist/form/Toggle.svelte.d.ts +50 -0
- package/dist/form/Toggle.svelte.d.ts.map +1 -0
- package/dist/form/index.d.ts +15 -0
- package/dist/form/index.d.ts.map +1 -0
- package/dist/form/index.js +10 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/layout/README.md +172 -0
- package/dist/media/Carousel.svelte +2424 -0
- package/dist/media/Carousel.svelte.d.ts +47 -0
- package/dist/media/Carousel.svelte.d.ts.map +1 -0
- package/dist/media/Gallery.svelte +2881 -0
- package/dist/media/Gallery.svelte.d.ts +82 -0
- package/dist/media/Gallery.svelte.d.ts.map +1 -0
- package/dist/media/Image.svelte +389 -0
- package/dist/media/Image.svelte.d.ts +33 -0
- package/dist/media/Image.svelte.d.ts.map +1 -0
- package/dist/media/PDF.svelte +1793 -0
- package/dist/media/PDF.svelte.d.ts +44 -0
- package/dist/media/PDF.svelte.d.ts.map +1 -0
- package/dist/media/Panorama.svelte +1391 -0
- package/dist/media/Panorama.svelte.d.ts +47 -0
- package/dist/media/Panorama.svelte.d.ts.map +1 -0
- package/dist/media/Video.svelte +2501 -0
- package/dist/media/Video.svelte.d.ts +58 -0
- package/dist/media/Video.svelte.d.ts.map +1 -0
- package/dist/media/carousel.d.ts +211 -0
- package/dist/media/carousel.d.ts.map +1 -0
- package/dist/media/carousel.js +408 -0
- package/dist/media/index.d.ts +11 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/index.js +5 -0
- package/dist/navigation/BottomSheet.svelte +636 -0
- package/dist/navigation/BottomSheet.svelte.d.ts +27 -0
- package/dist/navigation/BottomSheet.svelte.d.ts.map +1 -0
- package/dist/navigation/Breadcrumbs.svelte +611 -0
- package/dist/navigation/Breadcrumbs.svelte.d.ts +28 -0
- package/dist/navigation/Breadcrumbs.svelte.d.ts.map +1 -0
- package/dist/navigation/Pagination.svelte +641 -0
- package/dist/navigation/Pagination.svelte.d.ts +27 -0
- package/dist/navigation/Pagination.svelte.d.ts.map +1 -0
- package/dist/navigation/Steps.svelte +965 -0
- package/dist/navigation/Steps.svelte.d.ts +43 -0
- package/dist/navigation/Steps.svelte.d.ts.map +1 -0
- package/dist/navigation/Tabs.svelte +698 -0
- package/dist/navigation/Tabs.svelte.d.ts +41 -0
- package/dist/navigation/Tabs.svelte.d.ts.map +1 -0
- package/dist/navigation/index.d.ts +8 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +5 -0
- package/package.json +139 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type PopoverPlacement = 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end';
|
|
2
|
+
export type PopoverStrategy = 'fixed' | 'absolute';
|
|
3
|
+
import { type Snippet } from 'svelte';
|
|
4
|
+
declare const Popover: import("svelte").Component<{
|
|
5
|
+
ref_element?: HTMLElement | undefined;
|
|
6
|
+
opened?: boolean;
|
|
7
|
+
placement?: PopoverPlacement;
|
|
8
|
+
strategy?: PopoverStrategy;
|
|
9
|
+
arrow?: boolean;
|
|
10
|
+
x?: number | undefined;
|
|
11
|
+
y?: number | undefined;
|
|
12
|
+
open_on_hover?: boolean;
|
|
13
|
+
open_on_click?: boolean;
|
|
14
|
+
open_on_focus?: boolean;
|
|
15
|
+
close_on_outside_click?: boolean;
|
|
16
|
+
close_on_inside_click?: boolean;
|
|
17
|
+
close_on_escape_key?: boolean;
|
|
18
|
+
disable_initial_focus?: boolean;
|
|
19
|
+
hover_delay?: number;
|
|
20
|
+
transparent?: boolean;
|
|
21
|
+
dense?: boolean;
|
|
22
|
+
comfortable?: boolean;
|
|
23
|
+
radius?: string | undefined;
|
|
24
|
+
children?: undefined | Snippet;
|
|
25
|
+
id?: string;
|
|
26
|
+
class?: string;
|
|
27
|
+
style?: string;
|
|
28
|
+
}, {}, "ref_element" | "opened">;
|
|
29
|
+
type Popover = ReturnType<typeof Popover>;
|
|
30
|
+
export default Popover;
|
|
31
|
+
//# sourceMappingURL=Popover.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.svelte.d.ts","sourceRoot":"","sources":["../../src/actions/Popover.svelte.ts"],"names":[],"mappings":"AAGC,MAAM,MAAM,gBAAgB,GACzB,KAAK,GACL,WAAW,GACX,SAAS,GACT,QAAQ,GACR,cAAc,GACd,YAAY,GACZ,MAAM,GACN,YAAY,GACZ,UAAU,GACV,OAAO,GACP,aAAa,GACb,WAAW,CAAC;AACf,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,UAAU,CAAC;AAOpD,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AA4/BrD,QAAA,MAAM,OAAO;kBA36B0E,WAAW,GAAG,SAAS;aAAW,OAAO;gBAAc,gBAAgB;eAAa,eAAe;YAAU,OAAO;QAAM,MAAM,GAAG,SAAS;QAAM,MAAM,GAAG,SAAS;oBAAkB,OAAO;oBAAkB,OAAO;oBAAkB,OAAO;6BAA2B,OAAO;4BAA0B,OAAO;0BAAwB,OAAO;4BAA0B,OAAO;kBAAgB,MAAM;kBAAgB,OAAO;YAAU,OAAO;kBAAgB,OAAO;aAAW,MAAM,GAAG,SAAS;eAAa,SAAS,GAAG,OAAO;;YAA8B,MAAM;YAAU,MAAM;gCA26B1lB,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { tick, type Snippet } from 'svelte';
|
|
3
|
+
import { DelightError } from '@delightstack/utilities';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An action for moving a component to a different parent element
|
|
7
|
+
* Usage: <div use:portal={'css selector'}> or <div use:portal={document.body}>
|
|
8
|
+
*/
|
|
9
|
+
export function portal(el: HTMLElement, target: HTMLElement | string = 'body') {
|
|
10
|
+
let targetEl: HTMLElement | null = null;
|
|
11
|
+
async function update(newTarget: HTMLElement | string) {
|
|
12
|
+
target = newTarget;
|
|
13
|
+
if (target === '.portals') {
|
|
14
|
+
targetEl = document.querySelector('.portals');
|
|
15
|
+
if (!targetEl) {
|
|
16
|
+
targetEl = document.createElement('div');
|
|
17
|
+
targetEl.classList.add('portals');
|
|
18
|
+
document.body.appendChild(targetEl);
|
|
19
|
+
}
|
|
20
|
+
} else if (typeof target === 'string') {
|
|
21
|
+
targetEl = document.querySelector(target);
|
|
22
|
+
if (targetEl === null) {
|
|
23
|
+
await tick();
|
|
24
|
+
targetEl = document.querySelector(target);
|
|
25
|
+
}
|
|
26
|
+
if (targetEl === null) {
|
|
27
|
+
throw new DelightError(`No element found matching css selector: "${target}"`);
|
|
28
|
+
}
|
|
29
|
+
} else if (target instanceof HTMLElement) {
|
|
30
|
+
targetEl = target;
|
|
31
|
+
} else {
|
|
32
|
+
throw new DelightError(
|
|
33
|
+
`Unknown portal target type: ${
|
|
34
|
+
target === null ? 'null' : typeof target
|
|
35
|
+
}. Allowed types: string (CSS selector) or HTMLElement.`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
targetEl.appendChild(el);
|
|
39
|
+
el.hidden = false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function destroy() {
|
|
43
|
+
el.remove();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
update(target);
|
|
47
|
+
return {
|
|
48
|
+
update,
|
|
49
|
+
destroy,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<script lang="ts">
|
|
55
|
+
const propId = $props.id();
|
|
56
|
+
let {
|
|
57
|
+
/** The DOM Element or CSS Selector where the portal elenent should be inserted */
|
|
58
|
+
target = '.portals' as HTMLElement | string,
|
|
59
|
+
|
|
60
|
+
/** The child elements to display inside the portal */
|
|
61
|
+
children = undefined as undefined | Snippet,
|
|
62
|
+
|
|
63
|
+
/** The ID of the portal element */
|
|
64
|
+
id = propId,
|
|
65
|
+
} = $props();
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
{#if children}
|
|
69
|
+
<div use:portal={target} hidden class="portal" {id}>
|
|
70
|
+
{@render children()}
|
|
71
|
+
</div>
|
|
72
|
+
{/if}
|
|
73
|
+
|
|
74
|
+
<style>
|
|
75
|
+
:global(.portals),
|
|
76
|
+
:global(.portals .portal) {
|
|
77
|
+
position: static;
|
|
78
|
+
display: contents;
|
|
79
|
+
}
|
|
80
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* An action for moving a component to a different parent element
|
|
4
|
+
* Usage: <div use:portal={'css selector'}> or <div use:portal={document.body}>
|
|
5
|
+
*/
|
|
6
|
+
export declare function portal(el: HTMLElement, target?: HTMLElement | string): {
|
|
7
|
+
update: (newTarget: HTMLElement | string) => Promise<void>;
|
|
8
|
+
destroy: () => void;
|
|
9
|
+
};
|
|
10
|
+
declare const Portal: import("svelte").Component<{
|
|
11
|
+
target?: HTMLElement | string;
|
|
12
|
+
children?: undefined | Snippet;
|
|
13
|
+
id?: string;
|
|
14
|
+
}, {}, "">;
|
|
15
|
+
type Portal = ReturnType<typeof Portal>;
|
|
16
|
+
export default Portal;
|
|
17
|
+
//# sourceMappingURL=Portal.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Portal.svelte.d.ts","sourceRoot":"","sources":["../../src/actions/Portal.svelte.ts"],"names":[],"mappings":"AAGC,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AAG5C;;;GAGG;AACH,wBAAgB,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,GAAE,WAAW,GAAG,MAAe;wBAE3C,WAAW,GAAG,MAAM;;EAwCrD;AA4BF,QAAA,MAAM,MAAM;aAzBsE,WAAW,GAAG,MAAM;eAAa,SAAS,GAAG,OAAO;;UAyBlF,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { tooltip, ripple } from '@delightstack/utilities';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A theme toggle component that cycles between light, dark, and auto modes.
|
|
6
|
+
* Uses a moon-with-stars icon for dark and a sun for light; transitions
|
|
7
|
+
* between them with a soft fade/scale microinteraction.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const STORAGE_KEY = 'delightstack:theme';
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
/** The current theme: 'light', 'dark', or 'auto' */
|
|
14
|
+
theme = $bindable('auto') as 'light' | 'dark' | 'auto',
|
|
15
|
+
|
|
16
|
+
/** Whether the current effective theme is dark. */
|
|
17
|
+
is_dark = $bindable(false) as boolean,
|
|
18
|
+
|
|
19
|
+
/** The size of the toggle button: '0' (small), '1' (medium), '2' (large), '3' (xlarge) */
|
|
20
|
+
size = '1' as '0' | '1' | '2' | '3',
|
|
21
|
+
|
|
22
|
+
/** Whether the system/auto option should be disabled (only light/dark) */
|
|
23
|
+
disable_auto = false,
|
|
24
|
+
|
|
25
|
+
/** Show a text label beside the icon ("Light" / "Dark" / "Auto"). */
|
|
26
|
+
show_label = false,
|
|
27
|
+
|
|
28
|
+
/** Custom text label override. Falls back to the current mode name. */
|
|
29
|
+
label = undefined as string | undefined,
|
|
30
|
+
|
|
31
|
+
/** Tooltip text shown on hover */
|
|
32
|
+
tooltip: tooltip_message = '',
|
|
33
|
+
|
|
34
|
+
/** The ID of the element. @defaults to a random ID */
|
|
35
|
+
id = undefined as string | undefined,
|
|
36
|
+
|
|
37
|
+
/** Specifies a custom class name for the container element */
|
|
38
|
+
class: class_name = '',
|
|
39
|
+
|
|
40
|
+
/** Called when the theme changes */
|
|
41
|
+
onchange = undefined as ((theme: 'light' | 'dark' | 'auto') => void) | undefined,
|
|
42
|
+
} = $props();
|
|
43
|
+
|
|
44
|
+
const SIZE_MAP = { '0': 18, '1': 22, '2': 28, '3': 34 } as const;
|
|
45
|
+
const svgSize = $derived(SIZE_MAP[size]);
|
|
46
|
+
|
|
47
|
+
let systemPrefersDark = $state(false);
|
|
48
|
+
|
|
49
|
+
const effectiveDark = $derived(
|
|
50
|
+
theme === 'dark' ? true : theme === 'light' ? false : systemPrefersDark,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
$effect(() => {
|
|
54
|
+
is_dark = effectiveDark;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
$effect(() => {
|
|
58
|
+
try {
|
|
59
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
60
|
+
if (stored === 'light' || stored === 'dark' || stored === 'auto') {
|
|
61
|
+
theme = disable_auto && stored === 'auto' ? 'light' : stored;
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// ignore
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const mql = window.matchMedia('(prefers-color-scheme: dark)');
|
|
68
|
+
systemPrefersDark = mql.matches;
|
|
69
|
+
|
|
70
|
+
function handleChange(e: MediaQueryListEvent) {
|
|
71
|
+
systemPrefersDark = e.matches;
|
|
72
|
+
}
|
|
73
|
+
mql.addEventListener('change', handleChange);
|
|
74
|
+
|
|
75
|
+
return () => {
|
|
76
|
+
mql.removeEventListener('change', handleChange);
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
$effect(() => {
|
|
81
|
+
document.documentElement.style.colorScheme = effectiveDark ? 'dark' : 'light';
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
function persistTheme(value: 'light' | 'dark' | 'auto') {
|
|
85
|
+
try {
|
|
86
|
+
localStorage.setItem(STORAGE_KEY, value);
|
|
87
|
+
} catch {
|
|
88
|
+
// ignore
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function cycleTheme() {
|
|
93
|
+
if (disable_auto) {
|
|
94
|
+
theme = theme === 'light' ? 'dark' : 'light';
|
|
95
|
+
} else {
|
|
96
|
+
if (theme === 'light') theme = 'dark';
|
|
97
|
+
else if (theme === 'dark') theme = 'auto';
|
|
98
|
+
else theme = 'light';
|
|
99
|
+
}
|
|
100
|
+
persistTheme(theme);
|
|
101
|
+
onchange?.(theme);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function handleKeyDown(e: KeyboardEvent) {
|
|
105
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
cycleTheme();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const modeLabel = $derived(
|
|
112
|
+
theme === 'auto' ? 'Auto' : theme === 'dark' ? 'Dark' : 'Light',
|
|
113
|
+
);
|
|
114
|
+
const ariaLabel = $derived(
|
|
115
|
+
theme === 'auto'
|
|
116
|
+
? 'Theme: auto (system preference)'
|
|
117
|
+
: theme === 'dark'
|
|
118
|
+
? 'Theme: dark'
|
|
119
|
+
: 'Theme: light',
|
|
120
|
+
);
|
|
121
|
+
</script>
|
|
122
|
+
|
|
123
|
+
<button
|
|
124
|
+
type="button"
|
|
125
|
+
{id}
|
|
126
|
+
class={['theme-toggle', `size-${size}`, class_name].filter(Boolean).join(' ')}
|
|
127
|
+
class:is-dark={effectiveDark}
|
|
128
|
+
class:is-auto={theme === 'auto'}
|
|
129
|
+
class:has-label={show_label}
|
|
130
|
+
aria-label={ariaLabel}
|
|
131
|
+
onclick={cycleTheme}
|
|
132
|
+
onkeydown={handleKeyDown}
|
|
133
|
+
{@attach tooltip(tooltip_message || (show_label ? '' : ariaLabel))}
|
|
134
|
+
{@attach ripple({})}>
|
|
135
|
+
<span class="icon" style:width="{svgSize}px" style:height="{svgSize}px">
|
|
136
|
+
<svg
|
|
137
|
+
class="sun"
|
|
138
|
+
width={svgSize}
|
|
139
|
+
height={svgSize}
|
|
140
|
+
viewBox="0 0 24 24"
|
|
141
|
+
fill="none"
|
|
142
|
+
stroke="currentColor"
|
|
143
|
+
stroke-width="2"
|
|
144
|
+
stroke-linecap="round"
|
|
145
|
+
stroke-linejoin="round"
|
|
146
|
+
aria-hidden="true">
|
|
147
|
+
<circle cx="12" cy="12" r="5" />
|
|
148
|
+
<g class="rays">
|
|
149
|
+
<line x1="12" y1="1" x2="12" y2="3" />
|
|
150
|
+
<line x1="12" y1="21" x2="12" y2="23" />
|
|
151
|
+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
|
|
152
|
+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
|
|
153
|
+
<line x1="1" y1="12" x2="3" y2="12" />
|
|
154
|
+
<line x1="21" y1="12" x2="23" y2="12" />
|
|
155
|
+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
|
|
156
|
+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
|
157
|
+
</g>
|
|
158
|
+
</svg>
|
|
159
|
+
<svg
|
|
160
|
+
class="moon"
|
|
161
|
+
width={svgSize}
|
|
162
|
+
height={svgSize}
|
|
163
|
+
viewBox="0 0 24 24"
|
|
164
|
+
fill="currentColor"
|
|
165
|
+
aria-hidden="true">
|
|
166
|
+
<!-- Crescent moon facing left, with two small twinkling stars. -->
|
|
167
|
+
<path d="M20 14.5A8.5 8.5 0 0 1 9.5 4a8.5 8.5 0 1 0 10.5 10.5z" />
|
|
168
|
+
<circle class="star star-1" cx="7" cy="5" r="0.9" />
|
|
169
|
+
<circle class="star star-2" cx="4" cy="10" r="0.6" />
|
|
170
|
+
</svg>
|
|
171
|
+
</span>
|
|
172
|
+
{#if show_label}
|
|
173
|
+
<span class="label">{label ?? modeLabel}</span>
|
|
174
|
+
{/if}
|
|
175
|
+
{#if theme === 'auto'}
|
|
176
|
+
<span class="auto-indicator" aria-hidden="true">A</span>
|
|
177
|
+
{/if}
|
|
178
|
+
</button>
|
|
179
|
+
|
|
180
|
+
<style>
|
|
181
|
+
button {
|
|
182
|
+
--icon-duration: 500ms;
|
|
183
|
+
--icon-easing: cubic-bezier(0.22, 1, 0.36, 1);
|
|
184
|
+
|
|
185
|
+
position: relative;
|
|
186
|
+
display: inline-flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
gap: 0.5em;
|
|
189
|
+
background: none;
|
|
190
|
+
border: none;
|
|
191
|
+
padding: 0.5em;
|
|
192
|
+
cursor: pointer;
|
|
193
|
+
color: currentColor;
|
|
194
|
+
border-radius: var(--radius-full, 9999px);
|
|
195
|
+
font: inherit;
|
|
196
|
+
transition:
|
|
197
|
+
background-color 250ms ease,
|
|
198
|
+
translate 200ms ease;
|
|
199
|
+
-webkit-tap-highlight-color: transparent;
|
|
200
|
+
|
|
201
|
+
&.has-label {
|
|
202
|
+
padding: 0.4em 0.9em;
|
|
203
|
+
border-radius: var(--radius-lg, 8px);
|
|
204
|
+
@supports (corner-shape: squircle) {
|
|
205
|
+
corner-shape: squircle;
|
|
206
|
+
border-radius: calc(var(--radius-lg, 8px) * var(--squircle-ratio, 2));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
&:hover {
|
|
210
|
+
background-color: rgb(from currentColor r g b / 0.08);
|
|
211
|
+
/* Snap the tint in on hover; the base rule eases it back out on leave. */
|
|
212
|
+
transition: translate 200ms ease;
|
|
213
|
+
}
|
|
214
|
+
&:active {
|
|
215
|
+
translate: 0px 1px clamp(-10px, calc(0.2em - 12px), -2px);
|
|
216
|
+
}
|
|
217
|
+
&:focus-visible {
|
|
218
|
+
outline: 2px solid currentColor;
|
|
219
|
+
outline-offset: 2px;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.icon {
|
|
223
|
+
position: relative;
|
|
224
|
+
display: inline-block;
|
|
225
|
+
flex-shrink: 0;
|
|
226
|
+
|
|
227
|
+
svg {
|
|
228
|
+
position: absolute;
|
|
229
|
+
inset: 0;
|
|
230
|
+
transition:
|
|
231
|
+
opacity var(--icon-duration) var(--icon-easing),
|
|
232
|
+
transform var(--icon-duration) var(--icon-easing);
|
|
233
|
+
transform-origin: center;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* Light mode: sun visible, moon hidden */
|
|
238
|
+
&:not(.is-dark) {
|
|
239
|
+
.sun {
|
|
240
|
+
opacity: 1;
|
|
241
|
+
transform: scale(1) rotate(0deg);
|
|
242
|
+
}
|
|
243
|
+
.moon {
|
|
244
|
+
opacity: 0;
|
|
245
|
+
transform: scale(0.4) rotate(-90deg);
|
|
246
|
+
}
|
|
247
|
+
.rays {
|
|
248
|
+
opacity: 1;
|
|
249
|
+
transform: scale(1) rotate(0deg);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Dark mode: moon visible, sun hidden */
|
|
254
|
+
&.is-dark {
|
|
255
|
+
.sun {
|
|
256
|
+
opacity: 0;
|
|
257
|
+
transform: scale(0.4) rotate(90deg);
|
|
258
|
+
}
|
|
259
|
+
.moon {
|
|
260
|
+
opacity: 1;
|
|
261
|
+
transform: scale(1) rotate(0deg);
|
|
262
|
+
}
|
|
263
|
+
.rays {
|
|
264
|
+
opacity: 0;
|
|
265
|
+
transform: scale(0) rotate(45deg);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.rays {
|
|
270
|
+
transform-origin: center;
|
|
271
|
+
transition:
|
|
272
|
+
opacity var(--icon-duration) var(--icon-easing),
|
|
273
|
+
transform var(--icon-duration) var(--icon-easing);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.moon .star {
|
|
277
|
+
transform-origin: center;
|
|
278
|
+
opacity: 0.85;
|
|
279
|
+
animation: twinkle 2.4s ease-in-out infinite;
|
|
280
|
+
}
|
|
281
|
+
.moon .star-2 {
|
|
282
|
+
animation-delay: 1.2s;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.label {
|
|
286
|
+
font-size: 0.9em;
|
|
287
|
+
line-height: 1;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* The "auto" badge sits in the lower-right corner. It's a small filled pill
|
|
291
|
+
* (text-colored, with the letter knocked out in the background color) so it
|
|
292
|
+
* reads clearly as an "A" and a ring separates it from the icon. The button
|
|
293
|
+
* no longer clips its overflow, so the badge is never cut off. */
|
|
294
|
+
.auto-indicator {
|
|
295
|
+
position: absolute;
|
|
296
|
+
bottom: -0.05em;
|
|
297
|
+
right: -0.05em;
|
|
298
|
+
display: inline-flex;
|
|
299
|
+
align-items: center;
|
|
300
|
+
justify-content: center;
|
|
301
|
+
min-width: 1.15em;
|
|
302
|
+
height: 1.15em;
|
|
303
|
+
padding: 0 0.2em;
|
|
304
|
+
font-size: 0.62em;
|
|
305
|
+
font-weight: 800;
|
|
306
|
+
line-height: 1;
|
|
307
|
+
border-radius: var(--radius-full, 9999px);
|
|
308
|
+
/* Fill with the foreground color and knock the letter out in the
|
|
309
|
+
* background color. Use explicit tokens (not currentColor) since this
|
|
310
|
+
* element overrides its own `color`, which would collapse the contrast. */
|
|
311
|
+
background-color: var(--color-text, currentColor);
|
|
312
|
+
color: var(--color-bg, #fff);
|
|
313
|
+
box-shadow: 0 0 0 2px var(--color-bg, #fff);
|
|
314
|
+
pointer-events: none;
|
|
315
|
+
}
|
|
316
|
+
/* With a text label the mode is already spelled out, so the badge is redundant. */
|
|
317
|
+
&.has-label .auto-indicator {
|
|
318
|
+
display: none;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
@keyframes twinkle {
|
|
323
|
+
0%,
|
|
324
|
+
100% {
|
|
325
|
+
opacity: 0.4;
|
|
326
|
+
transform: scale(0.85);
|
|
327
|
+
}
|
|
328
|
+
50% {
|
|
329
|
+
opacity: 1;
|
|
330
|
+
transform: scale(1.15);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
@media (prefers-reduced-motion: reduce) {
|
|
335
|
+
button {
|
|
336
|
+
.icon svg,
|
|
337
|
+
.rays {
|
|
338
|
+
transition: none;
|
|
339
|
+
}
|
|
340
|
+
.moon .star {
|
|
341
|
+
animation: none;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare const ThemeToggle: import("svelte").Component<{
|
|
2
|
+
theme?: "light" | "dark" | "auto";
|
|
3
|
+
is_dark?: boolean;
|
|
4
|
+
size?: "0" | "1" | "2" | "3";
|
|
5
|
+
disable_auto?: boolean;
|
|
6
|
+
show_label?: boolean;
|
|
7
|
+
label?: string | undefined;
|
|
8
|
+
tooltip?: string;
|
|
9
|
+
id?: string | undefined;
|
|
10
|
+
class?: string;
|
|
11
|
+
onchange?: ((theme: "light" | "dark" | "auto") => void) | undefined;
|
|
12
|
+
}, {}, "theme" | "is_dark">;
|
|
13
|
+
type ThemeToggle = ReturnType<typeof ThemeToggle>;
|
|
14
|
+
export default ThemeToggle;
|
|
15
|
+
//# sourceMappingURL=ThemeToggle.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemeToggle.svelte.d.ts","sourceRoot":"","sources":["../../src/actions/ThemeToggle.svelte.ts"],"names":[],"mappings":"AAiKA,QAAA,MAAM,WAAW;YAnJ8E,OAAO,GAAG,MAAM,GAAG,MAAM;cAAY,OAAO;WAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;mBAAiB,OAAO;iBAAe,OAAO;YAAU,MAAM,GAAG,SAAS;cAAY,MAAM;SAAO,MAAM,GAAG,SAAS;YAAU,MAAM;eAAa,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS;2BAmJ1T,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { default as Button } from './Button.svelte';
|
|
2
|
+
export { default as ButtonGroup } from './ButtonGroup.svelte';
|
|
3
|
+
export type { ButtonGroupContext } from './ButtonGroup.svelte';
|
|
4
|
+
export { default as Modal } from './Modal.svelte';
|
|
5
|
+
export { default as Alert, alert } from './Alert.svelte';
|
|
6
|
+
export { default as Popover, type PopoverPlacement, type PopoverStrategy, } from './Popover.svelte';
|
|
7
|
+
export { default as ContextMenu, contextMenu } from './ContextMenu.svelte';
|
|
8
|
+
export { default as Portal, portal } from './Portal.svelte';
|
|
9
|
+
export { scrollbar, type ScrollbarOptions } from './scrollbar';
|
|
10
|
+
export { default as CommandPalette } from './CommandPalette.svelte';
|
|
11
|
+
export type { CommandOption } from './CommandPalette.svelte';
|
|
12
|
+
export { default as ThemeToggle } from './ThemeToggle.svelte';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EACN,OAAO,IAAI,OAAO,EAClB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { default as Button } from './Button.svelte';
|
|
2
|
+
export { default as ButtonGroup } from './ButtonGroup.svelte';
|
|
3
|
+
export { default as Modal } from './Modal.svelte';
|
|
4
|
+
export { default as Alert, alert } from './Alert.svelte';
|
|
5
|
+
export { default as Popover, } from './Popover.svelte';
|
|
6
|
+
export { default as ContextMenu, contextMenu } from './ContextMenu.svelte';
|
|
7
|
+
export { default as Portal, portal } from './Portal.svelte';
|
|
8
|
+
export { scrollbar } from './scrollbar';
|
|
9
|
+
export { default as CommandPalette } from './CommandPalette.svelte';
|
|
10
|
+
export { default as ThemeToggle } from './ThemeToggle.svelte';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Attachment } from 'svelte/attachments';
|
|
2
|
+
export interface ScrollbarOptions {
|
|
3
|
+
/** Whether the scrollbar fades out when idle. Defaults to true. */
|
|
4
|
+
autohide?: boolean;
|
|
5
|
+
/** How long (in ms) after the last scroll/pointer activity before an autohiding scrollbar fades out. Defaults to 1000. */
|
|
6
|
+
autohide_delay?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Inset (in px) from the container's corners at both ends of each track.
|
|
9
|
+
* Defaults to half the container's computed border-radius, so the thumb
|
|
10
|
+
* never overlaps a rounded corner.
|
|
11
|
+
*/
|
|
12
|
+
corner_inset?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Per-edge track insets (in px) that override the corner-derived defaults
|
|
15
|
+
* for the edges they specify. Pass a function to have it re-evaluated on
|
|
16
|
+
* every layout (e.g. to track a sticky header's height); return undefined
|
|
17
|
+
* for an edge to keep its default.
|
|
18
|
+
*/
|
|
19
|
+
track_insets?: TrackInsets | ((node: HTMLElement) => TrackInsets);
|
|
20
|
+
}
|
|
21
|
+
export interface TrackInsets {
|
|
22
|
+
top?: number;
|
|
23
|
+
bottom?: number;
|
|
24
|
+
left?: number;
|
|
25
|
+
right?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A svelte attachment that replaces an element's native scrollbars with the
|
|
29
|
+
* delightstack overlay scrollbar: a token-driven thumb that floats over the
|
|
30
|
+
* content (no layout gutter), fades in while scrolling/hovering and back out
|
|
31
|
+
* when idle, insets itself past the container's rounded corners, and supports
|
|
32
|
+
* dragging and click-to-jump like a native bar.
|
|
33
|
+
*
|
|
34
|
+
* Native scrolling (wheel, keyboard, touch, momentum) is untouched — the
|
|
35
|
+
* element keeps scrolling itself; only the visual scrollbar is replaced. On
|
|
36
|
+
* touch-only devices the attachment does nothing and the native auto-hiding
|
|
37
|
+
* indicators remain.
|
|
38
|
+
*
|
|
39
|
+
* The element's parent is used as the positioning context for the overlay
|
|
40
|
+
* (it is given `position: relative` if static), so the element should keep
|
|
41
|
+
* the same box as its parent or be positioned statically within it.
|
|
42
|
+
* @example
|
|
43
|
+
* ```svelte
|
|
44
|
+
* <div class="content" {@attach scrollbar()}>...</div>
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function scrollbar(options?: ScrollbarOptions): Attachment<HTMLElement>;
|
|
48
|
+
//# sourceMappingURL=scrollbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrollbar.d.ts","sourceRoot":"","sources":["../../src/actions/scrollbar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,gBAAgB;IAChC,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,0HAA0H;IAC1H,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,WAAW,GAAG,CAAC,CAAC,IAAI,EAAE,WAAW,KAAK,WAAW,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,WAAW;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAkGD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,UAAU,CAAC,WAAW,CAAC,CA8UjF"}
|