diff --git a/web/src/lib/components/layout/CommandPalette.svelte b/web/src/lib/components/layout/CommandPalette.svelte new file mode 100644 index 0000000..e078cbb --- /dev/null +++ b/web/src/lib/components/layout/CommandPalette.svelte @@ -0,0 +1,200 @@ + + + + { + if (!o) closePalette(); + }} +> + + + + + + + + + No matches. + + + + + Go to + + + {#each SECTIONS as s (s.label)} + + + {s.label} + + {/each} + + + + {#if (heapsQuery.data ?? []).length > 0} + + + Heaps + + + {#each heapsQuery.data ?? [] as heap (heap.UID)} + + + {heap.Title} + {#if heap.PhotoCount} + + {heap.PhotoCount} + + {/if} + + {/each} + + + {/if} + + {#if folderEntries.length > 0} + + + Folders + + + {#each folderEntries as folder (folder.Path)} + + + {folder.Path} + + {/each} + + + {/if} + + + + Actions + + + {#each ACTIONS as a (a.label)} + + + {a.label} + + {/each} + + + + + + + + diff --git a/web/src/lib/stores/view.svelte.ts b/web/src/lib/stores/view.svelte.ts index 28f919a..24a553a 100644 --- a/web/src/lib/stores/view.svelte.ts +++ b/web/src/lib/stores/view.svelte.ts @@ -83,6 +83,8 @@ export const view = $state<{ previewOpen: boolean; /** Ephemeral: true while the keyboard-shortcuts overlay is open. */ shortcutsOpen: boolean; + /** Ephemeral: true while the ⌘K command palette is open. */ + paletteOpen: boolean; metadataSections: Record; }>({ rightSidebarCollapsed: initial.rightSidebarCollapsed ?? false, @@ -110,6 +112,7 @@ export const view = $state<{ tagsBrowserCollapsed: initial.tagsBrowserCollapsed ?? false, previewOpen: false, shortcutsOpen: false, + paletteOpen: false, metadataSections: initial.metadataSections && typeof initial.metadataSections === 'object' ? { ...initial.metadataSections } @@ -175,6 +178,14 @@ export function closeShortcuts(): void { view.shortcutsOpen = false; } +export function togglePalette(): void { + view.paletteOpen = !view.paletteOpen; +} + +export function closePalette(): void { + view.paletteOpen = false; +} + export function setThumbnailSize(size: ThumbnailSize): void { view.thumbnailSize = size; persist(); diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index b552a0f..aba87cc 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -21,6 +21,8 @@ import PreviewModal from '$lib/components/preview/PreviewModal.svelte'; import MoveToFolderDialog from '$lib/components/layout/MoveToFolderDialog.svelte'; import ShortcutsDialog from '$lib/components/layout/ShortcutsDialog.svelte'; + import CommandPalette from '$lib/components/layout/CommandPalette.svelte'; + import { togglePalette } from '$lib/stores/view.svelte'; let { children } = $props(); @@ -59,8 +61,18 @@ else stopIndexerWatch(); }); + // ⌘K lives at the window level (not gridKeyNav) so the palette opens + // from any route and even while a form field holds focus. + function onGlobalKey(e: KeyboardEvent) { + if ((e.metaKey || e.ctrlKey) && (e.key === 'k' || e.key === 'K')) { + e.preventDefault(); + togglePalette(); + } + } + + Mulimage @@ -125,6 +137,8 @@ + + {:else} {@render children?.()} {/if}