@immich/ui 0.49.3 → 0.50.1
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/AppShell/AppShellSidebar.svelte +1 -1
- package/dist/components/Avatar/Avatar.svelte +10 -10
- package/dist/components/Badge/Badge.svelte +15 -15
- package/dist/components/Breadcrumbs/Breadcrumbs.svelte +1 -1
- package/dist/components/Card/Card.svelte +8 -11
- package/dist/components/CommandPalette/CommandPaletteItem.svelte +7 -5
- package/dist/components/ConfirmModal/ConfirmModal.svelte +2 -2
- package/dist/components/ConfirmModal/ConfirmModal.svelte.d.ts +2 -2
- package/dist/components/ContextMenu/ContextMenu.svelte +34 -12
- package/dist/components/ContextMenu/ContextMenuButton.svelte +12 -1
- package/dist/components/FormModal/FormModal.svelte +2 -2
- package/dist/components/FormModal/FormModal.svelte.d.ts +2 -2
- package/dist/components/Textarea/Textarea.svelte +1 -1
- package/dist/components/Toast/ToastContent.svelte +7 -7
- package/dist/components/Toast/ToastPanel.svelte +4 -7
- package/dist/internal/Button.svelte +14 -17
- package/dist/services/command-palette-manager.svelte.d.ts +64 -4
- package/dist/services/translation.svelte.d.ts +1 -0
- package/dist/services/translation.svelte.js +2 -0
- package/dist/theme/default.css +4 -4
- package/dist/types.d.ts +6 -9
- package/dist/utilities/common.d.ts +2 -0
- package/dist/utilities/common.js +4 -0
- package/package.json +1 -1
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<Scrollable
|
|
19
19
|
class={cleanClass(
|
|
20
20
|
'bg-light text-dark absolute shrink-0 border-e shadow-lg transition-all duration-200 md:relative',
|
|
21
|
-
open ? `${zIndex.AppShellSidebar} w-[min(100vw,16rem)]` : 'w-
|
|
21
|
+
open ? `${zIndex.AppShellSidebar} w-[min(100vw,16rem)]` : 'w-0 border-e-0',
|
|
22
22
|
className,
|
|
23
23
|
)}
|
|
24
24
|
>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
const { color = 'primary', size = 'medium', name }: Props = $props();
|
|
12
12
|
|
|
13
13
|
const styles = tv({
|
|
14
|
-
base: 'flex h-full w-full items-center justify-center font-medium select-none',
|
|
14
|
+
base: 'flex h-full w-full items-center justify-center font-medium text-white select-none',
|
|
15
15
|
variants: {
|
|
16
16
|
size: {
|
|
17
17
|
tiny: 'h-5 w-5 text-xs',
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
},
|
|
23
23
|
color: {
|
|
24
24
|
primary: 'bg-primary text-light',
|
|
25
|
-
pink: '
|
|
26
|
-
red: '
|
|
27
|
-
yellow: '
|
|
28
|
-
purple: '
|
|
29
|
-
orange: '
|
|
30
|
-
gray: '
|
|
31
|
-
amber: '
|
|
32
|
-
blue: '
|
|
33
|
-
green: '
|
|
25
|
+
pink: 'bg-pink-400',
|
|
26
|
+
red: 'bg-red-500',
|
|
27
|
+
yellow: 'bg-yellow-500',
|
|
28
|
+
purple: 'bg-purple-600',
|
|
29
|
+
orange: 'bg-orange-600',
|
|
30
|
+
gray: 'bg-gray-600',
|
|
31
|
+
amber: 'bg-amber-600',
|
|
32
|
+
blue: 'bg-blue-500',
|
|
33
|
+
green: 'bg-green-600',
|
|
34
34
|
},
|
|
35
35
|
},
|
|
36
36
|
});
|
|
@@ -24,31 +24,31 @@
|
|
|
24
24
|
}: Props = $props();
|
|
25
25
|
|
|
26
26
|
const styles = tv({
|
|
27
|
-
base: 'border
|
|
27
|
+
base: 'text-light inline-flex items-center border font-medium antialiased',
|
|
28
28
|
variants: {
|
|
29
29
|
shape: styleVariants.shape,
|
|
30
30
|
color: {
|
|
31
|
-
primary: '
|
|
32
|
-
secondary: '
|
|
33
|
-
success: '
|
|
34
|
-
info: '
|
|
35
|
-
warning: '
|
|
36
|
-
danger: '
|
|
31
|
+
primary: 'bg-primary',
|
|
32
|
+
secondary: 'bg-dark',
|
|
33
|
+
success: 'bg-success',
|
|
34
|
+
info: 'bg-info',
|
|
35
|
+
warning: 'bg-warning',
|
|
36
|
+
danger: 'bg-danger text-danger-50',
|
|
37
37
|
},
|
|
38
38
|
textSize: styleVariants.textSize,
|
|
39
39
|
paddingSize: {
|
|
40
|
-
tiny: 'px-1.5 py-
|
|
41
|
-
small: 'px-1.75 py-0.
|
|
42
|
-
medium: 'px-2.5 py-
|
|
40
|
+
tiny: 'px-1.5 py-1',
|
|
41
|
+
small: 'px-1.75 py-0.75',
|
|
42
|
+
medium: 'px-2.5 py-1',
|
|
43
43
|
large: 'px-2.75 py-1',
|
|
44
44
|
giant: 'px-3 py-1.25',
|
|
45
45
|
},
|
|
46
46
|
roundedSize: {
|
|
47
|
-
tiny: 'rounded-
|
|
48
|
-
small: 'rounded-
|
|
49
|
-
medium: 'rounded-
|
|
50
|
-
large: 'rounded-
|
|
51
|
-
giant: 'rounded-
|
|
47
|
+
tiny: 'rounded-lg',
|
|
48
|
+
small: 'rounded-lg',
|
|
49
|
+
medium: 'rounded-lg',
|
|
50
|
+
large: 'rounded-xl',
|
|
51
|
+
giant: 'rounded-xl',
|
|
52
52
|
},
|
|
53
53
|
},
|
|
54
54
|
});
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
</span>
|
|
20
20
|
{/snippet}
|
|
21
21
|
|
|
22
|
-
<nav class={cleanClass('flex items-center gap-1', className)} {...props}>
|
|
22
|
+
<nav class={cleanClass('flex flex-wrap items-center gap-1', className)} {...props}>
|
|
23
23
|
{#each items as item, index (index)}
|
|
24
24
|
{#if index > 0}
|
|
25
25
|
{#if typeof separator === 'object' && 'text' in separator}
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
import { cubicOut } from 'svelte/easing';
|
|
10
10
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
11
11
|
import { slide } from 'svelte/transition';
|
|
12
|
-
import { twMerge } from 'tailwind-merge';
|
|
13
12
|
import { tv } from 'tailwind-variants';
|
|
14
13
|
|
|
15
14
|
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
@@ -87,14 +86,12 @@
|
|
|
87
86
|
const headerPadding = $derived(headerBorder || !expanded);
|
|
88
87
|
|
|
89
88
|
const headerContainerClasses = $derived(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
headerChild?.class,
|
|
97
|
-
),
|
|
89
|
+
cleanClass(
|
|
90
|
+
headerContainerStyles({
|
|
91
|
+
padding: headerPadding,
|
|
92
|
+
border: headerBorder,
|
|
93
|
+
}),
|
|
94
|
+
headerChild?.class,
|
|
98
95
|
),
|
|
99
96
|
);
|
|
100
97
|
</script>
|
|
@@ -137,14 +134,14 @@
|
|
|
137
134
|
{#if bodyChild && expanded}
|
|
138
135
|
<div
|
|
139
136
|
transition:slide={{ duration: expandable ? 200 : 0, easing: cubicOut }}
|
|
140
|
-
class={
|
|
137
|
+
class={cleanClass('immich-scrollbar h-full w-full overflow-auto p-4', bodyChild?.class)}
|
|
141
138
|
>
|
|
142
139
|
{@render bodyChild?.snippet()}
|
|
143
140
|
</div>
|
|
144
141
|
{/if}
|
|
145
142
|
|
|
146
143
|
{#if footerChild}
|
|
147
|
-
<div class={
|
|
144
|
+
<div class={cleanClass('flex items-center border-t p-4', footerChild.class)}>
|
|
148
145
|
{@render footerChild.snippet()}
|
|
149
146
|
</div>
|
|
150
147
|
{/if}
|
|
@@ -43,11 +43,13 @@
|
|
|
43
43
|
fullWidth
|
|
44
44
|
variant={selected ? 'outline' : 'ghost'}
|
|
45
45
|
color="secondary"
|
|
46
|
-
class="flex justify-between gap-3 border text-start {selected
|
|
46
|
+
class="hover:bg-primary-50 flex justify-between gap-3 border py-4 text-start {selected
|
|
47
|
+
? 'border-primary/50 bg-primary-50'
|
|
48
|
+
: 'border-light-200 dark:border-light-300'}"
|
|
47
49
|
>
|
|
48
50
|
<div class="flex flex-col">
|
|
49
|
-
<div class="flex items-center gap-
|
|
50
|
-
<Text fontWeight="bold">{item.title}</Text>
|
|
51
|
+
<div class="flex place-items-center gap-2">
|
|
52
|
+
<Text fontWeight="semi-bold">{item.title}</Text>
|
|
51
53
|
<Icon icon={item.icon} size="1.25rem" class={item.iconClass} />
|
|
52
54
|
</div>
|
|
53
55
|
{#if item.description}
|
|
@@ -58,9 +60,9 @@
|
|
|
58
60
|
>
|
|
59
61
|
{/if}
|
|
60
62
|
<div class="mt-2">
|
|
61
|
-
<Badge
|
|
63
|
+
<Badge color="primary" size="small">{item.type}</Badge>
|
|
62
64
|
{#if item.isGlobal}
|
|
63
|
-
<Badge
|
|
65
|
+
<Badge color="warning" size="small">Global</Badge>
|
|
64
66
|
{/if}
|
|
65
67
|
</div>
|
|
66
68
|
</div>
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import ModalBody from '../Modal/ModalBody.svelte';
|
|
5
5
|
import ModalFooter from '../Modal/ModalFooter.svelte';
|
|
6
6
|
import HStack from '../Stack/HStack.svelte';
|
|
7
|
-
import type { Color } from '../../types.js';
|
|
8
7
|
import { t } from '../../services/translation.svelte.js';
|
|
8
|
+
import type { Color, ModalSize } from '../../types.js';
|
|
9
9
|
import type { Snippet } from 'svelte';
|
|
10
10
|
|
|
11
11
|
interface Props {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
confirmText?: string;
|
|
16
16
|
confirmColor?: Color;
|
|
17
17
|
disabled?: boolean;
|
|
18
|
-
size?:
|
|
18
|
+
size?: ModalSize;
|
|
19
19
|
onClose: (confirmed: boolean) => void;
|
|
20
20
|
promptSnippet?: Snippet;
|
|
21
21
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Color } from '../../types.js';
|
|
1
|
+
import type { Color, ModalSize } from '../../types.js';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
interface Props {
|
|
4
4
|
title?: string;
|
|
@@ -7,7 +7,7 @@ interface Props {
|
|
|
7
7
|
confirmText?: string;
|
|
8
8
|
confirmColor?: Color;
|
|
9
9
|
disabled?: boolean;
|
|
10
|
-
size?:
|
|
10
|
+
size?: ModalSize;
|
|
11
11
|
onClose: (confirmed: boolean) => void;
|
|
12
12
|
promptSnippet?: Snippet;
|
|
13
13
|
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import Text from '../Text/Text.svelte';
|
|
4
4
|
import { zIndex } from '../../constants.js';
|
|
5
5
|
import { styleVariants } from '../../styles.js';
|
|
6
|
-
import {
|
|
6
|
+
import { type ActionItem, type ContextMenuProps, type MenuItems } from '../../types.js';
|
|
7
|
+
import { isMenuItemType } from '../../utilities/common.js';
|
|
7
8
|
import { cleanClass, isEnabled } from '../../utilities/internal.js';
|
|
8
9
|
import { DropdownMenu } from 'bits-ui';
|
|
9
10
|
import { fly } from 'svelte/transition';
|
|
@@ -20,10 +21,6 @@
|
|
|
20
21
|
...restProps
|
|
21
22
|
}: ContextMenuProps = $props();
|
|
22
23
|
|
|
23
|
-
const isDivider = (item: ActionItem | MenuItemType): item is MenuItemType => {
|
|
24
|
-
return item === MenuItemType.Divider;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
24
|
const itemStyles = tv({
|
|
28
25
|
base: 'hover:bg-light-200 flex w-full items-center gap-1 rounded-lg p-1 text-start hover:cursor-pointer',
|
|
29
26
|
variants: {
|
|
@@ -83,10 +80,35 @@
|
|
|
83
80
|
}
|
|
84
81
|
};
|
|
85
82
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
const getFilteredItems = (items?: MenuItems) => {
|
|
84
|
+
if (!items) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const results = [];
|
|
89
|
+
for (const item of items) {
|
|
90
|
+
if (item && (isMenuItemType(item) || isEnabled(item))) {
|
|
91
|
+
results.push(item);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// remove trailing dividers
|
|
97
|
+
for (let i = results.length - 1; i >= 0; i--) {
|
|
98
|
+
const item = results[i];
|
|
99
|
+
if (isMenuItemType(item)) {
|
|
100
|
+
results.pop();
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return results;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const filteredItems = $derived(getFilteredItems(items));
|
|
111
|
+
const filteredBottomItems = $derived(getFilteredItems(bottomItems) as ActionItem[]);
|
|
90
112
|
|
|
91
113
|
const alignOffset = $derived(target.clientWidth / 2);
|
|
92
114
|
const sideOffset = $derived(-target.clientHeight / 2);
|
|
@@ -100,8 +122,8 @@
|
|
|
100
122
|
{#if open}
|
|
101
123
|
<div {...wrapperProps} class={zIndex.ContextMenu}>
|
|
102
124
|
<div {...props} {...restProps} class={cleanClass(wrapperStyles({ size }), className)} transition:fly>
|
|
103
|
-
{#each filteredItems as item, i (
|
|
104
|
-
{#if
|
|
125
|
+
{#each filteredItems as item, i (isMenuItemType(item) ? i : item.title)}
|
|
126
|
+
{#if isMenuItemType(item)}
|
|
105
127
|
<DropdownMenu.Separator class="dark:border-light-300 my-0.5 border-t" />
|
|
106
128
|
{:else}
|
|
107
129
|
<DropdownMenu.Item
|
|
@@ -118,7 +140,7 @@
|
|
|
118
140
|
{/if}
|
|
119
141
|
{/each}
|
|
120
142
|
|
|
121
|
-
{#if filteredBottomItems}
|
|
143
|
+
{#if filteredBottomItems.length > 0}
|
|
122
144
|
<DropdownMenu.Separator class="dark:border-light-300 my-0.5 border-t" />
|
|
123
145
|
<div class="flex gap-1 px-1">
|
|
124
146
|
{#each filteredBottomItems as item (item.title)}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import IconButton from '../IconButton/IconButton.svelte';
|
|
3
3
|
import { menuManager } from '../../services/menu-manager.svelte.js';
|
|
4
|
+
import { t } from '../../services/translation.svelte.js';
|
|
4
5
|
import type { ContextMenuButtonProps } from '../../types.js';
|
|
5
6
|
import { mdiDotsVertical } from '@mdi/js';
|
|
6
7
|
|
|
@@ -10,8 +11,10 @@
|
|
|
10
11
|
icon = mdiDotsVertical,
|
|
11
12
|
variant = 'ghost',
|
|
12
13
|
shape = 'round',
|
|
14
|
+
'aria-label': ariaLabel,
|
|
13
15
|
items,
|
|
14
16
|
bottomItems,
|
|
17
|
+
translations,
|
|
15
18
|
...rest
|
|
16
19
|
}: ContextMenuButtonProps = $props();
|
|
17
20
|
|
|
@@ -20,4 +23,12 @@
|
|
|
20
23
|
};
|
|
21
24
|
</script>
|
|
22
25
|
|
|
23
|
-
<IconButton
|
|
26
|
+
<IconButton
|
|
27
|
+
{icon}
|
|
28
|
+
{color}
|
|
29
|
+
{shape}
|
|
30
|
+
{variant}
|
|
31
|
+
aria-label={ariaLabel ?? t('open_menu', translations)}
|
|
32
|
+
{...rest}
|
|
33
|
+
{onclick}
|
|
34
|
+
/>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import ModalFooter from '../Modal/ModalFooter.svelte';
|
|
6
6
|
import HStack from '../Stack/HStack.svelte';
|
|
7
7
|
import { t } from '../../services/translation.svelte.js';
|
|
8
|
-
import type { Color } from '../../types.js';
|
|
8
|
+
import type { Color, ModalSize } from '../../types.js';
|
|
9
9
|
import { generateId } from '../../utilities/internal.js';
|
|
10
10
|
import type { Snippet } from 'svelte';
|
|
11
11
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
submitText?: string;
|
|
16
16
|
submitColor?: Color;
|
|
17
17
|
disabled?: boolean;
|
|
18
|
-
size?:
|
|
18
|
+
size?: ModalSize;
|
|
19
19
|
preventDefault?: boolean;
|
|
20
20
|
onClose: () => void;
|
|
21
21
|
onSubmit: (event: SubmitEvent) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Color } from '../../types.js';
|
|
1
|
+
import type { Color, ModalSize } from '../../types.js';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
type Props = {
|
|
4
4
|
title: string;
|
|
@@ -6,7 +6,7 @@ type Props = {
|
|
|
6
6
|
submitText?: string;
|
|
7
7
|
submitColor?: Color;
|
|
8
8
|
disabled?: boolean;
|
|
9
|
-
size?:
|
|
9
|
+
size?: ModalSize;
|
|
10
10
|
preventDefault?: boolean;
|
|
11
11
|
onClose: () => void;
|
|
12
12
|
onSubmit: (event: SubmitEvent) => void;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
const { label, description, readOnly, required, invalid, disabled, ...labelProps } = $derived(getFieldContext());
|
|
23
23
|
|
|
24
24
|
const styles = tv({
|
|
25
|
-
base: 'w-full bg-gray-200 outline-none disabled:cursor-not-allowed disabled:bg-gray-300 disabled:text-gray-400 dark:bg-gray-
|
|
25
|
+
base: 'focus-within:ring-primary dark:focus-within:ring-primary w-full bg-gray-100 ring-1 ring-gray-200 outline-none focus-within:ring-1 disabled:cursor-not-allowed disabled:bg-gray-300 disabled:text-gray-400 dark:bg-gray-800 dark:ring-black dark:disabled:bg-gray-800 dark:disabled:text-gray-200',
|
|
26
26
|
variants: {
|
|
27
27
|
shape: styleVariants.shape,
|
|
28
28
|
padding: {
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
);
|
|
28
28
|
|
|
29
29
|
const iconStyles = tv({
|
|
30
|
-
base: 'h-8 w-8 shrink-0 rounded-xl py-1.75',
|
|
30
|
+
base: 'h-8 w-8 shrink-0 rounded-xl py-1.75 text-white',
|
|
31
31
|
variants: {
|
|
32
32
|
color: {
|
|
33
|
-
primary: 'bg-primary
|
|
34
|
-
secondary: 'bg-
|
|
35
|
-
success: 'bg-success
|
|
36
|
-
info: 'bg-info
|
|
37
|
-
warning: 'bg-warning
|
|
38
|
-
danger: 'bg-danger
|
|
33
|
+
primary: 'bg-primary dark:bg-primary-200',
|
|
34
|
+
secondary: 'bg-dark dark:bg-light-300',
|
|
35
|
+
success: 'bg-success dark:bg-success-200',
|
|
36
|
+
info: 'bg-info dark:text-info-50',
|
|
37
|
+
warning: 'bg-warning dark:text-warning-50',
|
|
38
|
+
danger: 'bg-danger dark:text-danger-50',
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
});
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import { isCustomToast } from '../../services/toast-manager.svelte.js';
|
|
5
5
|
import type { ToastPanelProps } from '../../types.js';
|
|
6
6
|
import { cleanClass } from '../../utilities/internal.js';
|
|
7
|
-
import { twMerge } from 'tailwind-merge';
|
|
8
7
|
|
|
9
8
|
const { items, class: className, ...props }: ToastPanelProps = $props();
|
|
10
9
|
|
|
@@ -12,12 +11,10 @@
|
|
|
12
11
|
</script>
|
|
13
12
|
|
|
14
13
|
<div
|
|
15
|
-
class={
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
className,
|
|
20
|
-
),
|
|
14
|
+
class={cleanClass(
|
|
15
|
+
isEmpty ? 'hidden' : 'absolute top-0 right-0 flex flex-col items-end justify-end gap-2 p-4',
|
|
16
|
+
zIndex.ToastPanel,
|
|
17
|
+
className,
|
|
21
18
|
)}
|
|
22
19
|
{...props}
|
|
23
20
|
>
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import { cleanClass } from '../utilities/internal.js';
|
|
8
8
|
import { Button as ButtonPrimitive } from 'bits-ui';
|
|
9
9
|
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
|
10
|
-
import { twMerge } from 'tailwind-merge';
|
|
11
10
|
import { tv } from 'tailwind-variants';
|
|
12
11
|
|
|
13
12
|
type InternalButtonProps = ButtonProps & {
|
|
@@ -99,22 +98,20 @@
|
|
|
99
98
|
|
|
100
99
|
const classList = $derived(
|
|
101
100
|
cleanClass(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
className,
|
|
117
|
-
),
|
|
101
|
+
buttonVariants({
|
|
102
|
+
shape,
|
|
103
|
+
fullWidth,
|
|
104
|
+
textPadding: icon ? undefined : size,
|
|
105
|
+
textSize: size,
|
|
106
|
+
iconSize: icon ? size : undefined,
|
|
107
|
+
disabled,
|
|
108
|
+
roundedSize: shape === 'semi-round' ? size : undefined,
|
|
109
|
+
filledColor: variant === 'filled' ? color : undefined,
|
|
110
|
+
filledColorHover: variant === 'filled' ? color : undefined,
|
|
111
|
+
outlineColor: variant === 'outline' ? color : undefined,
|
|
112
|
+
ghostColor: variant === 'ghost' ? color : undefined,
|
|
113
|
+
}),
|
|
114
|
+
className,
|
|
118
115
|
),
|
|
119
116
|
);
|
|
120
117
|
|
|
@@ -4,16 +4,76 @@ export declare const asText: (...items: unknown[]) => string;
|
|
|
4
4
|
declare class CommandPaletteManager {
|
|
5
5
|
#private;
|
|
6
6
|
selectedIndex: number;
|
|
7
|
-
items: (
|
|
7
|
+
items: ({
|
|
8
|
+
title: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
type?: string;
|
|
11
|
+
searchText?: string;
|
|
12
|
+
icon: import("../types.js").IconLike;
|
|
13
|
+
iconClass?: string;
|
|
14
|
+
color?: import("../types.js").Color;
|
|
15
|
+
onAction: import("../types.js").ActionItemHandler;
|
|
16
|
+
shortcuts?: MaybeArray<import("../actions/shortcut.js").Shortcut>;
|
|
17
|
+
shortcutOptions?: {
|
|
18
|
+
ignoreInputFields?: boolean;
|
|
19
|
+
preventDefault?: boolean;
|
|
20
|
+
};
|
|
21
|
+
isGlobal?: boolean;
|
|
22
|
+
} & import("../types.js").IfLike & {
|
|
8
23
|
id: string;
|
|
9
24
|
})[];
|
|
10
|
-
filteredItems: (
|
|
25
|
+
filteredItems: ({
|
|
26
|
+
title: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
type?: string;
|
|
29
|
+
searchText?: string;
|
|
30
|
+
icon: import("../types.js").IconLike;
|
|
31
|
+
iconClass?: string;
|
|
32
|
+
color?: import("../types.js").Color;
|
|
33
|
+
onAction: import("../types.js").ActionItemHandler;
|
|
34
|
+
shortcuts?: MaybeArray<import("../actions/shortcut.js").Shortcut>;
|
|
35
|
+
shortcutOptions?: {
|
|
36
|
+
ignoreInputFields?: boolean;
|
|
37
|
+
preventDefault?: boolean;
|
|
38
|
+
};
|
|
39
|
+
isGlobal?: boolean;
|
|
40
|
+
} & import("../types.js").IfLike & {
|
|
11
41
|
id: string;
|
|
12
42
|
})[];
|
|
13
|
-
recentItems: (
|
|
43
|
+
recentItems: ({
|
|
44
|
+
title: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
type?: string;
|
|
47
|
+
searchText?: string;
|
|
48
|
+
icon: import("../types.js").IconLike;
|
|
49
|
+
iconClass?: string;
|
|
50
|
+
color?: import("../types.js").Color;
|
|
51
|
+
onAction: import("../types.js").ActionItemHandler;
|
|
52
|
+
shortcuts?: MaybeArray<import("../actions/shortcut.js").Shortcut>;
|
|
53
|
+
shortcutOptions?: {
|
|
54
|
+
ignoreInputFields?: boolean;
|
|
55
|
+
preventDefault?: boolean;
|
|
56
|
+
};
|
|
57
|
+
isGlobal?: boolean;
|
|
58
|
+
} & import("../types.js").IfLike & {
|
|
14
59
|
id: string;
|
|
15
60
|
})[];
|
|
16
|
-
results: (
|
|
61
|
+
results: ({
|
|
62
|
+
title: string;
|
|
63
|
+
description?: string;
|
|
64
|
+
type?: string;
|
|
65
|
+
searchText?: string;
|
|
66
|
+
icon: import("../types.js").IconLike;
|
|
67
|
+
iconClass?: string;
|
|
68
|
+
color?: import("../types.js").Color;
|
|
69
|
+
onAction: import("../types.js").ActionItemHandler;
|
|
70
|
+
shortcuts?: MaybeArray<import("../actions/shortcut.js").Shortcut>;
|
|
71
|
+
shortcutOptions?: {
|
|
72
|
+
ignoreInputFields?: boolean;
|
|
73
|
+
preventDefault?: boolean;
|
|
74
|
+
};
|
|
75
|
+
isGlobal?: boolean;
|
|
76
|
+
} & import("../types.js").IfLike & {
|
|
17
77
|
id: string;
|
|
18
78
|
})[];
|
|
19
79
|
get isEnabled(): boolean;
|
|
@@ -17,6 +17,8 @@ const defaultTranslations = {
|
|
|
17
17
|
hide_password: 'Hide password',
|
|
18
18
|
// theme switcher
|
|
19
19
|
dark_theme: 'Toggle dark theme',
|
|
20
|
+
// context menu
|
|
21
|
+
open_menu: 'Open menu',
|
|
20
22
|
// command palette
|
|
21
23
|
command_palette_prompt_default: 'Quickly find pages, actions, or commands',
|
|
22
24
|
command_palette_to_select: 'to select',
|
package/dist/theme/default.css
CHANGED
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
--immich-ui-primary-900: oklch(0.211 0.068 273.01);
|
|
120
120
|
--immich-ui-primary-950: oklch(0.15 0.05 273.01);
|
|
121
121
|
|
|
122
|
-
--immich-ui-success-50: oklch(0.
|
|
122
|
+
--immich-ui-success-50: oklch(0.983 0.0115 162.06);
|
|
123
123
|
--immich-ui-success-100: oklch(0.937 0.109 148.66);
|
|
124
124
|
--immich-ui-success-200: oklch(0.863 0.249 147.5);
|
|
125
125
|
--immich-ui-success-300: oklch(0.813 0.234 147.54);
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
--immich-ui-success-900: oklch(0.252 0.073 147.47);
|
|
132
132
|
--immich-ui-success-950: oklch(0.194 0.056 147.87);
|
|
133
133
|
|
|
134
|
-
--immich-ui-danger-50: oklch(0.
|
|
134
|
+
--immich-ui-danger-50: oklch(0.9747 0.0109 24.32);
|
|
135
135
|
--immich-ui-danger-100: oklch(0.926 0.034 17.84);
|
|
136
136
|
--immich-ui-danger-200: oklch(0.853 0.074 19.77);
|
|
137
137
|
--immich-ui-danger-300: oklch(0.774 0.125 21.53);
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
--immich-ui-danger-900: oklch(0.245 0.094 29.51);
|
|
144
144
|
--immich-ui-danger-950: oklch(0.186 0.07 29.56);
|
|
145
145
|
|
|
146
|
-
--immich-ui-warning: oklch(0.
|
|
146
|
+
--immich-ui-warning: oklch(0.9887 0.0126 86.83);
|
|
147
147
|
--immich-ui-warning-50: oklch(0.983 0.01 58.27);
|
|
148
148
|
--immich-ui-warning-100: oklch(0.959 0.027 63.96);
|
|
149
149
|
--immich-ui-warning-200: oklch(0.925 0.051 64.24);
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
--immich-ui-warning-900: oklch(0.27 0.057 76.33);
|
|
157
157
|
--immich-ui-warning-950: oklch(0.209 0.044 77.51);
|
|
158
158
|
|
|
159
|
-
--immich-ui-info-50: oklch(0.
|
|
159
|
+
--immich-ui-info-50: oklch(0.9801 0.0096 252.81);
|
|
160
160
|
--immich-ui-info-100: oklch(0.922 0.036 268.3);
|
|
161
161
|
--immich-ui-info-200: oklch(0.845 0.073 265.19);
|
|
162
162
|
--immich-ui-info-300: oklch(0.769 0.114 261.53);
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import type { Shortcut } from './actions/shortcut.js';
|
|
1
2
|
import type { Translations } from './services/translation.svelte.js';
|
|
2
3
|
import type { DateTime } from 'luxon';
|
|
3
4
|
import type { Component, Snippet } from 'svelte';
|
|
4
5
|
import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes, HTMLInputAttributes, HTMLLabelAttributes, HTMLTextareaAttributes } from 'svelte/elements';
|
|
5
|
-
import type { Shortcut } from './actions/shortcut.js';
|
|
6
6
|
export type Color = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info';
|
|
7
7
|
export type TextColor = Color | 'muted';
|
|
8
8
|
export type TextVariant = 'italic';
|
|
@@ -71,9 +71,9 @@ export type CloseButtonProps = {
|
|
|
71
71
|
export type ContextMenuButtonProps = ButtonBase & {
|
|
72
72
|
icon?: IconLike;
|
|
73
73
|
position?: ContextMenuPosition;
|
|
74
|
-
'aria-label': string;
|
|
75
74
|
items: MenuItems;
|
|
76
75
|
bottomItems?: Array<ActionItem | undefined>;
|
|
76
|
+
translations?: TranslationProps<'open_menu'>;
|
|
77
77
|
} & Omit<HTMLButtonAttributes, 'color' | 'size'>;
|
|
78
78
|
export type IconButtonProps = ButtonBase & {
|
|
79
79
|
icon: IconLike;
|
|
@@ -243,8 +243,8 @@ export type DatePickerProps = {
|
|
|
243
243
|
export type IfLike = {
|
|
244
244
|
$if?: () => boolean;
|
|
245
245
|
};
|
|
246
|
-
export type ActionItemHandler<T =
|
|
247
|
-
export type ActionItem
|
|
246
|
+
export type ActionItemHandler<T extends ActionItem = ActionItem> = (item: T) => void | Promise<void>;
|
|
247
|
+
export type ActionItem = {
|
|
248
248
|
title: string;
|
|
249
249
|
description?: string;
|
|
250
250
|
type?: string;
|
|
@@ -252,17 +252,14 @@ export type ActionItem<T = never> = Omit<{
|
|
|
252
252
|
icon: IconLike;
|
|
253
253
|
iconClass?: string;
|
|
254
254
|
color?: Color;
|
|
255
|
-
onAction: ActionItemHandler
|
|
256
|
-
data: T;
|
|
255
|
+
onAction: ActionItemHandler;
|
|
257
256
|
shortcuts?: MaybeArray<Shortcut>;
|
|
258
257
|
shortcutOptions?: {
|
|
259
258
|
ignoreInputFields?: boolean;
|
|
260
259
|
preventDefault?: boolean;
|
|
261
260
|
};
|
|
262
261
|
isGlobal?: boolean;
|
|
263
|
-
} & IfLike
|
|
264
|
-
T
|
|
265
|
-
] extends [never] ? 'data' : ''>;
|
|
262
|
+
} & IfLike;
|
|
266
263
|
export type BreadcrumbsProps = {
|
|
267
264
|
separator?: IconLike | {
|
|
268
265
|
text: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MenuItemType, type ActionItem } from '../types.js';
|
|
1
2
|
import type { DateTime } from 'luxon';
|
|
2
3
|
export declare const resolveUrl: (url: string, currentHostname?: string) => string;
|
|
3
4
|
export declare const isExternalLink: (href: string) => boolean;
|
|
@@ -14,6 +15,7 @@ export type ArticleMetadata = {
|
|
|
14
15
|
section?: string;
|
|
15
16
|
tags?: string[];
|
|
16
17
|
};
|
|
18
|
+
export declare const isMenuItemType: (item: ActionItem | MenuItemType) => item is MenuItemType;
|
|
17
19
|
export declare const resolveMetadata: (site: Metadata, page?: Metadata, article?: ArticleMetadata) => {
|
|
18
20
|
type: string;
|
|
19
21
|
siteName: string;
|
package/dist/utilities/common.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { env } from '$env/dynamic/public';
|
|
2
|
+
import { MenuItemType } from '../types.js';
|
|
2
3
|
const getImmichApp = (host) => {
|
|
3
4
|
if (!host || !host.endsWith('immich.app')) {
|
|
4
5
|
return false;
|
|
@@ -25,6 +26,9 @@ export const resolveUrl = (url, currentHostname) => {
|
|
|
25
26
|
export const isExternalLink = (href) => {
|
|
26
27
|
return !(href.startsWith('/') || href.startsWith('#'));
|
|
27
28
|
};
|
|
29
|
+
export const isMenuItemType = (item) => {
|
|
30
|
+
return item === MenuItemType.Divider;
|
|
31
|
+
};
|
|
28
32
|
export const resolveMetadata = (site, page, article) => {
|
|
29
33
|
const title = page ? `${page.title} | ${site.title}` : site.title;
|
|
30
34
|
const description = page?.description ?? site.description;
|