Skip to content

Commit 4bdde44

Browse files
committed
Tighten Modal API and align dialog patterns
Add an optional onenter prop to Modal so the consolidated keyboard contract (Escape-closes, Enter-confirms) lives in one place. ConfirmDialog drops its own Enter window listener and forwards onenter to Modal. SaveDialog does the same and trades its open= true literal for an open prop forwarded by the parent, so its API matches ConfirmDialog and the Export modal. ConfirmDialog Cancel restyles to the borderless 'text-fg-dimmed hover:text-fg-secondary' pattern used by SaveDialog, Export, and the rest of the app's secondary buttons. LockIcon gains a strokeWidth prop matching SearchIcon's shape so the two share the same configuration surface.
1 parent 34e0d2a commit 4bdde44

6 files changed

Lines changed: 40 additions & 48 deletions

File tree

frontend/src/lib/components/blueprints/BlueprintsView.svelte

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,12 @@
137137
{/if}
138138
</div>
139139

140-
{#if showSaveDialog}
141-
<SaveDialog
142-
onclose={() => (showSaveDialog = false)}
143-
onsave={() => {
144-
showSaveDialog = false;
145-
loadBlueprints();
146-
}}
147-
/>
148-
{/if}
140+
<SaveDialog
141+
open={showSaveDialog}
142+
onclose={() => (showSaveDialog = false)}
143+
onsave={() => {
144+
showSaveDialog = false;
145+
loadBlueprints();
146+
}}
147+
/>
149148
</div>

frontend/src/lib/components/blueprints/SaveDialog.svelte

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,27 @@
1111
} from '$lib/stores/theme.svelte';
1212
import Modal from '$lib/components/shared/Modal.svelte';
1313
14-
let {onclose, onsave}: {onclose: () => void; onsave: () => void} = $props();
14+
let {
15+
open = true,
16+
onclose,
17+
onsave,
18+
}: {open?: boolean; onclose: () => void; onsave: () => void} = $props();
1519
let name = $state('');
1620
let isSaving = $state(false);
1721
let showOverrideConfirm = $state(false);
1822
let nameInput = $state<HTMLInputElement | null>(null);
1923
let attemptedSubmit = $state(false);
2024
2125
$effect(() => {
22-
if (!showOverrideConfirm) nameInput?.focus();
26+
if (open && !showOverrideConfirm) nameInput?.focus();
2327
});
2428
2529
let nameError = $derived(
2630
attemptedSubmit && !name.trim() ? 'Theme name is required' : ''
2731
);
2832
29-
// Enter on the form commits; Esc/backdrop dismissal goes through Modal's
30-
// onclose, which we override below to step back from the override-confirm
31-
// sub-panel before fully closing.
32-
$effect(() => {
33-
const onKey = (e: KeyboardEvent) => {
34-
if (e.key === 'Enter' && !showOverrideConfirm) {
35-
e.preventDefault();
36-
handleSave();
37-
}
38-
};
39-
window.addEventListener('keydown', onKey);
40-
return () => window.removeEventListener('keydown', onKey);
41-
});
42-
33+
// Esc/backdrop dismissal goes through Modal's onclose, which we override
34+
// to step back from the override-confirm sub-panel before fully closing.
4335
function handleClose() {
4436
if (showOverrideConfirm) {
4537
showOverrideConfirm = false;
@@ -48,6 +40,10 @@
4840
}
4941
}
5042
43+
function handleEnter() {
44+
if (!showOverrideConfirm) handleSave();
45+
}
46+
5147
async function handleSave() {
5248
attemptedSubmit = true;
5349
if (!name.trim()) {
@@ -98,7 +94,7 @@
9894
}
9995
</script>
10096

101-
<Modal open={true} onclose={handleClose} z="z-40">
97+
<Modal {open} onclose={handleClose} onenter={handleEnter} z="z-40">
10298
{#if showOverrideConfirm}
10399
<h3 class="text-fg-primary mb-3 text-[12px] font-medium">
104100
Override existing theme?

frontend/src/lib/components/layout/ActionBar.svelte

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -578,13 +578,11 @@
578578
</div>
579579
</Modal>
580580

581-
<!-- Save Blueprint Dialog -->
582-
{#if showSaveDialog}
583-
<SaveDialog
584-
onclose={() => (showSaveDialog = false)}
585-
onsave={() => (showSaveDialog = false)}
586-
/>
587-
{/if}
581+
<SaveDialog
582+
open={showSaveDialog}
583+
onclose={() => (showSaveDialog = false)}
584+
onsave={() => (showSaveDialog = false)}
585+
/>
588586

589587
{#if confirmKind}
590588
{@const cfg = CONFIRM_CONFIG[confirmKind]}

frontend/src/lib/components/shared/ConfirmDialog.svelte

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,11 @@
2424
let confirmEl = $state<HTMLButtonElement | null>(null);
2525
2626
$effect(() => {
27-
if (!open) return;
28-
confirmEl?.focus();
29-
const onKey = (e: KeyboardEvent) => {
30-
if (e.key === 'Enter') {
31-
e.preventDefault();
32-
onconfirm();
33-
}
34-
};
35-
window.addEventListener('keydown', onKey);
36-
return () => window.removeEventListener('keydown', onKey);
27+
if (open) confirmEl?.focus();
3728
});
3829
</script>
3930

40-
<Modal {open} onclose={oncancel}>
31+
<Modal {open} onclose={oncancel} onenter={onconfirm}>
4132
<h3 class="text-fg-primary mb-1.5 text-[12px] font-medium">
4233
{title}
4334
</h3>
@@ -49,7 +40,7 @@
4940
<div class="flex justify-end gap-2">
5041
<button
5142
type="button"
52-
class="text-fg-secondary border-border hover:bg-bg-hover border px-3 py-1 text-[11px] transition-colors"
43+
class="text-fg-dimmed hover:text-fg-secondary px-3 py-1 text-[11px] transition-colors"
5344
onclick={oncancel}>{cancelLabel}</button
5445
>
5546
<button

frontend/src/lib/components/shared/LockIcon.svelte

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
<script lang="ts">
2-
let {locked, size = 'w-3.5 h-3.5'}: {locked: boolean; size?: string} =
3-
$props();
2+
let {
3+
locked,
4+
size = 'w-3.5 h-3.5',
5+
strokeWidth = 2,
6+
}: {locked: boolean; size?: string; strokeWidth?: number} = $props();
47
</script>
58

69
<svg
710
class={size}
811
viewBox="0 0 24 24"
912
fill="none"
1013
stroke="currentColor"
11-
stroke-width="2"
14+
stroke-width={strokeWidth}
1215
stroke-linecap="round"
1316
stroke-linejoin="round"
1417
>

frontend/src/lib/components/shared/Modal.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
let {
55
open,
66
onclose,
7+
onenter,
78
panelClass = 'w-80',
89
z = 'z-50',
910
children,
1011
}: {
1112
open: boolean;
1213
onclose: () => void;
14+
onenter?: () => void;
1315
panelClass?: string;
1416
z?: string;
1517
children: Snippet;
@@ -21,6 +23,9 @@
2123
if (e.key === 'Escape') {
2224
e.preventDefault();
2325
onclose();
26+
} else if (e.key === 'Enter' && onenter) {
27+
e.preventDefault();
28+
onenter();
2429
}
2530
};
2631
window.addEventListener('keydown', onKey);

0 commit comments

Comments
 (0)