fix(launcher): fix cfg modal default-open and outside-click persistence
Two bugs in the Launcher Config Modal after the Drawer→Modal migration: 1. Pre-existing persisted configs (missing hide_drawer__cfg field) caused !undefined = true, opening the modal on every fresh load. Fixed by adding a field-level initialization guard after the full-object guard. 2. $-syntax writes inside untrack() were suppressed by svelte-persisted-store, so outside-click closure was never persisted. Fixed by using events_loc.update() directly to ensure the write reaches localStorage serialization. Added equality guard to effect 1 to prevent spurious modal flicker from whole-store re-fires. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -91,6 +91,36 @@ if (!$events_loc?.launcher) {
|
|||||||
hide_drawer__debug: true
|
hide_drawer__debug: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// WHY: The initialization block above only runs when launcher is completely absent.
|
||||||
|
// If the user has an older persisted config (from before the Modal migration),
|
||||||
|
// hide_drawer__cfg may be missing → undefined → !undefined = true → modal opens
|
||||||
|
// on every load. Explicitly initialize it here to ensure it is always a boolean.
|
||||||
|
if ($events_loc.launcher.hide_drawer__cfg === undefined) {
|
||||||
|
$events_loc.launcher.hide_drawer__cfg = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let modal_cfg_open = $state(!$events_loc.launcher.hide_drawer__cfg);
|
||||||
|
|
||||||
|
// Sync store → modal: biohazard button writes hide_drawer__cfg = false to open.
|
||||||
|
// Equality guard prevents spurious writes from unrelated $events_loc updates
|
||||||
|
// (Svelte 4 whole-store subscription fires on every field write to the store).
|
||||||
|
$effect(() => {
|
||||||
|
const should_open = !$events_loc.launcher.hide_drawer__cfg;
|
||||||
|
if (modal_cfg_open !== should_open) {
|
||||||
|
modal_cfg_open = should_open;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sync modal → store: use events_loc.update() directly rather than $-syntax so
|
||||||
|
// the write always reaches the persisted store's serialization. $-syntax writes
|
||||||
|
// inside $effect contexts may be suppressed and not trigger localStorage persistence.
|
||||||
|
$effect(() => {
|
||||||
|
const should_hide = !modal_cfg_open;
|
||||||
|
events_loc.update((loc) => {
|
||||||
|
if (loc.launcher) loc.launcher.hide_drawer__cfg = should_hide;
|
||||||
|
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
|
||||||
@@ -898,59 +928,41 @@ $effect(() => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Drawer
|
<Modal
|
||||||
dismissable={false}
|
bind:open={modal_cfg_open}
|
||||||
onclick={() => ($events_loc.launcher.hide_drawer__cfg = true)}
|
autoclose={false}
|
||||||
class="w-full border border-gray-300 bg-orange-50 opacity-90 transition-all duration-300 hover:opacity-97 md:w-96 lg:w-[32rem] dark:border-gray-600 dark:bg-slate-800"
|
outsideclose
|
||||||
placement="left"
|
size="xl"
|
||||||
{...{
|
class="relative flex flex-col items-center justify-center p-0 overflow-hidden"
|
||||||
transitionType: 'fly',
|
id="modal_cfg">
|
||||||
transitionParams: {
|
<Launcher_cfg></Launcher_cfg>
|
||||||
x: -520,
|
|
||||||
duration: 200,
|
|
||||||
easing: sineIn
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
bind:hidden={$events_loc.launcher.hide_drawer__cfg}
|
|
||||||
id="sidebar1">
|
|
||||||
<!-- Stop-propagation wrapper: prevents clicks inside the visual panel from
|
|
||||||
bubbling up to the <dialog> element. The onclick on the <Drawer> above
|
|
||||||
is spread through to the native <dialog> by Flowbite, overriding its
|
|
||||||
broken outsideclose detection. With this wrapper, ONLY genuine backdrop
|
|
||||||
clicks (outside the visible panel) reach the dialog and close the drawer. -->
|
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
|
|
||||||
<div role="presentation" onclick={(e) => e.stopPropagation()}>
|
|
||||||
<Launcher_cfg></Launcher_cfg>
|
|
||||||
|
|
||||||
<hr class="my-2 border-gray-300 dark:border-gray-600" />
|
<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">
|
||||||
<div
|
<a
|
||||||
class="flex max-w-md flex-row flex-wrap items-center justify-center gap-0.5">
|
href="/events/{$events_slct.event_id}"
|
||||||
|
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
||||||
|
<Search size="1em" class="m-1" />
|
||||||
|
Session Search
|
||||||
|
</a>
|
||||||
|
{#if $events_slct?.event_location_id}
|
||||||
<a
|
<a
|
||||||
href="/events/{$events_slct.event_id}"
|
href="/events/{$events_slct.event_id}/location/{$events_slct.event_location_id}"
|
||||||
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
||||||
<Search size="1em" class="m-1" />
|
<MapPin size="1em" class="m-1" />
|
||||||
Session Search
|
View Selected Location
|
||||||
</a>
|
</a>
|
||||||
{#if $events_slct?.event_location_id}
|
{/if}
|
||||||
<a
|
{#if $events_slct?.event_session_id}
|
||||||
href="/events/{$events_slct.event_id}/location/{$events_slct.event_location_id}"
|
<a
|
||||||
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
href="/events/{$events_slct.event_id}/session/{$events_slct.event_session_id}"
|
||||||
<MapPin size="1em" class="m-1" />
|
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500">
|
||||||
View Selected Location
|
<GraduationCap size="1em" class="m-1" />
|
||||||
</a>
|
View Selected Session
|
||||||
{/if}
|
</a>
|
||||||
{#if $events_slct?.event_session_id}
|
{/if}
|
||||||
<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>
|
||||||
</Drawer>
|
</Modal>
|
||||||
|
|
||||||
<Drawer
|
<Drawer
|
||||||
activateClickOutside={false}
|
activateClickOutside={false}
|
||||||
|
|||||||
Reference in New Issue
Block a user