ui: fix admin/docs theme flash + persist sidebar open/closed state
Theme flash (admin pages, docs, stats, progress — anywhere SSR'd):
the JWT middlewares built the context user WITHOUT the Theme column,
so every page rendering theme-{user.Theme} from c.Get("user") painted
an empty class (:root tokyo-night default) and only settled on the real
theme after initializeTheme -> loadUserTheme round-tripped the server.
Both middlewares now carry liveUser.Theme into the context user;
verified live: /admin /stats /progress /docs /docs-deep /dashboard
/collections all SSR theme-hackerman.
Defense in depth for the same bug: loadTheme() no longer re-applies
localStorage over a server-rendered body theme (applyTheme records even
the default, so any signed-out visit baked tokyo-night into localStorage
and every signed-in page flipped to it post-paint). Public auth/landing
bodies dropped their hardcoded theme classes so ThemeFlashGuard's
pre-paint html class actually governs them; docs theme <select> now
syncs from the body class and re-syncs after the profile fetch.
Sidebar state (the unpleasant part): the app sidebar's openPanel was
reinitialized from the pathname on every load; it now restores from
localStorage ('sidebar-open-panel') with the pathname default as
fallback and -persists every toggle. Docs sidebar sections/groups
carry data-key attributes and toggleCollapsible persists collapsed
state per key ('docs-nav-state'); restoreDocsNav() applies it at init —
server-rendered defaults still govern first visit.
make test green; rendering ownership OK (no new inline scripts); 146
vitests pass; live-verified SSR classes on 7 pages.
This commit is contained in:
1 parent
983980d07a
commit
f1a6de7cd7
50 files changed
+915
-803
No files matched your search
@@ -84,7 +84,8 @@ templ Header(user User, currentPath string) {
|
||||
</nav>
|
||||
<!-- Bottom: theme picker + user -->
|
||||
<div
|
||||
x-data={ "{ openPanel: window.location.pathname.startsWith('/admin') ? 'admin' : null, themeMode: '" + string(ThemeModeOf(user.Theme)) + "' }" }
|
||||
x-data={ "{ openPanel: (function () { try { var v = localStorage.getItem('sidebar-open-panel'); if (v !== null) { return v === '' ? null : v; } } catch (e) {} return window.location.pathname.startsWith('/admin') ? 'admin' : null; })(), themeMode: '" + string(ThemeModeOf(user.Theme)) + "' }" }
|
||||
x-init="$watch('openPanel', function (v) { try { localStorage.setItem('sidebar-open-panel', v === null ? '' : v); } catch (e) {} })"
|
||||
class="shrink-0 px-3 py-3 space-y-2 border-t"
|
||||
style="border-color: color-mix(in srgb, var(--text-primary) 7%, transparent);"
|
||||
>
|
||||
|
||||
Reference in new issue
Block a user