Skip to content

Modernize UI/UX (tracking: post-Tailwind-v4 work) #632

@srid

Description

@srid

Tracking issue for the visual + UX modernization work that follows the Tailwind v4 migration. Split out deliberately so the v4 migration lands and stabilizes in isolation — regressions there should be attributable to the tokens change, not bundled with redesign.

1. Visual refresh

  • Spacing, typography, sidebar density pass on the existing layouts in emanote/default/templates/.
  • Native <details>-based collapsible sidebar, replacing the toggleHidden() inline script in components/breadcrumbs.tpl:41-45 and the Heist-conditional expand/collapse in components/sidebar-tree.tpl:83 (existing TODO). This is genuine JS elimination.
  • TOC scroll tracking (components/toc.tpl:21-73, existing TODO "We should get rid of JavaScript!" — issue Render TOC without JavaScript #520): swap window.onscroll + offsetTop arithmetic for IntersectionObserver. This improves the JS, it doesn't eliminate it — see section 3 below for the module boundary.
  • Proper mobile sidebar drawer (overlay, scroll-lock, focus trap). Current mobile UX is a class-toggle, not really a drawer.
  • Icon partial: consolidate the copy-pasted inline heroicon SVGs in sidebar.tpl, breadcrumbs.tpl, toc.tpl, etc. into a single reusable Heist partial.

4. UX features

  • Command palette (Ctrl+K already opens Stork search; extend to actions: jump-to-tag, jump-to-recent, toggle sidebar, toggle theme).
  • Keyboard navigation through the sidebar route tree (arrow keys, Enter to open).
  • Recently-viewed notes (localStorage), surfaced in sidebar or command palette.
  • Better empty states (no results, empty folder, no backlinks).
  • Proper 404 page design (currently uses special/error.tpl).

3. JS module boundary (blocks section 4)

Decide before section 4 starts, not during. Section 4 features need non-trivial JS. To avoid proliferating inline <script> blocks that accrete across templates, commit to a module boundary upfront:

  • All interactive JS lives in one bundled file loaded once from _emanote-static/, not inlined across templates.
  • Templates expose state via data-* attributes; JS reads them. No Heist-spliced JS values.
  • Library choice: Alpine.js (declarative, minimal, ~15kb) vs. vanilla Web Components (zero deps, more boilerplate) vs. plain vanilla with a small helper module. Decide as part of scoping section 4.

Existing inline scripts to consolidate under the new module: stork search controller in components/stork/stork-search-head.tpl:17-99, code-copy-button injection in components/styles.tpl:160-198, TOC tracker in components/toc.tpl.

Sequencing

  1. Section 1 lands first on top of v4 (visible but orthogonal to behavior).
  2. Decide JS module boundary (section 3 scoping).
  3. Section 4 features built on the decided boundary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions