@immich/ui 0.47.0 → 0.49.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/dist/components/Breadcrumbs/Breadcrumbs.svelte +39 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.svelte.d.ts +4 -0
- package/dist/components/Card/Card.svelte +7 -7
- package/dist/components/ContextMenu/ContextMenu.svelte +4 -4
- package/dist/components/ContextMenu/ContextMenuButton.svelte +23 -0
- package/dist/components/ContextMenu/ContextMenuButton.svelte.d.ts +4 -0
- package/dist/components/Scrollable/Scrollable.svelte +0 -42
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/theme/default.css +40 -0
- package/dist/types.d.ts +34 -12
- package/package.json +2 -2
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Icon from '../Icon/Icon.svelte';
|
|
3
|
+
import Link from '../Link/Link.svelte';
|
|
4
|
+
import type { BreadcrumbItem, BreadcrumbsProps } from '../../types.js';
|
|
5
|
+
import { cleanClass } from '../../utilities/internal.js';
|
|
6
|
+
import { mdiChevronRight } from '@mdi/js';
|
|
7
|
+
|
|
8
|
+
let { separator = mdiChevronRight, class: className, items, ...props }: BreadcrumbsProps = $props();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
{#snippet child({ title, icon }: BreadcrumbItem)}
|
|
12
|
+
<span class="flex items-center gap-1">
|
|
13
|
+
{#if icon}
|
|
14
|
+
<Icon {icon} size="1.25rem" />
|
|
15
|
+
{/if}
|
|
16
|
+
{#if title}
|
|
17
|
+
<span>{title}</span>
|
|
18
|
+
{/if}
|
|
19
|
+
</span>
|
|
20
|
+
{/snippet}
|
|
21
|
+
|
|
22
|
+
<nav class={cleanClass('flex items-center gap-1', className)} {...props}>
|
|
23
|
+
{#each items as item, index (index)}
|
|
24
|
+
{#if index > 0}
|
|
25
|
+
{#if typeof separator === 'object' && 'text' in separator}
|
|
26
|
+
<span class="mx-1">{separator.text}</span>
|
|
27
|
+
{:else}
|
|
28
|
+
<Icon icon={separator} size="1rem" />
|
|
29
|
+
{/if}
|
|
30
|
+
{/if}
|
|
31
|
+
{#if item.href}
|
|
32
|
+
<Link href={item.href} class="underline">
|
|
33
|
+
{@render child(item)}
|
|
34
|
+
</Link>
|
|
35
|
+
{:else}
|
|
36
|
+
{@render child(item)}
|
|
37
|
+
{/if}
|
|
38
|
+
{/each}
|
|
39
|
+
</nav>
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { withChildrenSnippets } from '../../common/use-child.svelte.js';
|
|
3
3
|
import IconButton from '../IconButton/IconButton.svelte';
|
|
4
|
-
import Scrollable from '../Scrollable/Scrollable.svelte';
|
|
5
4
|
import { ChildKey } from '../../constants.js';
|
|
6
5
|
import type { Color } from '../../types.js';
|
|
7
6
|
import { cleanClass } from '../../utilities/internal.js';
|
|
8
7
|
import { mdiChevronDown } from '@mdi/js';
|
|
9
|
-
import { slide } from 'svelte/transition';
|
|
10
|
-
import { cubicOut } from 'svelte/easing';
|
|
11
8
|
import { type Snippet } from 'svelte';
|
|
9
|
+
import { cubicOut } from 'svelte/easing';
|
|
12
10
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
11
|
+
import { slide } from 'svelte/transition';
|
|
13
12
|
import { twMerge } from 'tailwind-merge';
|
|
14
13
|
import { tv } from 'tailwind-variants';
|
|
15
14
|
|
|
@@ -136,10 +135,11 @@
|
|
|
136
135
|
{/if}
|
|
137
136
|
|
|
138
137
|
{#if bodyChild && expanded}
|
|
139
|
-
<div
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
<div
|
|
139
|
+
transition:slide={{ duration: expandable ? 200 : 0, easing: cubicOut }}
|
|
140
|
+
class={twMerge(cleanClass('immich-scrollbar h-full w-full overflow-auto p-4', bodyChild?.class))}
|
|
141
|
+
>
|
|
142
|
+
{@render bodyChild?.snippet()}
|
|
143
143
|
</div>
|
|
144
144
|
{/if}
|
|
145
145
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import Text from '../Text/Text.svelte';
|
|
4
4
|
import { zIndex } from '../../constants.js';
|
|
5
5
|
import { styleVariants } from '../../styles.js';
|
|
6
|
-
import { MenuItemType, type ContextMenuProps, type
|
|
6
|
+
import { MenuItemType, type ContextMenuProps, type ActionItem } from '../../types.js';
|
|
7
7
|
import { cleanClass, isEnabled } from '../../utilities/internal.js';
|
|
8
8
|
import { DropdownMenu } from 'bits-ui';
|
|
9
9
|
import { fly } from 'svelte/transition';
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
...restProps
|
|
21
21
|
}: ContextMenuProps = $props();
|
|
22
22
|
|
|
23
|
-
const isDivider = (item:
|
|
23
|
+
const isDivider = (item: ActionItem | MenuItemType): item is MenuItemType => {
|
|
24
24
|
return item === MenuItemType.Divider;
|
|
25
25
|
};
|
|
26
26
|
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
<DropdownMenu.Item
|
|
108
108
|
textValue={item.title}
|
|
109
109
|
closeOnSelect
|
|
110
|
-
onSelect={(
|
|
110
|
+
onSelect={() => item.onAction(item)}
|
|
111
111
|
class="px-1"
|
|
112
112
|
>
|
|
113
113
|
<div class={itemStyles({ color: item.color })}>
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
<DropdownMenu.Item
|
|
126
126
|
textValue={item.title}
|
|
127
127
|
closeOnSelect
|
|
128
|
-
onSelect={(
|
|
128
|
+
onSelect={() => item.onAction(item)}
|
|
129
129
|
title={item.title}
|
|
130
130
|
>
|
|
131
131
|
<div class={cleanClass(itemStyles({ color: item.color }))}>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import IconButton from '../IconButton/IconButton.svelte';
|
|
3
|
+
import { menuManager } from '../../services/menu-manager.svelte.js';
|
|
4
|
+
import type { ContextMenuButtonProps } from '../../types.js';
|
|
5
|
+
import { mdiDotsVertical } from '@mdi/js';
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
color = 'secondary',
|
|
9
|
+
position = 'top-right',
|
|
10
|
+
icon = mdiDotsVertical,
|
|
11
|
+
variant = 'ghost',
|
|
12
|
+
shape = 'round',
|
|
13
|
+
items,
|
|
14
|
+
bottomItems,
|
|
15
|
+
...rest
|
|
16
|
+
}: ContextMenuButtonProps = $props();
|
|
17
|
+
|
|
18
|
+
const onclick = async (event: Event) => {
|
|
19
|
+
await menuManager.show({ target: event.currentTarget as HTMLElement, position, items, bottomItems });
|
|
20
|
+
};
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<IconButton {icon} {color} {shape} {variant} {...rest} {onclick} />
|
|
@@ -23,45 +23,3 @@
|
|
|
23
23
|
<div bind:this={ref} class={cleanClass('immich-scrollbar h-full w-full overflow-auto', className)}>
|
|
24
24
|
{@render children?.()}
|
|
25
25
|
</div>
|
|
26
|
-
|
|
27
|
-
<style>
|
|
28
|
-
/* width */
|
|
29
|
-
.immich-scrollbar::-webkit-scrollbar {
|
|
30
|
-
width: 8px;
|
|
31
|
-
height: 8px;
|
|
32
|
-
visibility: hidden;
|
|
33
|
-
}
|
|
34
|
-
/* Track */
|
|
35
|
-
.immich-scrollbar::-webkit-scrollbar-track {
|
|
36
|
-
background: #f1f1f1;
|
|
37
|
-
border-radius: 16px;
|
|
38
|
-
visibility: hidden;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/* Handle */
|
|
42
|
-
.immich-scrollbar::-webkit-scrollbar-thumb {
|
|
43
|
-
background: rgba(85, 86, 87, 0.408);
|
|
44
|
-
border-radius: 16px;
|
|
45
|
-
visibility: hidden;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/* Handle on hover */
|
|
49
|
-
.immich-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
50
|
-
background: #4250afad;
|
|
51
|
-
border-radius: 16px;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/*
|
|
55
|
-
* Show scrollbar elements when hovering or actively scrolling
|
|
56
|
-
* Applies to the main scrollbar, track, and thumb components
|
|
57
|
-
* Changes visibility from hidden to visible on user interaction
|
|
58
|
-
*/
|
|
59
|
-
.immich-scrollbar:hover::-webkit-scrollbar,
|
|
60
|
-
.immich-scrollbar:active::-webkit-scrollbar,
|
|
61
|
-
.immich-scrollbar:hover::-webkit-scrollbar-track,
|
|
62
|
-
.immich-scrollbar:active::-webkit-scrollbar-track,
|
|
63
|
-
.immich-scrollbar:hover::-webkit-scrollbar-thumb,
|
|
64
|
-
.immich-scrollbar:active::-webkit-scrollbar-thumb {
|
|
65
|
-
visibility: visible;
|
|
66
|
-
}
|
|
67
|
-
</style>
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export { default as AppShellHeader } from './components/AppShell/AppShellHeader.
|
|
|
17
17
|
export { default as AppShellSidebar } from './components/AppShell/AppShellSidebar.svelte';
|
|
18
18
|
export { default as Avatar } from './components/Avatar/Avatar.svelte';
|
|
19
19
|
export { default as Badge } from './components/Badge/Badge.svelte';
|
|
20
|
+
export { default as Breadcrumbs } from './components/Breadcrumbs/Breadcrumbs.svelte';
|
|
20
21
|
export { default as Button } from './components/Button/Button.svelte';
|
|
21
22
|
export { default as Card } from './components/Card/Card.svelte';
|
|
22
23
|
export { default as CardBody } from './components/Card/CardBody.svelte';
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ export { default as AppShellHeader } from './components/AppShell/AppShellHeader.
|
|
|
19
19
|
export { default as AppShellSidebar } from './components/AppShell/AppShellSidebar.svelte';
|
|
20
20
|
export { default as Avatar } from './components/Avatar/Avatar.svelte';
|
|
21
21
|
export { default as Badge } from './components/Badge/Badge.svelte';
|
|
22
|
+
export { default as Breadcrumbs } from './components/Breadcrumbs/Breadcrumbs.svelte';
|
|
22
23
|
export { default as Button } from './components/Button/Button.svelte';
|
|
23
24
|
export { default as Card } from './components/Card/Card.svelte';
|
|
24
25
|
export { default as CardBody } from './components/Card/CardBody.svelte';
|
package/dist/theme/default.css
CHANGED
|
@@ -299,3 +299,43 @@
|
|
|
299
299
|
border-color: var(--immich-ui-default-border);
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
|
+
|
|
303
|
+
/* width */
|
|
304
|
+
.immich-scrollbar::-webkit-scrollbar {
|
|
305
|
+
width: 8px;
|
|
306
|
+
height: 8px;
|
|
307
|
+
visibility: hidden;
|
|
308
|
+
}
|
|
309
|
+
/* Track */
|
|
310
|
+
.immich-scrollbar::-webkit-scrollbar-track {
|
|
311
|
+
background: #f1f1f1;
|
|
312
|
+
border-radius: 16px;
|
|
313
|
+
visibility: hidden;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* Handle */
|
|
317
|
+
.immich-scrollbar::-webkit-scrollbar-thumb {
|
|
318
|
+
background: rgba(85, 86, 87, 0.408);
|
|
319
|
+
border-radius: 16px;
|
|
320
|
+
visibility: hidden;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* Handle on hover */
|
|
324
|
+
.immich-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
325
|
+
background: #4250afad;
|
|
326
|
+
border-radius: 16px;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/*
|
|
330
|
+
* Show scrollbar elements when hovering or actively scrolling
|
|
331
|
+
* Applies to the main scrollbar, track, and thumb components
|
|
332
|
+
* Changes visibility from hidden to visible on user interaction
|
|
333
|
+
*/
|
|
334
|
+
.immich-scrollbar:hover::-webkit-scrollbar,
|
|
335
|
+
.immich-scrollbar:active::-webkit-scrollbar,
|
|
336
|
+
.immich-scrollbar:hover::-webkit-scrollbar-track,
|
|
337
|
+
.immich-scrollbar:active::-webkit-scrollbar-track,
|
|
338
|
+
.immich-scrollbar:hover::-webkit-scrollbar-thumb,
|
|
339
|
+
.immich-scrollbar:active::-webkit-scrollbar-thumb {
|
|
340
|
+
visibility: visible;
|
|
341
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -67,6 +67,13 @@ export type CloseButtonProps = {
|
|
|
67
67
|
class?: string;
|
|
68
68
|
translations?: TranslationProps<'close'>;
|
|
69
69
|
} & ButtonOrAnchor;
|
|
70
|
+
export type ContextMenuButtonProps = ButtonBase & {
|
|
71
|
+
icon?: IconLike;
|
|
72
|
+
position?: ContextMenuPosition;
|
|
73
|
+
'aria-label': string;
|
|
74
|
+
items: MenuItems;
|
|
75
|
+
bottomItems?: Array<ActionItem | undefined>;
|
|
76
|
+
} & Omit<HTMLButtonAttributes, 'color' | 'size'>;
|
|
70
77
|
export type IconButtonProps = ButtonBase & {
|
|
71
78
|
icon: IconLike;
|
|
72
79
|
flipped?: boolean;
|
|
@@ -203,23 +210,13 @@ export type ToastButton = {
|
|
|
203
210
|
variant?: Variants;
|
|
204
211
|
onClick: () => void;
|
|
205
212
|
};
|
|
206
|
-
export type MenuSelectHandler = (context: {
|
|
207
|
-
event: Event;
|
|
208
|
-
item: MenuItem;
|
|
209
|
-
}) => void;
|
|
210
|
-
export type MenuItem = {
|
|
211
|
-
title: string;
|
|
212
|
-
icon: IconLike;
|
|
213
|
-
color?: Color;
|
|
214
|
-
onSelect?: MenuSelectHandler;
|
|
215
|
-
} & IfLike;
|
|
216
213
|
export declare enum MenuItemType {
|
|
217
214
|
Divider = "divider"
|
|
218
215
|
}
|
|
219
|
-
export type MenuItems = Array<
|
|
216
|
+
export type MenuItems = Array<ActionItem | MenuItemType | undefined>;
|
|
220
217
|
export type MenuProps = {
|
|
221
218
|
items: MenuItems;
|
|
222
|
-
bottomItems?: (
|
|
219
|
+
bottomItems?: (ActionItem | undefined)[];
|
|
223
220
|
size?: MenuSize;
|
|
224
221
|
} & HTMLAttributes<HTMLDivElement>;
|
|
225
222
|
export type ContextMenuPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
@@ -242,4 +239,29 @@ export type DatePickerProps = {
|
|
|
242
239
|
export type IfLike = {
|
|
243
240
|
$if?: () => boolean;
|
|
244
241
|
};
|
|
242
|
+
export type ActionItemHandler<T = never> = (item: ActionItem<T>) => void | Promise<void>;
|
|
243
|
+
export type ActionItem<T = never> = Omit<{
|
|
244
|
+
title: string;
|
|
245
|
+
icon: IconLike;
|
|
246
|
+
color?: Color;
|
|
247
|
+
onAction: ActionItemHandler<T>;
|
|
248
|
+
data: T;
|
|
249
|
+
} & IfLike, [
|
|
250
|
+
T
|
|
251
|
+
] extends [never] ? 'data' : ''>;
|
|
252
|
+
export type BreadcrumbsProps = {
|
|
253
|
+
separator?: IconLike | {
|
|
254
|
+
text: string;
|
|
255
|
+
};
|
|
256
|
+
items: BreadcrumbItem[];
|
|
257
|
+
} & HTMLAttributes<HTMLElement>;
|
|
258
|
+
export type BreadcrumbItem = {
|
|
259
|
+
href?: string;
|
|
260
|
+
} & ({
|
|
261
|
+
title: string;
|
|
262
|
+
icon?: IconLike;
|
|
263
|
+
} | {
|
|
264
|
+
title?: string;
|
|
265
|
+
icon: IconLike;
|
|
266
|
+
});
|
|
245
267
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@immich/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.0",
|
|
4
4
|
"license": "GNU Affero General Public License version 3",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"@immich/svelte-markdown-preprocess": "^0.1.0"
|
|
59
59
|
},
|
|
60
60
|
"volta": {
|
|
61
|
-
"node": "24.11.
|
|
61
|
+
"node": "24.11.1"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"create": "node scripts/create.js",
|