diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/CommandPalette/CommandPalette.svelte | 96 |
1 files changed, 84 insertions, 12 deletions
diff --git a/src/lib/CommandPalette/CommandPalette.svelte b/src/lib/CommandPalette/CommandPalette.svelte index 02616ba9..56542270 100644 --- a/src/lib/CommandPalette/CommandPalette.svelte +++ b/src/lib/CommandPalette/CommandPalette.svelte @@ -15,6 +15,8 @@ let filtered: CommandPaletteItem[] = []; let selectedIndex = -1; let inputRef: HTMLInputElement; + let isVisible = false; + let timeoutID: ReturnType<typeof setTimeout> | null = null; $: filtered = items .filter((item) => item.name.toLowerCase().includes(search.toLowerCase())) @@ -23,6 +25,23 @@ $: if (selectedIndex >= filtered.length) selectedIndex = filtered.length - 1; $: if (selectedIndex < 0 && filtered.length > 0) selectedIndex = 0; + $: if (open && !isVisible) { + isVisible = true; + + if (timeoutID !== null) { + clearTimeout(timeoutID); + + timeoutID = null; + } + } else if (!open && isVisible) { + if (timeoutID === null) { + timeoutID = setTimeout(() => { + isVisible = false; + timeoutID = null; + }, 200); + } + } + const executeItem = (item: CommandPaletteItem) => { if (item.onClick) item.onClick(); if (!item.preventDefault) window.location.href = item.url; @@ -53,17 +72,18 @@ onMount(() => { window.addEventListener('keydown', handleGlobalKey); - return () => window.removeEventListener('keydown', handleGlobalKey); + return () => { + window.removeEventListener('keydown', handleGlobalKey); + + if (timeoutID !== null) clearTimeout(timeoutID); + }; }); const handleClickOutside = (event: MouseEvent) => { const target = event.target as HTMLElement; - if (target.classList.contains('command-palette-overlay')) { - open = false; - } else if (!target.closest('.dropdown')) { + if (target.classList.contains('command-palette-overlay') || !target.closest('.dropdown')) open = false; - } }; const handleGlobalKey = (e: KeyboardEvent) => { @@ -79,14 +99,13 @@ <svelte:window on:click={handleClickOutside} /> -{#if open} +{#if isVisible} <div - class="command-palette-overlay" + class="command-palette-overlay {open ? 'fade-in' : 'fade-out'}" on:click={() => (open = false)} - on:keydown={(e) => e.key === 'Escape' && (open = false)} /> - <div class="dropdown"> + <div class="dropdown {open ? 'fade-in' : 'fade-out'}"> <div class="dropdown-content card card-small"> <input bind:this={inputRef} @@ -140,11 +159,19 @@ background-color: rgba(0, 0, 0, 0.6); z-index: 100; backdrop-filter: blur(3px); - animation: fadeIn 0.15s ease-in-out; cursor: pointer; + opacity: 0; } - @keyframes fadeIn { + .command-palette-overlay.fade-in { + animation: overlayFadeIn 0.15s ease-in-out forwards; + } + + .command-palette-overlay.fade-out { + animation: overlayFadeOut 0.2s ease-in-out forwards; + } + + @keyframes overlayFadeIn { from { opacity: 0; backdrop-filter: blur(0px); @@ -156,14 +183,59 @@ } } + @keyframes overlayFadeOut { + from { + opacity: 1; + backdrop-filter: blur(3px); + } + + to { + opacity: 0; + backdrop-filter: blur(0px); + } + } + .dropdown { position: fixed; top: 15%; left: 50%; - transform: translateX(-50%); z-index: 101; width: min(600px, 90%); font-size: 1.05em; + opacity: 0; + transform: translateX(-50%) translateY(-10px); + } + + .dropdown.fade-in { + animation: dropdownFadeIn 0.2s ease-in-out forwards; + } + + .dropdown.fade-out { + animation: dropdownFadeOut 0.2s ease-in-out forwards; + } + + @keyframes dropdownFadeIn { + from { + opacity: 0; + transform: translateX(-50%) translateY(-10px); + } + + to { + opacity: 1; + transform: translateX(-50%) translateY(0); + } + } + + @keyframes dropdownFadeOut { + from { + opacity: 1; + transform: translateX(-50%) translateY(0); + } + + to { + opacity: 0; + transform: translateX(-50%) translateY(-10px); + } } .command-input { |