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
@@ -23,7 +23,7 @@ templ DocsLayout(nav Navigation, doc Document, user User, currentPath string) {
|
||||
<link href="/static/style.css" rel="stylesheet"/>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg"/>
|
||||
</head>
|
||||
<body x-data="docs" x-init="initializeSearch(); initializeCodeCopyButtons()" class={ "theme-" + user.Theme + " page-docs font-sans antialiased" }>
|
||||
<body x-data="docs" x-init="restoreDocsNav(); initializeSearch(); initializeCodeCopyButtons()" class={ "theme-" + user.Theme + " page-docs font-sans antialiased" }>
|
||||
@DocsTopbar(user)
|
||||
<!-- Mobile drawer backdrop -->
|
||||
<div id="docs-overlay" class="hidden fixed inset-0 z-40 lg:hidden" style="background: var(--surface-overlay);" onclick="document.getElementById('docs-sidebar').classList.add('-translate-x-full'); this.classList.add('hidden')"></div>
|
||||
@@ -198,7 +198,7 @@ templ DocsSidebar(nav Navigation, currentPath string) {
|
||||
@Icon("chevron-down", "h-4 w-4")
|
||||
</span>
|
||||
</button>
|
||||
<div class="nav-items pb-1" data-collapsed={ collapsibleState(section.Collapsed) }>
|
||||
<div class="nav-items pb-1" data-key={ section.Title } data-collapsed={ collapsibleState(section.Collapsed) }>
|
||||
for _, item := range section.Items {
|
||||
<a href={ item.URL } class={ docsNavClass(currentPath, item.URL, "pl-7") }>
|
||||
<span>{ item.Title }</span>
|
||||
@@ -217,7 +217,7 @@ templ DocsSidebar(nav Navigation, currentPath string) {
|
||||
@Icon("chevron-down", "h-3.5 w-3.5")
|
||||
</span>
|
||||
</button>
|
||||
<div class="nav-group-items" data-collapsed={ collapsibleState(group.Collapsed) }>
|
||||
<div class="nav-group-items" data-key={ section.Title + " / " + group.Title } data-collapsed={ collapsibleState(group.Collapsed) }>
|
||||
for _, item := range group.Items {
|
||||
<a href={ item.URL } class={ docsNavClass(currentPath, item.URL, "pl-9") }>
|
||||
<span class="truncate">{ item.Title }</span>
|
||||
@@ -268,7 +268,7 @@ templ DocsNotFound(title string, message string) {
|
||||
<link href="/static/style.css" rel="stylesheet"/>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg"/>
|
||||
</head>
|
||||
<body class="theme-tokyo-night min-h-screen font-sans antialiased">
|
||||
<body class="min-h-screen font-sans antialiased">
|
||||
<div class="min-h-screen flex items-center justify-center p-4">
|
||||
<div class="card p-8 max-w-md w-full text-center">
|
||||
<span class="inline-grid place-items-center mb-4" style="color: var(--accent);">
|
||||
|
||||
Reference in new issue
Block a user