Website: Merge Events + Updates into a News section, add Buttondown newsletters [ENG-2148] - #1306
Website: Merge Events + Updates into a News section, add Buttondown newsletters [ENG-2148]#1306jsmorabito wants to merge 9 commits into
Conversation
…newsletters Renames the homepage "Events" section to "News" and merges in blog posts and Buttondown newsletter issues, sorted by date. Newsletters are fetched live from Buttondown's API, filtered to sent + publicly archived emails whose subject contains "Newsletter" (configurable via BUTTONDOWN_NEWSLETTER_SUBJECT_FILTER), and paginate through all results. Requires a BUTTONDOWN_API_KEY env var to activate; falls back to an empty list otherwise so the build isn't blocked on it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
new Date() parses date-only ISO strings as UTC midnight, but toLocaleDateString with no timeZone option formats in the host's local zone — shifting the displayed date back a day on any server running behind UTC. Pin formatting to UTC so the displayed date matches the source value regardless of server timezone. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Previously, a failed pagination request logged an error and broke out of the loop, returning whatever pages had already been fetched as if that were the complete newsletter history — silently showing an incomplete backfill as correct. Throwing lets the existing outer catch discard the partial result and fall back to an empty list, consistent with how a missing API key is already handled. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The merged News section previously rendered every static event, every published blog post, and every matching Buttondown newsletter with no limit — unlike the old Updates section, which capped at 3 recent posts. Left unbounded, this list only grows over time. Cap it to the 10 most recent items; the full blog archive remains reachable via "See all posts". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The removed Updates section showed "By {author}" for each post; the
merged News list dropped that field entirely. Fold it into the meta
line, consistent with the "date | label" pattern used by events and
newsletters.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
sortNewsByDateDesc in page.tsx was a byte-for-byte copy of sortBlogsByDate in readBlogs.tsx. Extract sortByDateDesc into a shared generic utility and use it in both places. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… both Each STATIC_NEWS_ITEMS entry independently hand-wrote both a sortable date and a prose meta string repeating that date, with nothing to keep them in sync. Restructure as event sources with a date + location (and an optional dateLabel override for the one multi-day event), and derive the display string via formatDisplayDate — matching the approach already used for blog posts and newsletters. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Buttondown's page-number pagination isn't guaranteed stable if an email is created mid-fetch, so the same newsletter could theoretically appear twice in newsletterItems. Since href is used as the React key for the news list, dedupe by href before sorting/rendering to avoid duplicate-key warnings and undefined reconciliation behavior. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Previously the "Events"/"Updates" nav items and section were only shown when there was content; this PR's merge into "News" dropped that guard entirely, always rendering the nav link and section even if there were nothing to show. Move the static items into a shared app/data/news.ts module so layout.tsx can cheaply check for them without duplicating page.tsx's async blog/newsletter fetches, and guard the section itself with the already-computed `news.length > 0`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Ran a code review over this diff and fixed everything it surfaced, each as its own commit:
All commits pass |
|
@mdroidian can you take a look at this and let me know if I did things correctly? this update is part of several that will be consolidating info on the site and making it easier to navigate |
Did you test this locally with the API key? Was it tested it with blog posts? I'm slightly worried about the fact that we are calling a third party API on every page load of our homepage, but a quick check seems like it is using NextJS ISR correctly. |
Summary
{blogs.length > 0 && (...)}and there are currently zero published posts incontent/blog/(only an unpublishedEXAMPLE.mdxtemplate), so it never actually rendered on the live site — this PR removes that hidden/dead code path and folds its data source (published blog posts, whenever they exist) into the new News feed instead./#news). ("Updates" was already conditionally hidden from nav too, via the samehasUpdatescheck, so this isn't a visible nav change today.)Why
Consolidates three content sources (static events, blog posts, newsletter issues) into one chronological News list on the homepage, so newsletter issues sent via Buttondown show up automatically instead of needing a manual homepage edit each time — and so blog posts get a working home to render into once any are published.
How it works
apps/website/app/utils/buttondown.ts— fetchesGET /v1/emails?status=sent&subject=Newsletterfrom Buttondown, paginating through allnextpages, and keeps only emails witharchival_mode === "enabled"(fully public in the archive).apps/website/app/types/news.ts/apps/website/app/utils/formatDate.ts— sharedNewsItemshape and date formatting used to merge static events, blog posts, and newsletter items into one sorted list.apps/website/app/(home)/page.tsx/layout.tsx— the merged section and nav link.Config needed to go live
BUTTONDOWN_API_KEY(required) — without it, the newsletter fetch is skipped silently and the News section just shows static events (and any published blog posts). Generate this in the Buttondown dashboard under Settings → Programming (API), then add it as an env var in Vercel (production) andapps/website/.env.local(local dev). I don't have Vercel access, so someone with access needs to add this for it to go live.BUTTONDOWN_NEWSLETTER_SUBJECT_FILTER(optional) — override the "Newsletter" subject-match string if the naming convention ever changes; set to an empty string to disable the filter and show all public sent emails.Next steps
BUTTONDOWN_API_KEYto the production environment (and ideally.env.localfor local dev)."Newsletter"somewhere in the subject line — anything that doesn't will be silently excluded.STATIC_NEWS_ITEMSentries inpage.tsxnow that real events can be added the same way, or if that array should stay hand-maintained for talks/panels that aren't Buttondown emails.published: truein its frontmatter incontent/blog/).Test plan
pnpm check-typesandpnpm lintshow no new errors (confirmed pre-existing issues are unrelated/present onmaintoo)BUTTONDOWN_API_KEYis added to an environment