diff options
| author | Fuwn <[email protected]> | 2025-05-14 01:32:56 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2025-05-14 01:32:56 -0700 |
| commit | f880840f73b69dc07d08f0a246e5bd887cc46a12 (patch) | |
| tree | 8787d2196b2ca40086f4323949af667bcd806b2b /src/lib | |
| parent | feat(CommandPalette): Add backdrop (diff) | |
| download | due.moe-f880840f73b69dc07d08f0a246e5bd887cc46a12.tar.xz due.moe-f880840f73b69dc07d08f0a246e5bd887cc46a12.zip | |
feat(CommandPalette): Global toggle fading
Diffstat (limited to 'src/lib')
| -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 { |