Kingdom.md — Navigation design
Design for the file-tree navigation, focused on staying usable at arbitrary nesting depth, across the desktop sidebar and the mobile drawer. Brainstormed 2026-06-16, then validated and revised by prototyping. Read-only viewer; calm Warm Editorial aesthetic.
Status: validated against the working prototype (
working/design-prototype.html). The chosen model is the inline subnav (below). The originally-brainstormed re-rooting + focus-header approach was superseded during prototyping — kept here as the decision trail. Pairs with a futurenav-plan.md.
What changed (and why): the brainstorm settled on auto-promote re-rooting — a deep folder takes over the whole sidebar and the kingdom switcher morphs into a focus-header. In the prototype that mode-shift felt jarring (the sidebar swaps out from under you, the anchor moves). The pivot: a deep folder instead opens a small inline subnav panel in place — its own breadcrumb + contents — leaving the rest of the tree visible and the kingdom switcher untouched. Same goal (arbitrary depth, no runaway indent), calmer feel.
Understanding summary
- What: how Kingdom.md's file tree behaves under arbitrary depth, on desktop (sidebar) and mobile (drawer).
- Why: indented trees degrade past ~3–4 levels (indent budget runs out, levels stop being distinguishable, deep branches sprawl). Support arbitrary nesting without presuming how deep anyone's corpus goes.
- Who: someone browsing a read-only personal markdown corpus in the viewer.
- Reuses what's built: the reading-pane breadcrumb and Cmd+K / "/" search.
- Non-goals: folder-notes (folders are never pages); encoding nav state in the URL; solving nav↔open-doc divergence for MVP.
Assumptions
- Navigating the tree/subnav is nav-only — expanding, drilling into a folder, or moving inside a subnav changes only what the sidebar shows, never the reading pane. Only clicking a file changes content. So "you are here" (open doc) and "you are looking here" (where the nav is browsing) can legitimately diverge.
- Each document already has its own URL (server-rendered Laravel routes).
- The viewer stays server-rendered Blade + minimal Alpine; tree/subnav state is client-side.
Decision log
-
Branch vs. leaf — folders are pure containers. Folders open/drill; files open; no node is ever both. Alternatives: folder-notes / split-target (a folder that's also a page). Why: a markdown corpus splits cleanly into containers (folders) and leaves (
.mdfiles); the only "landing" concept is the existing per-kingdom landing-page resolution (findLandingamongREADME.md/kingdom.md/ etc.), which is per-kingdom, not per-folder. -
Pattern — hybrid: indented tree (shallow) + inline subnav (deep). Up to a depth cap the sidebar is a normal indented tree; past it, a folder opens a contained subnav panel that navigates the deep subtree without indenting further, scrolling sideways, or disturbing the rest of the tree. Alternatives, and why not:
- Re-rooting / drill-down (re-root the whole sidebar into the deep folder; kingdom switcher becomes a focus-header) — prototyped, then rejected: the whole-sidebar takeover and the morphing anchor were a jarring mode-shift.
- Horizontal Miller columns — rejected: costs horizontal space / horizontal scroll, wrong for a narrow sidebar + reading focus. The subnav is a vertical, single-column Miller (a breadcrumb + one contents list) — Miller's unlimited depth without the sideways scroll.
- Always-on indented tree — degrades past ~4 levels. Pure drill-down — loses the overview.
-
Trigger — depth cap of 3. Folders expand/collapse inline for the first 3 levels; a folder at the cap (whose children would be a 4th level) opens its inline subnav instead of indenting. Why: guarantees indentation can never run away, at any corpus depth, with no new global UI. (The brainstorm's "auto-promote vs. explicit-focus A/B" is moot — the subnav is the mechanism.)
-
Climb-out lives inside the subnav. The subnav has its own breadcrumb header (e.g.
drafts / archive / 2024); clicking a segment climbs to that level within the panel. The kingdom switcher is never repurposed (this supersedes the brainstormed focus-header and its "up one level" fallback). Multiple deep folders can each have their own open subnav independently. -
Motion — directional slides inside the subnav. Drilling deeper slides the contents in from the right; climbing up slides them in from the left. Pure horizontal slide, no opacity fade. The subnav's first open also gets a brief fade-in. All gated to play once (on the move that triggered them), never on unrelated re-renders.
-
Sort order — folders first, then alphabetical (in both the tree and the subnav). Why: matches the conventional file-explorer expectation.
-
Breadcrumb(s) stay decoupled. There are two independent breadcrumbs that never cross-wire: the reading-pane breadcrumb tracks the open document's path (and does not drive the nav); the subnav breadcrumb is local to one deep folder's panel (drill position only). Consequence: the nav↔open-doc divergence "snap back to what I'm reading" problem is deferred for MVP (acceptable gap; recover by reopening the doc or via search).
-
Deep-linking. The URL encodes the current document only (clean per-doc routes; refresh / back / shareable links work). Tree/subnav state is ephemeral client-side state; on load the sidebar opens the path to the current doc. Why: YAGNI — no need to encode nav state in the URL.
-
Mobile — same model in the drawer. Cap 3, inline subnav, directional slides — no separate mobile nav logic. Drilling/opening a subnav keeps the drawer open; tapping a file closes it and navigates.
-
Collapse preserves the active lineage (the open doc never hides). Collapsing a folder hides its off-path direct children but keeps its on-path child — so the active file and its whole ancestor chain stay visible no matter which ancestor you collapse. Deeper folders keep their own expand/collapse state: collapsing an ancestor does not force-collapse an expanded descendant. Example: with
design-notes/planning/drafts/recursive-plan.mdopen anddraftsexpanded, collapsingplanninghidesplanning's off-path children (lens-audit.md) but keepsdraftsvisible — and sincedraftsstays expanded, its contents stay shown too. Why: you should always be able to see where you are in the tree, and collapsing should only hide what you actually collapsed. Applies identically to the inline subnav: a cap folder containing the open doc can't be collapsed away — its subnav stays revealed to the active file. Built 2026-06-17. Revised from the brainstorm's original "strip every off-path branch" to this gentler per-folder rule (honors deeper folders' own state) after it felt wrong in testing.
Final design
The model in one line: an indented tree of the kingdom's contents shown up to 3 levels deep; a folder at the cap opens an inline subnav panel in place — a self-contained breadcrumb
- single contents list — that browses the deep subtree to any depth without indenting further, scrolling sideways, or re-rooting the sidebar. The kingdom switcher never changes.
The tree (levels 0–2)
- Folders expand/collapse inline; files open the document; folders past the cap open a subnav.
- Sorted folders-first, then alphabetical. Long names ellipsis-truncate; hovering a file pops its
frontmatter (title / type / updated / tags) as a tooltip from behind the sidebar. Every row also
carries a native
titletooltip with its full name (so a truncated name is recoverable on hover; complements the frontmatter card, which shows the human title rather than the filename).
The subnav (the depth valve)
- A bounded, inset panel rendered in place under the cap folder's row; the rest of the tree continues below it.
- Breadcrumb header = the drill path within this folder; segments climb. Contents list = the current level's children (folders-first/alphabetical), vertically scrollable if tall.
- Drilling a subfolder replaces the list and extends the breadcrumb (slide from the right); climbing via the breadcrumb slides from the left. No horizontal scrolling, ever.
Highlight & divergence
- The open document is highlighted whenever it's currently visible (in the tree or an open subnav).
- Collapse never hides the open doc — collapsing any ancestor keeps the active file + its lineage visible (Decision 10). (Built 2026-06-17.)
- Browsing the nav away from the open doc is allowed (nav-only); re-syncing back is not an MVP feature.
Load & URLs
- Per-document URL = the source of truth for "what you're reading."
- On load the sidebar opens the path to the current doc (expanding ancestors / opening the relevant subnav). Tree/subnav state is client-side (Alpine), re-derived from the current doc. (The prototype starts at the kingdom root for demo purposes; the real app auto-reveals.)
Accessibility baseline (established in the prototype — Task 6 must preserve)
- Tree/subnav rows are real
<button>s (focusable, Enter/Space-activatable), not click-divs. Folder + cap rows carryaria-expanded(kept in sync on toggle); the open doc carriesaria-current="page"; decorative icons arearia-hidden; the tree<ul>is labelled. - Focus management on drill/climb (subnav). A sliding panel that moves content without moving focus is a keyboard/screen-reader dead end. When the subnav drills into a folder, focus moves into the new level (its first item, or the breadcrumb tail); when it climbs via a breadcrumb segment, focus returns there. This is the drill-down (single-column Miller) pattern's standard accessibility expectation — established here 2026-06-17 from a Miller-columns/drill-down research pass, closing a gap the prototype's purely-visual slide left open. (Pairs with: reset the panel's scroll to top on each level change, so a tall level never opens mid-scrolled.)
prefers-reduced-motionneutralizes transitions too (the furl, the caret), not just the keyframe slides.- Upgrade path (not required for MVP): the full WAI-ARIA
treepattern —role="tree"/"treeitem"with roving-tabindex + arrow-key navigation — instead of every row being its own tab stop.
Open / deferred items
- Deferred (not MVP): nav↔open-doc divergence re-sync; folder-notes; encoding tree/subnav state in the URL; auto-collapse-siblings (accordion).
- Built in Task 6 (2026-06-17): collapse preserves the active lineage (Decision 10), via the gentler per-folder rule above. Off-path siblings just hide (instant, no animation) — the fully-animated version (off-path siblings furl away while the active row stays put) remains a nice-to-have, not done.
- Tuning knobs in the prototype: the depth cap (
CAP), per-level indent, subnav max-height, slide speed/distance.
Background — deep-nav pattern taxonomy (reference)
Captured from a prior research pass (informed Decision 2):
- Indented tree — whole tree visible; degrades at 3–4 levels.
- Static rail + panel — buys ~one level of relief, then degrades like an indented tree.
- Recursive drill-down / re-rooting — unlimited depth, every screen 1–2 levels deep; trade = no whole-tree view. (Brainstormed as our depth valve; superseded by the inline subnav.)
- Miller columns — unlimited depth, more ancestor context, costs horizontal space. (Our subnav is a vertical, single-column variant — Miller's depth without the sideways scroll.)
- IA red flag: routinely needing 4+ levels can mean the taxonomy itself is too deep.
Sources: boundev.ai multilevel-menu UX guide; easternstandard infinite-nesting menus; folwell.umn.edu vertical navigation; uxplanet sidebar best practices; eleken UX navigation.