Skip to content

Add /training page (+ twin polish on /events)#473

Open
bryceerobertson wants to merge 23 commits into
developmentfrom
training-page
Open

Add /training page (+ twin polish on /events)#473
bryceerobertson wants to merge 23 commits into
developmentfrom
training-page

Conversation

@bryceerobertson

@bryceerobertson bryceerobertson commented Jul 20, 2026

Copy link
Copy Markdown
Member
  • New /training page: upcoming programs from the Training table and a new Recurring training table (51 programs), switchable via an Upcoming / Recurring toggle. Cards carry the Figma attribute set – type pills, stipend, time commitment, entry bar, focus, deadline – with icons extracted from the Figma spec.
  • Filters: Applications / Type / Focus / Entry bar / Stipend / Length / Location, with faceted counts like the 80,000 Hours job board (each dropdown's numbers respect the other active filters). Same faceting applied to /events.
  • Recurring cards show a typical length (new Airtable field, derived from each program's historical iterations) and join the Length filter.
  • Shared StickyBar component: the mode toggle sticks under the global nav on both pages, with a full-bleed blur backdrop while stuck. The nav's hide/reveal slide is now driven by JS so the toggle tracks it with no gap; toggle clicks jump back to the top of the listings.
  • Nav: "Training programs" item (placeholder icon – see below) and count badges for /training and /events, derived from the pages' own data.
  • /events twins: faceted filter counts, sticky Online/In person toggle, city search placeholder "Type your city or country", cross-link renamed to "Training programs", shared newsletter box with updated heading.
  • Nav "+N more" menu, sitemap, and last-updated wiring included. Pre-launch TODOs (contribute-form URLs, Airtable share view, Last modified fields, /events-and-training redirect) are tracked in code TODOs and stay out of scope here.
  • Note the listings in Upcoming are placeholders

@melissasamworth and @emilymarais – things that aren't in the Figma, seeking your sign-off:

  1. Focus and Entry bar filters on /training – added beyond the Figma filter row; easy to drop if unwanted.
  2. Month grouping of upcoming listings (like /events) – the Figma shows one flat list.
  3. Sticky toggle behavior – the Upcoming/Recurring toggle pins below the nav while scrolling; not specified in the design.
  4. Nav icon for Training programs – the graduation cap is a placeholder. Shortlisted alternatives: certificate with ribbon, whiteboard/easel, signpost, dumbbell. Your call.
  5. Filters persist when switching Upcoming ↔ Recurring – felt right, but flagging for your view.
  6. Also, we now have an extra thing in the global nav. Do we want to hide one to keep the number the same? There's none that stand out as one I'd want to hide though.

🤖 Generated with Claude Code

bryceerobertson and others added 15 commits July 18, 2026 17:55
- New data layer reading the Training and Recurring training tables by
  permanent field ID (deadline-based expiry, applications-not-yet-open
  checkbox, length buckets, start-date ordering; recurring sorts A-Z)
- Page built from the events/self-study patterns: hero with events
  cross-link and the shared newsletter box, Upcoming/Recurring toggle,
  featured pair per set, filter row (Applications, Type, Stipend,
  Length, Location), two-column card grid, contribute sidebar
- NewsletterSignup promoted to a shared component with a heading prop
- New card icons (stipend, entry bar, focus, repeat) plus a grad-cap
  nav icon; /training added to the nav and sitemap

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Mode toggles on both pages stick to the viewport top with a blurred
  backdrop, so it stays clear which set is on screen
- Training filter row spans the full container (heading no longer wraps)
  and gains Focus and Entry bar dropdowns plus the result count label
- Part-time rows get a half-filled clock icon per the Figma spec
- "View data in Airtable" cards note that past programs/events are
  included, via a new ContributeButtons prop

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- All card attribute icons replaced with the exact vectors from the
  Figma spec PDF (part-time clock, hollow-center target, entry bars,
  stipend coin stacks) plus a new "Applications closed" paper variant
- Airtable sidebar card matched to the mockup: muted teal-300 label,
  --teal-800 arrow badge with the white Figma arrow
- Section heading removed from the training filter row, which now uses
  the shared FilterBar with the live result count as its label
- Upcoming training programs grouped under month-of-start headings,
  mirroring /events
- Sticky mode toggles rebuilt as a shared StickyBar component: backdrop
  only shows while actually stuck, and the bar slides below the global
  nav (via a --nav-offset variable the nav now publishes) instead of
  being covered when the nav reveals on scroll-up

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Nav now publishes its live bottom edge every animation frame, so the
  sticky toggles track its slide exactly (no more speed-mismatch gap)
  and expose --nav-height for scroll positioning
- Sticky bar backdrop bleeds to the viewport edges like the nav's
- Clicking a mode toggle jumps back to the top of the listings, placed
  right below the global nav
- Airtable sidebar card reshaped to the Figma proportions: taller, with
  the illustration inset below the border and a larger arrow badge
  overlapping its corner

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…height

- Animate the nav's hide/reveal in JS (rAF) instead of a CSS transition:
  transitions advance after rAF callbacks, so the sticky toggles tracking
  --nav-offset trailed one frame behind and showed a brief gap
- Toggle clicks no longer reveal the global nav on the jump to top
  (StickyBar announces the programmatic jump; nav suppresses reveal)
- More vertical padding on the sticky toggles (8px -> 16px)
- Airtable card: restore 24px arrow badge at 8/8, reduce height to match
  the Figma card (label starts 36px down instead of 76px)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nt label

- Toggle-click jump lands the anchor below the nav when the nav is already
  showing (it stays put), instead of pinning the bar over the content
- Sticky toggle vertical padding 16px -> 12px
- FilterBar result count flows left after the chips per the Figma, not
  pushed to the row's far right

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Geometry already matched frame-for-frame, but at fractional pixel
positions the nav's composited transform and the bar's layout top
anti-alias differently, flashing a sub-pixel seam in both slide
directions. Snap the slide to whole pixels and tuck the bar's backdrop
2px under the nav (which stacks above) so a seam can't render.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Derived from the pages' own data functions like /self-study, so the
badges always match the on-page totals. /training counts both sets the
page lists (upcoming + recurring).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Hero cross-link arrow joins the page name (no lone-arrow wrap on
  mobile); /events link now says "Training programs"
- Durations over 8 weeks read in months ("33 weeks" -> "8 months")
- StickyBar backdrop now also appears when the bar is pushed down by the
  revealing nav before the page has scrolled past it (stuck detection
  compares the sentinel against the bar's live sticky top line instead
  of the viewport top)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New "Typical length" field on the Recurring training table (populated
from each program's historical iterations in the legacy table, e.g.
"10 weeks", "3-6 months"). Recurring cards show it on the calendar row;
the Length filter now works in both modes - recurring programs bucket
by the midpoint of their typical range on the same thresholds as dated
programs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The search already matches on the full "City, Country" string.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ai-safety-com Ready Ready Preview, Comment Jul 23, 2026 12:31am

Request Review

Same swap as PR #474 on this branch's copies (hero spans, nav borders,
underline, about card, search modal) plus the three green card borders
that only exist here: the events Near-me card, the featured-card tagline
pill, and the newsletter signup card. Category pill colors (Workshop,
Course) are a separate accent palette and stay green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/training?view=recurring and /events?view=in-person deep-link to their
tab; the default tabs keep the bare URL. Toggling rewrites the address
bar with replaceState (no history stacking), and a Suspense-isolated
useSearchParams listener keeps tab and URL in sync across soft
navigations without costing either page its static generation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bryceerobertson

Copy link
Copy Markdown
Member Author

5d68f5e makes the mode toggles shareable: /training?view=recurring and /events?view=in-person open with that tab already active, while the default tabs keep the bare URLs. Toggling updates the address bar with replaceState (no history stacking), unknown values fall back to the default tab, and a Suspense-isolated useSearchParams listener keeps the tab and URL in sync across soft navigations – both pages remain statically generated (confirmed with a production build). Verified on localhost: deep links, toggling both directions, invalid values, same-page nav clicks, and browser back.

— Claude Code

Cards keep the full Airtable value (Pay to attend (assistance
available), Free (cash prize available), …); the filter collapses
them to the two agreed groups. Replaces the placeholder
Free / Paid / Paid (Stipend Available) options.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@emilymarais

emilymarais commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Review notes on /training (+ the events polish). I've split the actionable fixes into small PRs against this branch:

Fixed — small PRs into training-page

  • Featured tag shows a generic "Featured program" instead of the specific type — MATS Summer 2026 and the Anthropic AI Safety Fellows Program both read "Featured program". Tags should name the training type. → Training: featured tag shows the program type, not 'program' #481 (derives the tag from the program type, e.g. "Featured fellowship", matching /events).
  • Filter bar widthTraining: constrain the filter bar to the listing (9-col) width #482. It feels more intuitive to have the filters not cross past the 9-column width of the filtered list, but with this many filters (7) a constrained bar wraps and doesn't look great either. Neither option is clearly better to me - would be interested to see what Melissa's thoughts are on this.

For Bryce — data

  • The training card images aren't logos like on /events — they're mostly .jpg photos rather than org logos. Are these placeholders in the training table's Logo field, to be swapped before launch?

Re: your flagged comments

  • Month grouping of upcoming listings (Figma shows a flat list) — I'm not sure if this was intentional or not by Melissa - deferring to her on this one.
  • Filters persist when switching Upcoming ↔ Recurring — I agree, this feels right to me.
  • Sticky Upcoming/Recurring toggle — I like it sticky (better than not), but it's a little unintuitive that only the toggle is sticky while the rest of the filters aren't. Melissa had a vision for this, so deferring to her.
  • Upcoming/Recurring labels aren't clearly mutually exclusive — as a user it's not obvious whether recurring programs also appear under "upcoming". Might need clearer labelling.
  • Extra global-nav item now that /training is added — I have no strong opinions on this.

@melissasamworth

melissasamworth commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

I agree with Emily's take about the pill in the featured cards.

Re: filter bar width, I don't care. It looks janky either way. I just want to publish it and figure this out on the next version.

The rest of my feedback is in my loom. Bryce check it out. Basically just make the graduation hat bigger, and take away funding from the global nav. Everything else is fine for now.

Then in another dogfooding video that I posted on Discord actually, I noted the data is wrong. Bring in the real data and let's give it a final pass, after finishing whatever else is launch blocking.

@melissasamworth melissasamworth 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.

Good overall, except for the couple requests here.

Comment thread src/app/events/page.module.css Outdated
.nearMe {
padding: 48px;
border: 1px solid color-mix(in srgb, var(--bright-green) 20%, transparent);
border: 1px solid color-mix(in srgb, var(--bright-teal-300) 20%, transparent);

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.

Can we try to combine these classes? You should be able to use a utility class to define padding, then make a border class to choose the bright-teal some-what transparent (just choose 30%) border style, so it's applied universally.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in 0ca2771. The near-me box now uses the existing global .border-only class (a 1px border of --teal-bright-500 at 30%, the same treatment as the contribute cards in the sidebar), and its own class keeps only the padding and border radius. The mode toggle's active border now uses that same 30% mix, so the translucent teal border is defined once and applied universally. The padding stays as a rule in the page class because globals.css has directional padding utilities only (no all-sides one) — easy to add a padding-48px utility if you'd prefer that.

— Claude Code

Comment thread src/app/training/page.module.css Outdated
@@ -0,0 +1,61 @@
.heroRow {

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.

Can we try to bring this into the components that are used for every page? The newsletter can be part of the header component for all pages but we just choose to show or hide it.

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.

By this I mean all this CSS, there's no reason it should exist for only the training page.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in 0ca2771training/page.module.css is deleted entirely. The newsletter now lives in the shared PageHeader component behind a newsletter prop, shown or hidden per page as you suggested (events and training turn it on; every other page is unchanged). The rest of the duplicated CSS moved into the components that own it: the Upcoming/Recurring and Online/In person switch is a shared ModeToggle component, the filter bar's mobile stacking rule lives in FilterBar, and the sidebar column wrapper lives in ContributeButtons.

— Claude Code

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.

"training/page.module.css is deleted entirely" music to my ears

The featured tag used the Airtable Featured tagline field first, which is
set to a generic 'Featured program' for some rows (e.g. MATS, Anthropic
Fellows). Derive it from the program type instead (matching /events), so it
reads 'Featured fellowship', 'Featured bootcamp', etc.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@bryceerobertson

Copy link
Copy Markdown
Member Author

@emilymarais sweet I've merged #481. I'll close #482 without merging given Melissa's preference to leave that for a future version.

Re training card images: yup all just placeholder data for now.

bryceerobertson and others added 4 commits July 22, 2026 18:40
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Melissa's call on PR #473: six visible items is enough. The mobile menu
still lists every page, so /funding stays reachable there and as the
first item of the overflow dropdown.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dules

Melissa's review on #473: the training page's CSS was a copy of the
events page's, and translucent teal borders were defined three ways.

- PageHeader owns the hero-with-newsletter layout via a 'newsletter'
  prop, per Melissa's show-or-hide suggestion; the cross-link passes
  through as children.
- ModeToggle is a shared component; its active border uses the same
  30% teal-bright-500 mix as the global .border-only.
- FilterBar carries its own mobile stacking rule (self-study now
  stacks too, matching the other listing pages) and loses the
  className prop and inline styles.
- ContributeButtons gains the listing-page sidebar wrapper both
  clients duplicated.
- The events near-me box borrows the global .border-only instead of
  defining its own border; training/page.module.css is gone entirely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bryceerobertson

Copy link
Copy Markdown
Member Author

@melissasamworth: made the graduation hat bigger and took away Funding from the global nav. Adding real data is the very last step – /events-and-training data changes so rapidly that there needs to be basically no gap between adding the data and making the pages live, otherwise I'm duplicating data management between the old and the new. The exception is recurring training programs, that can be finalised already.

I've made those code changes you requested.

@bryceerobertson

Copy link
Copy Markdown
Member Author

To do now: Melissa checks my most recent changes, then I'll add real data, do a final QA, inform you guys and probably give you ~24hours to do your own check, then push live. Sound good? Aiming to go live early next week.

@melissasamworth

Copy link
Copy Markdown
Contributor

Looks good. I hate QA, can I just trust that you'll do it, you're really good at it.

@emilymarais

Copy link
Copy Markdown
Collaborator

Happy to do a final check before review!

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.

3 participants