Skip to content

Add /progress dashboard + homepage Resume Reading widget#42

Merged
nomadicmehul merged 3 commits intomainfrom
feature/progress-page-stacked
Apr 14, 2026
Merged

Add /progress dashboard + homepage Resume Reading widget#42
nomadicmehul merged 3 commits intomainfrom
feature/progress-page-stacked

Conversation

@nomadicmehul
Copy link
Copy Markdown
Owner

Summary

Adds a top-level /progress dashboard and a "Resume Reading" widget on the homepage, both powered by the same localStorage data that Captain's Bridge writes when users mark sections complete.

Stacked on top of PR #41 (feature/captains-bridge-reader). Targets that branch as its base, so this PR's diff reads as the pure Progress feature — no Bridge noise. When #41 merges to main, retarget this PR's base to main (GitHub offers one click) and no rebase is needed.

What this ships

/progress page

  • Hero — four stat cards: sections read, pages touched, pages complete, last active (relative + absolute timestamp).
  • By Category — expandable groups for every learning path, tool, and cloud provider detected in the doc tree. Each group shows a dual progress bar (touched vs complete). Click to reveal every doc with status dot / / , title, and N/M counter.
  • Empty state — clean CTA block when no progress exists, with links to DevOps path + Docker start.
  • Manage — four control cards:
    • ⬇ Export — downloads cloudcaptain-progress-YYYY-MM-DD.json
    • ⬆ Import — merge or replace from a previously exported file
    • 🪄 Seed demo data — fills 8 sample entries spread over the last 10 days for demos / screenshots; reversible via "Remove demo data"
    • ↻ Reset — requires user to type DELETE to confirm
  • Live updates via cc-bridge-read-change (same-tab) and storage (cross-tab) events.
  • Footer link and new navbar link 📖 Progress for discoverability.

Homepage Resume Reading widget

  • ⚓ CAPTAIN'S LOG — Resume where you left off card, slotted between the hero and stats sections.
  • Top 3 in-progress docs (readCount > 0 && !isComplete), sorted by most-recently-updated.
  • Each row: title, N / M progress, relative time (2h ago), animated bar, doc path, Continue →.
  • Renders nothing when there's no partial progress, so first-time visitors see an unchanged hero+stats flow.
  • Wrapped in BrowserOnly — SSR is unaffected.

Architecture

localStorage  (written by Bridge's useReadProgress)
  cloudcaptain.bridge.read./docs/tools/docker/fundamentals = {
    readSections: ["what-is-docker", "containers-vs-vms"],
    totalSections: 8,
    lastUpdated: 1713028347000
  }
        │
        ▼
  getAllReadEntries()           ←  readProgress.ts (duplicates Bridge contract)
        │
        ▼
  useAllDocsData()              ←  Docusaurus plugin-content-docs client API
  (full doc tree + titles)
        │
        ▼
  classifyDoc(pathname)         ←  groupDocs.ts (regex → category + icon)
        │
        ▼
  ┌────────────────────┬────────────────────────┐
  │  /progress         │  homepage widget       │
  │  ProgressHero      │  ResumeReadingWidget   │
  │  ProgressByTool    │                        │
  │  ProgressControls  │                        │
  └────────────────────┴────────────────────────┘

Files added

website/src/pages/progress.tsx                                 (top-level page, SSR-safe)
website/src/components/Progress/
  ProgressHero.tsx              (four stat cards)
  ProgressByTool.tsx            (expandable category groups + dual progress bars)
  ProgressControls.tsx          (export / import / seed / reset, typed DELETE)
  ResumeReadingWidget.tsx       (homepage "Captain's Log" card)
  readProgress.ts               (localStorage reader / writer / export / import)
  groupDocs.ts                  (pathname → category matcher, ordered)
  seedDemo.ts                   (8 synthetic entries, reversible)
  styles.module.css             (dashboard styles)
  resumeWidget.module.css       (homepage widget styles)

website/src/pages/index.tsx     (wires BrowserOnly<ResumeReadingWidget />)
website/docusaurus.config.ts    (navbar + footer links)

Design notes

  • Client-only. No backend. No new npm dependencies. Everything runs in the browser.
  • Privacy first. Progress stays in localStorage; the page surfaces this in a footer note and on the Reset card. Export provides user-owned backup; there's no telemetry.
  • SSR safe. Every component that touches localStorage is gated by BrowserOnly or checks typeof localStorage. A minimal SSR skeleton renders on first paint and the real dashboard hydrates client-side.
  • Schema contract with Bridge. readProgress.ts duplicates the 20-line localStorage helper that lives inside the Bridge feature (useReadProgress.getAllReadEntries). This duplication is intentional — it keeps the two features decoupled at the source code level but honours the same cloudcaptain.bridge.read.{pathname} key schema at the data level. Refactor into a shared module is easy once both PRs merge.
  • Category grouping is centralized. groupDocs.ts holds the regex-to-category mapping with display icons and sort order — one file to update when a new tool section is added.
  • Demo seed is reversible. Seeded keys are tracked in cloudcaptain.bridge.demo-seed; unseedDemoProgress() removes only those keys. Real user progress is never clobbered (seeder refuses to overwrite entries with non-zero readCount).

Test plan

  • npm run build in website/ passes — no new warnings from this branch
  • Navigate to /progress
    • Empty state renders with CTA block when localStorage is clean
    • Click 🪄 Seed demo data — hero stats + groups populate instantly, 8 entries across Docker/K8s/Terraform/Linux/Git/DevOps
    • Expand any group — every doc appears with correct status dot
    • Click any doc link — navigates
  • Complete a real section via Bridge's m key on a tool page → dashboard live-updates without refresh
  • Open site in second tab, complete a section there → first tab's dashboard updates via storage event
  • ⬇ Export — downloads valid JSON (version:1, entries map)
  • ⬆ Import → Merge — adds entries without clobbering
  • ⬆ Import → Replace all — wipes then imports
  • ↻ Reset — requires typed DELETE confirmation; clears localStorage
  • 🪄 Seed demo dataRemove demo data — clean round-trip
  • Homepage — with progress seeded, "Captain's Log" card appears between hero and stats
    • Shows top 3 in-progress docs
    • Progress bars match stored readCount / totalSections
    • "View all progress →" → /progress
    • Each row navigates to the doc
  • Homepage — with progress cleared, widget does NOT render (clean hero+stats flow)
  • Navbar 📖 Progress link visible and routes correctly
  • Footer 📖 Your Progress link routes correctly
  • Mobile viewport (< 600px) — all three views (dashboard, widget, controls) remain usable

Not in this PR

  • Calendar heatmap visualization (Phase 2).
  • Cross-device sync (requires user accounts — explicitly out of scope).
  • Learning-path grouping from careerPaths.json (different semantic model; defer).

A top-level page at /progress that aggregates the read-progress data
written by the Captain's Bridge reader and shows it as a dashboard.

Pure client-side. No backend. No new npm dependencies. Reads
localStorage keys matching `cloudcaptain.bridge.read.*` and joins them
with the full list of docs from Docusaurus's useAllDocsData() client API.

Page layout (in order)
- ProgressHero — four stat cards: sections read, pages touched,
  pages complete, last active (relative + absolute timestamp).
- Empty state — only when no entries exist; links to DevOps path +
  Docker start, plus a nudge toward the Seed Demo Data button.
- ProgressByTool — expandable groups per tool and per learning path,
  each with a two-layer progress bar (touched + complete). Click a
  group to reveal every doc with its status dot (○/◐/●), title,
  and "N/M" counter.
- ProgressControls — four cards: Export JSON, Import JSON (merge
  or replace), Seed Demo Data (reversible), Reset everything
  (requires typed "DELETE" confirmation).

Utilities (website/src/components/Progress/)
- readProgress.ts — localStorage scanner + import/export helpers.
  Duplicates Bridge's contract so the page could be ported back to a
  main-based branch if needed.
- groupDocs.ts — classifies every doc pathname into a category
  (Learning paths, Docker, Kubernetes, Terraform, Ansible, Helm,
  Linux, Bash, Python, Git, YAML, AWS, Azure, GCP, Interview Prep,
  plus a generic catch-all). Display order + icon configurable.
- seedDemo.ts — seedDemoProgress() writes 8 synthetic entries
  spread across the last 10 days. Safe: refuses to clobber pages
  that already have non-zero readCount. Reversible: unseedDemoProgress()
  tracks the keys it wrote via a meta entry.

Live updates
- The page listens for 'cc-bridge-read-change' (same-tab custom event
  from useReadProgress) and 'storage' (cross-tab) and rerenders when
  read state changes. Mark a section complete in another tab and the
  dashboard updates without a manual refresh.

Privacy
- All data stays in localStorage. The page banner makes this explicit.
- Export produces a portable JSON file; Import supports merge or
  replace (replace requires re-confirmation via the Reset flow).
- Reset requires the user to type DELETE in a confirmation box and is
  irreversible.

Build-time
- No sidebar entry needed — this is a top-level page, not a doc.
- Footer gets a "📖 Your Progress" link under the "More" column so
  users can find it without needing the URL.
- useAllDocsData() returns whatever the docs plugin indexed, so the
  page automatically covers new tools as they're added to /docs/tools.

SSR
- Layout renders an SSR-safe skeleton (Loading…). The real dashboard
  mounts client-side via BrowserOnly because localStorage doesn't
  exist on the server.
Two small wins layered onto the /progress page:

Navbar link
- docusaurus.config.ts: adds "📖 Progress" between "Captain's Journey"
  and "Contribute" on the left nav. Discoverability for the dashboard
  without needing to hunt through the footer.

Homepage Resume Reading widget
- New component: website/src/components/Progress/ResumeReadingWidget.tsx
- Renders a "⚓ CAPTAIN'S LOG — Resume where you left off" card between
  the hero and stats sections of the homepage.
- Surfaces the top 3 in-progress docs (readCount > 0 AND !isComplete),
  sorted by most-recently-updated.
- Each row shows: doc title, N / M sections progress counter, relative
  time (e.g. "2h ago", "3d ago"), an animated progress bar, the doc
  path, and a "Continue →" CTA. Whole row is a Link to the doc.
- Header has "View all progress →" link to /progress.
- Joins localStorage entries with useAllDocsData() to resolve doc titles
  from Docusaurus's indexed doc list (falls back to humanized path
  segment if a title isn't found).
- Live updates via 'cc-bridge-read-change' (same-tab) and 'storage'
  (cross-tab) event listeners, matching the /progress page behaviour.
- Renders nothing when there's no partial progress, so first-time
  visitors to the homepage see an unchanged hero+stats flow.
- Wrapped in BrowserOnly at the index.tsx call site so SSR is
  unaffected (localStorage doesn't exist on the server).

New file: website/src/components/Progress/resumeWidget.module.css
  Lightweight per-widget CSS module to keep its styling isolated from
  the dashboard's styles.module.css.
The navbar had hit item-overflow with six links (Learning Paths, Tools
& Tech, Cloud Providers, Captain's Journey, Progress, Contribute) on
the left plus Sponsor/Coffee/Stars on the right. "Progress" is
personal state — it doesn't belong alongside site-structure navigation.

- docusaurus.config.ts: drop the '📖 Progress' navbar item.

Progress remains discoverable via:
  - Homepage "Captain's Log" resume widget (primary surface)
  - Footer "📖 Your Progress" link
  - Direct URL /progress
@nomadicmehul nomadicmehul self-assigned this Apr 13, 2026
Base automatically changed from feature/captains-bridge-reader to main April 14, 2026 11:48
@nomadicmehul nomadicmehul merged commit 53d4d7c into main Apr 14, 2026
@nomadicmehul nomadicmehul deleted the feature/progress-page-stacked branch April 14, 2026 12:49
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