Skip to content

feat(blog): add series support with featured shelf and per-series pages#7925

Merged
AmanVarshney01 merged 4 commits into
mainfrom
series-blog
May 28, 2026
Merged

feat(blog): add series support with featured shelf and per-series pages#7925
AmanVarshney01 merged 4 commits into
mainfrom
series-blog

Conversation

@ankur-arch
Copy link
Copy Markdown
Contributor

@ankur-arch ankur-arch commented May 28, 2026

Summary

  • Adds first-class series support for the blog: posts opt in via series: <key> + seriesIndex in frontmatter, with title, description, and an optional featured flag defined once in apps/blog/src/lib/series-registry.ts.
  • Home page surfaces series under the tag filter as a responsive chip row plus a prominent highlight card for the featured series. Full index lives at /blog/series, and each series gets its own page at /blog/series/<key>.
  • Individual posts get a small marker under the tags ("Part N of M in " linking to the series page) and a detailed overview + prev/next navigation at the bottom.
  • Migrates all 9 existing series off the inline series: { title } shape onto keys, and adds a new prisma-next series across 8 posts.
  • Fixes the AI tag rendering as Ai by extending formatTag with a small acronym map.

How to add a post to a series

In the post's frontmatter:

series: prisma-next
seriesIndex: 3

Prev/next are derived automatically from seriesIndex. Override per-post with prev: / next: (slug strings) if needed.

How to add a new series

Add a key in apps/blog/src/lib/series-registry.ts:

"my-key": {
  title: "My Series",
  description: "What it's about.",
  featured: true, // optional — surfaces it on the home shelf
},

Then set series: my-key and seriesIndex: N on each post.

Test plan

  • Home page renders the series chip row + featured highlight card below the tag filter and above the post grid; responsive on mobile.
  • /blog/series lists every series, featured first with the brand-accented border.
  • /blog/series/prisma-next (and every other key) renders the series description and all its posts in order.
  • On a multi-post series page (e.g. /blog/rethinking-database-migrations), the marker under the tags shows the correct "Part N of M", the bottom overview lists every post with the current one marked Reading, and the prev/next cards point to the right neighbours.
  • /blog/series/does-not-exist returns 404.
  • An AI-tagged post (e.g. /blog/agentic-engineering-at-prisma) shows the tag as AI, not Ai.
  • pnpm types:check from apps/blog passes.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Organize blog posts into named series with series pages, a series index, and series-aware navigation (Part X of Y, previous/next).
    • Series UI components: banner, marker, navigation and a homepage series shelf to discover and highlight collections.
    • Blog listing and post pages now surface series context and counts.
  • Chores

    • Updated blog frontmatter/schema to support series, ordering, and navigation fields; migrated many posts to the new format.

Review Change Stack

Introduce first-class series support for the blog. Posts opt in via a
`series: <key>` + `seriesIndex` pair in frontmatter, where the key
resolves to a single source of truth in `series-registry.ts` for title,
description, and an optional `featured` flag.

The home page now surfaces series under the tag filter as a responsive
chip row plus a prominent highlight card for the featured series; the
full list lives at `/blog/series`, and each series gets its own page at
`/blog/series/<key>`. On individual posts, a small marker under the
tags states "Part N of M in <series>" and links to the series page,
with a detailed overview and prev/next navigation rendered at the
bottom of the article.

Migrates all 9 existing series off the inline `series: { title }` shape
to keys, and threads the new `prisma-next` series across the 8 posts
that make up that arc. Also fixes the AI tag rendering as "Ai" by
extending `formatTag` with an acronym map.

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

vercel Bot commented May 28, 2026

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

Project Deployment Actions Updated (UTC)
blog Ready Ready Preview, Comment May 28, 2026 2:50pm
docs Ready Ready Preview, Comment May 28, 2026 2:50pm
eclipse Ready Ready Preview, Comment May 28, 2026 2:50pm
site Ready Ready Preview, Comment May 28, 2026 2:50pm

Request Review

@ankur-arch ankur-arch self-assigned this May 28, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 824788af-6f99-4c62-bc59-6e71e369f82b

📥 Commits

Reviewing files that changed from the base of the PR and between 3bebcbc and 77d0a9b.

📒 Files selected for processing (14)
  • apps/blog/content/blog/announcing-prisma-orm-7-0-0/index.mdx
  • apps/blog/content/blog/from-rust-to-typescript-a-new-chapter-for-prisma-orm/index.mdx
  • apps/blog/content/blog/nestjs-prisma-authentication-7D056s1s0k3l/index.mdx
  • apps/blog/content/blog/nestjs-prisma-relational-data-7D056s1kOabc/index.mdx
  • apps/blog/content/blog/prisma-6-9-0-release/index.mdx
  • apps/blog/content/blog/prisma-orm-without-rust-latest-performance-benchmarks/index.mdx
  • apps/blog/content/blog/rust-to-typescript-update-boosting-prisma-orm-performance/index.mdx
  • apps/blog/content/blog/try-the-new-rust-free-version-of-prisma-orm-early-access/index.mdx
  • apps/blog/content/blog/wnip-q2-2022-pmn7rulcj8x/index.mdx
  • apps/blog/content/blog/wnip-q4-2022-f66prwkjx72s/index.mdx
  • apps/blog/src/components/SeriesShelf.tsx
  • apps/blog/src/lib/format.ts
  • apps/blog/src/lib/series-registry.ts
  • apps/blog/src/lib/series.ts

Walkthrough

This PR converts series frontmatter to string keys, adds a typed series registry and helpers, migrates post frontmatter and links, adds series UI components and a home shelf, and implements series index/detail pages with SEO.

Changes

Blog Series Platform

Layer / File(s) Summary
Series schema and configuration
apps/blog/source.config.ts
Blog post frontmatter schema adds optional series, seriesIndex, prev, and next. MDX plugin imports reformatted and package-manager conversions (bun) extended.
Series registry and helpers
apps/blog/src/lib/series-registry.ts, apps/blog/src/lib/series.ts
Add seriesRegistry, getSeriesMetadata, isKnownSeriesKey, getSeriesPosts, and getSeriesContext; types for SeriesKey, SeriesMetadata, SeriesPostRef, and SeriesContext.
Blog post frontmatter migration
apps/blog/content/blog/*/index.mdx (many files)
Update MDX frontmatter to use string series identifiers; add seriesIndex fields and update in-body series links where applicable.
Series UI components and formatting
apps/blog/src/components/SeriesBanner.tsx, SeriesMarker.tsx, SeriesNavigation.tsx, SeriesShelf.tsx, apps/blog/src/lib/format.ts
New components: SeriesBanner, SeriesMarker, SeriesNavigation, FeaturedSeriesShelf, SeriesIndexGrid; formatTag extended with an acronym map.
Series index and detail pages
apps/blog/src/app/(blog)/series/page.tsx, apps/blog/src/app/(blog)/series/[key]/page.tsx
New series index and per-series pages with card mapping, SEO metadata, static params, and revalidate=false.
Home and post integration
apps/blog/src/app/(blog)/page.tsx, apps/blog/src/app/(blog)/[slug]/page.tsx, apps/blog/src/components/BlogHomeClient.tsx
Home builds a featured series shelf and passes it to BlogHomeClient. Post pages compute seriesContext and render SeriesMarker, SeriesBanner, and SeriesNavigation when present; JSON‑LD helper refactored.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: adding series support to the blog with a shelf component and dedicated series pages. It's concise, specific, and reflects the primary changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

@argos-ci
Copy link
Copy Markdown

argos-ci Bot commented May 28, 2026

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - May 28, 2026, 2:57 PM

…series" link

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 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/blog/content/blog/prisma-orm-without-rust-latest-performance-benchmarks/index.mdx`:
- Line 11: The frontmatter series key was changed to
"rust-to-typescript-migration-journey" but the internal series link in the post
body still points to the old slug; update the link target on the post (the link
referenced around line 29) from
"/blog/series/prisma-orm-the-complete-rust-to-typescript-migration-journey" to
the key-based path "/blog/series/rust-to-typescript-migration-journey" so the
series route matches the new frontmatter key.

In
`@apps/blog/content/blog/rust-to-typescript-update-boosting-prisma-orm-performance/index.mdx`:
- Line 12: The article's frontmatter sets series:
rust-to-typescript-migration-journey but the in-article series link still uses
the old slug; update the in-article series URL/slug to match the frontmatter
value (replace the old series slug string with
"rust-to-typescript-migration-journey") so the link points to the migrated
series key referenced by the series field.

In `@apps/blog/src/components/SeriesShelf.tsx`:
- Around line 110-113: The current construction of chips can exceed CHIP_LIMIT
when featured has more than the expected count because only nonFeatured is
sliced; replace the concatenation logic so you first combine featured and
nonFeatured (using the existing arrays) and then slice the resulting array to
CHIP_LIMIT (e.g., take the first CHIP_LIMIT items), ensuring the final chips
array never exceeds CHIP_LIMIT; update the code that defines chips (referencing
chips, featured, nonFeatured, and CHIP_LIMIT) to perform the slice on the
combined array instead of slicing only nonFeatured.

In `@apps/blog/src/lib/format.ts`:
- Line 19: Replace the prototype-inclusive "in" check with an own-property check
when looking up acronyms: instead of using "tag in TAG_ACRONYMS" (which can
match prototype keys), call an own-property guard like
Object.prototype.hasOwnProperty.call(TAG_ACRONYMS, tag) or
Object.hasOwn(TAG_ACRONYMS, tag) and only then return TAG_ACRONYMS[tag]; keep
the same TAG_ACRONYMS and tag identifiers so the change is localized to that
lookup.

In `@apps/blog/src/lib/series-registry.ts`:
- Around line 80-89: The current checks in getSeriesMetadata and
isKnownSeriesKey use the `in` operator which can match prototype properties;
change both to use an own-property check (e.g.,
Object.prototype.hasOwnProperty.call(seriesRegistry, key) or
Object.hasOwn(seriesRegistry, key) depending on your TS target) so only true
keys in seriesRegistry are treated as known—update the check in
getSeriesMetadata (before casting/returning entry) and in isKnownSeriesKey to
use the chosen own-property test.

In `@apps/blog/src/lib/series.ts`:
- Around line 86-95: The explicit prev/next resolution
(explicitPrev/explicitNext via findBySlug) must be constrained to the same
series to avoid jumping out of the current series: after resolving
explicitPrev/explicitNext, verify the resolved post's series matches the current
post's series (e.g. derive currentSeries from posts[currentIndex].series or
data.series) and only assign to prevPage/nextPage if the series matches;
otherwise fall back to the positionalPrev/positionalNext. Update the logic
around findBySlug, explicitPrev, explicitNext, prevPage and nextPage to perform
this series-equality check before using the explicit links.
🪄 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: 5c6464e4-86b8-417e-a055-c9d570e007c9

📥 Commits

Reviewing files that changed from the base of the PR and between 3a3c51a and 3bebcbc.

📒 Files selected for processing (61)
  • apps/blog/content/blog/backend-prisma-typescript-orm-with-postgresql-auth-mngp1ps7kip4/index.mdx
  • apps/blog/content/blog/backend-prisma-typescript-orm-with-postgresql-data-modeling-tsjs1ps7kip1/index.mdx
  • apps/blog/content/blog/backend-prisma-typescript-orm-with-postgresql-deployment-bbba1ps7kip5/index.mdx
  • apps/blog/content/blog/backend-prisma-typescript-orm-with-postgresql-rest-api-validation-dcba1ps7kip3/index.mdx
  • apps/blog/content/blog/data-migrations-in-prisma-next/index.mdx
  • apps/blog/content/blog/e2e-type-safety-graphql-react-1-I2GxIfxkSZ/index.mdx
  • apps/blog/content/blog/e2e-type-safety-graphql-react-2-j9mEyHY0Ej/index.mdx
  • apps/blog/content/blog/e2e-type-safety-graphql-react-3-fbV2ZVIGWg/index.mdx
  • apps/blog/content/blog/e2e-type-safety-graphql-react-4-JaHA8GbkER/index.mdx
  • apps/blog/content/blog/from-rust-to-typescript-a-new-chapter-for-prisma-orm/index.mdx
  • apps/blog/content/blog/fullstack-nextjs-graphql-prisma-2-fwpc6ds155/index.mdx
  • apps/blog/content/blog/fullstack-nextjs-graphql-prisma-3-clxbrcqppv/index.mdx
  • apps/blog/content/blog/fullstack-nextjs-graphql-prisma-4-1k1kc83x3v/index.mdx
  • apps/blog/content/blog/fullstack-nextjs-graphql-prisma-5-m2fna60h7c/index.mdx
  • apps/blog/content/blog/fullstack-nextjs-graphql-prisma-oklidw1rhw/index.mdx
  • apps/blog/content/blog/fullstack-remix-prisma-mongodb-1-7d0bftxbmb6r/index.mdx
  • apps/blog/content/blog/fullstack-remix-prisma-mongodb-2-ZTmOy58p4re8/index.mdx
  • apps/blog/content/blog/fullstack-remix-prisma-mongodb-3-By5pmN5Nzo1v/index.mdx
  • apps/blog/content/blog/fullstack-remix-prisma-mongodb-4-l3mwep4zlim2/index.mdx
  • apps/blog/content/blog/fullstack-remix-prisma-mongodb-5-gOhQsnfUPXSx/index.mdx
  • apps/blog/content/blog/improving-query-performance-using-indexes-1-zuLNZwBkuL/index.mdx
  • apps/blog/content/blog/improving-query-performance-using-indexes-2-MyoiJNMFTsfq/index.mdx
  • apps/blog/content/blog/improving-query-performance-using-indexes-3-kduk351qv1/index.mdx
  • apps/blog/content/blog/introducing-graphql-nexus-code-first-graphql-server-development-ll6s1yy5cxl5/index.mdx
  • apps/blog/content/blog/nestjs-prisma-authentication-7D056s1s0k3l/index.mdx
  • apps/blog/content/blog/nestjs-prisma-error-handling-7D056s1kOop2/index.mdx
  • apps/blog/content/blog/nestjs-prisma-relational-data-7D056s1kOabc/index.mdx
  • apps/blog/content/blog/nestjs-prisma-rest-api-7D056s1BmOL0/index.mdx
  • apps/blog/content/blog/nestjs-prisma-validation-7D056s1kOla1/index.mdx
  • apps/blog/content/blog/prisma-6-9-0-release/index.mdx
  • apps/blog/content/blog/prisma-next-call-for-extension-authors/index.mdx
  • apps/blog/content/blog/prisma-next-early-access-write-your-contract-prompt-your-agent-ship-your-app/index.mdx
  • apps/blog/content/blog/prisma-next-roadmap-april-milestone/index.mdx
  • apps/blog/content/blog/prisma-next-roadmap/index.mdx
  • apps/blog/content/blog/prisma-orm-without-rust-latest-performance-benchmarks/index.mdx
  • apps/blog/content/blog/rethinking-database-migrations/index.mdx
  • apps/blog/content/blog/rust-free-prisma-orm-is-ready-for-production/index.mdx
  • apps/blog/content/blog/rust-to-typescript-update-boosting-prisma-orm-performance/index.mdx
  • apps/blog/content/blog/testing-series-1-8eRB5p0Y8o/index.mdx
  • apps/blog/content/blog/testing-series-2-xPhjjmIEsM/index.mdx
  • apps/blog/content/blog/testing-series-3-aBUyF8nxAn/index.mdx
  • apps/blog/content/blog/testing-series-4-OVXtDis201/index.mdx
  • apps/blog/content/blog/testing-series-5-xWogenROXm/index.mdx
  • apps/blog/content/blog/the-next-evolution-of-prisma-orm/index.mdx
  • apps/blog/content/blog/the-problems-of-schema-first-graphql-development-x1mn4cb0tyl3/index.mdx
  • apps/blog/content/blog/try-the-new-rust-free-version-of-prisma-orm-early-access/index.mdx
  • apps/blog/content/blog/typescript-migrations-in-prisma-next/index.mdx
  • apps/blog/content/blog/using-graphql-nexus-with-a-database-pmyl3660ncst/index.mdx
  • apps/blog/source.config.ts
  • apps/blog/src/app/(blog)/[slug]/page.tsx
  • apps/blog/src/app/(blog)/page.tsx
  • apps/blog/src/app/(blog)/series/[key]/page.tsx
  • apps/blog/src/app/(blog)/series/page.tsx
  • apps/blog/src/components/BlogHomeClient.tsx
  • apps/blog/src/components/SeriesBanner.tsx
  • apps/blog/src/components/SeriesMarker.tsx
  • apps/blog/src/components/SeriesNavigation.tsx
  • apps/blog/src/components/SeriesShelf.tsx
  • apps/blog/src/lib/format.ts
  • apps/blog/src/lib/series-registry.ts
  • apps/blog/src/lib/series.ts

Comment thread apps/blog/src/components/SeriesShelf.tsx Outdated
Comment thread apps/blog/src/lib/format.ts Outdated
Comment thread apps/blog/src/lib/series-registry.ts Outdated
Comment thread apps/blog/src/lib/series.ts
@AmanVarshney01
Copy link
Copy Markdown
Member

Good stuff 🚀

@AmanVarshney01 AmanVarshney01 merged commit ffe9059 into main May 28, 2026
16 of 17 checks passed
@AmanVarshney01 AmanVarshney01 deleted the series-blog branch May 28, 2026 14:51
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