@sveltekitchen/sveltekitchen 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -2
- package/dist/components/Accordion.svelte +36 -0
- package/dist/components/Accordion.svelte.d.ts +15 -0
- package/dist/components/AccordionItem.svelte +73 -0
- package/dist/components/AccordionItem.svelte.d.ts +21 -0
- package/dist/components/Alert.svelte +23 -0
- package/dist/components/Alert.svelte.d.ts +15 -0
- package/dist/components/Badge.svelte +16 -0
- package/dist/components/Badge.svelte.d.ts +15 -0
- package/dist/components/Button.svelte +43 -0
- package/dist/components/Button.svelte.d.ts +25 -0
- package/dist/components/Calendar.svelte +88 -0
- package/dist/components/Calendar.svelte.d.ts +13 -0
- package/dist/components/Card.svelte +68 -0
- package/dist/components/Card.svelte.d.ts +25 -0
- package/dist/components/Chevron.svelte +36 -0
- package/dist/components/Chevron.svelte.d.ts +19 -0
- package/dist/components/Collapsible.svelte +46 -0
- package/dist/components/Collapsible.svelte.d.ts +19 -0
- package/dist/components/ConfirmDialog.svelte +70 -0
- package/dist/components/ConfirmDialog.svelte.d.ts +27 -0
- package/dist/components/DatePicker.svelte +60 -0
- package/dist/components/DatePicker.svelte.d.ts +17 -0
- package/dist/components/Divider.svelte +25 -0
- package/dist/components/Divider.svelte.d.ts +17 -0
- package/dist/components/Dropdown.svelte +100 -0
- package/dist/components/Dropdown.svelte.d.ts +21 -0
- package/dist/components/Form/Checkbox.svelte +37 -0
- package/dist/components/Form/Checkbox.svelte.d.ts +19 -0
- package/dist/components/Form/Field.svelte +28 -0
- package/dist/components/Form/Field.svelte.d.ts +21 -0
- package/dist/components/Form/Input.svelte +56 -0
- package/dist/components/Form/Input.svelte.d.ts +29 -0
- package/dist/components/Form/MaskedInput.svelte +152 -0
- package/dist/components/Form/MaskedInput.svelte.d.ts +25 -0
- package/dist/components/Form/Radio.svelte +28 -0
- package/dist/components/Form/Radio.svelte.d.ts +19 -0
- package/dist/components/Form/RadioGroup.svelte +28 -0
- package/dist/components/Form/RadioGroup.svelte.d.ts +19 -0
- package/dist/components/Form/Select.svelte +20 -0
- package/dist/components/Form/Select.svelte.d.ts +19 -0
- package/dist/components/Form/Textarea.svelte +30 -0
- package/dist/components/Form/Textarea.svelte.d.ts +25 -0
- package/dist/components/Form/Toggle.svelte +21 -0
- package/dist/components/Form/Toggle.svelte.d.ts +17 -0
- package/dist/components/Modal.svelte +77 -0
- package/dist/components/Modal.svelte.d.ts +27 -0
- package/dist/components/Pagination.svelte +77 -0
- package/dist/components/Pagination.svelte.d.ts +17 -0
- package/dist/components/Progress.svelte +34 -0
- package/dist/components/Progress.svelte.d.ts +21 -0
- package/dist/components/Spinner.svelte +24 -0
- package/dist/components/Spinner.svelte.d.ts +13 -0
- package/dist/components/Table.svelte +100 -0
- package/dist/components/Table.svelte.d.ts +21 -0
- package/dist/components/ThemeToggle.svelte +22 -0
- package/dist/components/ThemeToggle.svelte.d.ts +11 -0
- package/dist/components/Tooltip.svelte +45 -0
- package/dist/components/Tooltip.svelte.d.ts +15 -0
- package/dist/css/base/root.css +103 -0
- package/dist/css/base.css +47 -0
- package/dist/css/components/accordion.css +151 -0
- package/dist/css/components/alert.css +56 -0
- package/dist/css/components/badge.css +56 -0
- package/dist/css/components/button.css +171 -0
- package/dist/css/components/calendar.css +105 -0
- package/dist/css/components/card.css +128 -0
- package/dist/css/components/checkbox-radio.css +105 -0
- package/dist/css/components/collapsible.css +61 -0
- package/dist/css/components/divider.css +42 -0
- package/dist/css/components/dock-layout.css +111 -0
- package/dist/css/components/dropdown.css +68 -0
- package/dist/css/components/floating-shell.css +93 -0
- package/dist/css/components/form.css +286 -0
- package/dist/css/components/login.css +145 -0
- package/dist/css/components/modal.css +179 -0
- package/dist/css/components/nav.css +190 -0
- package/dist/css/components/nestable.css +187 -0
- package/dist/css/components/pagination.css +50 -0
- package/dist/css/components/progress.css +50 -0
- package/dist/css/components/sidebar.css +78 -0
- package/dist/css/components/spinner.css +36 -0
- package/dist/css/components/table.css +98 -0
- package/dist/css/components/tooltip.css +77 -0
- package/dist/css/components/topbar-layout.css +108 -0
- package/dist/css/icons/icons.css +52 -0
- package/dist/css/index.css +20 -0
- package/dist/css/layout/container.css +12 -0
- package/dist/css/layout/grid.css +40 -0
- package/dist/css/layout/shell.css +185 -0
- package/dist/css/overlay/default.css +27 -0
- package/dist/css/tokens/colors.css +81 -0
- package/dist/css/tokens/radius.css +8 -0
- package/dist/css/tokens/shadows.css +23 -0
- package/dist/css/tokens/spacing.css +30 -0
- package/dist/css/tokens/transitions.css +10 -0
- package/dist/css/tokens/typography.css +44 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +52 -0
- package/dist/layout/NavItem.svelte +84 -0
- package/dist/layout/NavItem.svelte.d.ts +25 -0
- package/dist/layout/Shell.svelte +7 -0
- package/dist/layout/Shell.svelte.d.ts +13 -0
- package/dist/layout/SidebarProfile.svelte +31 -0
- package/dist/layout/SidebarProfile.svelte.d.ts +19 -0
- package/dist/layouts/AppShell.svelte +60 -0
- package/dist/layouts/AppShell.svelte.d.ts +21 -0
- package/dist/layouts/BarLayout.svelte +60 -0
- package/dist/layouts/BarLayout.svelte.d.ts +21 -0
- package/dist/layouts/BottomBarLayout.svelte +23 -0
- package/dist/layouts/BottomBarLayout.svelte.d.ts +15 -0
- package/dist/layouts/DockLayout.svelte +81 -0
- package/dist/layouts/DockLayout.svelte.d.ts +15 -0
- package/dist/layouts/FloatingDockLayout.svelte +56 -0
- package/dist/layouts/FloatingDockLayout.svelte.d.ts +13 -0
- package/dist/layouts/FloatingLayout.svelte +80 -0
- package/dist/layouts/FloatingLayout.svelte.d.ts +19 -0
- package/dist/layouts/FloatingLeftLayout.svelte +59 -0
- package/dist/layouts/FloatingLeftLayout.svelte.d.ts +15 -0
- package/dist/layouts/FloatingShell.svelte +80 -0
- package/dist/layouts/FloatingShell.svelte.d.ts +19 -0
- package/dist/layouts/FloatingTopLayout.svelte +68 -0
- package/dist/layouts/FloatingTopLayout.svelte.d.ts +15 -0
- package/dist/layouts/HybridLayout.svelte +20 -0
- package/dist/layouts/HybridLayout.svelte.d.ts +17 -0
- package/dist/layouts/IconRailLayout.svelte +75 -0
- package/dist/layouts/IconRailLayout.svelte.d.ts +15 -0
- package/dist/layouts/LeftBarLayout.svelte +19 -0
- package/dist/layouts/LeftBarLayout.svelte.d.ts +15 -0
- package/dist/layouts/RightBarLayout.svelte +21 -0
- package/dist/layouts/RightBarLayout.svelte.d.ts +15 -0
- package/dist/layouts/SideBar.svelte +86 -0
- package/dist/layouts/SideBar.svelte.d.ts +17 -0
- package/dist/layouts/SidebarLayout.svelte +11 -0
- package/dist/layouts/SidebarLayout.svelte.d.ts +15 -0
- package/dist/layouts/TopBar.svelte +90 -0
- package/dist/layouts/TopBar.svelte.d.ts +21 -0
- package/dist/layouts/TopBarLayout.svelte +26 -0
- package/dist/layouts/TopBarLayout.svelte.d.ts +15 -0
- package/dist/theme/theme.svelte.d.ts +11 -0
- package/dist/theme/theme.svelte.js +48 -0
- package/package.json +56 -4
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default SidebarProfile;
|
|
2
|
+
type SidebarProfile = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const SidebarProfile: import("svelte").Component<{
|
|
7
|
+
name?: string;
|
|
8
|
+
role?: string;
|
|
9
|
+
initials?: string;
|
|
10
|
+
avatarSrc?: any;
|
|
11
|
+
children: any;
|
|
12
|
+
} & Record<string, any>, {}, "">;
|
|
13
|
+
type $$ComponentProps = {
|
|
14
|
+
name?: string;
|
|
15
|
+
role?: string;
|
|
16
|
+
initials?: string;
|
|
17
|
+
avatarSrc?: any;
|
|
18
|
+
children: any;
|
|
19
|
+
} & Record<string, any>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// AppShell — one app layout driven by two independent, bindable menu props:
|
|
3
|
+
//
|
|
4
|
+
// topMenu → renders a top bar (omit for no top bar)
|
|
5
|
+
// sideMenu → renders a sidebar (omit for no sidebar)
|
|
6
|
+
//
|
|
7
|
+
// both → hybrid (top bar + sidebar)
|
|
8
|
+
// one → top-only or side-only
|
|
9
|
+
// none → just content
|
|
10
|
+
//
|
|
11
|
+
// Each menu is its own bindable prop, so users wire and update them
|
|
12
|
+
// independently:
|
|
13
|
+
// <AppShell bind:topMenu bind:sideMenu>{content}</AppShell>
|
|
14
|
+
//
|
|
15
|
+
// Menu contract (same for both regions):
|
|
16
|
+
// { brand?, sections: [{ label?, items: [{ id, label, icon?, href?, badge?, children? }] }], active? }
|
|
17
|
+
import TopBar from './TopBar.svelte';
|
|
18
|
+
import SideBar from './SideBar.svelte';
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
topMenu = $bindable(undefined),
|
|
22
|
+
sideMenu = $bindable(undefined),
|
|
23
|
+
sideRight = false, // place the sidebar on the right
|
|
24
|
+
actions, // snippet: top bar right-side actions
|
|
25
|
+
footer, // snippet: sidebar footer (e.g. profile)
|
|
26
|
+
children,
|
|
27
|
+
...rest
|
|
28
|
+
} = $props();
|
|
29
|
+
|
|
30
|
+
let hasTop = $derived(!!topMenu);
|
|
31
|
+
let hasSide = $derived(!!sideMenu);
|
|
32
|
+
|
|
33
|
+
// Flatten the top menu's sections into a horizontal item list.
|
|
34
|
+
let topItems = $derived(hasTop ? (topMenu.sections ?? []).flatMap((s) => s.items ?? []) : []);
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<div class="lyt lyt-col" {...rest}>
|
|
38
|
+
{#if hasTop}
|
|
39
|
+
<TopBar
|
|
40
|
+
brand={topMenu.brand}
|
|
41
|
+
items={topItems}
|
|
42
|
+
active={topMenu.active}
|
|
43
|
+
{actions}
|
|
44
|
+
/>
|
|
45
|
+
{/if}
|
|
46
|
+
|
|
47
|
+
{#if hasSide}
|
|
48
|
+
<div class="lyt-row lyt-fill" class:lyt-side-right={sideRight}>
|
|
49
|
+
<SideBar
|
|
50
|
+
brand={hasTop ? undefined : sideMenu.brand}
|
|
51
|
+
sections={sideMenu.sections}
|
|
52
|
+
active={sideMenu.active}
|
|
53
|
+
{footer}
|
|
54
|
+
/>
|
|
55
|
+
<main class="lyt-main"><div class="lyt-inner">{@render children?.()}</div></main>
|
|
56
|
+
</div>
|
|
57
|
+
{:else}
|
|
58
|
+
<main class="lyt-main"><div class="lyt-inner">{@render children?.()}</div></main>
|
|
59
|
+
{/if}
|
|
60
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default AppShell;
|
|
2
|
+
type AppShell = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const AppShell: import("svelte").Component<{
|
|
7
|
+
topMenu?: any;
|
|
8
|
+
sideMenu?: any;
|
|
9
|
+
sideRight?: boolean;
|
|
10
|
+
actions: any;
|
|
11
|
+
footer: any;
|
|
12
|
+
children: any;
|
|
13
|
+
} & Record<string, any>, {}, "topMenu" | "sideMenu">;
|
|
14
|
+
type $$ComponentProps = {
|
|
15
|
+
topMenu?: any;
|
|
16
|
+
sideMenu?: any;
|
|
17
|
+
sideRight?: boolean;
|
|
18
|
+
actions: any;
|
|
19
|
+
footer: any;
|
|
20
|
+
children: any;
|
|
21
|
+
} & Record<string, any>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// BarLayout — one app layout driven by two independent, bindable menu props:
|
|
3
|
+
//
|
|
4
|
+
// topMenu → renders a top bar (omit for no top bar)
|
|
5
|
+
// sideMenu → renders a sidebar (omit for no sidebar)
|
|
6
|
+
//
|
|
7
|
+
// both → hybrid (top bar + sidebar)
|
|
8
|
+
// one → top-only or side-only
|
|
9
|
+
// none → just content
|
|
10
|
+
//
|
|
11
|
+
// Each menu is its own bindable prop, so users wire and update them
|
|
12
|
+
// independently:
|
|
13
|
+
// <BarLayout bind:topMenu bind:sideMenu>{content}</AppShell>
|
|
14
|
+
//
|
|
15
|
+
// Menu contract (same for both regions):
|
|
16
|
+
// { brand?, sections: [{ label?, items: [{ id, label, icon?, href?, badge?, children? }] }], active? }
|
|
17
|
+
import TopBar from './TopBar.svelte';
|
|
18
|
+
import SideBar from './SideBar.svelte';
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
topMenu = $bindable(undefined),
|
|
22
|
+
sideMenu = $bindable(undefined),
|
|
23
|
+
sideRight = false, // place the sidebar on the right
|
|
24
|
+
actions, // snippet: top bar right-side actions
|
|
25
|
+
footer, // snippet: sidebar footer (e.g. profile)
|
|
26
|
+
children,
|
|
27
|
+
...rest
|
|
28
|
+
} = $props();
|
|
29
|
+
|
|
30
|
+
let hasTop = $derived(!!topMenu);
|
|
31
|
+
let hasSide = $derived(!!sideMenu);
|
|
32
|
+
|
|
33
|
+
// Flatten the top menu's sections into a horizontal item list.
|
|
34
|
+
let topItems = $derived(hasTop ? (topMenu.sections ?? []).flatMap((s) => s.items ?? []) : []);
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<div class="lyt lyt-col" {...rest}>
|
|
38
|
+
{#if hasTop}
|
|
39
|
+
<TopBar
|
|
40
|
+
brand={topMenu.brand}
|
|
41
|
+
items={topItems}
|
|
42
|
+
active={topMenu.active}
|
|
43
|
+
{actions}
|
|
44
|
+
/>
|
|
45
|
+
{/if}
|
|
46
|
+
|
|
47
|
+
{#if hasSide}
|
|
48
|
+
<div class="lyt-row lyt-fill" class:lyt-side-right={sideRight}>
|
|
49
|
+
<SideBar
|
|
50
|
+
brand={hasTop ? undefined : sideMenu.brand}
|
|
51
|
+
sections={sideMenu.sections}
|
|
52
|
+
active={sideMenu.active}
|
|
53
|
+
{footer}
|
|
54
|
+
/>
|
|
55
|
+
<main class="lyt-main"><div class="lyt-inner">{@render children?.()}</div></main>
|
|
56
|
+
</div>
|
|
57
|
+
{:else}
|
|
58
|
+
<main class="lyt-main"><div class="lyt-inner">{@render children?.()}</div></main>
|
|
59
|
+
{/if}
|
|
60
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default BarLayout;
|
|
2
|
+
type BarLayout = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const BarLayout: import("svelte").Component<{
|
|
7
|
+
topMenu?: any;
|
|
8
|
+
sideMenu?: any;
|
|
9
|
+
sideRight?: boolean;
|
|
10
|
+
actions: any;
|
|
11
|
+
footer: any;
|
|
12
|
+
children: any;
|
|
13
|
+
} & Record<string, any>, {}, "topMenu" | "sideMenu">;
|
|
14
|
+
type $$ComponentProps = {
|
|
15
|
+
topMenu?: any;
|
|
16
|
+
sideMenu?: any;
|
|
17
|
+
sideRight?: boolean;
|
|
18
|
+
actions: any;
|
|
19
|
+
footer: any;
|
|
20
|
+
children: any;
|
|
21
|
+
} & Record<string, any>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// BottomBarLayout — a fillable content area + a single bottom bar region.
|
|
3
|
+
// Bottom bar is a horizontal menu pinned to the bottom. Nestable.
|
|
4
|
+
import TopBar from './TopBar.svelte';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
menu = $bindable(undefined),
|
|
8
|
+
actions,
|
|
9
|
+
children,
|
|
10
|
+
...rest
|
|
11
|
+
} = $props();
|
|
12
|
+
|
|
13
|
+
let items = $derived(menu ? (menu.sections ?? []).flatMap((s) => s.items ?? []) : []);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<div class="nl nl-col" {...rest}>
|
|
17
|
+
<div class="nl-fill nl-scroll">{@render children?.()}</div>
|
|
18
|
+
{#if menu}
|
|
19
|
+
<div class="nl-bottom">
|
|
20
|
+
<TopBar brand={menu.brand} {items} active={menu.active} {actions} />
|
|
21
|
+
</div>
|
|
22
|
+
{/if}
|
|
23
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default BottomBarLayout;
|
|
2
|
+
type BottomBarLayout = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const BottomBarLayout: import("svelte").Component<{
|
|
7
|
+
menu?: any;
|
|
8
|
+
actions: any;
|
|
9
|
+
children: any;
|
|
10
|
+
} & Record<string, any>, {}, "menu">;
|
|
11
|
+
type $$ComponentProps = {
|
|
12
|
+
menu?: any;
|
|
13
|
+
actions: any;
|
|
14
|
+
children: any;
|
|
15
|
+
} & Record<string, any>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// DockLayout — a macOS-style floating dock: a centered, rounded bar of icons
|
|
3
|
+
// floating over the content near the bottom. Minimal brand/actions in the
|
|
4
|
+
// corners. One bindable `menu` drives the dock items.
|
|
5
|
+
//
|
|
6
|
+
// <DockLayout bind:menu>{content}</DockLayout>
|
|
7
|
+
//
|
|
8
|
+
// Menu contract (shared):
|
|
9
|
+
// { brand?, sections: [{ items: [{ id, label, icon?, href?, children? }] }], active? }
|
|
10
|
+
import ThemeToggle from '../components/ThemeToggle.svelte';
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
menu = $bindable({ brand: {}, sections: [], active: undefined }),
|
|
14
|
+
actions, // snippet: top-right actions (defaults to ThemeToggle)
|
|
15
|
+
children,
|
|
16
|
+
...rest
|
|
17
|
+
} = $props();
|
|
18
|
+
|
|
19
|
+
let brand = $derived(menu?.brand ?? {});
|
|
20
|
+
let items = $derived((menu?.sections ?? []).flatMap((s) => s.items ?? []));
|
|
21
|
+
|
|
22
|
+
// Flyout for dock items that have children (opens upward).
|
|
23
|
+
let openId = $state(null);
|
|
24
|
+
function toggle(id) { openId = openId === id ? null : id; }
|
|
25
|
+
$effect(() => {
|
|
26
|
+
if (openId == null) return;
|
|
27
|
+
function onDoc(e) { if (!e.target.closest?.('.dk-flywrap')) openId = null; }
|
|
28
|
+
document.addEventListener('pointerdown', onDoc);
|
|
29
|
+
return () => document.removeEventListener('pointerdown', onDoc);
|
|
30
|
+
});
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<div class="dk" {...rest}>
|
|
34
|
+
{#if brand?.label}
|
|
35
|
+
<div class="dk-corner dk-corner-left">
|
|
36
|
+
{#if brand.icon}<span class="material-symbols-outlined dk-brand-icon">{brand.icon}</span>{/if}
|
|
37
|
+
<span class="dk-brand-name">{brand.label}</span>
|
|
38
|
+
</div>
|
|
39
|
+
{/if}
|
|
40
|
+
<div class="dk-corner dk-corner-right">
|
|
41
|
+
{#if actions}{@render actions()}{:else}<ThemeToggle />{/if}
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<main class="dk-main">
|
|
45
|
+
<div class="dk-inner">{@render children?.()}</div>
|
|
46
|
+
</main>
|
|
47
|
+
|
|
48
|
+
<nav class="dk-dock" aria-label="Primary">
|
|
49
|
+
{#each items as item}
|
|
50
|
+
{#if item.children}
|
|
51
|
+
<div class="dk-flywrap">
|
|
52
|
+
{#if openId === item.id}
|
|
53
|
+
<div class="dk-flyout">
|
|
54
|
+
{#each item.children as child}
|
|
55
|
+
<a href={child.href} class="dk-flyout-item" onclick={() => (openId = null)}>
|
|
56
|
+
{#if child.icon}<span class="material-symbols-outlined">{child.icon}</span>{/if}
|
|
57
|
+
{child.label}
|
|
58
|
+
</a>
|
|
59
|
+
{/each}
|
|
60
|
+
</div>
|
|
61
|
+
{/if}
|
|
62
|
+
<button
|
|
63
|
+
class="dk-item"
|
|
64
|
+
class:active={item.id === menu.active}
|
|
65
|
+
title={item.label}
|
|
66
|
+
aria-label={item.label}
|
|
67
|
+
onclick={() => toggle(item.id)}
|
|
68
|
+
>
|
|
69
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
70
|
+
<span class="dk-label">{item.label}</span>
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
{:else}
|
|
74
|
+
<a href={item.href} class="dk-item" class:active={item.id === menu.active} title={item.label}>
|
|
75
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
76
|
+
<span class="dk-label">{item.label}</span>
|
|
77
|
+
</a>
|
|
78
|
+
{/if}
|
|
79
|
+
{/each}
|
|
80
|
+
</nav>
|
|
81
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default DockLayout;
|
|
2
|
+
type DockLayout = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const DockLayout: import("svelte").Component<{
|
|
7
|
+
menu?: Record<string, any>;
|
|
8
|
+
actions: any;
|
|
9
|
+
children: any;
|
|
10
|
+
} & Record<string, any>, {}, "menu">;
|
|
11
|
+
type $$ComponentProps = {
|
|
12
|
+
menu?: Record<string, any>;
|
|
13
|
+
actions: any;
|
|
14
|
+
children: any;
|
|
15
|
+
} & Record<string, any>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// FloatingDockLayout — content with a centered floating dock of icons near
|
|
3
|
+
// the bottom (macOS-style). Nestable single-region layout. Items with
|
|
4
|
+
// children open an upward flyout.
|
|
5
|
+
let { menu = $bindable(undefined), children, ...rest } = $props();
|
|
6
|
+
let items = $derived(menu ? (menu.sections ?? []).flatMap((s) => s.items ?? []) : []);
|
|
7
|
+
|
|
8
|
+
let openId = $state(null);
|
|
9
|
+
const toggle = (id) => { openId = openId === id ? null : id; };
|
|
10
|
+
$effect(() => {
|
|
11
|
+
if (openId == null) return;
|
|
12
|
+
const onDoc = (e) => { if (!e.target.closest?.('.nldk-flywrap')) openId = null; };
|
|
13
|
+
document.addEventListener('pointerdown', onDoc);
|
|
14
|
+
return () => document.removeEventListener('pointerdown', onDoc);
|
|
15
|
+
});
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<div class="nl nl-col nldk" {...rest}>
|
|
19
|
+
<div class="nl-fill nl-scroll nldk-content">{@render children?.()}</div>
|
|
20
|
+
{#if menu}
|
|
21
|
+
<div class="nldk-dockwrap">
|
|
22
|
+
<nav class="nldk-dock" aria-label="Primary">
|
|
23
|
+
{#each items as item}
|
|
24
|
+
{#if item.children?.length}
|
|
25
|
+
<div class="nldk-flywrap">
|
|
26
|
+
{#if openId === item.id}
|
|
27
|
+
<div class="nldk-flyout">
|
|
28
|
+
{#each item.children as child}
|
|
29
|
+
<a href={child.href} class="nldk-flyout-item" onclick={() => (openId = null)}>
|
|
30
|
+
{#if child.icon}<span class="material-symbols-outlined">{child.icon}</span>{/if}
|
|
31
|
+
{child.label}
|
|
32
|
+
</a>
|
|
33
|
+
{/each}
|
|
34
|
+
</div>
|
|
35
|
+
{/if}
|
|
36
|
+
<button
|
|
37
|
+
class="nldk-item"
|
|
38
|
+
class:active={item.id === menu.active || item.children.some((c) => c.id === menu.active)}
|
|
39
|
+
title={item.label} aria-label={item.label}
|
|
40
|
+
onclick={() => toggle(item.id)}
|
|
41
|
+
>
|
|
42
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
43
|
+
<span class="nldk-label">{item.label}</span>
|
|
44
|
+
</button>
|
|
45
|
+
</div>
|
|
46
|
+
{:else}
|
|
47
|
+
<a href={item.href} class="nldk-item" class:active={item.id === menu.active} title={item.label} aria-label={item.label}>
|
|
48
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
49
|
+
<span class="nldk-label">{item.label}</span>
|
|
50
|
+
</a>
|
|
51
|
+
{/if}
|
|
52
|
+
{/each}
|
|
53
|
+
</nav>
|
|
54
|
+
</div>
|
|
55
|
+
{/if}
|
|
56
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default FloatingDockLayout;
|
|
2
|
+
type FloatingDockLayout = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const FloatingDockLayout: import("svelte").Component<{
|
|
7
|
+
menu?: any;
|
|
8
|
+
children: any;
|
|
9
|
+
} & Record<string, any>, {}, "menu">;
|
|
10
|
+
type $$ComponentProps = {
|
|
11
|
+
menu?: any;
|
|
12
|
+
children: any;
|
|
13
|
+
} & Record<string, any>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// FloatingLayout — a layout where the menus float as detached, rounded cards
|
|
3
|
+
// over the content, rather than attached bars.
|
|
4
|
+
//
|
|
5
|
+
// topMenu → a floating card along the top (horizontal)
|
|
6
|
+
// sideMenu → a floating card on the left (vertical)
|
|
7
|
+
//
|
|
8
|
+
// Each is its own bindable prop, using the shared menu contract:
|
|
9
|
+
// { brand?, sections: [{ label?, items: [{ id, label, icon?, href?, badge?, children? }] }], active? }
|
|
10
|
+
//
|
|
11
|
+
// <FloatingLayout bind:topMenu bind:sideMenu>{content}</FloatingShell>
|
|
12
|
+
import ThemeToggle from '../components/ThemeToggle.svelte';
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
topMenu = $bindable(undefined),
|
|
16
|
+
sideMenu = $bindable(undefined),
|
|
17
|
+
actions, // snippet: top card right-side actions
|
|
18
|
+
footer, // snippet: side card footer
|
|
19
|
+
children,
|
|
20
|
+
...rest
|
|
21
|
+
} = $props();
|
|
22
|
+
|
|
23
|
+
let hasTop = $derived(!!topMenu);
|
|
24
|
+
let hasSide = $derived(!!sideMenu);
|
|
25
|
+
let topItems = $derived(hasTop ? (topMenu.sections ?? []).flatMap((s) => s.items ?? []) : []);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<div class="fl-root" {...rest}>
|
|
29
|
+
{#if hasTop}
|
|
30
|
+
<div class="fl-topcard">
|
|
31
|
+
{#if topMenu.brand?.label}
|
|
32
|
+
<div class="fl-brand">
|
|
33
|
+
{#if topMenu.brand.icon}<span class="material-symbols-outlined fl-brand-icon">{topMenu.brand.icon}</span>{/if}
|
|
34
|
+
{topMenu.brand.label}
|
|
35
|
+
</div>
|
|
36
|
+
{/if}
|
|
37
|
+
<nav class="fl-topnav">
|
|
38
|
+
{#each topItems as item}
|
|
39
|
+
<a href={item.href} class="fl-toplink" class:active={item.id === topMenu.active}>
|
|
40
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
41
|
+
{item.label}
|
|
42
|
+
</a>
|
|
43
|
+
{/each}
|
|
44
|
+
</nav>
|
|
45
|
+
<div class="fl-actions">
|
|
46
|
+
{#if actions}{@render actions()}{:else}<ThemeToggle />{/if}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
{/if}
|
|
50
|
+
|
|
51
|
+
<div class="fl-body">
|
|
52
|
+
{#if hasSide}
|
|
53
|
+
<aside class="fl-sidecard">
|
|
54
|
+
{#if sideMenu.brand?.label && !hasTop}
|
|
55
|
+
<div class="fl-brand fl-side-brand">
|
|
56
|
+
{#if sideMenu.brand.icon}<span class="material-symbols-outlined fl-brand-icon">{sideMenu.brand.icon}</span>{/if}
|
|
57
|
+
{sideMenu.brand.label}
|
|
58
|
+
</div>
|
|
59
|
+
{/if}
|
|
60
|
+
<nav class="fl-sidenav">
|
|
61
|
+
{#each sideMenu.sections as section}
|
|
62
|
+
{#if section.label}<div class="fl-side-label">{section.label}</div>{/if}
|
|
63
|
+
{#each section.items as item}
|
|
64
|
+
<a href={item.href} class="fl-sidelink" class:active={item.id === sideMenu.active}>
|
|
65
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
66
|
+
<span class="fl-sidelabel">{item.label}</span>
|
|
67
|
+
{#if item.badge != null}<span class="fl-badge">{item.badge}</span>{/if}
|
|
68
|
+
</a>
|
|
69
|
+
{/each}
|
|
70
|
+
{/each}
|
|
71
|
+
</nav>
|
|
72
|
+
{#if footer}<div class="fl-side-foot">{@render footer()}</div>{/if}
|
|
73
|
+
</aside>
|
|
74
|
+
{/if}
|
|
75
|
+
|
|
76
|
+
<main class="fl-content">
|
|
77
|
+
<div class="fl-inner">{@render children?.()}</div>
|
|
78
|
+
</main>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default FloatingLayout;
|
|
2
|
+
type FloatingLayout = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const FloatingLayout: import("svelte").Component<{
|
|
7
|
+
topMenu?: any;
|
|
8
|
+
sideMenu?: any;
|
|
9
|
+
actions: any;
|
|
10
|
+
footer: any;
|
|
11
|
+
children: any;
|
|
12
|
+
} & Record<string, any>, {}, "topMenu" | "sideMenu">;
|
|
13
|
+
type $$ComponentProps = {
|
|
14
|
+
topMenu?: any;
|
|
15
|
+
sideMenu?: any;
|
|
16
|
+
actions: any;
|
|
17
|
+
footer: any;
|
|
18
|
+
children: any;
|
|
19
|
+
} & Record<string, any>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// FloatingLeftLayout — a detached, rounded left menu card floating over the
|
|
3
|
+
// content. Nestable single-region layout. Supports 2-level submenus.
|
|
4
|
+
let { menu = $bindable(undefined), footer, children, ...rest } = $props();
|
|
5
|
+
let brand = $derived(menu?.brand ?? {});
|
|
6
|
+
|
|
7
|
+
let toggled = $state({});
|
|
8
|
+
const isChildActive = (item) => item.children?.some((c) => c.id === menu?.active);
|
|
9
|
+
const isOpen = (item) => toggled[item.id] ?? isChildActive(item);
|
|
10
|
+
const toggle = (item) => { toggled = { ...toggled, [item.id]: !isOpen(item) }; };
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div class="nl nl-row nlf-pad" {...rest}>
|
|
14
|
+
{#if menu}
|
|
15
|
+
<aside class="nlf-sidecard">
|
|
16
|
+
{#if brand.label}
|
|
17
|
+
<div class="nlf-brand nlf-side-brand">
|
|
18
|
+
{#if brand.icon}<span class="material-symbols-outlined nlf-brand-icon">{brand.icon}</span>{/if}
|
|
19
|
+
{brand.label}
|
|
20
|
+
</div>
|
|
21
|
+
{/if}
|
|
22
|
+
<nav class="nlf-sidenav">
|
|
23
|
+
{#each (menu.sections ?? []) as section}
|
|
24
|
+
{#if section.label}<div class="nlf-side-label">{section.label}</div>{/if}
|
|
25
|
+
{#each section.items as item}
|
|
26
|
+
{#if item.children?.length}
|
|
27
|
+
<button type="button" class="nlf-sidelink nlf-parent"
|
|
28
|
+
class:active={item.id === menu.active || isChildActive(item)}
|
|
29
|
+
aria-expanded={isOpen(item)} onclick={() => toggle(item)}>
|
|
30
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
31
|
+
<span class="nlf-sidelabel">{item.label}</span>
|
|
32
|
+
{#if item.badge != null}<span class="nlf-badge">{item.badge}</span>{/if}
|
|
33
|
+
<span class="material-symbols-outlined nlf-chevron" class:open={isOpen(item)}>chevron_right</span>
|
|
34
|
+
</button>
|
|
35
|
+
{#if isOpen(item)}
|
|
36
|
+
<div class="nlf-subnav">
|
|
37
|
+
{#each item.children as child}
|
|
38
|
+
<a href={child.href} class="nlf-sublink" class:active={child.id === menu.active}>
|
|
39
|
+
{#if child.icon}<span class="material-symbols-outlined">{child.icon}</span>{/if}
|
|
40
|
+
<span class="nlf-sidelabel">{child.label}</span>
|
|
41
|
+
</a>
|
|
42
|
+
{/each}
|
|
43
|
+
</div>
|
|
44
|
+
{/if}
|
|
45
|
+
{:else}
|
|
46
|
+
<a href={item.href} class="nlf-sidelink" class:active={item.id === menu.active}>
|
|
47
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
48
|
+
<span class="nlf-sidelabel">{item.label}</span>
|
|
49
|
+
{#if item.badge != null}<span class="nlf-badge">{item.badge}</span>{/if}
|
|
50
|
+
</a>
|
|
51
|
+
{/if}
|
|
52
|
+
{/each}
|
|
53
|
+
{/each}
|
|
54
|
+
</nav>
|
|
55
|
+
{#if footer}<div class="nlf-side-foot">{@render footer()}</div>{/if}
|
|
56
|
+
</aside>
|
|
57
|
+
{/if}
|
|
58
|
+
<div class="nl-fill nl-scroll nlf-content">{@render children?.()}</div>
|
|
59
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default FloatingLeftLayout;
|
|
2
|
+
type FloatingLeftLayout = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const FloatingLeftLayout: import("svelte").Component<{
|
|
7
|
+
menu?: any;
|
|
8
|
+
footer: any;
|
|
9
|
+
children: any;
|
|
10
|
+
} & Record<string, any>, {}, "menu">;
|
|
11
|
+
type $$ComponentProps = {
|
|
12
|
+
menu?: any;
|
|
13
|
+
footer: any;
|
|
14
|
+
children: any;
|
|
15
|
+
} & Record<string, any>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// FloatingShell — a layout where the menus float as detached, rounded cards
|
|
3
|
+
// over the content, rather than attached bars.
|
|
4
|
+
//
|
|
5
|
+
// topMenu → a floating card along the top (horizontal)
|
|
6
|
+
// sideMenu → a floating card on the left (vertical)
|
|
7
|
+
//
|
|
8
|
+
// Each is its own bindable prop, using the shared menu contract:
|
|
9
|
+
// { brand?, sections: [{ label?, items: [{ id, label, icon?, href?, badge?, children? }] }], active? }
|
|
10
|
+
//
|
|
11
|
+
// <FloatingShell bind:topMenu bind:sideMenu>{content}</FloatingShell>
|
|
12
|
+
import ThemeToggle from '../components/ThemeToggle.svelte';
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
topMenu = $bindable(undefined),
|
|
16
|
+
sideMenu = $bindable(undefined),
|
|
17
|
+
actions, // snippet: top card right-side actions
|
|
18
|
+
footer, // snippet: side card footer
|
|
19
|
+
children,
|
|
20
|
+
...rest
|
|
21
|
+
} = $props();
|
|
22
|
+
|
|
23
|
+
let hasTop = $derived(!!topMenu);
|
|
24
|
+
let hasSide = $derived(!!sideMenu);
|
|
25
|
+
let topItems = $derived(hasTop ? (topMenu.sections ?? []).flatMap((s) => s.items ?? []) : []);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<div class="fl-root" {...rest}>
|
|
29
|
+
{#if hasTop}
|
|
30
|
+
<div class="fl-topcard">
|
|
31
|
+
{#if topMenu.brand?.label}
|
|
32
|
+
<div class="fl-brand">
|
|
33
|
+
{#if topMenu.brand.icon}<span class="material-symbols-outlined fl-brand-icon">{topMenu.brand.icon}</span>{/if}
|
|
34
|
+
{topMenu.brand.label}
|
|
35
|
+
</div>
|
|
36
|
+
{/if}
|
|
37
|
+
<nav class="fl-topnav">
|
|
38
|
+
{#each topItems as item}
|
|
39
|
+
<a href={item.href} class="fl-toplink" class:active={item.id === topMenu.active}>
|
|
40
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
41
|
+
{item.label}
|
|
42
|
+
</a>
|
|
43
|
+
{/each}
|
|
44
|
+
</nav>
|
|
45
|
+
<div class="fl-actions">
|
|
46
|
+
{#if actions}{@render actions()}{:else}<ThemeToggle />{/if}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
{/if}
|
|
50
|
+
|
|
51
|
+
<div class="fl-body">
|
|
52
|
+
{#if hasSide}
|
|
53
|
+
<aside class="fl-sidecard">
|
|
54
|
+
{#if sideMenu.brand?.label && !hasTop}
|
|
55
|
+
<div class="fl-brand fl-side-brand">
|
|
56
|
+
{#if sideMenu.brand.icon}<span class="material-symbols-outlined fl-brand-icon">{sideMenu.brand.icon}</span>{/if}
|
|
57
|
+
{sideMenu.brand.label}
|
|
58
|
+
</div>
|
|
59
|
+
{/if}
|
|
60
|
+
<nav class="fl-sidenav">
|
|
61
|
+
{#each sideMenu.sections as section}
|
|
62
|
+
{#if section.label}<div class="fl-side-label">{section.label}</div>{/if}
|
|
63
|
+
{#each section.items as item}
|
|
64
|
+
<a href={item.href} class="fl-sidelink" class:active={item.id === sideMenu.active}>
|
|
65
|
+
{#if item.icon}<span class="material-symbols-outlined">{item.icon}</span>{/if}
|
|
66
|
+
<span class="fl-sidelabel">{item.label}</span>
|
|
67
|
+
{#if item.badge != null}<span class="fl-badge">{item.badge}</span>{/if}
|
|
68
|
+
</a>
|
|
69
|
+
{/each}
|
|
70
|
+
{/each}
|
|
71
|
+
</nav>
|
|
72
|
+
{#if footer}<div class="fl-side-foot">{@render footer()}</div>{/if}
|
|
73
|
+
</aside>
|
|
74
|
+
{/if}
|
|
75
|
+
|
|
76
|
+
<main class="fl-content">
|
|
77
|
+
<div class="fl-inner">{@render children?.()}</div>
|
|
78
|
+
</main>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default FloatingShell;
|
|
2
|
+
type FloatingShell = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const FloatingShell: import("svelte").Component<{
|
|
7
|
+
topMenu?: any;
|
|
8
|
+
sideMenu?: any;
|
|
9
|
+
actions: any;
|
|
10
|
+
footer: any;
|
|
11
|
+
children: any;
|
|
12
|
+
} & Record<string, any>, {}, "topMenu" | "sideMenu">;
|
|
13
|
+
type $$ComponentProps = {
|
|
14
|
+
topMenu?: any;
|
|
15
|
+
sideMenu?: any;
|
|
16
|
+
actions: any;
|
|
17
|
+
footer: any;
|
|
18
|
+
children: any;
|
|
19
|
+
} & Record<string, any>;
|