Skip to content

[chore] Storybook coverage audit for apps/website (#2492)#2510

Merged
joshestein merged 18 commits into
masterfrom
josh/2492-update-stories
May 26, 2026
Merged

[chore] Storybook coverage audit for apps/website (#2492)#2510
joshestein merged 18 commits into
masterfrom
josh/2492-update-stories

Conversation

@joshestein

@joshestein joshestein commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Closes #2492. Adds Storybook coverage for 20 marketing/landing/courses components in apps/website that earn their keep via meaningful states, prop variants, MSW-driven data, or auth-gated render paths. Establishes a lockstep "keep stories in sync" rule in CLAUDE.md so future component changes update their stories in the same PR.

Stories added (20)

Only components where a story reveals something the live page route doesn't easily show.

  • advising/AdvisorsSection (Default + Loading via MSW)
  • career-transition-grant/GranteesSection (Default + Empty via MSW)
  • courses/UnitLayout (LoggedIn / LoggedOut / LastChunkOfUnit), FacilitatorFeedbackHeader (Default + WithRoundName)
  • grants/GranteesListSection (Default with limit / WithTitleAndSubtitle / Empty), GrantProgramCard (primary / secondary / OnHiatus emphasis)
  • incubator-week/AboutBlueDotSection (Default + NoApplicationUrl)
  • join-us/JobsListSection (Default + ContractorOnly — exercises the regular/contractor split logic)
  • lander/TestimonialCarousel (homepage / lander / WithQuotes / FewTestimonials)
  • lander/components/AlumniStoryCarousel, CaseStudiesSection, CourseBenefitsTextSection (paragraphs vs items API modes), CourseOutcomesSection (3 variants + accent colors), FieldBuildingSection (Default + Compact heading), PathwaysSection (Default + WithCallout), PrerequisitesSection (Default + WithCta), ScheduleListSection (Default / IntensiveOnly / NoRoundsFallback), SectionNav (Default + WithoutCta + scroll decorator), WhoIsThisForTextSection (paragraphs vs items)
  • programs/ProgramsList (MSW-driven per-row grant stats)

Story updated (1)

  • homepage/UpcomingRounds.stories.tsx — refreshes stale course names ("AGI Safety Fundamentals" → "AGI Strategy", "AI Safety Fundamentals: AI Governance" → "AI Governance", "AI Safety Fundamentals: Technical Alignment" → "Technical AI Safety", "Biosecurity Fundamentals" → "Biosecurity").

CLAUDE.md lockstep rule

Root CLAUDE.md and apps/website/CLAUDE.md get an add/modify/remove story-sync rule. The add rule lists three skip cases:

  1. Pure-logic/utility/admin-internal components.
  2. Components fully rendered inside an existing parent story.
  3. Pure-static marketing sections with no props, no data fetching, and no variants — the live page route is already the canonical preview.

Stories pay off when they expose multiple states (loading/empty/error), prop API surfaces (variants, emphasis levels), auth-gated render paths, or MSW-driven data variations.

What was deliberately skipped

  • Pure-static-copy sections (e.g. advising/HowItWorksSection, several incubator-week/*, join-us/CultureSection, join-us/WhyUsSection, all fieldbuilder-week/*) — single Default with hardcoded copy, no props, no MSW. Live page route is the canonical preview. Skip per rule case 3.
  • MissionsListSection, PathwaysListSection — pure PageListRow wrappers; row styling is owned by the PageListRow.stories.tsx.
  • Nav/_*.tsx — internal pieces fully rendered by Nav.stories.tsx.
  • lander/course-content/*.tsx — data factories (createXxxContent), not UI.
  • lander/CourseLander.tsx, lander/AiSafetyOpsLander.tsx — page-level orchestrators; sections covered individually.
  • courses/CourseShell, NextStepsChunk, ResourceDisplay, ResourceListItem, ListenToArticleButton — rendered inside UnitLayout.stories.tsx.
  • courses/CourseSchedule, CourseUnitsSection — rendered inside the existing CoursesPage.stories.tsx.
  • grants/grantPrograms.tsx — data file, no component.
  • community/CircleWidget.tsx — loads a 3rd-party chat script via side-effect, nothing visual.
  • /about, /settings clusters — explicitly out of scope.

MSW handler hoisting

Stories that fetch via tRPC have their happy-path handlers hoisted to meta.parameters.msw.handlers (rather than per-story parameters.msw.handlers) so the autodocs Docs page renders the same content as the Default story. Per-story handlers are used only for overrides (Empty, Loading).

Test plan

  • npm run build in apps/storybook/ succeeds
  • npm test in apps/website/ passes
  • npm run lint in apps/website/ passes
  • npx tsc --noEmit in apps/website/ clean
  • Verified Docs preview matches Default story for all MSW-driven stories

🤖 Generated with Claude Code

Add stories for ~44 marketing/landing components that had none, and add a
lockstep "keep stories in sync" rule to CLAUDE.md so future component
changes update their stories in the same PR.

Coverage added across: lander/components, lander root, courses/UnitLayout
+ FacilitatorFeedbackHeader, advising/, incubator-week/, fieldbuilder-week/,
rapid-grants/, career-transition-grant/, grants/, join-us/, missions/,
programs/. Skipped pure-data files (course-content factories, grantPrograms),
side-effect-only components (CircleWidget), and internals already
encapsulated by parent stories (Nav/_ prefixed pieces, courses sections
rendered inside CoursesPage / UnitLayout).

Also refreshes stale course names in homepage/UpcomingRounds.stories.tsx
("AGI Safety Fundamentals" -> "AGI Strategy", etc).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@joshestein

Copy link
Copy Markdown
Collaborator Author

@claude review

@claude

claude Bot commented May 19, 2026

Copy link
Copy Markdown

Claude finished @joshestein's task —— View job


Review Complete: PR #2492 Storybook Coverage Audit

Todo List

  • Review CLAUDE.md changes for the new lockstep rule
  • Sample new story files for structure and best practices
  • Check the existing story update (UpcomingRounds)
  • Analyze patterns across all new stories
  • Provide comprehensive review feedback

Overall Assessment: Excellent Work

This PR successfully adds comprehensive Storybook coverage for marketing components while establishing clear governance rules to prevent future story drift.

What's Great

📋 CLAUDE.md Governance Rules

  • Crystal-clear lockstep rule (CLAUDE.md:36-40) covering add/modify/remove scenarios
  • Proper cross-reference in apps/website/CLAUDE.md:156
  • Smart exceptions for internal components and parent-covered components

🎯 Story Quality & Consistency

  • 44 new stories follow excellent patterns across the board
  • Proper TypeScript with Meta<typeof Component> and StoryObj<typeof meta>
  • Comprehensive argTypes documentation with descriptions and controls
  • Smart use of MSW for tRPC mocking (e.g., AdvisorsSection, WhoYouAreSection)
  • Good variant coverage (Default + edge cases like Loading states, different emphases)
  • Appropriate layout settings (fullscreen for sections, padded for cards)

🔧 Technical Excellence

  • Rich mock data that demonstrates component capabilities
  • Proper component documentation via docs.description.component
  • Clean imports and exports following established patterns
  • Auth state variants where relevant (UnitLayout includes LoggedIn story)

📊 Coverage Claims Verified

  • Claims "~44 new stories" → Verified: 44 new + 3 modified = 47 files ✅
  • Total story count now 110 (significant increase from baseline)
  • Appropriate scope exclusions documented in PR body

Minor Observations

  1. UpcomingRounds Update - The PR claims to refresh "stale course names" like "AGI Safety Fundamentals" → "AGI Strategy", but the current story shows course titles like "Technical AI Safety", "AI Governance", "AGI Strategy" which appear up-to-date. The stale-name updates may have happened in a different story or been resolved differently.

  2. Consistent Naming - Story titles use varied casing patterns (website/CourseLander/TestimonialCarousel vs Website/Homepage/UpcomingRounds). Minor inconsistency but doesn't affect functionality.

  3. Mock Data Quality - Mock data is realistic and comprehensive (e.g., TestimonialCarousel has 6 diverse testimonials with proper job titles, realistic quotes, and placeholder images).

Architecture Compliance

  • ✅ Follows existing component patterns from the codebase
  • ✅ Proper tRPC mocking using MSW handlers
  • ✅ Uses realistic test data via testUtils helpers where appropriate
  • ✅ Follows layout and documentation standards
  • ✅ No unnecessary abstractions or over-engineering

Recommendation: Approve and Merge

This PR represents thoughtful, comprehensive work that significantly improves the design system's documentation while establishing sustainable governance practices. The story quality is consistently high and demonstrates deep understanding of both Storybook best practices and the codebase patterns.

The lockstep rule addition is particularly valuable - it ensures this excellent coverage doesn't decay over time as components evolve.


@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds Storybook stories for approximately 20 components across the website—covering advising, grant programmes, courses, incubator week, join-us recruitment, lander sections, and programme discovery—alongside updates to contributor guidance documenting synchronisation rules for story maintenance. The stories use typed mock data, MSW-backed tRPC query mocking, and multiple story variants to cover different rendering states (populated/empty lists, authentication variants, colour theming, optional content presence). The contributor guidance changes in both root and website-specific CLAUDE.md files establish explicit rules for adding stories when components are created, updating stories when component props change, and removing stories when components are removed.

Possibly related PRs

  • bluedotimpact/bluedot#2351: Updates the same apps/website/CLAUDE.md file with contributor instructions covering Storybook and PR-writing guidance overlap.
  • bluedotimpact/bluedot#1770: Introduced the original UpcomingRounds.stories.tsx file whose mock courseTitle strings this PR updates to current course names.
  • bluedotimpact/bluedot#2241: Adds/updates Storybook files for lander components (FieldBuildingSection, PathwaysSection) that directly correspond to component changes in that PR.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is completely missing. The author provided no description content, though the template requires explanation of changes and a developer checklist. Add a comprehensive description explaining the Storybook coverage audit objectives, list of components covered, and confirm that the developer checklist items (particularly Storybook stories consideration) have been addressed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main objective: adding Storybook coverage for marketing/landing components in the apps/website directory, directly addressing the PR's primary purpose.
Linked Issues check ✅ Passed The PR fully addresses all three objectives from issue #2492: old/outdated stories have been updated (UpcomingRounds.stories.tsx), critical missing components now have stories added (~44 new story files), and CLAUDE.md has been updated with lockstep guidance requiring stories to be maintained alongside component changes.
Out of Scope Changes check ✅ Passed All changes are scoped to Storybook coverage and CLAUDE.md guidance updates. No extraneous modifications to component implementations, business logic, or unrelated infrastructure are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch josh/2492-update-stories

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds Storybook stories for 20 previously uncovered components in apps/website and establishes a lockstep story-sync rule in both CLAUDE.md files so future component changes include story updates in the same PR.

  • 20 new story files covering advising, courses, grants, lander, and programs components — each with meaningful state variants (loading/empty, logged-in/out, prop combinations) and MSW-driven tRPC data where applicable; happy-path handlers are hoisted to meta.parameters.msw.handlers so autodocs renders correctly.
  • 1 updated story (UpcomingRounds.stories.tsx) refreshes stale course names in mock data to match current branding.
  • CLAUDE.md rule defines clear add/modify/remove criteria with three explicit skip cases, replacing the previous open-ended ask-the-user guidance.

Confidence Score: 5/5

All changes are additive Storybook story files and CLAUDE.md documentation — no production runtime code is modified.

The diff is entirely new .stories.tsx files, a one-line update to an existing story's mock data, and two CLAUDE.md edits. None of these touch production paths, database logic, API handlers, or shared utilities. MSW handler patterns follow the established repo conventions, auth helpers are used correctly, and the CLAUDE.md rule is well-scoped with clear skip criteria.

No files require special attention — all changes are isolated to Storybook fixtures and documentation.

Important Files Changed

Filename Overview
CLAUDE.md Adds a clear add/modify/remove Storybook story-sync rule with well-defined skip cases; replaces the previous softer ask-the-user language.
apps/website/CLAUDE.md Updates the single-line Storybook guidance to point at the new full sync rule in root CLAUDE.md.
apps/website/src/components/homepage/UpcomingRounds.stories.tsx Refreshes stale course names in mock data to match current branding; straightforward fixture update.
apps/website/src/components/courses/UnitLayout.stories.tsx New story covering LoggedIn / LoggedOut / LastChunkOfUnit states with MSW-hoisted handlers at meta level; allUnitChunks typed inline rather than against BasicChunk but is functional.
apps/website/src/components/grants/GranteesListSection.stories.tsx Happy-path MSW handler correctly hoisted to meta level; Default / WithTitleAndSubtitle / Empty variants cover all meaningful prop combinations.
apps/website/src/components/programs/ProgramsList.stories.tsx MSW handlers for programs.getAll and both grant-stats queries hoisted at meta level; single Default story is appropriate given single meaningful render path.
apps/website/src/components/lander/components/ScheduleListSection.stories.tsx All three stories use per-story MSW handlers since each requires a different data response; covers the full range of round-availability states.
apps/website/src/components/lander/components/CourseOutcomesSection.stories.tsx Imports real accent-color constants from course-content factories for consistent visual representation; three variants cover heading style and accent color differences.
apps/website/src/components/lander/TestimonialCarousel.stories.tsx Four stories cover homepage/lander variants, hideQuotes toggle, and few-items edge case; argTypes well documented.
apps/website/src/components/lander/components/PathwaysSection.stories.tsx WithCallout story uses JSX nodes in args with matching control: false in argTypes, correct approach for ReactNode props.
apps/website/src/components/career-transition-grant/GranteesSection.stories.tsx Default + Empty states cover both the populated grid and empty case; happy-path handler hoisted to meta level.
apps/website/src/components/join-us/JobsListSection.stories.tsx Default + ContractorOnly stories cover the regular/contractor split logic; data passed as props so no MSW needed.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    META["meta: Meta T
(title, component, tags: autodocs)"]
    META_MSW["meta.parameters.msw.handlers
(happy-path handler hoisted here)"]
    STORY_DEFAULT["Default story
(inherits meta handlers)"]
    STORY_VARIANT["Variant story
(inherits meta handlers)"]
    STORY_OVERRIDE["Empty / Loading story
(per-story handler override)"]
    AUTH["loggedOutStory / loggedInStory
spreads into meta or story"]
    DOCS["Autodocs Docs page
(renders primary story with meta handlers)"]
    META --> META_MSW
    META --> STORY_DEFAULT
    META --> STORY_VARIANT
    META --> STORY_OVERRIDE
    META --> AUTH
    META_MSW --> DOCS
    STORY_DEFAULT --> DOCS
    STORY_OVERRIDE -- overrides msw.handlers per-story --> STORY_OVERRIDE
Loading

Reviews (2): Last reviewed commit: "[chore] Drop PathwaysListSection story +..." | Re-trigger Greptile

},
];

const allUnitChunks: Record<string, { id: string; chunkTitle: string; chunkOrder: string; estimatedTime: number | null; chunkResources: string[] | null; chunkExercises: string[] | null }[]> = {};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The manual type annotation for allUnitChunks spells out a superset of BasicChunk (adding chunkResources and chunkExercises which don't exist on BasicChunk). Using the imported BasicChunk type keeps the story structurally tied to the router's actual type and avoids drift if BasicChunk ever changes.

Suggested change
const allUnitChunks: Record<string, { id: string; chunkTitle: string; chunkOrder: string; estimatedTime: number | null; chunkResources: string[] | null; chunkExercises: string[] | null }[]> = {};
const allUnitChunks: Record<string, BasicChunk[]> = {};

import { loggedInStory, loggedOutStory } from '@bluedot/ui/src/utils/storybook';
import { createMockChunk, createMockUnit } from '../../__tests__/testUtils';
import { trpcStorybookMsw } from '../../__tests__/trpcMswSetup.browser';
import UnitLayout, { type ChunkWithContent } from './UnitLayout';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 If the allUnitChunks type is changed to Record<string, BasicChunk[]> (see other suggestion), you'll also want to add the BasicChunk import here so the type annotation resolves correctly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/website/src/components/programs/ProgramsList.stories.tsx (1)

82-95: ⚡ Quick win

Extract shared MSW handlers to avoid drift.

The same handlers are repeated in both stories (Line 82 and Line 103). Centralising them keeps future mock updates consistent.

Proposed refactor
+const handlers = [
+  trpcStorybookMsw.programs.getAll.query(() => samplePrograms),
+  trpcStorybookMsw.grants.getRapidGrantStats.query(() => ({
+    count: 42,
+    totalAmountUsd: 184500,
+  })),
+  trpcStorybookMsw.grants.getCareerTransitionGrantStats.query(() => ({
+    count: 8,
+    totalAmountUsd: 360000,
+  })),
+];
+
 export const Default: Story = {
   args: {},
   parameters: {
     msw: {
-      handlers: [
-        trpcStorybookMsw.programs.getAll.query(() => samplePrograms),
-        trpcStorybookMsw.grants.getRapidGrantStats.query(() => ({
-          count: 42,
-          totalAmountUsd: 184500,
-        })),
-        trpcStorybookMsw.grants.getCareerTransitionGrantStats.query(() => ({
-          count: 8,
-          totalAmountUsd: 360000,
-        })),
-      ],
+      handlers,
     },
   },
 };
@@
 export const WithUtmCampaign: Story = {
   args: {
     utmCampaign: 'spring-2026',
   },
   parameters: {
     msw: {
-      handlers: [
-        trpcStorybookMsw.programs.getAll.query(() => samplePrograms),
-        trpcStorybookMsw.grants.getRapidGrantStats.query(() => ({
-          count: 42,
-          totalAmountUsd: 184500,
-        })),
-        trpcStorybookMsw.grants.getCareerTransitionGrantStats.query(() => ({
-          count: 8,
-          totalAmountUsd: 360000,
-        })),
-      ],
+      handlers,
     },
   },
 };

As per coding guidelines, "Extract repeated logic into well-named functions or components."

Also applies to: 103-116

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/website/src/components/programs/ProgramsList.stories.tsx` around lines
82 - 95, Extract the repeated MSW handlers into a single shared constant and
reuse it in both stories: create a well-named array (e.g.,
sharedProgramHandlers) containing the trpcStorybookMsw.programs.getAll.query(()
=> samplePrograms), trpcStorybookMsw.grants.getRapidGrantStats.query(() => ({
count: 42, totalAmountUsd: 184500 })), and
trpcStorybookMsw.grants.getCareerTransitionGrantStats.query(() => ({ count: 8,
totalAmountUsd: 360000 })); then replace the duplicated handler lists in each
story’s msw.handlers with that sharedProgramHandlers constant so future mock
updates are maintained in one place.
apps/website/src/components/lander/components/SectionNav.stories.tsx (1)

18-29: ⚡ Quick win

Replace decorator inline styles with Tailwind utility classes.

The decorator currently uses inline style objects, fixed height, and a raw hex background; this should be moved to Tailwind classes (using min-h-* instead of fixed h-*) to stay aligned with project styling conventions.

Suggested refactor
   decorators: [
     (Story) => (
-      <div style={{ minHeight: '200vh' }}>
-        <div style={{
-          height: '600px', background: '`#f5f5f5`', display: 'flex', alignItems: 'center', justifyContent: 'center',
-        }}>
+      <div className="min-h-[200vh]">
+        <div className="min-h-[600px] bg-slate-100 flex items-center justify-center">
           Scroll down to reveal the SectionNav. It only appears once you scroll past ~500px.
         </div>
         <Story />
-        <div id="who" style={{ minHeight: '600px', padding: '40px' }}>Section: Who this is for</div>
-        <div id="outcomes" style={{ minHeight: '600px', padding: '40px' }}>Section: Outcomes</div>
-        <div id="structure" style={{ minHeight: '600px', padding: '40px' }}>Section: Structure</div>
-        <div id="pathways" style={{ minHeight: '600px', padding: '40px' }}>Section: Pathways</div>
-        <div id="faq" style={{ minHeight: '600px', padding: '40px' }}>Section: FAQ</div>
+        <div id="who" className="min-h-[600px] p-10">Section: Who this is for</div>
+        <div id="outcomes" className="min-h-[600px] p-10">Section: Outcomes</div>
+        <div id="structure" className="min-h-[600px] p-10">Section: Structure</div>
+        <div id="pathways" className="min-h-[600px] p-10">Section: Pathways</div>
+        <div id="faq" className="min-h-[600px] p-10">Section: FAQ</div>
       </div>
     ),
   ],

As per coding guidelines, "apps/website/**/*.{tsx,ts}: Apply consistent patterns—prefer Tailwind CSS. Only use inline styles when you can't express something in Tailwind." and "apps/website/**/*.{tsx,ts}: Prefer min-h-[Xpx] over h-[Xpx]".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/website/src/components/lander/components/SectionNav.stories.tsx` around
lines 18 - 29, In SectionNav.stories.tsx replace the inline style objects on the
Story decorator wrapper and child divs with Tailwind utilities: change the outer
div style={{ minHeight: '200vh' }} to className="min-h-[200vh]"; change the hero
block style={{ height: '600px', background: '`#f5f5f5`', display: 'flex',
alignItems: 'center', justifyContent: 'center' }} to className="min-h-[600px]
bg-[`#f5f5f5`] flex items-center justify-center"; and change each section div
style={{ minHeight: '600px', padding: '40px' }} (the divs with
id="who","outcomes","structure","pathways","faq") to className="min-h-[600px]
p-10" so the Story decorator uses Tailwind min-h utilities and
project-consistent spacing/colors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/website/src/components/advising/AdvisorsSection.stories.tsx`:
- Around line 60-62: In the Loading story handler
trpcStorybookMsw.teamMembers.getOneOnOneAdvisors.query you currently await new
Promise(() => {}) and then have an unreachable return []; remove the unreachable
"return []" line and either let the handler simply await the unresolved promise
to simulate loading or replace the await+return pair with a single "return new
Promise(() => {})" so the loading state is reached without dead code; update
only the trpcStorybookMsw.teamMembers.getOneOnOneAdvisors.query block in
AdvisorsSection.stories.tsx.

---

Nitpick comments:
In `@apps/website/src/components/lander/components/SectionNav.stories.tsx`:
- Around line 18-29: In SectionNav.stories.tsx replace the inline style objects
on the Story decorator wrapper and child divs with Tailwind utilities: change
the outer div style={{ minHeight: '200vh' }} to className="min-h-[200vh]";
change the hero block style={{ height: '600px', background: '`#f5f5f5`', display:
'flex', alignItems: 'center', justifyContent: 'center' }} to
className="min-h-[600px] bg-[`#f5f5f5`] flex items-center justify-center"; and
change each section div style={{ minHeight: '600px', padding: '40px' }} (the
divs with id="who","outcomes","structure","pathways","faq") to
className="min-h-[600px] p-10" so the Story decorator uses Tailwind min-h
utilities and project-consistent spacing/colors.

In `@apps/website/src/components/programs/ProgramsList.stories.tsx`:
- Around line 82-95: Extract the repeated MSW handlers into a single shared
constant and reuse it in both stories: create a well-named array (e.g.,
sharedProgramHandlers) containing the trpcStorybookMsw.programs.getAll.query(()
=> samplePrograms), trpcStorybookMsw.grants.getRapidGrantStats.query(() => ({
count: 42, totalAmountUsd: 184500 })), and
trpcStorybookMsw.grants.getCareerTransitionGrantStats.query(() => ({ count: 8,
totalAmountUsd: 360000 })); then replace the duplicated handler lists in each
story’s msw.handlers with that sharedProgramHandlers constant so future mock
updates are maintained in one place.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a3e0a242-dd61-49e1-8f14-babbe479a9a6

📥 Commits

Reviewing files that changed from the base of the PR and between 54c162c and d8eb8fe.

📒 Files selected for processing (48)
  • CLAUDE.md
  • apps/website/CLAUDE.md
  • apps/website/src/components/advising/AdvisorsSection.stories.tsx
  • apps/website/src/components/advising/HowItWorksSection.stories.tsx
  • apps/website/src/components/advising/WhatThisIsForSection.stories.tsx
  • apps/website/src/components/advising/WhatToExpectSection.stories.tsx
  • apps/website/src/components/advising/WhoYouAreSection.stories.tsx
  • apps/website/src/components/career-transition-grant/ExpectationsSection.stories.tsx
  • apps/website/src/components/career-transition-grant/GranteesSection.stories.tsx
  • apps/website/src/components/career-transition-grant/WhatThisIsForSection.stories.tsx
  • apps/website/src/components/courses/FacilitatorFeedbackHeader.stories.tsx
  • apps/website/src/components/courses/UnitLayout.stories.tsx
  • apps/website/src/components/fieldbuilder-week/FieldBuildersSection.stories.tsx
  • apps/website/src/components/fieldbuilder-week/TheWeekSection.stories.tsx
  • apps/website/src/components/fieldbuilder-week/WhatCouldYouBuildSection.stories.tsx
  • apps/website/src/components/fieldbuilder-week/WhoYouAreSection.stories.tsx
  • apps/website/src/components/grants/GrantProgramCard.stories.tsx
  • apps/website/src/components/grants/GranteesListSection.stories.tsx
  • apps/website/src/components/homepage/UpcomingRounds.stories.tsx
  • apps/website/src/components/incubator-week/AboutBlueDotSection.stories.tsx
  • apps/website/src/components/incubator-week/AboutYouSection.stories.tsx
  • apps/website/src/components/incubator-week/LogisticsSection.stories.tsx
  • apps/website/src/components/incubator-week/TheWeekSection.stories.tsx
  • apps/website/src/components/incubator-week/TrackRecordSection.stories.tsx
  • apps/website/src/components/incubator-week/WhatThisIsForSection.stories.tsx
  • apps/website/src/components/incubator-week/WhatYouGetSection.stories.tsx
  • apps/website/src/components/join-us/CultureSection.stories.tsx
  • apps/website/src/components/join-us/JobsListSection.stories.tsx
  • apps/website/src/components/join-us/WhyUsSection.stories.tsx
  • apps/website/src/components/lander/TestimonialCarousel.stories.tsx
  • apps/website/src/components/lander/components/AlumniLogosSection.stories.tsx
  • apps/website/src/components/lander/components/AlumniStoryCarousel.stories.tsx
  • apps/website/src/components/lander/components/CaseStudiesSection.stories.tsx
  • apps/website/src/components/lander/components/CourseBenefitsTextSection.stories.tsx
  • apps/website/src/components/lander/components/CourseOutcomesSection.stories.tsx
  • apps/website/src/components/lander/components/FieldBuildingSection.stories.tsx
  • apps/website/src/components/lander/components/HowTheCourseWorksSection.stories.tsx
  • apps/website/src/components/lander/components/PathwaysListSection.stories.tsx
  • apps/website/src/components/lander/components/PathwaysSection.stories.tsx
  • apps/website/src/components/lander/components/PrerequisitesSection.stories.tsx
  • apps/website/src/components/lander/components/ScheduleListSection.stories.tsx
  • apps/website/src/components/lander/components/SectionNav.stories.tsx
  • apps/website/src/components/lander/components/WhoIsThisForTextSection.stories.tsx
  • apps/website/src/components/missions/MissionsListSection.stories.tsx
  • apps/website/src/components/programs/ProgramsList.stories.tsx
  • apps/website/src/components/rapid-grants/FundedProjectsSection.stories.tsx
  • apps/website/src/components/rapid-grants/HowItWorksSection.stories.tsx
  • apps/website/src/components/rapid-grants/WhatThisIsForSection.stories.tsx

Comment thread apps/website/src/components/advising/AdvisorsSection.stories.tsx Outdated
- UnitLayout.stories: use imported BasicChunk type for allUnitChunks
  instead of inline superset (Greptile)
- AdvisorsSection.stories: drop unreachable return [] in Loading story
  (CodeRabbit)
- ProgramsList.stories: hoist repeated MSW handlers into shared const
  (CodeRabbit)
- SectionNav.stories: replace decorator inline styles with Tailwind
  utilities (CodeRabbit)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@joshestein

Copy link
Copy Markdown
Collaborator Author

Addressed bot feedback in f36727a9:

  • Greptile P2 (UnitLayout.stories.tsx): switched allUnitChunks to Record<string, BasicChunk[]> and dropped the extra chunkResources / chunkExercises fields the inline type was carrying (they're not on BasicChunk so the original superset was actively misleading).
  • CodeRabbit actionable (AdvisorsSection.stories.tsx): removed unreachable return [] in the Loading story; now () => new Promise(() => {}).
  • CodeRabbit nitpick (ProgramsList.stories.tsx): hoisted the duplicated msw handlers into a single shared handlers const at the meta.parameters.msw level so both stories pick it up.
  • CodeRabbit nitpick (SectionNav.stories.tsx): replaced decorator inline styles with Tailwind utilities (min-h-[200vh], min-h-[600px] p-10, bg-color-canvas).

Re-triggering Claude review.

@joshestein

Copy link
Copy Markdown
Collaborator Author

@claude review

@claude

This comment was marked as outdated.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/website/src/components/lander/components/SectionNav.stories.tsx`:
- Line 19: Replace the CSS utility class used for the background in
SectionNav.stories.tsx (the div with className containing "bg-color-canvas")
with the repo's named palette utility (e.g., "bg-bluedot-..." that matches the
intended surface tone); update the className string in the same JSX element to
remove "bg-color-canvas" and use the appropriate "bg-bluedot-*" token so the
component follows the bluedot palette convention.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 817352b3-b246-41da-b4ba-6d76fdcd61c7

📥 Commits

Reviewing files that changed from the base of the PR and between d8eb8fe and f4b4911.

📒 Files selected for processing (5)
  • CLAUDE.md
  • apps/website/src/components/advising/AdvisorsSection.stories.tsx
  • apps/website/src/components/courses/UnitLayout.stories.tsx
  • apps/website/src/components/lander/components/SectionNav.stories.tsx
  • apps/website/src/components/programs/ProgramsList.stories.tsx

Comment thread apps/website/src/components/lander/components/SectionNav.stories.tsx Outdated
joshestein and others added 6 commits May 26, 2026 09:01
CodeRabbit flagged bg-color-canvas in the SectionNav scroll decorator.
Project CLAUDE.md bans the semantic color-* tokens in favor of the named
bluedot-* palette utilities. Match how bg-bluedot-lightest is used in
sibling lander components (AlumniLogosSection, CaseStudiesSection).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`Default` previously used `headingVariant: 'compact'` while `DefaultHeading`
omitted the prop (giving the actual `'default'` variant). Swap so `Default`
maps to the default heading variant and `Compact` documents the compact one.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Story-level `parameters.msw.handlers` don't always apply in the autodocs
preview iframe, leaving the Docs page blank while the Default story renders
correctly. Move the happy-path handlers to `meta.parameters.msw.handlers`
and override only for edge cases (Empty, Loading). Switch from `satisfies`
to explicit `Meta<typeof Component>` annotation to avoid portable-type
inference issues when MSW handler types leak into meta.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pure-static marketing sections with no props, no data fetching, and no
variants don't reveal anything the live page route doesn't already show.
Stories pay off when they expose state (loading/empty), prop variants,
auth-gated paths, or MSW-driven data shapes.

Deletes 17 single-`Default` stories across advising, career-transition-grant,
fieldbuilder-week, incubator-week, and join-us that wrapped hardcoded copy.

Refines the root CLAUDE.md lockstep rule with a third skip case for these.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
joshestein and others added 2 commits May 26, 2026 09:47
Single Default story whose MSW mock returns the same unit counts as the
component's `?? 5` / `?? 8` fallbacks, so the fetched data was never
observable. Renders identical prose to the live page route. Applies the
refined lockstep rule to stories that don't expose state/variant/data
variation worth seeing in isolation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deletes single-Default stories whose only data variation is an inline link
href, plus a wrapper story that duplicates a sibling's variants:

- fieldbuilder-week/WhoYouAreSection — MSW only feeds apply link href
- rapid-grants/WhatThisIsForSection — same pattern
- rapid-grants/HowItWorksSection — mocks only one of two trpc queries; stats
  fall through to fallback copy so MSW value is never observable
- rapid-grants/FundedProjectsSection — wrapper around GranteesListSection
  which already has Default/WithTitleAndSubtitle/Empty variants
- lander/components/AlumniLogosSection — static logo grid, no MSW, no variants

Also drops ProgramsList `WithUtmCampaign` (only affects URLs, no visible
change).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
joshestein and others added 3 commits May 26, 2026 10:26
Label-only change has no visible structural diff from Default. Default
and NoApplicationUrl already cover the two meaningful render paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MissionsListSection: filters status='Live' then renders PageListRow rows.
No logic beyond what PageListRow's own story shows. Delete entirely.

JobsListSection: drop NoOpenRoles (empty-state visual covered by PageListRow
story). Keep Default + ContractorOnly which exercise the regular/contractor
split logic that's unique to this component.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PathwaysListSection: pure PageListRow wrapper with heading + intro. Both
Default and NoIntro variants only exercise heading-display logic, not the
row styling (which PageListRow's own story owns). Delete.

AlumniStoryCarousel + CaseStudiesSection: drop WithSubtitle variant from
each. Subtitle prop just adds an italic string with no structural diff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Will-Howard Will-Howard temporarily deployed to josh/2492-update-stories - bluedot-preview PR #2510 May 26, 2026 08:35 — with Render Destroyed
@Will-Howard Will-Howard temporarily deployed to josh/2492-update-stories - bluedot-storybook-preview PR #2510 May 26, 2026 08:35 — with Render Destroyed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/website/src/components/grants/GranteesListSection.stories.tsx (1)

83-108: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add a Loading story variant.

The component explicitly renders a loading state with <ProgressDots />, but no story demonstrates it. Add a Loading story that uses a never-resolving promise to mock the loading state.

📖 Proposed Loading story
 export const Empty: Story = {
   args: {
     heading: 'Projects we\'ve funded',
   },
   parameters: {
     msw: {
       handlers: [
         trpcStorybookMsw.grants.getAllPublicRapidGrantees.query(() => []),
       ],
     },
   },
 };
+
+export const Loading: Story = {
+  args: {
+    heading: 'Projects we\'ve funded',
+  },
+  parameters: {
+    msw: {
+      handlers: [
+        trpcStorybookMsw.grants.getAllPublicRapidGrantees.query(() => new Promise(() => {})),
+      ],
+    },
+  },
+};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/website/src/components/grants/GranteesListSection.stories.tsx` around
lines 83 - 108, Add a new Loading story export to
GranteesListSection.stories.tsx that triggers the component's loading state by
mocking the trpc query to never resolve: create export const Loading: Story = {
args: { heading: 'Projects we\'ve funded' }, parameters: { msw: { handlers: [
trpcStorybookMsw.grants.getAllPublicRapidGrantees.query(() => new Promise(() =>
{})) ] } } } so the component renders its <ProgressDots /> loading UI; place it
alongside Default/WithTitleAndSubtitle/Empty.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/website/src/components/grants/GranteesListSection.stories.tsx`:
- Around line 83-108: Add a new Loading story export to
GranteesListSection.stories.tsx that triggers the component's loading state by
mocking the trpc query to never resolve: create export const Loading: Story = {
args: { heading: 'Projects we\'ve funded' }, parameters: { msw: { handlers: [
trpcStorybookMsw.grants.getAllPublicRapidGrantees.query(() => new Promise(() =>
{})) ] } } } so the component renders its <ProgressDots /> loading UI; place it
alongside Default/WithTitleAndSubtitle/Empty.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 41221e8d-38e9-4b50-b0a0-8b8543e17d41

📥 Commits

Reviewing files that changed from the base of the PR and between 0d711ee and 536ff50.

📒 Files selected for processing (9)
  • CLAUDE.md
  • apps/website/src/components/advising/AdvisorsSection.stories.tsx
  • apps/website/src/components/career-transition-grant/GranteesSection.stories.tsx
  • apps/website/src/components/grants/GranteesListSection.stories.tsx
  • apps/website/src/components/incubator-week/AboutBlueDotSection.stories.tsx
  • apps/website/src/components/join-us/JobsListSection.stories.tsx
  • apps/website/src/components/lander/components/AlumniStoryCarousel.stories.tsx
  • apps/website/src/components/lander/components/CaseStudiesSection.stories.tsx
  • apps/website/src/components/programs/ProgramsList.stories.tsx
💤 Files with no reviewable changes (5)
  • apps/website/src/components/lander/components/CaseStudiesSection.stories.tsx
  • apps/website/src/components/join-us/JobsListSection.stories.tsx
  • apps/website/src/components/programs/ProgramsList.stories.tsx
  • apps/website/src/components/incubator-week/AboutBlueDotSection.stories.tsx
  • apps/website/src/components/lander/components/AlumniStoryCarousel.stories.tsx

@joshestein

Copy link
Copy Markdown
Collaborator Author

@greptileai rereview

@joshestein joshestein merged commit 6694261 into master May 26, 2026
8 checks passed
@joshestein joshestein deleted the josh/2492-update-stories branch May 26, 2026 08: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.

Update Storybooks

2 participants