aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-05-14 01:32:56 -0700
committerFuwn <[email protected]>2025-05-14 01:32:56 -0700
commitf880840f73b69dc07d08f0a246e5bd887cc46a12 (patch)
tree8787d2196b2ca40086f4323949af667bcd806b2b /src/lib
parentfeat(CommandPalette): Add backdrop (diff)
downloaddue.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.svelte96
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 {