fix(launcher): replace Flowbite Modal with custom overlay for cfg panel
Two problems with the Flowbite <Modal> approach: 1. Built-in dismissable CloseButton rendered with no functional dismiss path (no title/form), appearing centered in the panel. 2. size="xl" (max-w-7xl) left no backdrop area on typical laptop screens, making outsideclose impossible to trigger. Replace with a simple custom overlay: full-screen backdrop div that closes on click, inner panel with stopPropagation. Matches the original Drawer pattern. close_cfg() writes to store immediately on backdrop click for reliable persistence independent of effect timing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import { sineIn } from 'svelte/easing';
|
|||||||
// *** Import other supporting libraries
|
// *** Import other supporting libraries
|
||||||
import { liveQuery } from 'dexie';
|
import { liveQuery } from 'dexie';
|
||||||
import { Drawer, Modal } from 'flowbite-svelte';
|
import { Drawer, Modal } from 'flowbite-svelte';
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
import { listen, idle, onIdle, restartCountdown } from 'svelte-idle';
|
import { listen, idle, onIdle, restartCountdown } from 'svelte-idle';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -122,6 +123,15 @@ $effect(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Called by backdrop click. Writes to store immediately (don't rely on effect timing).
|
||||||
|
function close_cfg() {
|
||||||
|
modal_cfg_open = false;
|
||||||
|
events_loc.update((loc) => {
|
||||||
|
if (loc.launcher) loc.launcher.hide_drawer__cfg = true;
|
||||||
|
return loc;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Generate a stable per-device client ID on first load and persist it.
|
// Generate a stable per-device client ID on first load and persist it.
|
||||||
// events_loc is backed by svelte-persisted-store (localStorage) so this
|
// events_loc is backed by svelte-persisted-store (localStorage) so this
|
||||||
// survives page reloads. Without this, client_id falls back to Date.now()
|
// survives page reloads. Without this, client_id falls back to Date.now()
|
||||||
@@ -928,41 +938,53 @@ $effect(() => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Modal
|
{#if modal_cfg_open}
|
||||||
bind:open={modal_cfg_open}
|
<!-- Backdrop: full-screen overlay. Clicking anywhere on it closes the cfg panel. -->
|
||||||
autoclose={false}
|
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
|
||||||
outsideclose
|
|
||||||
size="xl"
|
|
||||||
class="relative flex flex-col items-center justify-center p-0 overflow-hidden"
|
|
||||||
id="modal_cfg">
|
|
||||||
<Launcher_cfg></Launcher_cfg>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="bg-surface-100-900 flex max-w-full flex-row flex-wrap items-center justify-center gap-2 border-t border-surface-500/10 p-4">
|
role="presentation"
|
||||||
<a
|
class="fixed inset-0 z-50 flex items-center justify-center bg-gray-900/60 p-4"
|
||||||
href="/events/{$events_slct.event_id}"
|
onclick={close_cfg}
|
||||||
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
transition:fade={{ duration: 200 }}>
|
||||||
<Search size="1em" class="m-1" />
|
<!-- Panel: stop-propagation so clicks inside don't reach the backdrop handler. -->
|
||||||
Session Search
|
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
|
||||||
</a>
|
<div
|
||||||
{#if $events_slct?.event_location_id}
|
role="dialog"
|
||||||
<a
|
aria-modal="true"
|
||||||
href="/events/{$events_slct.event_id}/location/{$events_slct.event_location_id}"
|
aria-label="Launcher Settings"
|
||||||
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
tabindex="-1"
|
||||||
<MapPin size="1em" class="m-1" />
|
class="flex max-h-[90vh] w-full max-w-5xl flex-col overflow-hidden rounded-lg shadow-2xl"
|
||||||
View Selected Location
|
onclick={(e) => e.stopPropagation()}>
|
||||||
</a>
|
<Launcher_cfg></Launcher_cfg>
|
||||||
{/if}
|
|
||||||
{#if $events_slct?.event_session_id}
|
<div
|
||||||
<a
|
class="bg-surface-100-900 flex flex-row flex-wrap items-center justify-center gap-2 border-t border-surface-500/10 p-4">
|
||||||
href="/events/{$events_slct.event_id}/session/{$events_slct.event_session_id}"
|
<a
|
||||||
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
href="/events/{$events_slct.event_id}"
|
||||||
<GraduationCap size="1em" class="m-1" />
|
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
||||||
View Selected Session
|
<Search size="1em" class="m-1" />
|
||||||
</a>
|
Session Search
|
||||||
{/if}
|
</a>
|
||||||
|
{#if $events_slct?.event_location_id}
|
||||||
|
<a
|
||||||
|
href="/events/{$events_slct.event_id}/location/{$events_slct.event_location_id}"
|
||||||
|
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
||||||
|
<MapPin size="1em" class="m-1" />
|
||||||
|
View Selected Location
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
{#if $events_slct?.event_session_id}
|
||||||
|
<a
|
||||||
|
href="/events/{$events_slct.event_id}/session/{$events_slct.event_session_id}"
|
||||||
|
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
||||||
|
<GraduationCap size="1em" class="m-1" />
|
||||||
|
View Selected Session
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
{/if}
|
||||||
|
|
||||||
<Drawer
|
<Drawer
|
||||||
activateClickOutside={false}
|
activateClickOutside={false}
|
||||||
|
|||||||
Reference in New Issue
Block a user