Simplification per spec: the menu tracks state through the URL alone.
Land on /docs: fully closed, headers only (an explicit home rule now
overrides the contains-URL rule, since the root overview doc lives in
Getting Started and would otherwise auto-open it). Land on any doc page:
its containing section + group render open at first paint, current link
bold — no JS, no jump, arrows consistent. Navigate elsewhere: old
closes, new opens.
Deleted: docs_nav cookie const/parse, ApplyNavOverrides, cookie write +
collect/persist helpers in web/src/docs.ts, data-key attributes in the
sidebar templ, and the first-section-open fallback (docs home used to
force-open the first section — spec'd as closed).
toggleCollapsible remains for in-page peeking; purely ephemeral.
The [data-collapsed=true] CSS from the previous round stays — it is what
makes the server-rendered state actually hide sections at paint (the
original bug was that this CSS never existed).
Tests: TestBuildNavigationNothingCurrent now asserts zero sections open
on unmatched paths; TestBuildNavigation asserts Getting Started closed
on a device page (no site-wide pin). make test green; 146 vitests; live
verified: home 0 expanded, doc pages exactly 2 (section+group).
Three problems, one root cause each:
1. Sidebar jump: the server rendered its own default (current section
open, rest collapsed) and restoreDocsNav corrected it after paint —
open-then-close. Fix: persistence moved server-side. toggleCollapsible
now writes a docs_nav cookie (strictly-necessary UI state, no
identifiers, SameSite=Lax); ApplyNavOverrides merges it into the nav
before render, so first paint IS the visitor's state. The post-paint
restore is deleted.
2. Arrows out of sync / double-click: two visibility mechanisms
disagreed. There was NO data-collapsed CSS at all — collapsed sections
were only ever hidden by JS after paint, and the arrow rotation came
from a different (server) state. Now: style.css hides on
[data-collapsed=true] (single source of truth, server-rendered),
applyCollapsed sets only the attribute, arrows rotate from the same
merged value. Live check: 37/37 collapsibles arrow-consistent.
3. api-reference.md links: all 20+ quick links were directory-style
(authentication/ etc.) that 404 on the docs site, plus stale targets
(books/, ../collections-api.md, websocket 'coming soon'). Rewritten to
real per-file links — all 9 unique targets return 200 live. Same rot
fixed in admin/hash-conflicts.md, development.md, android-app.md,
create_media_item.md, koreader-protocol.md; docs/index.md redirected
from the deleted collections-api monolith (stale 530-line duplicate of
the gated api/collections docs — deleted, per the WO2 doctrine).
New gate: TestDocsRelativeLinks walks docs/developer/** and fails make
test on any relative link that is directory-style or unresolvable —
overview links can never silently rot again.
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.
Docs pages no longer embed the app Header (whose hx-post login form silently
degraded to a native GET, leaking credentials into the URL — this page never
loaded htmx). New docs-owned topbar: search, theme picker, Open App; anonymous
visitors get a plain /login link. Optional-auth middleware (hand-rolled —
echojwt's ErrorHandler return ends the chain, producing empty 200s) populates
the user for signed-in visitors.
Navigation rebuilt from the docs directory tree: 6 sections, subcategory
groups, server-rendered expansion and active states. Search results are a
templ partial (/docs/search/partial); code highlighting is server-side chroma
(previously dead hljs CSS); prose is theme-aware via typography DEFAULT vars
(prose-invert painted unreadable text under light themes). /docs renders the
index directly; standalone 404 without the tailwind CDN.
Tests: navigation routing/expansion (internal/docs), render pins asserting no
login form/password field/app sidebar ever return on docs pages.
lint-rendering: exempt *.test.ts fixtures (jsdom DOM building); docs.ts
baseline 5 -> 1.
- Removed ~400 lines of inline JavaScript from docs.templ
- Moved toggleSection function to docs.ts (now uses Alpine )
- Added highlightCurrentPage function to docs.ts
- Added initializeCodeCopyButtons function to docs.ts
- Updated template to use x-init for initialization
- Functions exported for use in Alpine.data
- Remove DOMContentLoaded event listeners from analytics.ts and docs.ts
- Rely on x-init attribute in templates for page initialization
- Clean up unused exports from collections.ts Alpine data
- Add x-init calls to admin_library, analytics, and docs templates
- Normalize quote style in collections WebSocket script (single to double)
- Disable Add Books button in collection detail (pending implementation)
- Wrap all Alpine.data() object literals in arrow functions (() => ({}))
- This fixes "n.bind is not a function" errors when Alpine initializes components
- Alpine.data() requires a factory function, not a plain object
- Ensures each component instance gets its own closure and proper this binding
Fixed 24 TypeScript files:
- admin.ts, analytics.ts, api.ts, api-explorer-docs.ts
- bookshelf.ts, collection-rules.ts, collections.ts, conflicts.ts
- device-management.ts, docs.ts, header.ts, index.ts
- library.ts, linking.ts, login.ts, password_validation.ts
- profile-modal.ts, profile.ts, queue.ts, register.ts
- search.ts, theme.ts, toast-error.ts, toast.ts, unlinked_books.ts
Before: Alpine.data("name", { method1, method2 })
After: Alpine.data("name", () => ({ method1, method2 }))
This is a critical fix for Alpine.js v3+ where components must be
registered as factory functions to ensure proper reactivity and
prevent binding errors during initialization.
- dashboard.templ: Replaced individual script tags with single main.js import
- admin_users.templ, custom_section.templ: Minor formatting/cleanup
- docs.templ: Updated script imports (excluded from Alpine conversion per user request)
- api.ts, docs.ts, password_validation.ts: Minor updates for compatibility
Features:
- Complete dashboard redesign with improved UI components and layout
- Implement custom section builder for personalized book organization
- Add new events tracking system for user interactions
- Enhance search functionality with better static search.js
- Update TypeScript type definitions for API responses
Backend:
- Update Go dependencies in go.mod
- Add new frontend routes in router
Templates:
- Update admin and dashboard templates with new components
Frontend:
- Refactor analytics, collections, conflicts, and queue modules
- Add new documentation features in docs.ts
- Implement linking between books and collections
- Add toast notifications for user feedback
- Include placeholder book SVG asset
This commit consolidates multiple feature additions and improvements
across the entire stack including backend, templates, and frontend.