bref-ui 0.0.13 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/base/index.d.ts +1 -0
- package/dist/base/index.js +1 -0
- package/dist/base/theme/theme.svelte +1 -2
- package/dist/base/tree-view/index.d.ts +3 -0
- package/dist/base/tree-view/index.js +3 -0
- package/dist/base/tree-view/tree-node.svelte +108 -0
- package/dist/base/tree-view/tree-node.svelte.d.ts +5 -0
- package/dist/base/tree-view/tree-view.svelte +39 -0
- package/dist/base/tree-view/tree-view.svelte.d.ts +4 -0
- package/dist/base/tree-view/types.d.ts +22 -0
- package/dist/base/tree-view/types.js +1 -0
- package/dist/internal/{demo-code-snippet.svelte → layout/code-snippet.svelte} +16 -14
- package/dist/internal/layout/code-snippet.svelte.d.ts +6 -0
- package/dist/internal/layout/header.svelte +50 -0
- package/dist/internal/layout/header.svelte.d.ts +3 -0
- package/dist/internal/{demo-section.svelte → layout/section.svelte} +2 -11
- package/dist/internal/layout/section.svelte.d.ts +10 -0
- package/dist/internal/layout/sidebar/footer.svelte +71 -0
- package/dist/internal/layout/sidebar/footer.svelte.d.ts +3 -0
- package/dist/internal/layout/sidebar/logo.svelte +38 -0
- package/dist/internal/{demo-header.svelte.d.ts → layout/sidebar/logo.svelte.d.ts} +14 -6
- package/dist/internal/layout/sidebar/sidebar.svelte +52 -0
- package/dist/internal/layout/sidebar/sidebar.svelte.d.ts +3 -0
- package/dist/internal/layout/types.d.ts +9 -0
- package/dist/internal/layout/types.js +84 -0
- package/package.json +1 -1
- package/dist/internal/demo-author.svelte +0 -29
- package/dist/internal/demo-author.svelte.d.ts +0 -18
- package/dist/internal/demo-button.svelte +0 -80
- package/dist/internal/demo-button.svelte.d.ts +0 -18
- package/dist/internal/demo-code-snippet.svelte.d.ts +0 -6
- package/dist/internal/demo-header.svelte +0 -57
- package/dist/internal/demo-icon-button.svelte +0 -76
- package/dist/internal/demo-icon-button.svelte.d.ts +0 -18
- package/dist/internal/demo-icon-section.svelte +0 -46
- package/dist/internal/demo-icon-section.svelte.d.ts +0 -18
- package/dist/internal/demo-loading.svelte +0 -95
- package/dist/internal/demo-loading.svelte.d.ts +0 -18
- package/dist/internal/demo-section.svelte.d.ts +0 -10
- package/dist/internal/demo-theming.svelte +0 -173
- package/dist/internal/demo-theming.svelte.d.ts +0 -3
- package/dist/internal/demo-types.svelte +0 -61
- package/dist/internal/demo-types.svelte.d.ts +0 -18
package/README.md
CHANGED
package/dist/base/index.d.ts
CHANGED
package/dist/base/index.js
CHANGED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { TreeNodeProps } from './types.js';
|
|
3
|
+
import Icon from '../icon/icon.svelte';
|
|
4
|
+
import TreeNode from './tree-node.svelte';
|
|
5
|
+
const { node, level, size, onSelect, selectedIds, filledIcon, wide }: TreeNodeProps = $props();
|
|
6
|
+
|
|
7
|
+
let expanded: boolean = $state(false);
|
|
8
|
+
let selected: boolean = $derived(selectedIds?.has(node.id) ?? false);
|
|
9
|
+
|
|
10
|
+
const hasChildren = $derived(node.children && node.children.length > 0);
|
|
11
|
+
|
|
12
|
+
const toggleExpand = (e: MouseEvent) => {
|
|
13
|
+
e.stopPropagation();
|
|
14
|
+
if (hasChildren) expanded = !expanded;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const handleSelect = () => onSelect(node.id);
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
21
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
22
|
+
<div
|
|
23
|
+
class={size}
|
|
24
|
+
class:selected
|
|
25
|
+
style:padding-left="calc({level} * var(--tree-indent))"
|
|
26
|
+
onclick={handleSelect}
|
|
27
|
+
class:wide
|
|
28
|
+
>
|
|
29
|
+
{#if hasChildren}
|
|
30
|
+
<button class:expanded onclick={toggleExpand}>
|
|
31
|
+
<Icon name="chevron_right" {size} color={selected ? 'primary' : undefined} />
|
|
32
|
+
</button>
|
|
33
|
+
{:else}
|
|
34
|
+
<span class="spacer"></span>
|
|
35
|
+
{/if}
|
|
36
|
+
|
|
37
|
+
{#if node.icon}
|
|
38
|
+
<Icon
|
|
39
|
+
name={node.icon}
|
|
40
|
+
filled={selected || filledIcon}
|
|
41
|
+
{size}
|
|
42
|
+
color={selected ? 'primary' : undefined}
|
|
43
|
+
/>
|
|
44
|
+
{/if}
|
|
45
|
+
|
|
46
|
+
<span>{node.label}</span>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
{#if expanded && hasChildren}
|
|
50
|
+
{#each node.children as child (child.id)}
|
|
51
|
+
<TreeNode node={child} level={level + 1} {size} {onSelect} {selectedIds} {filledIcon} {wide} />
|
|
52
|
+
{/each}
|
|
53
|
+
{/if}
|
|
54
|
+
|
|
55
|
+
<style>
|
|
56
|
+
div,
|
|
57
|
+
span,
|
|
58
|
+
button {
|
|
59
|
+
transition: all 0.1s ease-in-out;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
div {
|
|
63
|
+
--tree-indent: 1em;
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
padding: 0.25em 0.5em;
|
|
67
|
+
gap: 0.25em;
|
|
68
|
+
border-radius: var(--border-radius);
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
div:hover {
|
|
73
|
+
background-color: color-mix(in srgb, var(--color-foreground) 10%, transparent);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.selected {
|
|
77
|
+
background-color: var(--color-primary-soft);
|
|
78
|
+
}
|
|
79
|
+
.selected:hover {
|
|
80
|
+
background-color: color-mix(in srgb, var(--color-primary) 20%, var(--color-primary-soft));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.selected span {
|
|
84
|
+
color: var(--color-primary);
|
|
85
|
+
}
|
|
86
|
+
span {
|
|
87
|
+
user-select: none;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
button {
|
|
91
|
+
all: unset;
|
|
92
|
+
display: flex;
|
|
93
|
+
padding: 0.25em;
|
|
94
|
+
cursor: pointer;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
button.expanded {
|
|
98
|
+
transform: rotate(90deg);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.spacer {
|
|
102
|
+
width: 1em;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.wide {
|
|
106
|
+
width: 100%;
|
|
107
|
+
}
|
|
108
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { TreeViewProps } from './types.js';
|
|
3
|
+
import TreeNode from './tree-node.svelte';
|
|
4
|
+
|
|
5
|
+
let { data, size = 'medium', onSelect, selectedIds, wide, filledIcon }: TreeViewProps = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<div role="tree" class={size} class:wide>
|
|
9
|
+
{#each data as node (node.id)}
|
|
10
|
+
<TreeNode {node} level={0} {size} {onSelect} {selectedIds} {wide} {filledIcon} />
|
|
11
|
+
{/each}
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
div {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.wide {
|
|
21
|
+
width: 100%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.x-small {
|
|
25
|
+
gap: 0.125rem;
|
|
26
|
+
}
|
|
27
|
+
.small {
|
|
28
|
+
gap: 0.25rem;
|
|
29
|
+
}
|
|
30
|
+
.medium {
|
|
31
|
+
gap: 0.5rem;
|
|
32
|
+
}
|
|
33
|
+
.large {
|
|
34
|
+
gap: 0.75rem;
|
|
35
|
+
}
|
|
36
|
+
.x-large {
|
|
37
|
+
gap: 1rem;
|
|
38
|
+
}
|
|
39
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Size } from '../types.ts';
|
|
2
|
+
import type { IconName, IconProps } from '../icon/types.ts';
|
|
3
|
+
export interface NodeDataProps {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
icon?: IconName;
|
|
7
|
+
children?: NodeDataProps[];
|
|
8
|
+
}
|
|
9
|
+
export interface BaseTreeProps {
|
|
10
|
+
onSelect: (id: string) => void;
|
|
11
|
+
selectedIds: Set<string>;
|
|
12
|
+
size?: Size;
|
|
13
|
+
filledIcon?: IconProps['filled'];
|
|
14
|
+
wide?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface TreeViewProps extends BaseTreeProps {
|
|
17
|
+
data: NodeDataProps[];
|
|
18
|
+
}
|
|
19
|
+
export interface TreeNodeProps extends BaseTreeProps {
|
|
20
|
+
node: NodeDataProps;
|
|
21
|
+
level: number;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import IconButton from '../../base/button/icon-button.svelte';
|
|
3
|
+
|
|
2
4
|
const {
|
|
3
5
|
snippet
|
|
4
6
|
}: {
|
|
@@ -7,7 +9,7 @@
|
|
|
7
9
|
|
|
8
10
|
let hasCopied = $state(false);
|
|
9
11
|
|
|
10
|
-
const
|
|
12
|
+
const onClick = () => {
|
|
11
13
|
navigator.clipboard.writeText(snippet).then(() => {
|
|
12
14
|
hasCopied = true;
|
|
13
15
|
setTimeout(() => (hasCopied = false), 3000);
|
|
@@ -19,17 +21,26 @@
|
|
|
19
21
|
<pre>
|
|
20
22
|
<code>{snippet}</code>
|
|
21
23
|
</pre>
|
|
22
|
-
|
|
24
|
+
|
|
25
|
+
<IconButton
|
|
26
|
+
{onClick}
|
|
27
|
+
size="x-small"
|
|
28
|
+
color={hasCopied ? 'success' : 'primary'}
|
|
29
|
+
variant={hasCopied ? 'filled' : 'soft'}
|
|
30
|
+
filled
|
|
31
|
+
name={hasCopied ? 'check' : 'copy_all'}
|
|
32
|
+
disabled={hasCopied}
|
|
33
|
+
/>
|
|
23
34
|
</div>
|
|
24
35
|
|
|
25
36
|
<style>
|
|
26
37
|
div {
|
|
27
38
|
display: flex;
|
|
28
39
|
width: 100%;
|
|
40
|
+
position: relative;
|
|
29
41
|
height: fit-content;
|
|
30
42
|
padding: 1rem;
|
|
31
|
-
gap:
|
|
32
|
-
flex-direction: column;
|
|
43
|
+
gap: 0.5rem;
|
|
33
44
|
border-radius: 0.75rem;
|
|
34
45
|
background: color-mix(in srgb, var(--color-foreground) 5%, transparent);
|
|
35
46
|
border: 1px solid color-mix(in srgb, var(--color-border) 30%, transparent);
|
|
@@ -48,6 +59,7 @@
|
|
|
48
59
|
code,
|
|
49
60
|
pre {
|
|
50
61
|
width: 100%;
|
|
62
|
+
flex: 1; align-self: center;
|
|
51
63
|
height: fit-content;
|
|
52
64
|
}
|
|
53
65
|
pre {
|
|
@@ -55,14 +67,4 @@
|
|
|
55
67
|
display: flex;
|
|
56
68
|
justify-content: flex-start;
|
|
57
69
|
}
|
|
58
|
-
button {
|
|
59
|
-
display: flex;
|
|
60
|
-
padding: 0.5rem 1rem;
|
|
61
|
-
width: 100%;
|
|
62
|
-
height: fit-content;
|
|
63
|
-
text-transform: capitalize;
|
|
64
|
-
align-items: center;
|
|
65
|
-
cursor: pointer;
|
|
66
|
-
justify-content: center;
|
|
67
|
-
}
|
|
68
70
|
</style>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Icon from '../../base/icon/icon.svelte';
|
|
3
|
+
import { PAGES, type PageProps } from '../layout/types.js';
|
|
4
|
+
import { page } from '$app/state';
|
|
5
|
+
|
|
6
|
+
const { title, description, icon } = $derived.by((): PageProps => {
|
|
7
|
+
if (page.status !== 200) {
|
|
8
|
+
return {
|
|
9
|
+
title: 'Error: ' + page.status,
|
|
10
|
+
description: page.error?.message || 'An unexpected error occurred.',
|
|
11
|
+
icon: 'error',
|
|
12
|
+
href: ''
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const firstPage = PAGES[0];
|
|
16
|
+
const allPages = PAGES.flatMap((p) => [p, ...(p.children || [])]);
|
|
17
|
+
const currentPage = allPages.find((p) => page.url.pathname.endsWith(p.href));
|
|
18
|
+
return currentPage || firstPage;
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<div class="container">
|
|
23
|
+
<div>
|
|
24
|
+
<Icon name={icon} size="large" color="primary" />
|
|
25
|
+
<h1>{title}</h1>
|
|
26
|
+
</div>
|
|
27
|
+
<p>{description}</p>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<style>
|
|
31
|
+
div {
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
min-height: fit-content;
|
|
35
|
+
height: fit-content;
|
|
36
|
+
}
|
|
37
|
+
.container {
|
|
38
|
+
width: 100%;
|
|
39
|
+
padding: 2rem;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
align-items: flex-start;
|
|
42
|
+
flex-shrink: 0;
|
|
43
|
+
}
|
|
44
|
+
p {
|
|
45
|
+
opacity: 0.8;
|
|
46
|
+
}
|
|
47
|
+
h1 {
|
|
48
|
+
font-size: 3rem;
|
|
49
|
+
}
|
|
50
|
+
</style>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
} = $props();
|
|
15
15
|
</script>
|
|
16
16
|
|
|
17
|
-
<section {id}>
|
|
17
|
+
<section {id} class="container">
|
|
18
18
|
{#if title}
|
|
19
19
|
<h2>{title}</h2>
|
|
20
20
|
{/if}
|
|
@@ -30,18 +30,9 @@
|
|
|
30
30
|
gap: 1rem;
|
|
31
31
|
align-items: center;
|
|
32
32
|
flex-direction: column;
|
|
33
|
-
background-color: color-mix(in srgb, var(--color-background) 90%, transparent);
|
|
34
|
-
backdrop-filter: blur(2rem);
|
|
35
33
|
padding: 2rem;
|
|
36
34
|
width: 100%;
|
|
37
|
-
|
|
38
|
-
transition: all 0.3s ease;
|
|
39
|
-
border-radius: 2rem;
|
|
40
|
-
border: 1px solid color-mix(in srgb, var(--color-foreground) 10%, transparent);
|
|
41
|
-
}
|
|
42
|
-
section:hover {
|
|
43
|
-
border: 1px solid color-mix(in srgb, var(--color-foreground) 20%, transparent);
|
|
44
|
-
box-shadow: 0 0 3rem color-mix(in srgb, var(--color-background) 50%, transparent);
|
|
35
|
+
flex-shrink: 0;
|
|
45
36
|
}
|
|
46
37
|
h2 {
|
|
47
38
|
font-size: 2rem;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
children: Snippet;
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
id?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const Section: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type Section = ReturnType<typeof Section>;
|
|
10
|
+
export default Section;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import IconButton from '../../../base/button/icon-button.svelte';
|
|
3
|
+
import {
|
|
4
|
+
type ThemeMode,
|
|
5
|
+
initializeThemeMode,
|
|
6
|
+
toggleThemeMode
|
|
7
|
+
} from '../../../base/theme/index.js';
|
|
8
|
+
import { untrack } from 'svelte';
|
|
9
|
+
import Icon from '../../../base/icon/icon.svelte';
|
|
10
|
+
|
|
11
|
+
let themeMode: ThemeMode = $state('light');
|
|
12
|
+
|
|
13
|
+
$effect.pre(() => {
|
|
14
|
+
untrack(() => {
|
|
15
|
+
themeMode = initializeThemeMode();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const onClick = () => {
|
|
20
|
+
const newMode = themeMode === 'dark' ? 'light' : 'dark';
|
|
21
|
+
toggleThemeMode(newMode);
|
|
22
|
+
themeMode = newMode;
|
|
23
|
+
};
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<div>
|
|
27
|
+
<IconButton
|
|
28
|
+
variant="ghost"
|
|
29
|
+
name={themeMode === 'dark' ? 'light_mode' : 'dark_mode'}
|
|
30
|
+
ariaLabel="Toggle theme"
|
|
31
|
+
{onClick}
|
|
32
|
+
/>
|
|
33
|
+
<span>
|
|
34
|
+
Made with <Icon name="favorite" color="danger" filled size="x-small" /> in Paris, by
|
|
35
|
+
<a href="https://github.com/feuersteiner" target="_blank" rel="noopener noreferrer"
|
|
36
|
+
>Feuerstein.</a
|
|
37
|
+
>
|
|
38
|
+
</span>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<style>
|
|
42
|
+
div {
|
|
43
|
+
display: flex;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
align-items: center;
|
|
46
|
+
width: 100%;
|
|
47
|
+
height: fit-content;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
gap: 0.5rem;
|
|
50
|
+
padding: 1rem;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
a {
|
|
54
|
+
text-decoration: none;
|
|
55
|
+
color: inherit;
|
|
56
|
+
display: inline-block;
|
|
57
|
+
width: 5rem;
|
|
58
|
+
height: 1.5rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
a:hover {
|
|
62
|
+
font-weight: bold;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
span {
|
|
66
|
+
font-size: 0.75rem;
|
|
67
|
+
text-align: center;
|
|
68
|
+
align-items: center;
|
|
69
|
+
color: color-mix(in srgb, var(--color-foreground) 50%, var(--color-background));
|
|
70
|
+
}
|
|
71
|
+
</style>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<div class="logo">
|
|
2
|
+
<div class="icon">
|
|
3
|
+
<img src={'favicon.svg'} alt="Logo" />
|
|
4
|
+
<span>Bref</span>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<p>A truly Svelte-esque UI Component Library.</p>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<style>
|
|
11
|
+
div {
|
|
12
|
+
display: flex;
|
|
13
|
+
gap: 1rem;
|
|
14
|
+
}
|
|
15
|
+
.icon {
|
|
16
|
+
align-items: center;
|
|
17
|
+
}
|
|
18
|
+
.logo {
|
|
19
|
+
padding: 1rem;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
width: 100%;
|
|
22
|
+
height: fit-content;
|
|
23
|
+
background-color: color-mix(in srgb, var(--color-foreground) 5%, transparent);
|
|
24
|
+
}
|
|
25
|
+
span {
|
|
26
|
+
font-size: 2rem;
|
|
27
|
+
font-family: 'Meow Script', cursive;
|
|
28
|
+
}
|
|
29
|
+
p {
|
|
30
|
+
font-size: 0.75rem;
|
|
31
|
+
opacity: 0.7;
|
|
32
|
+
font-weight: 300;
|
|
33
|
+
}
|
|
34
|
+
img {
|
|
35
|
+
width: 3rem;
|
|
36
|
+
height: 3rem;
|
|
37
|
+
}
|
|
38
|
+
</style>
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
export default Logo;
|
|
2
|
+
type Logo = SvelteComponent<{
|
|
3
|
+
[x: string]: never;
|
|
4
|
+
}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> & {
|
|
7
|
+
$$bindings?: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare const Logo: $$__sveltets_2_IsomorphicComponent<{
|
|
10
|
+
[x: string]: never;
|
|
11
|
+
}, {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
}, {}, {}, string>;
|
|
1
14
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
-
new (options: import(
|
|
15
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
3
16
|
$$bindings?: Bindings;
|
|
4
17
|
} & Exports;
|
|
5
18
|
(internal: unknown, props: {
|
|
@@ -11,8 +24,3 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
|
|
|
11
24
|
};
|
|
12
25
|
z_$$bindings?: Bindings;
|
|
13
26
|
}
|
|
14
|
-
declare const DemoHeader: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
}, {}, {}, string>;
|
|
17
|
-
type DemoHeader = InstanceType<typeof DemoHeader>;
|
|
18
|
-
export default DemoHeader;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Logo from './logo.svelte';
|
|
3
|
+
import Footer from './footer.svelte';
|
|
4
|
+
import { PAGES, type PageProps } from '../types.js';
|
|
5
|
+
import { page } from '$app/state';
|
|
6
|
+
import TreeView from '../../../base/tree-view/tree-view.svelte';
|
|
7
|
+
import type { NodeDataProps } from '../../../index.js';
|
|
8
|
+
import { goto } from '$app/navigation';
|
|
9
|
+
|
|
10
|
+
const pageToNode = (page: PageProps): NodeDataProps => ({
|
|
11
|
+
id: page.href,
|
|
12
|
+
label: page.title,
|
|
13
|
+
icon: page.icon,
|
|
14
|
+
children: page.children?.map(pageToNode)
|
|
15
|
+
});
|
|
16
|
+
const selectedPage = $derived.by(() => {
|
|
17
|
+
const allPages = PAGES.flatMap((p) => [p, ...(p.children || [])]);
|
|
18
|
+
return allPages.find((p) => page.url.pathname.endsWith(p.href)) ?? PAGES[0];
|
|
19
|
+
});
|
|
20
|
+
const selectedIds = $derived(new Set([selectedPage.href]));
|
|
21
|
+
const onSelect = (href: string) => goto(href);
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div class="container">
|
|
25
|
+
<Logo />
|
|
26
|
+
<div class="content">
|
|
27
|
+
<TreeView wide size="small" {selectedIds} {onSelect} data={PAGES.map(pageToNode)} />
|
|
28
|
+
</div>
|
|
29
|
+
<Footer />
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<style>
|
|
33
|
+
div {
|
|
34
|
+
display: flex;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
align-items: center;
|
|
37
|
+
height: 100%;
|
|
38
|
+
width: 100%;
|
|
39
|
+
}
|
|
40
|
+
.container {
|
|
41
|
+
max-width: 15rem;
|
|
42
|
+
width: 15rem;
|
|
43
|
+
/* height: 100%; */
|
|
44
|
+
}
|
|
45
|
+
.content {
|
|
46
|
+
flex: 1;
|
|
47
|
+
width: 100%;
|
|
48
|
+
justify-content: flex-start;
|
|
49
|
+
align-items: flex-start;
|
|
50
|
+
padding: 1rem;
|
|
51
|
+
}
|
|
52
|
+
</style>
|