feat(sys-bar): polish — frosted glass panel, smooth label transitions, footer clearance
- Panel and sticky header now use bg-white/85 + backdrop-blur-md (frosted glass) matching the compact bar's existing semi-transparent treatment - Button hover labels switched from hidden/inline (instant snap) to max-w/opacity transitions (duration-300 ease-in-out) — smooth expand-in, graceful fade-out - Inlined Appearance controls (theme select + mode/font buttons) replacing Element_theme sub-component to avoid w-72 / bg-blue conflicts inside the panel - Added Dev/Tools section (edit mode only): iframe toggle, reload, clear storage+DB, URL builder, debug overlay — separated from user-facing config - :global CSS in style block strips blue bg/border from Element_access_type and Element_sign_in_out when rendered inside .ae_sys_panel - bottom-4 → bottom-12 to clear route-level footers (absolute bottom-0, text-xs hover:text-base — expands to ~44px on hover) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,8 +8,9 @@
|
||||
* Hover: info strip appears above bar; button labels revealed
|
||||
* Expanded: full panel slides up above the bar
|
||||
*
|
||||
* Sub-components are reused unchanged — all business logic lives there.
|
||||
* This file only orchestrates layout, visibility, and the compact quick-actions.
|
||||
* Sub-components are reused unchanged for complex business logic
|
||||
* (access_type, sign_in_out). Simple controls (theme, cfg utilities)
|
||||
* are inlined here for clean panel layout without blue-bg conflicts.
|
||||
*/
|
||||
import {
|
||||
Bug,
|
||||
@@ -26,9 +27,8 @@
|
||||
import { ae_loc, ae_sess, ae_api } from '$lib/stores/ae_stores';
|
||||
|
||||
import Element_access_type from '$lib/app_components/e_app_access_type.svelte';
|
||||
import Element_app_cfg from '$lib/app_components/e_app_cfg.svelte';
|
||||
import Element_sign_in_out from '$lib/app_components/e_app_sign_in_out.svelte';
|
||||
import Element_theme from '$lib/app_components/e_app_theme.svelte';
|
||||
import E_app_url_builder from '$lib/app_components/e_app_url_builder.svelte';
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
@@ -70,6 +70,20 @@
|
||||
// DOM sync (class) is handled reactively in +layout.svelte effect #3
|
||||
}
|
||||
|
||||
// ── Dev: clear all browser storage + key IndexedDB tables, then reload ──
|
||||
function handle_clear_storage_db() {
|
||||
if (!confirm('Clear all local/session storage and IndexedDB? The page will reload.')) return;
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
indexedDB.deleteDatabase('ae_archives_db');
|
||||
indexedDB.deleteDatabase('ae_core_db');
|
||||
indexedDB.deleteDatabase('ae_events_db');
|
||||
indexedDB.deleteDatabase('ae_journals_db');
|
||||
indexedDB.deleteDatabase('ae_posts_db');
|
||||
indexedDB.deleteDatabase('ae_sponsorships_db');
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
// ── Menu expand / collapse ───────────────────────────────────────────────
|
||||
function toggle_expand() {
|
||||
if (!expand) {
|
||||
@@ -135,7 +149,7 @@
|
||||
let sec_access = $state(true);
|
||||
let sec_signin = $state(false);
|
||||
let sec_appearance = $state(false);
|
||||
let sec_admin = $state(false);
|
||||
let sec_dev = $state(false);
|
||||
|
||||
// ── Derived display helpers ──────────────────────────────────────────────
|
||||
let font_label = $derived.by(() => {
|
||||
@@ -163,6 +177,28 @@
|
||||
};
|
||||
return map[t] ?? t;
|
||||
});
|
||||
|
||||
// Theme options — keep in sync with e_app_url_builder.svelte
|
||||
const theme_options = [
|
||||
{ value: '', label: '-- None --' },
|
||||
{ value: 'cerberus', label: 'Cerberus' },
|
||||
{ value: 'concord', label: 'Concord' },
|
||||
{ value: 'crimson', label: 'Crimson' },
|
||||
{ value: 'hamlindigo', label: 'Hamlindigo' },
|
||||
{ value: 'modern', label: 'Modern' },
|
||||
{ value: 'nouveau', label: 'Nouveau' },
|
||||
{ value: 'rocket', label: 'Rocket' },
|
||||
{ value: 'terminus', label: 'Terminus' },
|
||||
{ value: 'vintage', label: 'Vintage' },
|
||||
{ value: 'wintry', label: 'Wintry' },
|
||||
{ value: 'AE_OSIT_default', label: 'OSIT' },
|
||||
{ value: 'AE_Firefly', label: 'Firefly ✦' },
|
||||
{ value: 'AE_Firefly_SteelBlue', label: 'Firefly SteelBlue ✦' },
|
||||
{ value: 'AE_Firefly_Indigo', label: 'Firefly Indigo ✦' },
|
||||
{ value: 'AE_Firefly_Rainbow', label: 'Firefly Rainbow ✨' },
|
||||
{ value: 'AE_c_IDAA_light', label: 'IDAA – light' },
|
||||
{ value: 'AE_c_LCI', label: 'LCI' },
|
||||
];
|
||||
</script>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════════════════════════
|
||||
@@ -173,7 +209,7 @@
|
||||
class="
|
||||
ae_sys_bar
|
||||
print:hidden
|
||||
fixed bottom-4 right-2
|
||||
fixed bottom-12 right-2
|
||||
z-50
|
||||
flex flex-col items-end gap-1
|
||||
"
|
||||
@@ -188,14 +224,15 @@
|
||||
flex flex-col items-stretch gap-0
|
||||
w-80 max-w-[94vw]
|
||||
max-h-[80vh] overflow-y-auto overflow-x-hidden
|
||||
bg-white dark:bg-gray-900
|
||||
border border-gray-200 dark:border-gray-700
|
||||
bg-white/85 dark:bg-gray-900/85
|
||||
backdrop-blur-md
|
||||
border border-gray-200/70 dark:border-gray-700/70
|
||||
rounded-xl shadow-2xl
|
||||
text-sm
|
||||
"
|
||||
>
|
||||
<!-- Panel header: person info + close -->
|
||||
<div class="flex items-center justify-between px-3 py-2 border-b border-gray-100 dark:border-gray-800 sticky top-0 bg-white dark:bg-gray-900 z-10">
|
||||
<div class="flex items-center justify-between px-3 py-2 border-b border-gray-100/70 dark:border-gray-800/70 sticky top-0 bg-white/85 dark:bg-gray-900/85 backdrop-blur-md z-10">
|
||||
<div class="flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400 min-w-0">
|
||||
{#if $ae_loc?.person_id}
|
||||
<User size="0.9em" class="shrink-0" />
|
||||
@@ -293,46 +330,130 @@
|
||||
<span class="opacity-50">{sec_appearance ? '▲' : '▼'}</span>
|
||||
</button>
|
||||
{#if sec_appearance}
|
||||
<div class="px-2 pb-2">
|
||||
<Element_theme
|
||||
hide={false}
|
||||
expand={true}
|
||||
set_theme_mode={true}
|
||||
set_theme_name={true}
|
||||
/>
|
||||
<div class="px-3 pb-3 space-y-3">
|
||||
|
||||
<!-- Theme name -->
|
||||
<div class="space-y-1">
|
||||
<div class="text-xs text-gray-400 dark:text-gray-500 uppercase tracking-wide">Theme</div>
|
||||
<select
|
||||
bind:value={$ae_loc.theme_name}
|
||||
onchange={(e) => document.documentElement.setAttribute('data-theme', (e.target as HTMLSelectElement).value)}
|
||||
class="select select-sm w-full text-xs"
|
||||
>
|
||||
{#each theme_options as opt}
|
||||
<option value={opt.value}>{opt.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Dark / Light mode + Font size (side by side) -->
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm flex-1 preset-tonal-secondary hover:preset-filled-secondary-500 transition-all"
|
||||
onclick={toggle_theme_mode}
|
||||
title="Toggle light/dark mode"
|
||||
>
|
||||
{#if $ae_loc?.theme_mode === 'dark'}
|
||||
<Moon size="1em" class="shrink-0" />
|
||||
<span class="text-xs ml-1">Dark</span>
|
||||
{:else}
|
||||
<Sun size="1em" class="shrink-0" />
|
||||
<span class="text-xs ml-1">Light</span>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm flex-1 preset-tonal-surface hover:preset-tonal-primary transition-all"
|
||||
onclick={cycle_font_size}
|
||||
title={font_title}
|
||||
>
|
||||
<span class="font-bold text-sm leading-none">{font_label}</span>
|
||||
<span class="text-xs ml-1">Font</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- ── Admin / Config (edit mode only, collapsible) ─────────────── -->
|
||||
<!-- ── Dev / Tools (edit mode only, collapsible) ────────────────── -->
|
||||
<!--
|
||||
Dev tools are separate from user-facing config.
|
||||
These are only useful during development and testing —
|
||||
reload, storage wipe, iframe toggle, URL builder, debug overlay.
|
||||
-->
|
||||
{#if $ae_loc.edit_mode}
|
||||
<div class="border-b border-gray-100 dark:border-gray-800">
|
||||
<button
|
||||
type="button"
|
||||
class="w-full flex items-center justify-between px-3 py-2 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
||||
onclick={() => sec_admin = !sec_admin}
|
||||
onclick={() => sec_dev = !sec_dev}
|
||||
>
|
||||
<span class="flex items-center gap-1">
|
||||
<span class="fas fa-tools opacity-60"></span>
|
||||
Admin / Config
|
||||
<Bug size="0.9em" class="opacity-60" />
|
||||
Dev / Tools
|
||||
</span>
|
||||
<span class="opacity-50">{sec_admin ? '▲' : '▼'}</span>
|
||||
<span class="opacity-50">{sec_dev ? '▲' : '▼'}</span>
|
||||
</button>
|
||||
{#if sec_admin}
|
||||
<div class="px-2 pb-2 flex flex-col gap-2">
|
||||
<Element_app_cfg hide={false} expand={true} />
|
||||
<!-- Debug overlay trigger -->
|
||||
{#if sec_dev}
|
||||
<div class="px-3 pb-3 space-y-2">
|
||||
|
||||
<!-- iframe mode toggle -->
|
||||
{#if $ae_loc.iframe}
|
||||
<a class="btn btn-sm preset-tonal-secondary w-full justify-end" href="/?iframe=false">
|
||||
<span class="fas fa-compress-arrows-alt opacity-60"></span>
|
||||
Exit iframe Mode
|
||||
</a>
|
||||
{:else}
|
||||
<a class="btn btn-sm preset-tonal-secondary w-full justify-end" href="/?iframe=true">
|
||||
<span class="fas fa-expand-arrows-alt opacity-60"></span>
|
||||
Enable iframe Mode
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
<!-- Reload -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm w-full preset-outlined-error-400-600 hover:preset-tonal-error transition-all"
|
||||
onclick={() => { $ae_loc.debug_menu.expand = !$ae_loc.debug_menu.expand; }}
|
||||
title="Toggle debug overlay ($ae_loc dump)"
|
||||
class="btn btn-sm preset-tonal-warning w-full justify-end"
|
||||
onclick={() => window.location.reload()}
|
||||
title="Hard reload the page"
|
||||
>
|
||||
<Bug size="1em" class="shrink-0" />
|
||||
<span class="text-xs ml-1">
|
||||
{$ae_loc.debug_menu.expand ? 'Hide' : 'Show'} Debug Overlay
|
||||
</span>
|
||||
<span class="fas fa-sync opacity-60"></span>
|
||||
Reload Page
|
||||
</button>
|
||||
|
||||
<!-- Clear storage + IndexedDB -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm preset-tonal-error w-full justify-end"
|
||||
onclick={handle_clear_storage_db}
|
||||
title="Clear localStorage, sessionStorage, and all IndexedDB tables — then reload"
|
||||
>
|
||||
<span class="fas fa-eraser opacity-60"></span>
|
||||
Clear Storage & DB
|
||||
</button>
|
||||
|
||||
<!-- URL param builder -->
|
||||
<div class="pt-1 border-t border-gray-100 dark:border-gray-800">
|
||||
<E_app_url_builder />
|
||||
</div>
|
||||
|
||||
<!-- Debug overlay toggle -->
|
||||
<div class="pt-1 border-t border-gray-100 dark:border-gray-800">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm w-full justify-end {$ae_loc.debug_menu.expand ? 'preset-filled-error-500' : 'preset-outlined-error-400-600'} hover:preset-tonal-error transition-all"
|
||||
onclick={() => { $ae_loc.debug_menu.expand = !$ae_loc.debug_menu.expand; }}
|
||||
title="Toggle debug overlay ($ae_loc dump)"
|
||||
>
|
||||
<Bug size="1em" class="shrink-0" />
|
||||
<span class="text-xs ml-1">
|
||||
{$ae_loc.debug_menu.expand ? 'Hide' : 'Show'} Debug Overlay
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -360,7 +481,7 @@
|
||||
pointer-events-none
|
||||
transition-opacity duration-200 delay-500
|
||||
flex items-center gap-1.5
|
||||
bg-white/90 dark:bg-gray-900/90
|
||||
bg-white/30 dark:bg-gray-900/30
|
||||
border border-gray-200/60 dark:border-gray-700/60
|
||||
backdrop-blur-sm rounded-lg
|
||||
px-2 py-1
|
||||
@@ -387,7 +508,7 @@
|
||||
ae_sys_bar__strip
|
||||
flex flex-row items-center gap-1
|
||||
h-9
|
||||
bg-white/80 dark:bg-gray-900/80
|
||||
bg-white/30 dark:bg-gray-900/30
|
||||
backdrop-blur-sm
|
||||
border border-gray-200/60 dark:border-gray-700/60
|
||||
rounded-xl
|
||||
@@ -427,7 +548,7 @@
|
||||
{:else}
|
||||
<ShieldUser size="1.1em" class="shrink-0" />
|
||||
{/if}
|
||||
<span class="hidden group-hover/shield:inline text-xs ml-0.5 transition-none">
|
||||
<span class="btn-label max-w-0 overflow-hidden opacity-0 group-hover/shield:max-w-20 group-hover/shield:opacity-100 transition-all duration-300 ease-in-out text-xs pl-1">
|
||||
{access_label ?? 'Auth?'}
|
||||
</span>
|
||||
</button>
|
||||
@@ -440,7 +561,7 @@
|
||||
title={font_title}
|
||||
>
|
||||
<span class="font-bold leading-none text-sm">{font_label}</span>
|
||||
<span class="hidden group-hover/font:inline text-xs ml-0.5 transition-none">Font</span>
|
||||
<span class="btn-label max-w-0 overflow-hidden opacity-0 group-hover/font:max-w-20 group-hover/font:opacity-100 transition-all duration-300 ease-in-out text-xs pl-1">Font</span>
|
||||
</button>
|
||||
|
||||
<!-- DARK / LIGHT TOGGLE ──────────────────────────────────────── -->
|
||||
@@ -452,10 +573,10 @@
|
||||
>
|
||||
{#if $ae_loc?.theme_mode === 'dark'}
|
||||
<Moon size="1.1em" class="shrink-0" />
|
||||
<span class="hidden group-hover/mode:inline text-xs ml-0.5 transition-none">Dark</span>
|
||||
<span class="btn-label max-w-0 overflow-hidden opacity-0 group-hover/mode:max-w-20 group-hover/mode:opacity-100 transition-all duration-300 ease-in-out text-xs pl-1">Dark</span>
|
||||
{:else}
|
||||
<Sun size="1.1em" class="shrink-0" />
|
||||
<span class="hidden group-hover/mode:inline text-xs ml-0.5 transition-none">Light</span>
|
||||
<span class="btn-label max-w-0 overflow-hidden opacity-0 group-hover/mode:max-w-20 group-hover/mode:opacity-100 transition-all duration-300 ease-in-out text-xs pl-1">Light</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
@@ -469,7 +590,7 @@
|
||||
title="Edit mode ON — click to turn off"
|
||||
>
|
||||
<span class="fas fa-toggle-on text-sm inline-block"></span>
|
||||
<span class="hidden group-hover/edit:inline text-xs ml-0.5 transition-none">Edit</span>
|
||||
<span class="btn-label max-w-0 overflow-hidden opacity-0 group-hover/edit:max-w-20 group-hover/edit:opacity-100 transition-all duration-300 ease-in-out text-xs pl-1">Edit</span>
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
@@ -479,7 +600,7 @@
|
||||
title="Edit mode OFF — click to turn on"
|
||||
>
|
||||
<span class="fas fa-toggle-off text-sm inline-block opacity-50"></span>
|
||||
<span class="hidden group-hover/edit:inline text-xs ml-0.5 transition-none">Edit</span>
|
||||
<span class="btn-label max-w-0 overflow-hidden opacity-0 group-hover/edit:max-w-20 group-hover/edit:opacity-100 transition-all duration-300 ease-in-out text-xs pl-1">Edit</span>
|
||||
</button>
|
||||
{/if}
|
||||
{/if}
|
||||
@@ -493,10 +614,10 @@
|
||||
>
|
||||
{#if expand}
|
||||
<CircleX size="1.1em" class="shrink-0" />
|
||||
<span class="hidden group-hover/menu:inline text-xs ml-0.5 transition-none">Close</span>
|
||||
<span class="btn-label max-w-0 overflow-hidden opacity-0 group-hover/menu:max-w-20 group-hover/menu:opacity-100 transition-all duration-300 ease-in-out text-xs pl-1">Close</span>
|
||||
{:else}
|
||||
<Menu size="1.1em" class="shrink-0" />
|
||||
<span class="hidden group-hover/menu:inline text-xs ml-0.5 transition-none">Menu</span>
|
||||
<span class="btn-label max-w-0 overflow-hidden opacity-0 group-hover/menu:max-w-20 group-hover/menu:opacity-100 transition-all duration-300 ease-in-out text-xs pl-1">Menu</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
@@ -505,3 +626,20 @@
|
||||
<!-- END: Compact bar -->
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/*
|
||||
* Strip blue backgrounds and fixed widths from sub-components when
|
||||
* rendered inside the sys panel. The panel provides its own white/dark
|
||||
* background and full-width layout — the sub-components' default styling
|
||||
* was designed for standalone use and clashes inside the panel.
|
||||
*/
|
||||
:global(.ae_sys_panel .ae_access_type),
|
||||
:global(.ae_sys_panel .ae_sign_in_out) {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user