|
1 | 1 | <script lang="ts"> |
2 | 2 | import { shortcuts } from '$lib/actions/shortcut.js'; |
3 | | - import CloseButton from '$lib/components/CloseButton/CloseButton.svelte'; |
4 | | - import CommandPaletteItem from '$lib/components/CommandPalette/CommandPaletteItem.svelte'; |
5 | | - import Icon from '$lib/components/Icon/Icon.svelte'; |
6 | | - import Input from '$lib/components/Input/Input.svelte'; |
7 | | - import Modal from '$lib/components/Modal/Modal.svelte'; |
8 | | - import ModalBody from '$lib/components/Modal/ModalBody.svelte'; |
9 | | - import ModalFooter from '$lib/components/Modal/ModalFooter.svelte'; |
10 | | - import ModalHeader from '$lib/components/Modal/ModalHeader.svelte'; |
11 | | - import Stack from '$lib/components/Stack/Stack.svelte'; |
12 | | - import Text from '$lib/components/Text/Text.svelte'; |
13 | 3 | import { commandPaletteManager } from '$lib/services/command-palette-manager.svelte'; |
14 | | - import { t } from '$lib/services/translation.svelte.js'; |
15 | | - import type { TranslationProps } from '$lib/types.js'; |
16 | | - import { mdiArrowDown, mdiArrowUp, mdiKeyboardEsc, mdiKeyboardReturn, mdiMagnify } from '@mdi/js'; |
17 | | -
|
18 | | - type Props = { |
19 | | - translations?: TranslationProps< |
20 | | - 'search_placeholder' | 'search_no_results' | 'search_recently_used' | 'command_palette_prompt_default' |
21 | | - >; |
22 | | - }; |
23 | | -
|
24 | | - let { translations }: Props = $props(); |
25 | | -
|
26 | | - let inputElement = $state<HTMLInputElement | null>(null); |
27 | 4 |
|
28 | 5 | const handleOpen = () => commandPaletteManager.open(); |
29 | | - const handleClose = () => commandPaletteManager.close(); |
30 | | - const handleUp = (event: KeyboardEvent) => handleNavigate(event, 'up'); |
31 | | - const handleDown = (event: KeyboardEvent) => handleNavigate(event, 'down'); |
32 | | - const handleSelect = (event: KeyboardEvent) => handleNavigate(event, 'select'); |
33 | | - const handleNavigate = async (event: KeyboardEvent, direction: 'up' | 'down' | 'select') => { |
34 | | - if (!commandPaletteManager.isOpen) { |
35 | | - return; |
36 | | - } |
37 | | -
|
38 | | - event.preventDefault(); |
39 | | -
|
40 | | - switch (direction) { |
41 | | - case 'up': { |
42 | | - commandPaletteManager.up(); |
43 | | - break; |
44 | | - } |
45 | | -
|
46 | | - case 'down': { |
47 | | - commandPaletteManager.down(); |
48 | | - break; |
49 | | - } |
50 | | -
|
51 | | - case 'select': { |
52 | | - await commandPaletteManager.select(); |
53 | | - break; |
54 | | - } |
55 | | - } |
56 | | - }; |
57 | 6 | </script> |
58 | 7 |
|
59 | 8 | <svelte:window |
60 | 9 | use:shortcuts={[ |
61 | 10 | { shortcut: { key: 'k', meta: true }, onShortcut: handleOpen }, |
62 | 11 | { shortcut: { key: 'k', ctrl: true }, onShortcut: handleOpen }, |
63 | 12 | { shortcut: { key: '/' }, preventDefault: true, onShortcut: handleOpen }, |
64 | | - { shortcut: { key: 'ArrowUp' }, preventDefault: false, ignoreInputFields: false, onShortcut: handleUp }, |
65 | | - { shortcut: { key: 'ArrowDown' }, preventDefault: false, ignoreInputFields: false, onShortcut: handleDown }, |
66 | | - { shortcut: { key: 'k', ctrl: true }, ignoreInputFields: false, onShortcut: handleUp }, |
67 | | - { shortcut: { key: 'k', meta: true }, ignoreInputFields: false, onShortcut: handleUp }, |
68 | | - { shortcut: { key: 'j', ctrl: true }, ignoreInputFields: false, onShortcut: handleDown }, |
69 | | - { shortcut: { key: 'j', meta: true }, ignoreInputFields: false, onShortcut: handleDown }, |
70 | | - { shortcut: { key: 'Enter' }, ignoreInputFields: false, onShortcut: handleSelect }, |
71 | | - { shortcut: { key: 'Escape' }, onShortcut: handleClose }, |
72 | 13 | ]} |
73 | 14 | /> |
74 | | - |
75 | | -{#if commandPaletteManager.isOpen} |
76 | | - <Modal size="large" onClose={handleClose} closeOnBackdropClick> |
77 | | - <ModalHeader> |
78 | | - <div class="flex place-items-center gap-1"> |
79 | | - <Input |
80 | | - bind:ref={inputElement} |
81 | | - bind:value={commandPaletteManager.query} |
82 | | - placeholder={t('search_placeholder', translations)} |
83 | | - leadingIcon={mdiMagnify} |
84 | | - tabindex={1} |
85 | | - /> |
86 | | - <div> |
87 | | - <CloseButton onclick={() => commandPaletteManager.close()} class="md:hidden" /> |
88 | | - </div> |
89 | | - </div> |
90 | | - </ModalHeader> |
91 | | - <ModalBody> |
92 | | - <Stack gap={2}> |
93 | | - {#if commandPaletteManager.query} |
94 | | - {#if commandPaletteManager.results.length === 0} |
95 | | - <Text>{t('search_no_results', translations)}</Text> |
96 | | - {/if} |
97 | | - {:else if commandPaletteManager.recentItems.length > 0} |
98 | | - <Text>{t('search_recently_used', translations)}</Text> |
99 | | - {:else} |
100 | | - <Text>{t('command_palette_prompt_default', translations)}</Text> |
101 | | - {/if} |
102 | | - |
103 | | - {#if commandPaletteManager.results.length > 0} |
104 | | - <div class="flex flex-col"> |
105 | | - {#each commandPaletteManager.results as item, i (i)} |
106 | | - <CommandPaletteItem |
107 | | - {item} |
108 | | - selected={commandPaletteManager.selectedIndex === i} |
109 | | - onRemove={commandPaletteManager.query ? undefined : () => commandPaletteManager.remove(i)} |
110 | | - onSelect={() => commandPaletteManager.select(i)} |
111 | | - /> |
112 | | - {/each} |
113 | | - </div> |
114 | | - {/if} |
115 | | - </Stack> |
116 | | - </ModalBody> |
117 | | - <ModalFooter> |
118 | | - <div class="flex w-full justify-around"> |
119 | | - <div class="flex gap-4"> |
120 | | - <div class="flex place-items-center gap-1"> |
121 | | - <span class="rounded bg-gray-300 p-1 dark:bg-gray-500"> |
122 | | - <Icon icon={mdiKeyboardReturn} size="1rem" /> |
123 | | - </span> |
124 | | - <Text size="small">to select</Text> |
125 | | - </div> |
126 | | - |
127 | | - <div class="flex place-items-center gap-1"> |
128 | | - <span class="flex gap-1 rounded bg-gray-300 p-1 dark:bg-gray-500"> |
129 | | - <Icon icon={mdiArrowUp} size="1rem" /> |
130 | | - <Icon icon={mdiArrowDown} size="1rem" /> |
131 | | - </span> |
132 | | - <Text size="small">to navigate</Text> |
133 | | - </div> |
134 | | - |
135 | | - <div class="flex place-items-center gap-1"> |
136 | | - <span class="rounded bg-gray-300 p-1 dark:bg-gray-500"> |
137 | | - <Icon icon={mdiKeyboardEsc} size="1rem" /> |
138 | | - </span> |
139 | | - <Text size="small">to close</Text> |
140 | | - </div> |
141 | | - </div> |
142 | | - </div> |
143 | | - </ModalFooter> |
144 | | - </Modal> |
145 | | -{/if} |
0 commit comments