Skip to content

Post-notebook polish: admin overhaul + public-site pass#37

Merged
AdaInTheLab merged 6 commits intomasterfrom
feat/post-notebook-polish
Apr 20, 2026
Merged

Post-notebook polish: admin overhaul + public-site pass#37
AdaInTheLab merged 6 commits intomasterfrom
feat/post-notebook-polish

Conversation

@AdaInTheLab
Copy link
Copy Markdown
Owner

Summary

A broad post-notebook-migration pass across the frontend. Three threads, all tied together:

  1. Retire the local /lab-notes surface now that notebook.thehumanpatternlab.com is live
  2. Rebuild the admin as Notebook + Tails workspaces with a real editor, revision history, and token revoke
  3. Polish every public-site page that was touched by the notebook migration (About, Departments, Team, Contact, legal)

Companion API work: AdaInTheLab/lab-api#28 adds the author_name / author_kind / tags persistence and revision history endpoints this PR consumes.

Changes by commit

🌉 ui: rename relay info box to "Liminal Bridge" (8a3ba5b)

Terminology consistency — the relay system is now called the Liminal Bridge everywhere.

📝 content: retire /lab-notes, redirect to notebook subdomain (d5972f9)

  • Router: all four /lab-notes routes (en/ko × list/detail) redirect to notebook.thehumanpatternlab.com
  • Nav: Header / Footer / Hero lab-notes links → external "Notebook" with ExternalLink icon (Docs pill gets the icon too for consistency)
  • Home: drop RecentLabNotesPreview section
  • 14 dead files deleted (pages, components, lib/api/data, css)
  • i18n cleanup (namespace + locale files + nav keys)
  • package.json drops stale sync:labnotes script
  • .gitignore adds .claude/
  • Header + Hero tests updated for new labels

⚙️ feat: wire Home widgets to live data (YouTube + Emotional Weather) (f08fde7)

  • fetchYouTube.js now pulls durations via a second videos?part=contentDetails call; ISO-8601 → H:MM:SS/M:SS
  • data/videos.ts reads from the generated youtube.json (committed; deploys don't need the API key)
  • Video pages drop fake categories, sort newest-first, conditionally render category/duration/published
  • New weatherReportLoader.ts parses the latest src/weather-report/*.md into an EmotionalWeatherSignal; EmotionalWeatherCard now defaults to the latest parsed report
  • tsconfig.json gets resolveJsonModule: true

⚙️ feat: admin overhaul (1cc86e2)

The big one. Details in the commit body, but the shape:

  • Type-scoped workspaces/admin/notebook (scoped AdminNotesPage wrapper) + new /admin/tails with its own lean form requiring author_name
  • Drawer editor — new Drawer component (right-side slide-in portal, Esc/backdrop close with optional dirty-check veto). Replaces the always-on form. AdminSystemRail removed from AdminLayout
  • Cards list — new NoteCard replaces the DB-table list view; status pills, type/dept/locale badges, excerpt, author + tags footer, inline delete confirm
  • Real markdown editor — new MarkdownEditor backed by CodeMirror 6 (@uiw/react-codemirror + @codemirror/lang-markdown + @codemirror/theme-one-dark). Toolbar dispatches CM6 transactions; Write/Preview tabs; Mod-B/I/K/E shortcuts. Lazy-loaded via MarkdownEditor.lazy.tsx so non-admin users don't pay the ~258 KB gzipped cost. vite.config.js gets a markdown manualChunk
  • Editor ergonomicsToast system replaces every alert(); slugify auto-generates slug from title (until manually edited); Cmd/Ctrl+S submits the drawer form; dirty-state tracking surfaces an "Unsaved" chip + blocks close via beforeunload + window.confirm()
  • Revision history — new RevisionHistory component inside the editor drawer; reads the two new lab-api endpoints; source-colored badges, current/published pills, lazy per-revision content fetch with cache
  • Tokens revokeAdminTokensPage gets a proper Revoke action with inline confirm + toast + status pill

🔧 refactor: fix pre-existing TS errors + extract mascot metadata (e4aac6d)

  • New src/data/mascotMeta.ts — single source of truth for mascot emoji, name, avatar path, and labteam profile slug (emoji + name were previously duplicated and drifting between DepartmentCard and DepartmentDetailPage)
  • LabTeamPage drops an invalid onClick prop on LabMemberCard (LabMemberCard already has its own internal "View profile →" Link)

🎨 style: public-site polish pass (48fc59e)

  • About: founders now pull from labTeam (real avatars + aura glow + link to profile); "Lead Human Pattern Analyst" → Cognitive Fox Ada; "See the full team →"; Philosophy grid gets lucide icons (Waves / Compass / Smile / PawPrint / Bot / Feather); 7 stacked text sections → 5; Lab mantra promoted to sticky aside
  • Departments: DepartmentCard is now a Link to the detail page with real mascot avatar; mascot name is a Link to /labteam/:slug; filter bar dropped (each mascot had exactly one department — the filter was pick-10-see-1); test updated for new structure
  • DepartmentDetail: wrapped in LayoutShell (was rendering outside, content ran flush-left); big mascot callout with aura glow linking to the profile; filler paragraph dropped; related-work section tightened
  • LabMemberDetail: duplicated name header removed; big avatar with aura; new "Home department" callout linking to the department they lead (reverse-lookup via mascotProfileSlug)
  • Contact: required fields marked with * + required/aria-required + autoComplete; labels wired via id/htmlFor (were unlinked); validation vs send-error messages split; "Notebook entry" topic added; stale "Lab Notes" bullet updated
  • Privacy: was rendering its own <main> with text-gray-* tokens (body text nearly invisible on the dark theme). Now in LayoutShell with slate-* tokens; H2 emojis dropped for consistency with the Content Use page; "upcoming Analytics Opt-Out Toggle" TODO replaced with a real alternative
  • Content Use: 3 stale "Lab Notes" references → "notebook entries"

Testing

  • npx tsc --noEmit — clean
  • npx vitest run — 38/38 tests pass
  • npx vite build — green; bundle hygiene: main index.js stays ~132 KB gzipped, CodeMirror + preview live in a separate 258 KB chunk that only loads when the editor is rendered
  • Pre-commit hook ran tests on every commit

Breaking changes

None for site users. For admin users: /admin/notes still works as before (now relabeled "All Notes" in the nav) — the new /admin/notebook and /admin/tails are additive.

Related

  • Depends on lab-api#28 for the author + tags persistence and revision history endpoints

Co-authored-by: Sage sage@thehumanpatternlab.com

AdaInTheLab and others added 6 commits April 19, 2026 20:44
Cosmetic update to match the terminology pass the rest of the stack
already went through (lab-api + RELAY_IMPLEMENTATION.md). The single-use
relay URL system is now consistently called the Liminal Bridge
everywhere.

- "🏛️ About Relay URLs" → "🌉 About Liminal Bridge"

Co-authored-by: Sage <sage@thehumanpatternlab.com>
Long-form lab notes now live at notebook.thehumanpatternlab.com. The
public marketing site no longer needs a local lab-notes surface —
everything redirects to the subdomain and the dead code is removed.

Changes:
- Router: all four /lab-notes routes (en/ko × list/detail) now render
  a NotebookRedirect component that window.location.replaces to the
  subdomain
- Nav: Header "Lab Notes" pill → "Notebook" external + ExternalLink
  icon (same pattern for the existing "Docs" external item so external
  linking is visually consistent)
- Footer "Lab Notes" link → external "Notebook" with icon
- Hero CTA "View Lab Notes" → external "Read the Notebook"
- Home: drop RecentLabNotesPreview section entirely
- Delete 14 dead files: LabNotesPage, LabNoteDetailPage, LabNoteCard +
  skeletons, RecentLabNotesPreview + css + skeleton, labNotes/notesIndex
  libs, labNotesClient, data/labNotes, data/labNote
- Delete now-empty src/components/labnotes/ directory
- i18n: drop labNotesPage namespace wiring, delete both
  pages.labNotes.json locale files, rename nav.lab-notes → nav.notebook
  (en + ko), remove sections.labNotes from pages.home (en + ko)
- .gitignore: add .claude/ (Claude memory scratch dir)
- Tests updated for the new nav + CTA labels

Co-authored-by: Sage <sage@thehumanpatternlab.com>
Two Home-page placeholders — the Emotional Weather card and the video
grid — now read from real sources instead of hand-authored stubs.

YouTube integration:
- fetchYouTube.js (run via `npm run fetch:youtube`) now fetches
  channel + uploads playlist, then makes a second contentDetails call
  to resolve ISO-8601 durations into "H:MM:SS" / "M:SS" strings
- Writes src/data/youtube.json (committed so deploys don't require the
  API key — just re-run the script when publishing a new video)
- src/data/videos.ts replaces hand-authored stubs with a shaper over
  youtube.json; first upload is marked isFeatured
- VideoCategory now optional (YouTube doesn't give us series metadata);
  dropped fake categories (Carmel's Judgment Logs, Orbson Reports)
- VideoArchivePage drops the category filter UI (each filter had one
  matching video anyway) and sorts newest-first
- VideoDetailPage + FeaturedVideo conditionally render category /
  duration / publish-date only when present
- tsconfig: enable resolveJsonModule for the youtube.json import

Emotional Weather:
- src/lib/weatherReportLoader.ts loads all src/weather-report/*.md via
  import.meta.glob, parses frontmatter + body (Summary / Temperature /
  Pressure / Wind / Precipitation / Advisory), picks the
  lexicographically latest filename and converts to an
  EmotionalWeatherSignal
- EmotionalWeatherCard now defaults to EMOTIONAL_WEATHER_LATEST with
  EMOTIONAL_WEATHER_STATIC as the fallback when no report parses

Result: the Home page widgets update when Ada publishes a new video
(+ runs the fetch) or drops a new weather-report markdown file, instead
of requiring a code change.

Co-authored-by: Sage <sage@thehumanpatternlab.com>
… revisions, revoke

Shift the admin from a single generic /admin/notes form into surfaces
that match where the content actually lives (notebook.thehumanpatternlab.com
and ironkitsune.tech/tails), and turn the editor from a schema-dump form
into something that feels like a tool.

Type-scoped workspaces:
- AdminNotesPage now accepts optional fixedType / heading / eyebrow
  props — filters the list client-side, locks the form's type field,
  customizes header copy
- New AdminNotebookPage at /admin/notebook: thin wrapper rendering
  AdminNotesPage with fixedType="labnote"
- New AdminTailsPage at /admin/tails: purpose-built lean form for
  short-form tail entries. author_name is required (matches the
  lab-api validation); drops department/shadow_density/card_style; form
  body + list both live inside the same drawer pattern as notebook
- /admin/notes stays as the "everything" power-user view
- AdminNav adds Notebook + Tails; "Lab Notes" renamed to "All Notes"

Drawer editor instead of always-on form:
- New Drawer component: right-side slide-in portal with sticky header
  + footer, Esc/backdrop/close routed through onRequestClose so pages
  can veto closing when the form is dirty; body scroll locked; focus
  restored on close
- AdminSystemRail removed from AdminLayout (disabled placeholders
  weren't earning their slot; drawer takes over the right side)
- Cards list replaces the DB-table list view; NoteCard shows status
  pill, type/dept/locale badges, title/slug, line-clamped excerpt,
  author + tags + last-edited; hover-reveal Edit/Delete with inline
  confirm (no more blocking confirm() dialog)
- "+ New Notebook" / "+ New Tail" buttons in the page header open the
  drawer with a blank form; cards open with the record loaded;
  successful save closes the drawer and refreshes the list

Real markdown editor:
- New MarkdownEditor component backed by @uiw/react-codemirror with
  markdown language support + one-dark theme tinted to the zinc/cyan
  palette; live-rendered preview uses react-markdown + remark-gfm
- Toolbar dispatches CM6 transactions so Bold/Italic/Link/Code/
  Heading/Quote/Bullet/Numbered list respect the current selection
- Keymap at Prec.highest: Mod-B, Mod-I, Mod-K (link), Mod-E (code)
- Tab-based Write / Preview switcher; Esc from preview returns to Write
- MarkdownEditor.lazy.tsx wraps the real editor in React.lazy +
  Suspense so non-admin users don't pay the ~258 KB gzipped cost
- vite.config.js: new "markdown" manualChunk bundles
  @uiw/react-codemirror + @codemirror/* + react-markdown + remark-gfm
  together so the chunk is cacheable independently of the main bundle

Editor ergonomics:
- Toast system (Toast.tsx + useToast hook) with success/error/info
  variants, mounted at AdminLayout; replaces all alert() calls
- slugify util auto-generates slug from title while the slug hasn't
  been manually edited and the note is new
- Cmd/Ctrl+S inside the drawer requestSubmit()s the form
- Dirty-state tracking (form vs baseline snapshot) surfaces an
  "Unsaved" chip in the drawer header + blocks accidental closes
  via beforeunload + an explicit confirm()

Revision history viewer:
- New RevisionHistory component inside the editor drawer (only when
  editing an existing record) — collapsible panel, lazy-loads
  revision list + per-revision detail via the lab-api endpoints
- Source-colored badges (web / cli / api / import), current +
  published pills, timestamp, byte size; click a revision to expand
  the full content (cached per-id)
- refreshKey bumps on successful save to reload history inline

Tokens revoke UI:
- AdminTokensPage got a proper Revoke action per active row — inline
  confirm (Confirm / Cancel), disabled state while revoking, toast on
  success. Scopes rendered as chips; status shown as pill
  (active / revoked with strikethrough label)
- Uses the existing POST /admin/tokens/:id/revoke endpoint (soft
  revoke — preserves audit trail)

New deps:
- @uiw/react-codemirror, @codemirror/lang-markdown,
  @codemirror/theme-one-dark

Co-authored-by: Sage <sage@thehumanpatternlab.com>
Three long-standing TS errors were blocking a clean typecheck. While
fixing them, consolidate the mascot display data that was drifting
between DepartmentCard and DepartmentDetailPage into one shared
module — which the Departments + About + LabMember detail work builds
on.

Changes:
- New src/data/mascotMeta.ts — single source of truth for mascot
  emoji, display name, avatar image path, and labteam profile slug
  keyed by MascotId. Previously the emoji+name maps were duplicated
  (and drifting) between DepartmentCard and DepartmentDetailPage
- LabTeamPage: drop invalid onClick prop + unused useNavigate import
  (LabMemberCard already has its own "View profile →" Link internally,
  so the duplicate onClick was both a TS error and redundant nav)

(DepartmentDetailPage + LabMemberDetailPage prop-name fixes and the
DepartmentCard consumption of mascotMeta land alongside the rest of
the polish rewrites in the next commit.)

Co-authored-by: Sage <sage@thehumanpatternlab.com>
…legal)

Full pass over the public surfaces now that the notebook migration is
done. Goal was coherence: every page uses LayoutShell, mascot
visuals come from the shared labTeam data, dark-theme tokens apply
everywhere, and dead-end flows get a real outbound link.

About:
- Founders section now pulls from labTeam (by id: ada, orbson,
  carmel, mcchonk) with real avatars + aura glow, each card a Link
  to the member's profile
- "Lead Human Pattern Analyst" anonymization → Cognitive Fox Ada
- "See the full team →" link under the grid; "Meet the Lab Team"
  added to the bottom CTA
- Philosophy grid items got lucide icons (Waves / Compass / Smile /
  PawPrint / Bot / Feather) in tinted cyan squares
- 7 stacked text sections → 5: Mission + "Where science meets
  creatures" + "Why chaos is data" collapsed into one "Why chaos is
  data" beat; the Lab mantra got promoted to a sticky aside next to
  the Philosophy grid

Departments:
- DepartmentCard: whole header + body is now a Link to
  /departments/:id; emoji gradient circle replaced with the real
  mascot avatar from mascotMeta; "Mascot: Name" in the footer is a
  Link to /labteam/:slug
- DepartmentsPage: dropped the filter bar (each mascot owned exactly
  one department — filter was really "pick one of 10 to see 1")
- DepartmentCard.test.tsx updated: wraps in MemoryRouter, asserts on
  avatar alt-text + link destinations (was checking emoji text)

Department detail:
- Was rendering outside LayoutShell — content ran flush-left past
  the centered container. Wrapped properly now
- Big mascot callout with aura glow (pulled from labTeam member's
  aura), links to the mascot's /labteam profile
- Dropped the "This department works closely with..." filler
  paragraph that appeared on every detail page
- "Related work" section tightened: no more "in the future, this
  section can..." placeholder, direct pointers to Notebook + Video
  Archive

Lab member detail:
- Dropped the duplicated header (LayoutShell was rendering name +
  title up top, card below was re-rendering the same)
- Big aura avatar (avatarSrc + radial glow in the member's primary
  aura color) instead of the small emoji-in-tile
- New "Home department" callout: if the mascot leads a department,
  linked card to /departments/:id (reverse-lookup via mascotProfileSlug)
- Lore & Documentation links get the consistent ExternalLink icon

Contact:
- Required fields marked with red * + required/aria-required
  attributes + autoComplete hints so browsers validate before submit
  and offer autofill
- Labels wired to inputs via id/htmlFor (was fully missing)
- Status is now a discriminated union; validation errors list the
  specific missing field(s); send-errors are separate and mention
  the direct-email fallback
- New "Notebook entry" topic option; right-rail "Lab Notes" bullet
  updated to "notebook entries"
- Send button gets a lucide Send icon

Privacy Policy:
- Was rendering its own <main> with text-gray-* tokens on a dark
  site — body text was nearly invisible. Now inside LayoutShell
  using slate-* / cyan-* tokens consistent with the rest of the site
- Dropped the H2 emojis (ContentUsePolicy has none — was jarring)
- Replaced "upcoming Analytics Opt-Out Toggle" promise (a TODO
  shipped live) with a real alternative: browser tracking protection
  / "Do Not Track"

Content Use Policy: three stale "Lab Notes" references → "notebook
entries".

Co-authored-by: Sage <sage@thehumanpatternlab.com>
@github-actions
Copy link
Copy Markdown

😼📘 Carmel Epistemic Stamp™

📘 Carmel Epistemic Stamp™
😼📘💬 "Your logic is sound… shockingly."

PR: #37Post-notebook polish: admin overhaul + public-site pass
Author: @AdaInTheLab

This automated judgment has been issued by the Chief Judgment Office (CJO).

@AdaInTheLab AdaInTheLab merged commit cec211d into master Apr 20, 2026
3 checks passed
@AdaInTheLab AdaInTheLab deleted the feat/post-notebook-polish branch April 20, 2026 00:54
@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 71.69811% with 15 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/lib/weatherReportLoader.ts 66.66% 2 Missing and 13 partials ⚠️

📢 Thoughts on this report? Let us know!

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.

2 participants