Skip to content

feat: pin featured newsroom posts; widen the category union - #7

Open
tylerkstevens wants to merge 1 commit into
mainfrom
feat/newsroom-featured
Open

feat: pin featured newsroom posts; widen the category union#7
tylerkstevens wants to merge 1 commit into
mainfrom
feat/newsroom-featured

Conversation

@tylerkstevens

Copy link
Copy Markdown
Collaborator

Two structural gaps in the newsroom: a post you want to keep visible sinks the moment anything newer publishes, and there are only four categories to publish under.

What changed

File Change
types/index.ts Widen NewsroomPost.category with 'grant' and 'manifesto'; add optional featured?: boolean
lib/newsroom.ts New comparePosts() — featured first, then date descending. getAllPosts() sorts by it; getLatestPost() prefers a featured post and falls back to the newest. toPost() normalises the frontmatter flag to a boolean
components/newsroom/PostCard.tsx Labels for the two new categories — Record<category, string> makes this a typecheck error otherwise
app/newsroom/page.tsx Render a featured post in its own bordered FEATURED block above a RECENT grid

With no featured post, /newsroom falls back to exactly the previous markup, including the large treatment on the first card. That's the important property — the feature is inert until a post opts in.

Tests

tests/newsroom-featured.test.mjs, 10 cases: no-featured ordering unchanged · a featured post beats a newer one · multiple featured stay date-sorted above the rest · featured: false behaves as absent · getLatestPost preference and fallback · empty newsroom · removing the flag restores the old result.

Node 20 can't import the TypeScript source and the repo takes no new dependencies, so the comparator is mirrored from lib/newsroom.ts, following the convention already used in photo-carousel-distance.test.mjs. Both sides carry a pointer to the other. Worth knowing this is weaker than testing the real function — if the source comparator changes, the mirror must change with it.

Two cases are not mirrors: they read the real MDX frontmatter off disk and assert every category is in the union and at most one post is featured. That guards the one failure a mirror can't see — a typo'd category silently falls back to 'announcement' in toPost().

Verification

Verified with a temporary post dated older than the MARA release and marked featured, so pinning had to beat date order to pass:

  • pinned into the FEATURED slot above the newer post
  • took the home-page LATEST ANNOUNCEMENT slot (getLatestPost())
  • rendered its GRANT category label
  • deleting it restored the previous /newsroom layout and home slot exactly

Checked in light and dark mode, no console errors. Temp post removed — content/ is unchanged by this PR.

npm test 21/21 (11 existing + 10 new) · npm run build clean, 19 routes.

npm run lint can't run on main yet (no ESLint config — see #6), so the four changed files were linted with a temporary flat config importing eslint-config-next: exit 0. Merging #6 first makes that workaround unnecessary. No file overlap between the two branches, so they merge cleanly in either order.

One open question for the reviewer

The spec for this item referenced an approved mock for the /newsroom featured layout. That mock doesn't exist in the source document — I checked. So the layout here is built to the written description (a bordered FEATURED block above a RECENT list) using the existing purple accent-bar section idiom. If a different layout was intended, this is the piece to redirect.

Roadmap item 6 (website-roadmap-2026-Q3.md, organization-spec).

🤖 Generated with Claude Code

Two structural gaps in the newsroom. Without them a pinned post sinks
the moment the next dated post publishes, and grant-cycle
announcements have no category to publish under.

- types/index.ts — widen NewsroomPost.category with 'grant' and
  'manifesto'; add optional `featured?: boolean`
- lib/newsroom.ts — add comparePosts(): featured first, then date
  descending. getAllPosts() sorts by it; getLatestPost() prefers a
  featured post and falls back to the newest. toPost() normalises the
  frontmatter flag to a boolean
- components/newsroom/PostCard.tsx — labels for the two new categories
  (Record<category, string> makes this a typecheck error otherwise)
- app/newsroom/page.tsx — render a featured post in its own bordered
  FEATURED block above a RECENT grid. With no featured post the page
  falls back to exactly the previous markup, including the large
  treatment on the first card

Tests (tests/newsroom-featured.test.mjs, 10 cases). Node 20 cannot
import the TS source and the repo takes no new dependencies, so the
comparator is mirrored from lib/newsroom.ts following the convention in
photo-carousel-distance.test.mjs; both sides carry a pointer to the
other. Covered: no-featured ordering is unchanged, a featured post
beats a newer one, multiple featured stay date-sorted above the rest,
`featured: false` behaves as absent, getLatestPost preference and
fallback, empty newsroom, and removing the flag restoring the old
result.

Two cases are not mirrors — they read the real MDX frontmatter off disk
and assert every category is in the union and at most one post is
featured. That guards the failure a mirror cannot see: a typo'd
category silently falls back to 'announcement' in toPost().

Verified with a temporary post dated older than the MARA release and
marked featured: it pinned into the FEATURED slot above the newer post,
took the home-page LATEST ANNOUNCEMENT slot, and rendered its GRANT
category label; deleting it restored the previous /newsroom layout and
home slot exactly. Checked in light and dark mode, no console errors.
Temp post removed — content/ is unchanged.

Roadmap item 6 (website-roadmap-2026-Q3.md, organization-spec).

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

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
website Ready Ready Preview Aug 4, 2026 10:23pm
website-256-f Ready Ready Preview Aug 4, 2026 10:23pm

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