@immich/ui 0.64.1 → 0.65.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/BasicModal/BasicModal.svelte +5 -1
- package/dist/components/BasicModal/BasicModal.svelte.d.ts +2 -0
- package/dist/components/CommandPalette/CommandPaletteDefaultProvider.svelte +1 -1
- package/dist/components/CommandPalette/CommandPaletteDefaultProvider.svelte.d.ts +1 -1
- package/dist/components/CommandPalette/CommandPaletteItem.svelte +1 -2
- package/dist/internal/CommandPaletteModal.svelte +27 -18
- package/dist/services/command-palette-manager.svelte.d.ts +16 -5
- package/dist/services/command-palette-manager.svelte.js +53 -10
- package/dist/site/constants.d.ts +0 -1
- package/dist/site/constants.js +0 -1
- package/package.json +1 -1
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
icon?: string | boolean;
|
|
13
13
|
closeText?: string;
|
|
14
14
|
closeColor?: Color;
|
|
15
|
+
closeOnBackdropClick?: boolean;
|
|
16
|
+
closeOnEsc?: boolean;
|
|
15
17
|
size?: ModalSize;
|
|
16
18
|
onClose: () => void;
|
|
17
19
|
children: Snippet;
|
|
@@ -22,13 +24,15 @@
|
|
|
22
24
|
icon,
|
|
23
25
|
closeText = t('close'),
|
|
24
26
|
closeColor = 'secondary',
|
|
27
|
+
closeOnBackdropClick = true,
|
|
28
|
+
closeOnEsc = true,
|
|
25
29
|
size = 'small',
|
|
26
30
|
onClose = () => {},
|
|
27
31
|
children,
|
|
28
32
|
}: Props = $props();
|
|
29
33
|
</script>
|
|
30
34
|
|
|
31
|
-
<Modal {title} {onClose} {size} {icon}>
|
|
35
|
+
<Modal {title} {onClose} {size} {icon} {closeOnBackdropClick} {closeOnEsc}>
|
|
32
36
|
<ModalBody {children} />
|
|
33
37
|
<ModalFooter>
|
|
34
38
|
<Button shape="round" color={closeColor} fullWidth onclick={onClose}>
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import Kbd from '../Kbd/Kbd.svelte';
|
|
7
7
|
import Text from '../Text/Text.svelte';
|
|
8
8
|
import type { ActionItem } from '../../types.js';
|
|
9
|
-
import { cleanClass } from '../../utilities/internal.js';
|
|
10
9
|
|
|
11
10
|
type Props = {
|
|
12
11
|
item: ActionItem;
|
|
@@ -63,7 +62,7 @@
|
|
|
63
62
|
<div class="flex shrink-0 flex-col justify-end gap-1">
|
|
64
63
|
{#each renderedShortcuts as shortcut (shortcut.join('-'))}
|
|
65
64
|
<div class="flex justify-end">
|
|
66
|
-
<Kbd size="tiny"
|
|
65
|
+
<Kbd size="tiny">{shortcut.join(' ')}</Kbd>
|
|
67
66
|
</div>
|
|
68
67
|
{/each}
|
|
69
68
|
</div>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { shortcuts } from '../actions/shortcut.js';
|
|
3
3
|
import CloseButton from '../components/CloseButton/CloseButton.svelte';
|
|
4
4
|
import CommandPaletteItem from '../components/CommandPalette/CommandPaletteItem.svelte';
|
|
5
|
+
import Heading from '../components/Heading/Heading.svelte';
|
|
5
6
|
import Icon from '../components/Icon/Icon.svelte';
|
|
6
7
|
import Input from '../components/Input/Input.svelte';
|
|
7
8
|
import Modal from '../components/Modal/Modal.svelte';
|
|
@@ -26,6 +27,10 @@
|
|
|
26
27
|
|
|
27
28
|
const { onClose, translations, initialQuery = '' }: Props = $props();
|
|
28
29
|
|
|
30
|
+
let query = $state(initialQuery);
|
|
31
|
+
|
|
32
|
+
$effect(() => commandPaletteManager.queryUpdate(query));
|
|
33
|
+
|
|
29
34
|
const handleUp = (event: KeyboardEvent) => handleNavigate(event, 'up');
|
|
30
35
|
const handleDown = (event: KeyboardEvent) => handleNavigate(event, 'down');
|
|
31
36
|
const handleSelect = (event: KeyboardEvent) => handleNavigate(event, 'select');
|
|
@@ -34,31 +39,26 @@
|
|
|
34
39
|
|
|
35
40
|
switch (direction) {
|
|
36
41
|
case 'up': {
|
|
37
|
-
|
|
42
|
+
commandPaletteManager.navigateUp();
|
|
38
43
|
break;
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
case 'down': {
|
|
42
|
-
if (!query && commandPaletteManager.
|
|
47
|
+
if (!query && commandPaletteManager.results.length === 0) {
|
|
43
48
|
commandPaletteManager.loadAllItems();
|
|
44
49
|
break;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
|
|
52
|
+
commandPaletteManager.navigateDown();
|
|
48
53
|
break;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
case 'select': {
|
|
52
|
-
onClose(commandPaletteManager.
|
|
57
|
+
onClose(commandPaletteManager.selectedItem);
|
|
53
58
|
break;
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
};
|
|
57
|
-
|
|
58
|
-
let selectedIndex = $state(0);
|
|
59
|
-
let query = $state(initialQuery);
|
|
60
|
-
|
|
61
|
-
$effect(() => commandPaletteManager.queryUpdate(query));
|
|
62
62
|
</script>
|
|
63
63
|
|
|
64
64
|
<svelte:window
|
|
@@ -90,25 +90,34 @@
|
|
|
90
90
|
<ModalBody>
|
|
91
91
|
<Stack gap={2}>
|
|
92
92
|
{#if query}
|
|
93
|
-
{#if commandPaletteManager.
|
|
93
|
+
{#if commandPaletteManager.results.length === 0}
|
|
94
94
|
<Text>{t('search_no_results', translations)}</Text>
|
|
95
95
|
{/if}
|
|
96
96
|
{:else}
|
|
97
97
|
<Text>{t('command_palette_prompt_default', translations)}</Text>
|
|
98
98
|
{/if}
|
|
99
99
|
|
|
100
|
-
{#
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
{#each commandPaletteManager.results as result, groupIndex (result.provider.name ?? groupIndex)}
|
|
101
|
+
{#if result.provider.name}
|
|
102
|
+
<Heading size="tiny" class="pt-2">{result.provider.name}</Heading>
|
|
103
|
+
{/if}
|
|
104
|
+
{#if commandPaletteManager.results.length > 0}
|
|
105
|
+
<div class="flex flex-col">
|
|
106
|
+
{#each result.items as item (item.id)}
|
|
107
|
+
<CommandPaletteItem
|
|
108
|
+
{item}
|
|
109
|
+
selected={commandPaletteManager.isSelected(item)}
|
|
110
|
+
onSelect={() => onClose(item)}
|
|
111
|
+
/>
|
|
112
|
+
{/each}
|
|
113
|
+
</div>
|
|
114
|
+
{/if}
|
|
115
|
+
{/each}
|
|
107
116
|
</Stack>
|
|
108
117
|
</ModalBody>
|
|
109
118
|
<ModalFooter>
|
|
110
119
|
<div class="flex w-full justify-around">
|
|
111
|
-
{#if !query && commandPaletteManager.
|
|
120
|
+
{#if !query && commandPaletteManager.results.length === 0}
|
|
112
121
|
<div class="flex place-items-center gap-1">
|
|
113
122
|
<span class="flex gap-1 rounded bg-gray-300 p-1 dark:bg-gray-500">
|
|
114
123
|
<Icon icon={mdiArrowDown} size="1rem" />
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import type { ActionItem, MaybePromise, TranslationProps } from '../types.js';
|
|
2
2
|
export type CommandPaletteTranslations = TranslationProps<'search_placeholder' | 'search_no_results' | 'command_palette_prompt_default' | 'command_palette_to_select' | 'command_palette_to_close' | 'command_palette_to_navigate' | 'command_palette_to_show_all'>;
|
|
3
3
|
export type ActionProvider = {
|
|
4
|
-
name
|
|
4
|
+
name?: string;
|
|
5
5
|
onSearch: (query?: string) => MaybePromise<ActionItem[]>;
|
|
6
6
|
};
|
|
7
7
|
export declare const defaultProvider: ({ name, actions }: {
|
|
8
|
-
name
|
|
8
|
+
name?: string;
|
|
9
9
|
actions: ActionItem[];
|
|
10
10
|
}) => {
|
|
11
|
-
name: string;
|
|
11
|
+
name: string | undefined;
|
|
12
12
|
onSearch: (query?: string) => ActionItem[];
|
|
13
13
|
};
|
|
14
14
|
declare class CommandPaletteManager {
|
|
15
15
|
#private;
|
|
16
16
|
get isEnabled(): boolean;
|
|
17
|
-
get
|
|
17
|
+
get results(): {
|
|
18
|
+
provider: ActionProvider;
|
|
19
|
+
items: Array<ActionItem & {
|
|
20
|
+
id: string;
|
|
21
|
+
}>;
|
|
22
|
+
}[];
|
|
23
|
+
get selectedItem(): {
|
|
18
24
|
title: string;
|
|
19
25
|
description?: string;
|
|
20
26
|
type?: string;
|
|
@@ -30,11 +36,16 @@ declare class CommandPaletteManager {
|
|
|
30
36
|
};
|
|
31
37
|
} & import("../types.js").IfLike & {
|
|
32
38
|
id: string;
|
|
33
|
-
}
|
|
39
|
+
};
|
|
40
|
+
isSelected(item: {
|
|
41
|
+
id: string;
|
|
42
|
+
}): boolean;
|
|
34
43
|
enable(): void;
|
|
35
44
|
setTranslations(translations?: CommandPaletteTranslations): void;
|
|
36
45
|
queryUpdate(query: string): void;
|
|
37
46
|
open(initialQuery?: string): void;
|
|
47
|
+
navigateUp(): void;
|
|
48
|
+
navigateDown(): void;
|
|
38
49
|
loadAllItems(): void;
|
|
39
50
|
addProvider(provider: ActionProvider): () => void;
|
|
40
51
|
}
|
|
@@ -14,12 +14,21 @@ class CommandPaletteManager {
|
|
|
14
14
|
#providers = [];
|
|
15
15
|
#isEnabled = false;
|
|
16
16
|
#isOpen = false;
|
|
17
|
-
#
|
|
17
|
+
#results = $state([]);
|
|
18
|
+
#selectedGroupIndex = $state(0);
|
|
19
|
+
#selectedItemIndex = $state(0);
|
|
18
20
|
get isEnabled() {
|
|
19
21
|
return this.#isEnabled;
|
|
20
22
|
}
|
|
21
|
-
get
|
|
22
|
-
return this.#
|
|
23
|
+
get results() {
|
|
24
|
+
return this.#results;
|
|
25
|
+
}
|
|
26
|
+
get selectedItem() {
|
|
27
|
+
const group = this.#results[this.#selectedGroupIndex];
|
|
28
|
+
return group?.items[this.#selectedItemIndex];
|
|
29
|
+
}
|
|
30
|
+
isSelected(item) {
|
|
31
|
+
return this.selectedItem?.id === item.id;
|
|
23
32
|
}
|
|
24
33
|
enable() {
|
|
25
34
|
if (this.#isEnabled) {
|
|
@@ -39,15 +48,20 @@ class CommandPaletteManager {
|
|
|
39
48
|
this.#translations = translations;
|
|
40
49
|
}
|
|
41
50
|
async #onSearch(query) {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
const newResults = await Promise.all(this.#providers.map(async (provider) => {
|
|
52
|
+
const items = await provider.onSearch(query);
|
|
53
|
+
return {
|
|
54
|
+
provider,
|
|
55
|
+
items: items.filter((item) => isEnabled(item)).map((item) => ({ ...item, id: generateId() })),
|
|
56
|
+
};
|
|
57
|
+
}));
|
|
58
|
+
this.#selectedGroupIndex = 0;
|
|
59
|
+
this.#selectedItemIndex = 0;
|
|
60
|
+
this.#results = newResults.filter((result) => result.items.length > 0);
|
|
47
61
|
}
|
|
48
62
|
queryUpdate(query) {
|
|
49
63
|
if (!query) {
|
|
50
|
-
this.#
|
|
64
|
+
this.#results = [];
|
|
51
65
|
return;
|
|
52
66
|
}
|
|
53
67
|
void this.#onSearch(query);
|
|
@@ -78,7 +92,7 @@ class CommandPaletteManager {
|
|
|
78
92
|
async #onClose(action) {
|
|
79
93
|
await action?.onAction(action);
|
|
80
94
|
this.#isOpen = false;
|
|
81
|
-
this.#
|
|
95
|
+
this.#results = [];
|
|
82
96
|
}
|
|
83
97
|
open(initialQuery) {
|
|
84
98
|
if (this.#isOpen) {
|
|
@@ -91,6 +105,35 @@ class CommandPaletteManager {
|
|
|
91
105
|
this.#isOpen = true;
|
|
92
106
|
void onClose.then((action) => this.#onClose(action));
|
|
93
107
|
}
|
|
108
|
+
navigateUp() {
|
|
109
|
+
const groups = this.#results;
|
|
110
|
+
if (groups.length === 0) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
this.#selectedItemIndex--;
|
|
114
|
+
if (this.#selectedItemIndex < 0) {
|
|
115
|
+
this.#selectedGroupIndex--; // previous group
|
|
116
|
+
if (this.#selectedGroupIndex < 0) {
|
|
117
|
+
this.#selectedGroupIndex = groups.length - 1; // first group
|
|
118
|
+
}
|
|
119
|
+
this.#selectedItemIndex = groups[this.#selectedGroupIndex].items.length - 1;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
navigateDown() {
|
|
123
|
+
const groups = this.#results;
|
|
124
|
+
if (groups.length === 0) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const group = groups[this.#selectedGroupIndex];
|
|
128
|
+
this.#selectedItemIndex++;
|
|
129
|
+
if (this.#selectedItemIndex >= group.items.length) {
|
|
130
|
+
this.#selectedItemIndex = 0;
|
|
131
|
+
this.#selectedGroupIndex++; // next group
|
|
132
|
+
if (this.#selectedGroupIndex >= groups.length) {
|
|
133
|
+
this.#selectedGroupIndex = 0; // first group
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
94
137
|
loadAllItems() {
|
|
95
138
|
void this.#onSearch();
|
|
96
139
|
}
|
package/dist/site/constants.d.ts
CHANGED
package/dist/site/constants.js
CHANGED