runeforge 0.0.55 → 0.0.57
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 +1355 -1342
- package/dist/components/Avatar.svelte +31 -31
- package/dist/components/IconRenderer.svelte +73 -22
- package/dist/components/IconRenderer.svelte.d.ts +2 -0
- package/dist/components/Modal.svelte +75 -75
- package/dist/components/common/Header.svelte +40 -40
- package/dist/components/crud/EmbeddedField.svelte +175 -175
- package/dist/components/crud/Field.svelte +469 -376
- package/dist/components/crud/GenericCRUD.svelte +426 -426
- package/dist/components/crud/SearchInput.svelte +53 -53
- package/dist/components/crud/columns/Avatar.svelte +15 -15
- package/dist/components/crud/columns/Icon.svelte +8 -8
- package/dist/components/crud/views/Create.svelte +232 -232
- package/dist/components/crud/views/Read.svelte +124 -124
- package/dist/components/crud/views/Update.svelte +208 -208
- package/dist/components/crud/views/list/List.svelte +291 -291
- package/dist/components/crud/views/list/Modals.svelte +56 -56
- package/dist/components/crud/views/list/Table.svelte +176 -176
- package/dist/components/crud/views/list/Toolbar.svelte +341 -341
- package/dist/components/form/Button.svelte +27 -27
- package/dist/components/form/Label.svelte +37 -37
- package/dist/components/form/MultiSelect.svelte +248 -248
- package/dist/components/form/PasswordInput.svelte +68 -68
- package/dist/components/form/Required.svelte +1 -1
- package/dist/components/form/Select.svelte +209 -209
- package/dist/components/form/Tree.svelte +62 -62
- package/dist/components/form/TreeNode.svelte +66 -66
- package/dist/components/navigation/Breadcrumbs.svelte +111 -111
- package/dist/components/table/ColumnFilter.svelte +168 -168
- package/dist/components/table/PaginatedTable.svelte +536 -536
- package/dist/components/table/Paginator.svelte +113 -113
- package/dist/components/table/SortHeader.svelte +43 -43
- package/dist/components/table/TableBody.svelte +150 -150
- package/dist/components/table/TableHeader.svelte +88 -88
- package/dist/i18n/en.js +1 -0
- package/dist/i18n/es.js +1 -0
- package/dist/i18n/types.d.ts +1 -0
- package/dist/icons/context.d.ts +5 -0
- package/dist/icons/context.js +10 -0
- package/dist/icons/defaults/Clear.svelte +6 -6
- package/dist/icons/defaults/Create.svelte +6 -6
- package/dist/icons/defaults/Delete.svelte +6 -6
- package/dist/icons/defaults/Download.svelte +7 -7
- package/dist/icons/defaults/Edit.svelte +7 -7
- package/dist/icons/defaults/Filter.svelte +6 -6
- package/dist/icons/defaults/FilterActive.svelte +6 -6
- package/dist/icons/defaults/Folder.svelte +6 -6
- package/dist/icons/defaults/Grip.svelte +7 -7
- package/dist/icons/defaults/Home.svelte +6 -6
- package/dist/icons/defaults/PasswordHide.svelte +9 -9
- package/dist/icons/defaults/PasswordShow.svelte +7 -7
- package/dist/icons/defaults/SortAsc.svelte +6 -6
- package/dist/icons/defaults/SortDesc.svelte +6 -6
- package/dist/icons/defaults/SortNone.svelte +6 -6
- package/dist/icons/defaults/View.svelte +7 -7
- package/dist/icons/sets/bootstrap.js +1 -4
- package/dist/icons/types.d.ts +0 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { SelectOption } from '../../types/attribute.js';
|
|
3
|
-
import { buildChildrenByParent, collectDescendantIds } from '../crud/utils/tree.js';
|
|
4
|
-
import TreeNode from './TreeNode.svelte';
|
|
5
|
-
|
|
6
|
-
let {
|
|
7
|
-
name,
|
|
8
|
-
value = $bindable([]),
|
|
9
|
-
options = [],
|
|
10
|
-
disabled = false,
|
|
11
|
-
columns = 1,
|
|
12
|
-
defaultExpanded = true,
|
|
13
|
-
}: {
|
|
14
|
-
name?: string;
|
|
15
|
-
value?: string[];
|
|
16
|
-
options?: SelectOption[];
|
|
17
|
-
disabled?: boolean;
|
|
18
|
-
columns?: number;
|
|
19
|
-
defaultExpanded?: boolean;
|
|
20
|
-
} = $props();
|
|
21
|
-
|
|
22
|
-
const childrenByParent = $derived(buildChildrenByParent(options));
|
|
23
|
-
const selected = $derived(new Set(value));
|
|
24
|
-
const roots = $derived(childrenByParent.get(null) ?? []);
|
|
25
|
-
|
|
26
|
-
function toggle(nodeValue: string, checked: boolean) {
|
|
27
|
-
const affected = [nodeValue, ...collectDescendantIds(nodeValue, childrenByParent)];
|
|
28
|
-
if (checked) {
|
|
29
|
-
value = [...new Set([...value, ...affected])];
|
|
30
|
-
} else {
|
|
31
|
-
const affectedSet = new Set(affected);
|
|
32
|
-
value = value.filter((v) => !affectedSet.has(v));
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
</script>
|
|
36
|
-
|
|
37
|
-
<div
|
|
38
|
-
class="overflow-y-auto rounded-box border border-base-300 p-2"
|
|
39
|
-
style="max-height: var(--runeforge-tree-max-height, 24rem)"
|
|
40
|
-
class:opacity-50={disabled}
|
|
41
|
-
class:pointer-events-none={disabled}
|
|
42
|
-
>
|
|
43
|
-
{#if name}
|
|
44
|
-
<input type="hidden" {name} value={JSON.stringify(value)} />
|
|
45
|
-
{/if}
|
|
46
|
-
{#if roots.length === 0}
|
|
47
|
-
<p class="px-1 py-2 text-sm text-base-content/40">—</p>
|
|
48
|
-
{/if}
|
|
49
|
-
<div class:leaf-columns={columns > 1} style={`--columns: ${columns}`}>
|
|
50
|
-
{#each roots as root (root.value)}
|
|
51
|
-
<TreeNode node={root} {childrenByParent} {selected} onToggle={toggle} {disabled} depth={0} {columns} {defaultExpanded} />
|
|
52
|
-
{/each}
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
|
|
56
|
-
<style>
|
|
57
|
-
@media (min-width: 1024px) {
|
|
58
|
-
.leaf-columns {
|
|
59
|
-
columns: var(--columns);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
</style>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SelectOption } from '../../types/attribute.js';
|
|
3
|
+
import { buildChildrenByParent, collectDescendantIds } from '../crud/utils/tree.js';
|
|
4
|
+
import TreeNode from './TreeNode.svelte';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
name,
|
|
8
|
+
value = $bindable([]),
|
|
9
|
+
options = [],
|
|
10
|
+
disabled = false,
|
|
11
|
+
columns = 1,
|
|
12
|
+
defaultExpanded = true,
|
|
13
|
+
}: {
|
|
14
|
+
name?: string;
|
|
15
|
+
value?: string[];
|
|
16
|
+
options?: SelectOption[];
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
columns?: number;
|
|
19
|
+
defaultExpanded?: boolean;
|
|
20
|
+
} = $props();
|
|
21
|
+
|
|
22
|
+
const childrenByParent = $derived(buildChildrenByParent(options));
|
|
23
|
+
const selected = $derived(new Set(value));
|
|
24
|
+
const roots = $derived(childrenByParent.get(null) ?? []);
|
|
25
|
+
|
|
26
|
+
function toggle(nodeValue: string, checked: boolean) {
|
|
27
|
+
const affected = [nodeValue, ...collectDescendantIds(nodeValue, childrenByParent)];
|
|
28
|
+
if (checked) {
|
|
29
|
+
value = [...new Set([...value, ...affected])];
|
|
30
|
+
} else {
|
|
31
|
+
const affectedSet = new Set(affected);
|
|
32
|
+
value = value.filter((v) => !affectedSet.has(v));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<div
|
|
38
|
+
class="overflow-y-auto rounded-box border border-base-300 p-2"
|
|
39
|
+
style="max-height: var(--runeforge-tree-max-height, 24rem)"
|
|
40
|
+
class:opacity-50={disabled}
|
|
41
|
+
class:pointer-events-none={disabled}
|
|
42
|
+
>
|
|
43
|
+
{#if name}
|
|
44
|
+
<input type="hidden" {name} value={JSON.stringify(value)} />
|
|
45
|
+
{/if}
|
|
46
|
+
{#if roots.length === 0}
|
|
47
|
+
<p class="px-1 py-2 text-sm text-base-content/40">—</p>
|
|
48
|
+
{/if}
|
|
49
|
+
<div class:leaf-columns={columns > 1} style={`--columns: ${columns}`}>
|
|
50
|
+
{#each roots as root (root.value)}
|
|
51
|
+
<TreeNode node={root} {childrenByParent} {selected} onToggle={toggle} {disabled} depth={0} {columns} {defaultExpanded} />
|
|
52
|
+
{/each}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<style>
|
|
57
|
+
@media (min-width: 1024px) {
|
|
58
|
+
.leaf-columns {
|
|
59
|
+
columns: var(--columns);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { SelectOption } from '../../types/attribute.js';
|
|
3
|
-
import TreeNode from './TreeNode.svelte';
|
|
4
|
-
|
|
5
|
-
let {
|
|
6
|
-
node,
|
|
7
|
-
childrenByParent,
|
|
8
|
-
selected,
|
|
9
|
-
onToggle,
|
|
10
|
-
disabled,
|
|
11
|
-
depth,
|
|
12
|
-
columns,
|
|
13
|
-
defaultExpanded,
|
|
14
|
-
}: {
|
|
15
|
-
node: SelectOption;
|
|
16
|
-
childrenByParent: Map<string | null, SelectOption[]>;
|
|
17
|
-
selected: Set<string>;
|
|
18
|
-
onToggle: (value: string, checked: boolean) => void;
|
|
19
|
-
disabled: boolean;
|
|
20
|
-
depth: number;
|
|
21
|
-
columns: number;
|
|
22
|
-
defaultExpanded: boolean;
|
|
23
|
-
} = $props();
|
|
24
|
-
|
|
25
|
-
let expanded = $state(defaultExpanded);
|
|
26
|
-
|
|
27
|
-
const children = $derived(childrenByParent.get(node.value) ?? []);
|
|
28
|
-
const hasChildren = $derived(children.length > 0);
|
|
29
|
-
</script>
|
|
30
|
-
|
|
31
|
-
<div class="flex flex-col" style={`--columns: ${columns}`}>
|
|
32
|
-
<div
|
|
33
|
-
class="flex w-full items-center gap-1 rounded py-1 pr-2 transition-colors hover:bg-base-200"
|
|
34
|
-
style={`padding-left: ${depth * 1.25}rem`}
|
|
35
|
-
>
|
|
36
|
-
{#if hasChildren}
|
|
37
|
-
<button
|
|
38
|
-
type="button"
|
|
39
|
-
class="btn btn-ghost btn-xs btn-circle"
|
|
40
|
-
aria-label={expanded ? 'Collapse' : 'Expand'}
|
|
41
|
-
onclick={() => (expanded = !expanded)}
|
|
42
|
-
>
|
|
43
|
-
<span class="inline-block text-xs transition-transform" class:rotate-90={expanded}>▸</span>
|
|
44
|
-
</button>
|
|
45
|
-
{:else}
|
|
46
|
-
<span class="inline-block size-6"></span>
|
|
47
|
-
{/if}
|
|
48
|
-
|
|
49
|
-
<input
|
|
50
|
-
type="checkbox"
|
|
51
|
-
class="checkbox checkbox-sm"
|
|
52
|
-
checked={selected.has(node.value)}
|
|
53
|
-
{disabled}
|
|
54
|
-
onchange={(e) => onToggle(node.value, (e.currentTarget as HTMLInputElement).checked)}
|
|
55
|
-
aria-label={node.label}
|
|
56
|
-
/>
|
|
57
|
-
|
|
58
|
-
<span>{node.label}</span>
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
{#if expanded && hasChildren}
|
|
62
|
-
{#each children as child (child.value)}
|
|
63
|
-
<TreeNode node={child} {childrenByParent} {selected} {onToggle} {disabled} depth={depth + 1} {columns} {defaultExpanded} />
|
|
64
|
-
{/each}
|
|
65
|
-
{/if}
|
|
66
|
-
</div>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SelectOption } from '../../types/attribute.js';
|
|
3
|
+
import TreeNode from './TreeNode.svelte';
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
node,
|
|
7
|
+
childrenByParent,
|
|
8
|
+
selected,
|
|
9
|
+
onToggle,
|
|
10
|
+
disabled,
|
|
11
|
+
depth,
|
|
12
|
+
columns,
|
|
13
|
+
defaultExpanded,
|
|
14
|
+
}: {
|
|
15
|
+
node: SelectOption;
|
|
16
|
+
childrenByParent: Map<string | null, SelectOption[]>;
|
|
17
|
+
selected: Set<string>;
|
|
18
|
+
onToggle: (value: string, checked: boolean) => void;
|
|
19
|
+
disabled: boolean;
|
|
20
|
+
depth: number;
|
|
21
|
+
columns: number;
|
|
22
|
+
defaultExpanded: boolean;
|
|
23
|
+
} = $props();
|
|
24
|
+
|
|
25
|
+
let expanded = $state(defaultExpanded);
|
|
26
|
+
|
|
27
|
+
const children = $derived(childrenByParent.get(node.value) ?? []);
|
|
28
|
+
const hasChildren = $derived(children.length > 0);
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<div class="flex flex-col" style={`--columns: ${columns}`}>
|
|
32
|
+
<div
|
|
33
|
+
class="flex w-full items-center gap-1 rounded py-1 pr-2 transition-colors hover:bg-base-200"
|
|
34
|
+
style={`padding-left: ${depth * 1.25}rem`}
|
|
35
|
+
>
|
|
36
|
+
{#if hasChildren}
|
|
37
|
+
<button
|
|
38
|
+
type="button"
|
|
39
|
+
class="btn btn-ghost btn-xs btn-circle"
|
|
40
|
+
aria-label={expanded ? 'Collapse' : 'Expand'}
|
|
41
|
+
onclick={() => (expanded = !expanded)}
|
|
42
|
+
>
|
|
43
|
+
<span class="inline-block text-xs transition-transform" class:rotate-90={expanded}>▸</span>
|
|
44
|
+
</button>
|
|
45
|
+
{:else}
|
|
46
|
+
<span class="inline-block size-6"></span>
|
|
47
|
+
{/if}
|
|
48
|
+
|
|
49
|
+
<input
|
|
50
|
+
type="checkbox"
|
|
51
|
+
class="checkbox checkbox-sm"
|
|
52
|
+
checked={selected.has(node.value)}
|
|
53
|
+
{disabled}
|
|
54
|
+
onchange={(e) => onToggle(node.value, (e.currentTarget as HTMLInputElement).checked)}
|
|
55
|
+
aria-label={node.label}
|
|
56
|
+
/>
|
|
57
|
+
|
|
58
|
+
<span>{node.label}</span>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
{#if expanded && hasChildren}
|
|
62
|
+
{#each children as child (child.value)}
|
|
63
|
+
<TreeNode node={child} {childrenByParent} {selected} {onToggle} {disabled} depth={depth + 1} {columns} {defaultExpanded} />
|
|
64
|
+
{/each}
|
|
65
|
+
{/if}
|
|
66
|
+
</div>
|
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { getIconSet } from '../../icons/context.js';
|
|
3
|
-
import { defaultIconSet } from '../../icons/sets/default.js';
|
|
4
|
-
import { getConfig } from '../../config/context.js';
|
|
5
|
-
import type { BreadcrumbItem } from '../../types/breadcrumb.js';
|
|
6
|
-
|
|
7
|
-
let {
|
|
8
|
-
items = [],
|
|
9
|
-
homeHref,
|
|
10
|
-
}: {
|
|
11
|
-
items?: BreadcrumbItem[];
|
|
12
|
-
homeHref?: string;
|
|
13
|
-
} = $props();
|
|
14
|
-
|
|
15
|
-
const icons = $derived(getIconSet() ?? defaultIconSet);
|
|
16
|
-
|
|
17
|
-
const home: BreadcrumbItem = $derived({
|
|
18
|
-
label: 'Inicio',
|
|
19
|
-
icon: icons.home,
|
|
20
|
-
link: { href: homeHref ?? getConfig().homeHref ?? '/' },
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
const allItems = $derived([home, ...items]);
|
|
24
|
-
</script>
|
|
25
|
-
|
|
26
|
-
<div class="breadcrumbs">
|
|
27
|
-
<ul>
|
|
28
|
-
{#each allItems as item, i (i)}
|
|
29
|
-
<li>
|
|
30
|
-
{#if item.link !== undefined}
|
|
31
|
-
<a class="inline-flex items-center gap-2" {...item.link}>
|
|
32
|
-
{#if item.icon}
|
|
33
|
-
{@const ItemIcon = item.icon}
|
|
34
|
-
<ItemIcon />
|
|
35
|
-
{/if}
|
|
36
|
-
<span>{item.label}</span>
|
|
37
|
-
</a>
|
|
38
|
-
{:else}
|
|
39
|
-
<span class="inline-flex items-center gap-2">
|
|
40
|
-
{#if item.icon}
|
|
41
|
-
{@const ItemIcon = item.icon}
|
|
42
|
-
<ItemIcon />
|
|
43
|
-
{/if}
|
|
44
|
-
<span>{item.label}</span>
|
|
45
|
-
</span>
|
|
46
|
-
{/if}
|
|
47
|
-
</li>
|
|
48
|
-
{/each}
|
|
49
|
-
</ul>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
<style>
|
|
53
|
-
div {
|
|
54
|
-
font-size: var(--runeforge-breadcrumb-font-size, 0.875rem);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
:global(.breadcrumbs svg) {
|
|
58
|
-
width: var(--runeforge-breadcrumb-icon-size, 1rem);
|
|
59
|
-
height: var(--runeforge-breadcrumb-icon-size, 1rem);
|
|
60
|
-
flex-shrink: 0;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/*
|
|
64
|
-
* DaisyUI breadcrumbs use @layer rules that Tailwind v4 doesn't propagate
|
|
65
|
-
* from node_modules. These unlayered rules override that gap.
|
|
66
|
-
*/
|
|
67
|
-
:global(.breadcrumbs > ul),
|
|
68
|
-
:global(.breadcrumbs > ol),
|
|
69
|
-
:global(.breadcrumbs > menu) {
|
|
70
|
-
display: flex;
|
|
71
|
-
align-items: center;
|
|
72
|
-
white-space: nowrap;
|
|
73
|
-
overflow-x: auto;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
:global(.breadcrumbs > ul > li),
|
|
77
|
-
:global(.breadcrumbs > ol > li),
|
|
78
|
-
:global(.breadcrumbs > menu > li) {
|
|
79
|
-
display: flex;
|
|
80
|
-
align-items: center;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
:global(.breadcrumbs > ul > li + li::before),
|
|
84
|
-
:global(.breadcrumbs > ol > li + li::before),
|
|
85
|
-
:global(.breadcrumbs > menu > li + li::before) {
|
|
86
|
-
content: '';
|
|
87
|
-
display: block;
|
|
88
|
-
opacity: 0.4;
|
|
89
|
-
border-top: 1px solid;
|
|
90
|
-
border-right: 1px solid;
|
|
91
|
-
width: 0.375rem;
|
|
92
|
-
height: 0.375rem;
|
|
93
|
-
margin-inline: 0.5rem 0.75rem;
|
|
94
|
-
rotate: 45deg;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/*
|
|
98
|
-
* Tailwind preflight sets svg { display: block }, which stacks icons above
|
|
99
|
-
* labels when the <a>/<span> inline-flex class isn't generated from node_modules.
|
|
100
|
-
*/
|
|
101
|
-
:global(.breadcrumbs > ul > li > a),
|
|
102
|
-
:global(.breadcrumbs > ul > li > span),
|
|
103
|
-
:global(.breadcrumbs > ol > li > a),
|
|
104
|
-
:global(.breadcrumbs > ol > li > span),
|
|
105
|
-
:global(.breadcrumbs > menu > li > a),
|
|
106
|
-
:global(.breadcrumbs > menu > li > span) {
|
|
107
|
-
display: inline-flex;
|
|
108
|
-
align-items: center;
|
|
109
|
-
gap: 0.5rem;
|
|
110
|
-
}
|
|
111
|
-
</style>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getIconSet } from '../../icons/context.js';
|
|
3
|
+
import { defaultIconSet } from '../../icons/sets/default.js';
|
|
4
|
+
import { getConfig } from '../../config/context.js';
|
|
5
|
+
import type { BreadcrumbItem } from '../../types/breadcrumb.js';
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
items = [],
|
|
9
|
+
homeHref,
|
|
10
|
+
}: {
|
|
11
|
+
items?: BreadcrumbItem[];
|
|
12
|
+
homeHref?: string;
|
|
13
|
+
} = $props();
|
|
14
|
+
|
|
15
|
+
const icons = $derived(getIconSet() ?? defaultIconSet);
|
|
16
|
+
|
|
17
|
+
const home: BreadcrumbItem = $derived({
|
|
18
|
+
label: 'Inicio',
|
|
19
|
+
icon: icons.home,
|
|
20
|
+
link: { href: homeHref ?? getConfig().homeHref ?? '/' },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const allItems = $derived([home, ...items]);
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<div class="breadcrumbs">
|
|
27
|
+
<ul>
|
|
28
|
+
{#each allItems as item, i (i)}
|
|
29
|
+
<li>
|
|
30
|
+
{#if item.link !== undefined}
|
|
31
|
+
<a class="inline-flex items-center gap-2" {...item.link}>
|
|
32
|
+
{#if item.icon}
|
|
33
|
+
{@const ItemIcon = item.icon}
|
|
34
|
+
<ItemIcon />
|
|
35
|
+
{/if}
|
|
36
|
+
<span>{item.label}</span>
|
|
37
|
+
</a>
|
|
38
|
+
{:else}
|
|
39
|
+
<span class="inline-flex items-center gap-2">
|
|
40
|
+
{#if item.icon}
|
|
41
|
+
{@const ItemIcon = item.icon}
|
|
42
|
+
<ItemIcon />
|
|
43
|
+
{/if}
|
|
44
|
+
<span>{item.label}</span>
|
|
45
|
+
</span>
|
|
46
|
+
{/if}
|
|
47
|
+
</li>
|
|
48
|
+
{/each}
|
|
49
|
+
</ul>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<style>
|
|
53
|
+
div {
|
|
54
|
+
font-size: var(--runeforge-breadcrumb-font-size, 0.875rem);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
:global(.breadcrumbs svg) {
|
|
58
|
+
width: var(--runeforge-breadcrumb-icon-size, 1rem);
|
|
59
|
+
height: var(--runeforge-breadcrumb-icon-size, 1rem);
|
|
60
|
+
flex-shrink: 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
* DaisyUI breadcrumbs use @layer rules that Tailwind v4 doesn't propagate
|
|
65
|
+
* from node_modules. These unlayered rules override that gap.
|
|
66
|
+
*/
|
|
67
|
+
:global(.breadcrumbs > ul),
|
|
68
|
+
:global(.breadcrumbs > ol),
|
|
69
|
+
:global(.breadcrumbs > menu) {
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
white-space: nowrap;
|
|
73
|
+
overflow-x: auto;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
:global(.breadcrumbs > ul > li),
|
|
77
|
+
:global(.breadcrumbs > ol > li),
|
|
78
|
+
:global(.breadcrumbs > menu > li) {
|
|
79
|
+
display: flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
:global(.breadcrumbs > ul > li + li::before),
|
|
84
|
+
:global(.breadcrumbs > ol > li + li::before),
|
|
85
|
+
:global(.breadcrumbs > menu > li + li::before) {
|
|
86
|
+
content: '';
|
|
87
|
+
display: block;
|
|
88
|
+
opacity: 0.4;
|
|
89
|
+
border-top: 1px solid;
|
|
90
|
+
border-right: 1px solid;
|
|
91
|
+
width: 0.375rem;
|
|
92
|
+
height: 0.375rem;
|
|
93
|
+
margin-inline: 0.5rem 0.75rem;
|
|
94
|
+
rotate: 45deg;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/*
|
|
98
|
+
* Tailwind preflight sets svg { display: block }, which stacks icons above
|
|
99
|
+
* labels when the <a>/<span> inline-flex class isn't generated from node_modules.
|
|
100
|
+
*/
|
|
101
|
+
:global(.breadcrumbs > ul > li > a),
|
|
102
|
+
:global(.breadcrumbs > ul > li > span),
|
|
103
|
+
:global(.breadcrumbs > ol > li > a),
|
|
104
|
+
:global(.breadcrumbs > ol > li > span),
|
|
105
|
+
:global(.breadcrumbs > menu > li > a),
|
|
106
|
+
:global(.breadcrumbs > menu > li > span) {
|
|
107
|
+
display: inline-flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
gap: 0.5rem;
|
|
110
|
+
}
|
|
111
|
+
</style>
|