fix(idaa): correct reactive loop fix + hide clutter in iframe sys bar
1. Replace incorrect untrack() with idempotent write guard in the sys_menu trusted-access effect. untrack() prevents new dep reads but ae_loc was already tracked from the outer condition reads, so the write still re-notified the effect every run. The guard (only write if value != false) breaks the cycle: run 2 finds value already false, skips the write, effect stops. Max 2 runs vs the previous infinite loop. 2. Hide auth shield, font-size cycler, and dark/light toggle in the sys bar when in iframe mode — host page owns those concerns. Edit mode toggle and the main expand button remain visible for staff. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -593,73 +593,79 @@ const theme_options = [
|
|||||||
dark:border-gray-700/60 dark:bg-gray-900/30
|
dark:border-gray-700/60 dark:bg-gray-900/30
|
||||||
"
|
"
|
||||||
class:border-primary-400={expand}>
|
class:border-primary-400={expand}>
|
||||||
<!-- AUTH STATUS SHIELD ───────────────────────────────────────── -->
|
<!-- AUTH STATUS SHIELD — hidden in iframe; host page manages auth context -->
|
||||||
<button
|
{#if !$ae_loc?.iframe}
|
||||||
type="button"
|
<button
|
||||||
class="
|
type="button"
|
||||||
btn btn-sm group/shield transition-all duration-200
|
class="
|
||||||
{$ae_loc?.access_type &&
|
btn btn-sm group/shield transition-all duration-200
|
||||||
$ae_loc?.access_type !== 'anonymous'
|
{$ae_loc?.access_type &&
|
||||||
? $ae_loc?.user_access_type &&
|
$ae_loc?.access_type !== 'anonymous'
|
||||||
$ae_loc?.access_type === $ae_loc?.user_access_type
|
? $ae_loc?.user_access_type &&
|
||||||
? 'variant-outline-surface hover:variant-ghost-warning'
|
$ae_loc?.access_type === $ae_loc?.user_access_type
|
||||||
: 'variant-outline-warning hover:variant-ghost-warning'
|
? 'variant-outline-surface hover:variant-ghost-warning'
|
||||||
: 'variant-outline-surface hover:variant-ghost-success'}
|
: 'variant-outline-warning hover:variant-ghost-warning'
|
||||||
"
|
: 'variant-outline-surface hover:variant-ghost-success'}
|
||||||
onclick={handle_shield_click}
|
"
|
||||||
title={$ae_loc?.access_type &&
|
onclick={handle_shield_click}
|
||||||
$ae_loc?.access_type !== 'anonymous'
|
title={$ae_loc?.access_type &&
|
||||||
? $ae_loc?.user_access_type &&
|
$ae_loc?.access_type !== 'anonymous'
|
||||||
$ae_loc?.access_type === $ae_loc?.user_access_type
|
? $ae_loc?.user_access_type &&
|
||||||
? `Access: ${$ae_loc?.access_type}. Click to use a passcode.`
|
$ae_loc?.access_type === $ae_loc?.user_access_type
|
||||||
: `Elevated access: ${$ae_loc?.access_type}. Click to clear.`
|
? `Access: ${$ae_loc?.access_type}. Click to use a passcode.`
|
||||||
: 'Anonymous. Click to sign in or enter a passcode.'}>
|
: `Elevated access: ${$ae_loc?.access_type}. Click to clear.`
|
||||||
{#if $ae_loc?.access_type && $ae_loc?.access_type !== 'anonymous'}
|
: 'Anonymous. Click to sign in or enter a passcode.'}>
|
||||||
{#if $ae_loc?.user_access_type && $ae_loc?.access_type === $ae_loc?.user_access_type}
|
{#if $ae_loc?.access_type && $ae_loc?.access_type !== 'anonymous'}
|
||||||
<ShieldEllipsis size="1.1em" class="shrink-0" />
|
{#if $ae_loc?.user_access_type && $ae_loc?.access_type === $ae_loc?.user_access_type}
|
||||||
|
<ShieldEllipsis size="1.1em" class="shrink-0" />
|
||||||
|
{:else}
|
||||||
|
<ShieldMinus size="1.1em" class="shrink-0" />
|
||||||
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<ShieldMinus size="1.1em" class="shrink-0" />
|
<ShieldUser size="1.1em" class="shrink-0" />
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
|
||||||
<ShieldUser size="1.1em" class="shrink-0" />
|
|
||||||
{/if}
|
|
||||||
<span
|
|
||||||
class="btn-label max-w-0 overflow-hidden pl-1 text-xs opacity-0 transition-all duration-300 ease-in-out group-hover/shield:max-w-20 group-hover/shield:opacity-100">
|
|
||||||
{access_label ?? 'Auth?'}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- FONT SIZE CYCLER ─────────────────────────────────────────── -->
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-sm preset-tonal-surface hover:preset-tonal-primary group/font transition-all duration-200"
|
|
||||||
onclick={cycle_font_size}
|
|
||||||
title={font_title}>
|
|
||||||
<span class="text-sm leading-none font-bold">{font_label}</span>
|
|
||||||
<span
|
|
||||||
class="btn-label max-w-0 overflow-hidden pl-1 text-xs opacity-0 transition-all duration-300 ease-in-out group-hover/font:max-w-20 group-hover/font:opacity-100"
|
|
||||||
>Font</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- DARK / LIGHT TOGGLE ──────────────────────────────────────── -->
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-sm preset-tonal-surface hover:preset-tonal-secondary group/mode transition-all duration-200"
|
|
||||||
onclick={toggle_theme_mode}
|
|
||||||
title="Toggle light/dark mode (currently: {$ae_loc?.theme_mode ??
|
|
||||||
'unknown'})">
|
|
||||||
{#if $ae_loc?.theme_mode === 'dark'}
|
|
||||||
<Moon size="1.1em" class="shrink-0" />
|
|
||||||
<span
|
<span
|
||||||
class="btn-label max-w-0 overflow-hidden pl-1 text-xs opacity-0 transition-all duration-300 ease-in-out group-hover/mode:max-w-20 group-hover/mode:opacity-100"
|
class="btn-label max-w-0 overflow-hidden pl-1 text-xs opacity-0 transition-all duration-300 ease-in-out group-hover/shield:max-w-20 group-hover/shield:opacity-100">
|
||||||
>Dark</span>
|
{access_label ?? 'Auth?'}
|
||||||
{:else}
|
</span>
|
||||||
<Sun size="1.1em" class="shrink-0" />
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- FONT SIZE CYCLER — hidden in iframe; font choice belongs to the host page -->
|
||||||
|
{#if !$ae_loc?.iframe}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-sm preset-tonal-surface hover:preset-tonal-primary group/font transition-all duration-200"
|
||||||
|
onclick={cycle_font_size}
|
||||||
|
title={font_title}>
|
||||||
|
<span class="text-sm leading-none font-bold">{font_label}</span>
|
||||||
<span
|
<span
|
||||||
class="btn-label max-w-0 overflow-hidden pl-1 text-xs opacity-0 transition-all duration-300 ease-in-out group-hover/mode:max-w-20 group-hover/mode:opacity-100"
|
class="btn-label max-w-0 overflow-hidden pl-1 text-xs opacity-0 transition-all duration-300 ease-in-out group-hover/font:max-w-20 group-hover/font:opacity-100"
|
||||||
>Light</span>
|
>Font</span>
|
||||||
{/if}
|
</button>
|
||||||
</button>
|
{/if}
|
||||||
|
|
||||||
|
<!-- DARK / LIGHT TOGGLE — hidden in iframe; theme is set by the host page -->
|
||||||
|
{#if !$ae_loc?.iframe}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-sm preset-tonal-surface hover:preset-tonal-secondary group/mode transition-all duration-200"
|
||||||
|
onclick={toggle_theme_mode}
|
||||||
|
title="Toggle light/dark mode (currently: {$ae_loc?.theme_mode ??
|
||||||
|
'unknown'})">
|
||||||
|
{#if $ae_loc?.theme_mode === 'dark'}
|
||||||
|
<Moon size="1.1em" class="shrink-0" />
|
||||||
|
<span
|
||||||
|
class="btn-label max-w-0 overflow-hidden pl-1 text-xs opacity-0 transition-all duration-300 ease-in-out group-hover/mode:max-w-20 group-hover/mode:opacity-100"
|
||||||
|
>Dark</span>
|
||||||
|
{:else}
|
||||||
|
<Sun size="1.1em" class="shrink-0" />
|
||||||
|
<span
|
||||||
|
class="btn-label max-w-0 overflow-hidden pl-1 text-xs opacity-0 transition-all duration-300 ease-in-out group-hover/mode:max-w-20 group-hover/mode:opacity-100"
|
||||||
|
>Light</span>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- EDIT MODE TOGGLE (authenticated+ only) ───────────────────── -->
|
<!-- EDIT MODE TOGGLE (authenticated+ only) ───────────────────── -->
|
||||||
{#if $ae_loc?.authenticated_access}
|
{#if $ae_loc?.authenticated_access}
|
||||||
|
|||||||
@@ -218,13 +218,15 @@ $effect(() => {
|
|||||||
// the iframe src to pass show_menu=true, so we watch for trusted_access and unhide it.
|
// the iframe src to pass show_menu=true, so we watch for trusted_access and unhide it.
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (browser && $ae_loc.iframe && $ae_loc.trusted_access) {
|
if (browser && $ae_loc.iframe && $ae_loc.trusted_access) {
|
||||||
// WHY untrack: writing to $ae_loc inside an effect that reads $ae_loc causes
|
// WHY the guard: ae_loc is a tracked dep here (reads above). Writing
|
||||||
// an infinite reactive loop (effect_update_depth_exceeded). The conditions we
|
// $ae_loc.sys_menu.hide re-notifies this effect every run — infinite loop.
|
||||||
// want to react to ($ae_loc.iframe / trusted_access) are tracked above; the
|
// untrack() does NOT help: it prevents new dep reads but the store still
|
||||||
// write is a side-effect that must not re-trigger this effect.
|
// notifies already-subscribed effects after the write.
|
||||||
untrack(() => {
|
// The idempotent write guard breaks the cycle: run 2 finds the value
|
||||||
|
// already false, skips the write, no further re-queue.
|
||||||
|
if ($ae_loc.sys_menu.hide !== false) {
|
||||||
$ae_loc.sys_menu.hide = false;
|
$ae_loc.sys_menu.hide = false;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user