Skip to content

Add Captain's Bridge — novel doc reading experience#41

Merged
nomadicmehul merged 4 commits intomainfrom
feature/captains-bridge-reader
Apr 14, 2026
Merged

Add Captain's Bridge — novel doc reading experience#41
nomadicmehul merged 4 commits intomainfrom
feature/captains-bridge-reader

Conversation

@nomadicmehul
Copy link
Copy Markdown
Owner

Summary

Introduces Captain's Bridge — a purpose-built doc reading layout that replaces Docusaurus's stock three-column row with a CSS-Grid canvas tailored for learning content. Ships as the default reading mode for all doc pages, with a one-click toggle back to the classic Docusaurus layout remembered per-browser.

Four commits, each reviewable independently:

# Commit What it does
1 45d4fc6 v1 — layered overlay (telemetry strip, right rail, bottom console, keyboard shortcuts, focus mode, localStorage read state, help modal).
2 9baf119 v2 — full DocItem/Layout replacement via eject-swizzle. Pure CSS Grid. Adds chapter cards (per-H2 progress bubble + ETA + auto-difficulty), reading gutter (left ribbon), resume banner, mark-section-complete buttons.
3 0aa4d98 Polish — completion toast with particle burst, cross-page sidebar progress dots (SidebarSpine), download-all-commands-as-.sh, tuned chapter card density.
4 0dfc2ba Trim — drop the under-performing "Concepts" tab; rail now has just Contents + Commands.

What users see

  • Sticky telemetry strip⚓ BRIDGE | progress 47% | section 04/12 | eta 6 min plus focus / rail / ? / classic buttons.
  • Left reading gutter — thin 2px ribbon fills green→cyan as you scroll; H2 markers appear as dots (click to jump, green when read).
  • Centered article (max 860px) with chapter cards before every H2 and a "✓ Mark section complete" button at the end of each section.
  • Right rail with two tabs:
    • Contents — headings with per-section read checkmarks (localStorage per URL).
    • Commands — CLI lines auto-extracted from code blocks with one-click copy, plus ⬇ .sh download (generates a runnable #!/usr/bin/env bash script with header, set -euo pipefail, and each command labelled by detected language) and ⎘ all copy-all.
  • Bottom console — vim-style shortcuts (j k gg G f t m n p / ? Esc), read counter (N/M read), prev/next doc, help.
  • Resume banner — appears when partial progress exists; "Jump to §X" link with visual progress bar.
  • Focus mode (f) — dims all paragraphs except the one at viewport center; scroll-tracked via requestAnimationFrame. Respects prefers-reduced-motion.
  • Sidebar spine — every doc link in the left nav gets a progress dot ( partial, complete) based on localStorage state. Live-updates across tabs via storage event + in-tab via a cc-bridge-read-change CustomEvent.
  • Completion toast🎉 <section> complete — 4/12 gradient pill with 5-particle CSS burst. 🏁 Page complete on the final section.
  • Classic toggle — one click falls back to stock Docusaurus; a FAB re-enables. Preference persists.
  • Keyboard help (?) — modal listing every shortcut.

Architecture

Swizzle-ejected theme/DocItem/Layout. The layout picks between:

  • BridgeLayout (default) — CSS Grid with five regions: header / gutter / main / rail / footer-console. Consumes unswizzled sub-components (DocItemContent, DocItemFooter, DocItemPaginator, DocBreadcrumbs, DocVersionBanner, ContentVisibility) so markdown, MDX, admonitions, mermaid, and every content plugin continue to work unchanged.
  • ClassicLayout (fallback) — verbatim stock Docusaurus layout. SSR also renders this to avoid hydration flash and to give search engines stable markup; BrowserOnly swaps to Bridge client-side.

Key hooks

  • useScrollProgress — computes active heading + progress % + ETA, rAF-throttled.
  • useExtractors — scans code blocks for CLI commands by language + keyword heuristics (kubectl, docker, terraform, helm, git, aws, az, gcloud, etc.).
  • useReadProgress — localStorage-backed {readSections, totalSections, lastUpdated} per pathname. Emits a window-scoped cc-bridge-read-change CustomEvent on every write so SidebarSpine updates without a tab switch. Exports getAllReadEntries() for cross-page aggregation.

Chapter enhancements

ChapterEnhancements.tsx traverses the post-rendered DOM and injects invisible host <div>s before each H2 + after the last block of each H2 section. React portals then render the chapter card and mark-complete button into those hosts — the markdown itself is never mutated, so hot-reload and MDX compilation are unaffected.

Difficulty heuristic

Per-section auto-classified from code-block density + inline-code count + word length:

score = codeBlocks × 2 + inlineCodes × 0.15 + words / 400
score < 4  → beginner ●○○
score < 10 → intermediate ●●○
else       → advanced ●●●

Tune weights in ChapterEnhancements.tsx.

Persistence keys

Key What
cloudcaptain.bridge.enabled Bridge on/off (global)
cloudcaptain.bridge.focus Focus mode
cloudcaptain.bridge.rail Rail open
cloudcaptain.bridge.railTab Active tab (contents or commands)
cloudcaptain.bridge.read.{pathname} {readSections, totalSections, lastUpdated}

Trade-offs

  • Ejected swizzleDocItem/Layout upstream changes won't auto-merge into the custom branch; ClassicLayout.tsx remains a verbatim copy for diffing on major Docusaurus bumps. DocItem/Layout changes roughly twice a year in upstream.
  • Desktop-first — rail hides under 996px, gutter hides under 768px. Mobile reading is prose-only + console; full feature surface is tuned for ≥1100px.
  • No new dependencies — pure React + CSS. No zustand, no framer, no hotkeys lib.
  • Dark aesthetic even in light mode — intentional "mission control" feel that signals Bridge is a distinct mode. Classic fallback respects light/dark normally.

Test plan

  • Open a long doc (e.g. /docs/tools/docker/fundamentals) — telemetry strip renders at top, gutter fills as you scroll, chapter cards appear above every H2, rail populates Contents + Commands.
  • Click "✓ Mark section complete" — chapter bubble fills, rail entry gets checkmark, gutter dot turns green, console counter ticks up, toast fires.
  • Refresh page — read state persists, Resume banner appears with "Jump to §X" link.
  • Complete all sections — final toast shows "🏁 Page complete".
  • Navigate between docs via sidebar — partial/complete dots appear next to previously-read pages.
  • Open site in second tab, complete a section there — first tab's sidebar updates automatically.
  • Keyboard: j / k / gg / G scrolling, f focus, t rail toggle, m mark read, n / p prev/next doc, / search focus, ? help.
  • Commands tab: ⬇ .sh downloads a runnable script; ⎘ all copies to clipboard.
  • Click classic in telemetry — layout falls back to stock Docusaurus; FAB re-enables Bridge.
  • Resize to 900px wide — rail hides, gutter stays, console compresses; below 768px, gutter hides too.
  • prefers-reduced-motion — focus mode + toast burst degrade to linear fade.
  • npm run build in website/ — passes with no new warnings introduced by this branch.

Files

website/src/theme/DocItem/Layout/
  index.tsx                        (ejected; delegates to BridgeLayout / ClassicLayout)
  styles.module.css                (stock Docusaurus styles, used by ClassicLayout)

website/src/components/CaptainsBridge/
  BridgeLayout.tsx                 (grid orchestrator, state, keyboard)
  ClassicLayout.tsx                (verbatim Docusaurus fallback)
  BridgeTelemetry.tsx              (sticky top strip)
  BridgeRail.tsx                   (right rail: Contents + Commands + .sh download)
  BridgeConsole.tsx                (bottom keyboard bar)
  BridgeHelp.tsx                   (shortcuts modal)
  BridgeGutter.tsx                 (left reading ribbon)
  ResumeBanner.tsx                 (top banner for partial progress)
  ChapterEnhancements.tsx          (per-H2 cards + mark-complete buttons via portals)
  CompletionToast.tsx              (celebratory pill + particle burst)
  SidebarSpine.tsx                 (cross-page progress dots on sidebar links)
  useScrollProgress.ts             (scroll → progress/section/ETA)
  useExtractors.ts                 (DOM → CLI commands)
  useReadProgress.ts               (localStorage read state + cross-tab sync)
  styles.module.css                (all Bridge styling)

website/src/css/custom.css         (focus-mode paragraph dimming only)

Not in this PR

  • Lab pane / live sandbox integration → see stacked branch feature/learn-lab-split.
  • Cross-learning-path /progress page.
  • WebVM / Pyodide in-page labs (Phase 3).

Introduces a brand-new doc reading layout that layers on top of Docusaurus
without replacing its DOM, keeping all existing markdown untouched.

Components (website/src/components/CaptainsBridge/):
- BridgeTelemetry:   sticky top strip with live progress %, section X/Y,
                     reading-time ETA, focus/rail/help/classic toggles.
- BridgeRail:        fixed right rail replacing stock TOC. Three tabs:
                       Contents  — headings with per-section read checkmarks
                       Commands  — auto-extracted CLI lines (kubectl, docker,
                                   terraform, helm, aws, az, gcloud, ansible,
                                   git, hcl, yaml, dockerfile…) with one-click copy
                       Concepts  — auto-extracted inline-code + bold terms with
                                   mention counts, linked to first occurrence
- BridgeConsole:     fixed bottom console exposing vim-style shortcuts,
                     mark-read button, prev/next doc, read counter.
- BridgeHelp:        modal overlay listing all shortcuts.
- Focus mode:        dims all paragraphs except the one at viewport center,
                     iA Writer-style, via scroll-synced class toggling.

Hooks:
- useScrollProgress: computes progress, active heading, reading-time ETA.
- useExtractors:     scans article DOM for CLI commands and key concepts.
- useReadProgress:   localStorage-backed per-page read-section state.

Keyboard shortcuts:  j/k scroll, gg/G jump, f focus, t toggle rail,
                     m mark read, n/p next/prev doc, / search, ? help, Esc.

Layout integration:
- Swizzled theme/DocItem/Layout as a --wrap, so all upstream updates still
  flow through. BrowserOnly prevents SSR issues.
- Global CSS in custom.css hides stock .theme-doc-toc-desktop when the rail
  is open, reserves 56px bottom padding for the console, and adds
  focus-mode dimming (respects prefers-reduced-motion).
- Fully responsive: rail hides under 996px, key descriptions compress
  under 600px.

Persistence:
- cloudcaptain.bridge.enabled   — Bridge on/off, FAB re-enables.
- cloudcaptain.bridge.focus     — focus mode.
- cloudcaptain.bridge.rail      — rail open/closed.
- cloudcaptain.bridge.read.{path} — read-section state per page.
Replaces the v1 layered-overlay approach (which clashed with Docusaurus's
3-column row layout) with a purpose-built CSS Grid canvas that fully owns
the doc page structure.

Architecture
- Eject-swizzled DocItem/Layout. When Bridge is enabled (default), renders
  BridgeLayout. When disabled, falls back to ClassicLayout (verbatim stock
  Docusaurus). SSR uses ClassicLayout to avoid hydration flash.
- Four-region CSS Grid: telemetry (header), gutter (left), main (center),
  rail (right). Console stays fixed. No more fixed/absolute positioning
  overlapping article content.
- Widened & centered article column (max-width 860px) for better readability.

New chapter UX
- ChapterEnhancements: traverses the article DOM post-render and injects
  host <div>s before each H2 + after the last block of each H2 section.
  React portals render chapter cards and 'Mark section complete' buttons
  into those hosts — markdown stays untouched.
- Chapter card shows: read bubble (○/●), per-section reading-time estimate
  (derived from section word count), and an auto-inferred difficulty badge
  (beginner/intermediate/advanced) computed from code-block + inline-code
  density + prose length.
- End-of-section 'Mark section complete' dashed button; toggles to solid
  green when clicked.

Reading gutter
- Thin 2px vertical ribbon on the left of the article. Fills top-down
  proportional to scroll progress. H2 markers overlaid at their relative
  position — click to jump, green when read.

Resume banner
- Appears above the article when some sections are read and some aren't.
  Shows progress count/percentage and links to the first unread section.

Files
- website/src/theme/DocItem/Layout/index.tsx      — thin delegator
- website/src/theme/DocItem/Layout/styles.module.css — stock Docusaurus styles (used by ClassicLayout)
- website/src/components/CaptainsBridge/
    BridgeLayout.tsx         — grid orchestrator, all state, keyboard shortcuts
    ClassicLayout.tsx        — stock fallback
    BridgeTelemetry.tsx      — top strip (unchanged from v1)
    BridgeRail.tsx           — right rail (unchanged from v1)
    BridgeConsole.tsx        — bottom console (unchanged from v1)
    BridgeHelp.tsx           — shortcuts modal (unchanged from v1)
    BridgeGutter.tsx         — NEW
    ResumeBanner.tsx         — NEW
    ChapterEnhancements.tsx  — NEW
    useScrollProgress.ts     — unchanged
    useExtractors.ts         — unchanged
    useReadProgress.ts       — unchanged
- website/src/css/custom.css — removed v1 layered-overlay hacks; now only
  contains focus-mode paragraph dimming
…ghter cards

CompletionToast (website/src/components/CaptainsBridge/CompletionToast.tsx)
- Fires a brief celebratory pill when a section is marked complete.
- Shows '🎉 <title> complete — N / M' or '🏁 Page complete' on final section.
- Animated particle burst (5 dots radiate out from the toast), cubic-bezier
  slide-in, fade-out over ~2.4s. Respects prefers-reduced-motion.
- Fires only on 'add' transitions in readSections (not unmarks).

SidebarSpine (website/src/components/CaptainsBridge/SidebarSpine.tsx)
- Cross-page progress dots injected into every left-sidebar doc link.
- '●' for pages where readCount >= totalSections (complete, green glow).
- '◐' for pages with partial progress (cyan glow).
- Uses MutationObserver on the sidebar so dots survive expand/collapse and
  route changes. Listens to:
    - window 'cc-bridge-read-change' (same-tab custom event, dispatched
      by useReadProgress on every write)
    - window 'storage' event (cross-tab)
    - document 'visibilitychange' (when user returns to the tab)
- Requires useReadProgress to persist totalSections alongside readSections,
  which it now does (see useReadProgress.ts update).

useReadProgress
- Now persists {readSections, totalSections, lastUpdated}.
- Exports setTotalSections() — BridgeLayout calls this whenever the scroll
  observer detects a new section count, so SidebarSpine can correctly
  classify 'complete' vs 'partial'.
- New export getAllReadEntries() scans every
  'cloudcaptain.bridge.read.*' localStorage key and returns a Map<path,
  {readCount, totalSections, lastUpdated}>. SidebarSpine consumes this.
- Writes dispatch a 'cc-bridge-read-change' CustomEvent so same-window
  listeners update without a storage event (which doesn't fire same-tab).

Commands-tab download (BridgeRail.tsx)
- New toolbar above the commands list with:
    '⬇ .sh'   — downloads a runnable bash script of all extracted commands,
                including a shebang, set -euo pipefail, a header with the
                page title / URL / timestamp, and each command labelled
                with its detected language. Filename is the slugified
                page title, e.g. 'docker-fundamentals-commands.sh'.
    '⎘ all'   — copies every command to clipboard, newline-separated.
- Shows 'N commands' counter aligned right.

Chapter card density tuning (styles.module.css)
- Replaced the full-width card with an inline left-border-only indicator:
  22px → 18px bubble, no background fill, no hover-lift. 85% opacity by
  default, 100% on hover/read. Much less intrusive, lets the heading
  remain the visual anchor.

All new features are reactive — completing a section on the current page
instantly updates the chapter card, rail entry, gutter dot, sidebar spine,
toast, and console counter in one frame.
The auto-extracted Concepts tab (bolded/inline-code terms deduped by count)
wasn't pulling its weight — most entries had count=1, truncation was ugly,
and it overlapped with Ctrl-F. Kill > half-fix.

- BridgeRail: drop the third tab. Rail now shows Contents + Commands only.
- BridgeLayout: Tab type narrowed to 'contents' | 'commands'; previously
  persisted 'concepts' preference silently migrates to 'contents'.
- useExtractors: drop extractConcepts() and the Concept type; extractor
  now returns {commands} only.
- styles.module.css: drop .railConcepts / .railConcept / .railConceptCount.
- No API/data migration needed beyond the silent tab fallback.
@nomadicmehul nomadicmehul self-assigned this Apr 13, 2026
@github-actions
Copy link
Copy Markdown

🚀 Preview Deployment

Your changes have been deployed to a preview URL:

https://cloudcaptain-pr-41.surge.sh

This preview will be updated on every push to this PR.


Deployed by GitHub Actions

@nomadicmehul nomadicmehul merged commit 500224d into main Apr 14, 2026
4 checks passed
@nomadicmehul nomadicmehul deleted the feature/captains-bridge-reader branch April 14, 2026 11:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant