Skip to content

feat: DR-7728 prisma with x#7698

Merged
carlagn merged 19 commits intomainfrom
feat/DR-7728-prisma-with-x
Apr 2, 2026
Merged

feat: DR-7728 prisma with x#7698
carlagn merged 19 commits intomainfrom
feat/DR-7728-prisma-with-x

Conversation

@carlagn
Copy link
Copy Markdown
Contributor

@carlagn carlagn commented Mar 24, 2026

Summary by CodeRabbit

  • New Features

    • Added new "Prisma with [Technology]" framework integration pages for Next.js, NestJS, and Remix with code examples and guides.
    • Added Prisma dark theme syntax highlighting for code blocks.
    • Updated site navigation with "Prisma Partners" section.
  • Refactor

    • Refactored post card rendering to use shared component library.
  • Documentation

    • Added setup guide for creating new framework integration pages.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 24, 2026

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

Project Deployment Actions Updated (UTC)
blog Ready Ready Preview, Comment Apr 2, 2026 9:48am
docs Ready Ready Preview, Comment Apr 2, 2026 9:48am
eclipse Ready Ready Preview, Comment Apr 2, 2026 9:48am
site Ready Ready Preview, Comment Apr 2, 2026 9:48am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR introduces a reusable "Prisma with" content layout system for framework pages, adds shared UI components for posts and author information, integrates Shiki-based code highlighting, refactors the blog PostCard to delegate to a shared component, updates site metadata sourcing, and provides static content JSON files for Next.js, NestJS, and Remix integration pages.

Changes

Cohort / File(s) Summary
Shared UI Components
packages/ui/src/components/post-card.tsx, packages/ui/src/components/author-avatar-group.tsx, packages/ui/src/components/quote.tsx
Added new reusable UI components: PostCard with featured/vertical layout variants, AuthorAvatarGroup for rendering author avatars and names, and Quote for testimonials with author metadata.
Blog PostCard Refactor
apps/blog/src/components/PostCard.tsx
Refactored to use the new shared PostCard component from @prisma-docs/ui, removing inline layout logic and delegating post rendering through a mapped SharedPostCardItem object.
Prisma-With Layout System
apps/site/src/components/prisma-with/layout.tsx, apps/site/src/components/prisma-with/index.ts
Added core layout composition system: PrismaWithLayout orchestrates multiple section components and defines the PrismaWithData schema for consistent framework page structure.
Prisma-With Section Components
apps/site/src/components/prisma-with/hero.tsx, apps/site/src/components/prisma-with/why-section.tsx, apps/site/src/components/prisma-with/how-section.tsx, apps/site/src/components/prisma-with/resources-section.tsx, apps/site/src/components/prisma-with/quote-section.tsx, apps/site/src/components/prisma-with/community-section.tsx
Implemented six reusable section components for framework pages, including async code highlighting in HowSection and HTML content parsing across multiple sections.
Framework Page Instances
apps/site/src/app/(prisma-with)/nextjs/page.tsx, apps/site/src/app/(prisma-with)/nestjs/page.tsx
Added new framework pages that load JSON content and inline code examples, rendering via PrismaWithLayout.
Framework Content Data
apps/site/src/data/prisma-with/nextjs.json, apps/site/src/data/prisma-with/nestjs.json, apps/site/src/data/prisma-with/remix.json
Added three static JSON content files defining complete hero, feature, tabbed guide, resources, testimonial, and community sections for each framework integration page.
Code Highlighting Setup
apps/site/src/lib/shiki_prisma.ts, apps/site/package.json
Introduced Shiki-based syntax highlighter with a custom prisma-dark theme and support for TypeScript/JavaScript/JSON/Bash languages; added shiki dependency.
Site Layout & Metadata
apps/site/src/app/layout.tsx, apps/site/src/app/og/image.png/route.tsx
Updated to source metadata from @/lib/site-metadata instead of @/lib/blog-metadata; added theme initialization script, replaced FontAwesome script source, adjusted navigation (Prisma Partners/Docs links), and removed top padding from body.
Styling Updates
apps/site/src/app/global.css, packages/eclipse/src/styles/globals.css
Added .hero utility class and reformatted animation keyframes in site styles; introduced --color-disabled variable and updated --color-stroke-ppg-weak in Eclipse theme, with multi-line formatting adjustments.
Documentation
apps/site/src/components/prisma-with/README.md
Added comprehensive guide documenting the Prisma-With layout system, JSON schema, component APIs, and step-by-step instructions for creating new framework pages.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'feat: DR-7728 prisma with x' uses an issue identifier and vague placeholder language that doesn't clearly communicate what was actually implemented. Replace the vague 'prisma with x' with a specific description of the feature. For example: 'feat: DR-7728 add prisma-with layout system with nextjs and nestjs pages' or similar, reflecting the new component infrastructure and page additions.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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


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

@argos-ci
Copy link
Copy Markdown

argos-ci bot commented Mar 24, 2026

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

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Apr 2, 2026, 9:54 AM

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: 4

🧹 Nitpick comments (7)
packages/eclipse/src/styles/globals.css (1)

89-89: Identical --color-disabled in both themes may reduce contrast in dark mode.

Both light and dark themes use #4a5568 (gray-600) for --color-disabled. Against the dark theme's #030712 background, this yields roughly 4.5:1 contrast—acceptable for large text but potentially borderline for smaller UI elements. Consider using a lighter shade (e.g., #718096 or #9ca3af) in dark mode for better visibility.

Also applies to: 229-229

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/eclipse/src/styles/globals.css` at line 89, The disabled color
variable --color-disabled is identical in both themes and is too low-contrast on
the dark background; update the dark-theme definition of --color-disabled (the
declaration that currently sets --color-disabled at the dark-theme block around
the second occurrence) to a lighter gray (e.g., `#718096` or `#9ca3af`) instead of
`#4a5568`, ensure you only change the dark-theme scope (leave the light theme
value intact), and verify the resulting contrast ratio meets accessibility
guidelines for small UI text.
packages/eclipse/src/components/button.tsx (1)

24-30: Minor: Double spaces in size variant class strings.

Lines 27 and 29 have double spaces (px-3 h-element-2xl and px-4 h-element-4xl). While Tailwind handles this gracefully, it's inconsistent with the other size variants.

🧹 Proposed fix
       size: {
         lg: "px-2 h-element-lg type-text-sm-strong",
         xl: "px-3 h-element-xl type-text-sm-strong",
-        "2xl": "px-3  h-element-2xl type-text-sm-strong",
+        "2xl": "px-3 h-element-2xl type-text-sm-strong",
         "3xl": "px-4 h-element-3xl type-text-sm-strong",
-        "4xl": "px-4  h-element-4xl type-heading-md",
+        "4xl": "px-4 h-element-4xl type-heading-md",
       },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/eclipse/src/components/button.tsx` around lines 24 - 30, The size
variant object in Button (the size property in
packages/eclipse/src/components/button.tsx) contains inconsistent double spaces
in the class strings for keys "2xl" and "4xl" ("px-3  h-element-2xl" and "px-4 
h-element-4xl"); update those two entries to remove the extra space so all size
classes match the single-space formatting used by the other variants in the size
object.
apps/site/src/app/(prisma-with)/nextjs/page.tsx (2)

190-190: Minor: Prefer in operator over Object.keys().includes().

Object.keys(code_obj).includes(body.value) creates an intermediate array. Using the in operator is more direct and slightly more efficient.

♻️ Simpler check
-                          {Object.keys(code_obj).includes(body.value) && (
+                          {body.value in code_obj && (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/app/`(prisma-with)/nextjs/page.tsx at line 190, Replace the
costly Object.keys(...).includes(...) check with the in operator: instead of
Object.keys(code_obj).includes(body.value) use a direct property presence check
like body.value in code_obj; update the JSX conditional that references code_obj
and body.value accordingly to avoid creating the intermediate array and keep
behavior unchanged.

80-95: Array indexing on data.hero.btns assumes at least two buttons exist.

Lines 80 and 89 directly access btns[0] and btns[1] without bounds checking. If the JSON structure changes to have fewer buttons, this will throw at runtime.

Consider adding optional chaining or restructuring:

♻️ Safer button rendering
          <div className="flex gap-4">
-            <Button variant="ppg" size="3xl" href={data.hero.btns[0].url}>
-              <span>{data.hero.btns[0].label}</span>
-              {data.hero.btns[0].icon && (
-                <i className={cn("ml-2", data.hero.btns[0].icon)} />
-              )}
-            </Button>
-            <Button
-              variant="default-stronger"
-              size="3xl"
-              href={data.hero.btns[1].url}
-            >
-              <span>{data.hero.btns[1].label}</span>
-              {data.hero.btns[1].icon && (
-                <i className={cn("ml-2", data.hero.btns[1].icon)} />
-              )}
-            </Button>
+            {data.hero.btns.map((btn, idx) => (
+              <Button
+                key={btn.url}
+                variant={idx === 0 ? "ppg" : "default-stronger"}
+                size="3xl"
+                href={btn.url}
+              >
+                <span>{btn.label}</span>
+                {btn.icon && <i className={cn("ml-2", btn.icon)} />}
+              </Button>
+            ))}
          </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/app/`(prisma-with)/nextjs/page.tsx around lines 80 - 95, The
code directly indexes data.hero.btns at btns[0] and btns[1] in the Button
rendering (inside page.tsx), which will throw if less than two buttons are
provided; update the rendering to safely handle missing items by either (a)
checking existence with optional chaining/guards before accessing
data.hero.btns[0] and data.hero.btns[1], or (b) iterating over data.hero.btns
(e.g., map) and rendering a Button for each entry, ensuring you reference
properties (label, url, icon) only when the item exists; apply this change to
the two Button usages so Button never receives undefined props.
packages/ui/src/components/quote.tsx (1)

38-45: Separator renders without a preceding title when only company is provided.

If author.title is undefined but author.company is set, the Separator will render as the first element in the title row, creating a visual artifact (a dangling vertical line before the company name).

Consider guarding the Separator so it only appears when both values exist:

♻️ Proposed fix
              {author.title && (
                <span className="font-[600] text-2xs uppercase">
                  {author.title}
                </span>
              )}
-              {author.company && (
+              {author.title && author.company && (
                <>
                  <Separator orientation="vertical" className="mx-1 h-3.5" />
-                  <span className="font-[400] text-xs uppercase text-foreground-ppg">
-                    {author.company}
-                  </span>
                </>
              )}
+              {author.company && (
+                <span className="font-[400] text-xs uppercase text-foreground-ppg">
+                  {author.company}
+                </span>
+              )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/quote.tsx` around lines 38 - 45, The Separator is
rendering even when author.title is missing, causing a dangling vertical line;
update the JSX in the quote component so the Separator is only rendered when
both author.title and author.company exist (i.e., change the condition around
Separator to check author.title && author.company rather than just
author.company), leaving the company <span className="font-[400] text-xs
uppercase text-foreground-ppg">{author.company}</span> to render independently
when only company is present; locate the fragment that contains Separator and
the company span in the Quote component and adjust the conditional rendering
accordingly.
apps/blog/src/components/PostCard.tsx (1)

52-61: Redundant date conversion on line 55.

post.date is already a string. You're converting it to a Date, then immediately back to an ISO string via toISOString(). Looking at formatDate in apps/blog/src/lib/format.ts, it already accepts an ISO string directly and handles the parsing internally.

♻️ Simplify the date formatting
  const sharedPost: SharedPostCardItem = {
    url: post.url,
    title: post.title,
-    date: formatDate(new Date(post.date).toISOString()),
+    date: formatDate(post.date),
    excerpt: post.excerpt,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/blog/src/components/PostCard.tsx` around lines 52 - 61, The date
conversion is redundant: in the SharedPostCardItem construction (sharedPost),
pass post.date directly to formatDate instead of new
Date(post.date).toISOString(); update the line in the sharedPost object from
date: formatDate(new Date(post.date).toISOString()) to date:
formatDate(post.date) so formatDate (in apps/blog/src/lib/format.ts) can parse
the ISO string itself and types remain consistent.
apps/site/src/lib/shiki_prisma.ts (1)

150-200: Mix of CSS variables and hardcoded hex colors may cause theme inconsistency.

Most token colors use CSS variables (e.g., var(--color-foreground-neutral-weak)), but several scopes use hardcoded hex values:

  • Line 153: #f92672 (tags)
  • Line 165: #96E072 (attribute strings)
  • Line 174: #f92672 (template expressions)
  • Line 180: #D5CED9 (meta template)
  • Line 186: #7cb7ff (primitive types)
  • Line 198: #FC644D (invalid tokens)

These won't adapt if you ever introduce a light-mode variant of this theme. If that's intentional (dark-only theme), this is fine. Otherwise, consider defining corresponding CSS variables for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/lib/shiki_prisma.ts` around lines 150 - 200, The theme uses
hardcoded hex colors for several token scopes (e.g., "entity.name.tag",
"meta.tag.attributes string.quoted",
"punctuation.definition.template-expression", "meta.template.expression",
"support.type.primitive", "invalid") which breaks theme adaptability; replace
those hardcoded foreground values with CSS variables (e.g.,
var(--color-token-tag), var(--color-token-attr-string),
var(--color-token-template), var(--color-token-primitive),
var(--color-token-invalid)) in the corresponding objects and add those CSS
variables to your theme root (and provide light-mode variants if needed) so
colors follow the established variable-driven system and can be switched for
light/dark themes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/site/src/app/og/image.png/route.tsx`:
- Line 1: The imported constants SITE_HOME_TITLE and SITE_HOME_DESCRIPTION are
not used — instead hardcoded strings are passed to the PrismaOGImage component;
update the PrismaOGImage invocation to pass SITE_HOME_TITLE and
SITE_HOME_DESCRIPTION (replace the literal "Prisma Blog" and the inline
description) so the OG image uses the centralized metadata values from
SITE_HOME_TITLE and SITE_HOME_DESCRIPTION.

In `@apps/site/src/data/prisma-with/nextjs.json`:
- Around line 81-117: The JSON contains three blog objects whose "url" fields
are duplicates (all "/blog/post-slug"); update each "url" value to the correct,
unique post slugs for the entries titled "How to use Prisma ORM with Next.js",
"Next.js 15 + Prisma Postgres Auth Example", and "Next.js 15 Demo App with
Prisma Postgres" by replacing the placeholder "/blog/post-slug" in their
respective objects with the real permalink for each post so each "url" field is
unique and points to the correct article.
- Around line 131-175: Several community card entries use placeholder URLs
("url": "#") which must be replaced before launch; locate the JSON objects with
titles "Modern SaaS Starter Kit: next-forge", "Prisma in Next.js - My Fav Way to
Work with Databases", "Fullstack Form Builder", "t3 Stack", and "Blitz.js" and
replace each "url": "#" with the actual target link (or a config/constant
reference) or add a clear TODO/comment pointing to the issue/PR that will supply
the correct URL so the cards navigate to real resources.

In `@packages/ui/src/components/author-avatar-group.tsx`:
- Around line 28-41: The Avatar key currently uses author.name which can
collide; change the key in the authors.map render to a stable unique value
(preferably a unique identifier like author.id if available) and fall back to a
composite or the array index to guarantee uniqueness (e.g. use author.id ||
`${author.name}-${index}` or author.id ?? index) when rendering Avatar in the
authors.map callback to avoid duplicate key warnings; update the key prop where
Avatar is returned.

---

Nitpick comments:
In `@apps/blog/src/components/PostCard.tsx`:
- Around line 52-61: The date conversion is redundant: in the SharedPostCardItem
construction (sharedPost), pass post.date directly to formatDate instead of new
Date(post.date).toISOString(); update the line in the sharedPost object from
date: formatDate(new Date(post.date).toISOString()) to date:
formatDate(post.date) so formatDate (in apps/blog/src/lib/format.ts) can parse
the ISO string itself and types remain consistent.

In `@apps/site/src/app/`(prisma-with)/nextjs/page.tsx:
- Line 190: Replace the costly Object.keys(...).includes(...) check with the in
operator: instead of Object.keys(code_obj).includes(body.value) use a direct
property presence check like body.value in code_obj; update the JSX conditional
that references code_obj and body.value accordingly to avoid creating the
intermediate array and keep behavior unchanged.
- Around line 80-95: The code directly indexes data.hero.btns at btns[0] and
btns[1] in the Button rendering (inside page.tsx), which will throw if less than
two buttons are provided; update the rendering to safely handle missing items by
either (a) checking existence with optional chaining/guards before accessing
data.hero.btns[0] and data.hero.btns[1], or (b) iterating over data.hero.btns
(e.g., map) and rendering a Button for each entry, ensuring you reference
properties (label, url, icon) only when the item exists; apply this change to
the two Button usages so Button never receives undefined props.

In `@apps/site/src/lib/shiki_prisma.ts`:
- Around line 150-200: The theme uses hardcoded hex colors for several token
scopes (e.g., "entity.name.tag", "meta.tag.attributes string.quoted",
"punctuation.definition.template-expression", "meta.template.expression",
"support.type.primitive", "invalid") which breaks theme adaptability; replace
those hardcoded foreground values with CSS variables (e.g.,
var(--color-token-tag), var(--color-token-attr-string),
var(--color-token-template), var(--color-token-primitive),
var(--color-token-invalid)) in the corresponding objects and add those CSS
variables to your theme root (and provide light-mode variants if needed) so
colors follow the established variable-driven system and can be switched for
light/dark themes.

In `@packages/eclipse/src/components/button.tsx`:
- Around line 24-30: The size variant object in Button (the size property in
packages/eclipse/src/components/button.tsx) contains inconsistent double spaces
in the class strings for keys "2xl" and "4xl" ("px-3  h-element-2xl" and "px-4 
h-element-4xl"); update those two entries to remove the extra space so all size
classes match the single-space formatting used by the other variants in the size
object.

In `@packages/eclipse/src/styles/globals.css`:
- Line 89: The disabled color variable --color-disabled is identical in both
themes and is too low-contrast on the dark background; update the dark-theme
definition of --color-disabled (the declaration that currently sets
--color-disabled at the dark-theme block around the second occurrence) to a
lighter gray (e.g., `#718096` or `#9ca3af`) instead of `#4a5568`, ensure you only
change the dark-theme scope (leave the light theme value intact), and verify the
resulting contrast ratio meets accessibility guidelines for small UI text.

In `@packages/ui/src/components/quote.tsx`:
- Around line 38-45: The Separator is rendering even when author.title is
missing, causing a dangling vertical line; update the JSX in the quote component
so the Separator is only rendered when both author.title and author.company
exist (i.e., change the condition around Separator to check author.title &&
author.company rather than just author.company), leaving the company <span
className="font-[400] text-xs uppercase
text-foreground-ppg">{author.company}</span> to render independently when only
company is present; locate the fragment that contains Separator and the company
span in the Quote component and adjust the conditional rendering accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e45877d2-0b31-4359-9122-048be6b88fc4

📥 Commits

Reviewing files that changed from the base of the PR and between 1305845 and 044101d.

⛔ Files ignored due to path filters (6)
  • apps/site/public/icons/technologies/nextjs-light.svg is excluded by !**/*.svg
  • apps/site/public/icons/technologies/nextjs.svg is excluded by !**/*.svg
  • apps/site/public/icons/technologies/prisma.svg is excluded by !**/*.svg
  • apps/site/public/icons/technologies/prisma_light.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/hero-grid.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • apps/blog/src/components/PostCard.tsx
  • apps/site/package.json
  • apps/site/src/app/(index)/page.tsx
  • apps/site/src/app/(prisma-with)/nextjs/page.tsx
  • apps/site/src/app/global.css
  • apps/site/src/app/layout.tsx
  • apps/site/src/app/og/image.png/route.tsx
  • apps/site/src/data/prisma-with/nextjs.json
  • apps/site/src/lib/cn.ts
  • apps/site/src/lib/shiki_prisma.ts
  • apps/site/src/lib/site-metadata.ts
  • packages/eclipse/src/components/button.tsx
  • packages/eclipse/src/styles/globals.css
  • packages/ui/src/components/author-avatar-group.tsx
  • packages/ui/src/components/post-card.tsx
  • packages/ui/src/components/quote.tsx
  • packages/ui/src/styles/globals.css

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: 3

🧹 Nitpick comments (1)
apps/site/src/app/(prisma-with)/nextjs/page.tsx (1)

79-95: Render the hero CTAs from the data array.

This section assumes data.hero.btns always has exactly two items. A one-button payload will throw at render time, and any extra CTA is silently ignored. Mapping the array keeps the hero aligned with the rest of the JSON-driven page.

Suggested refactor
-          <div className="flex gap-4 md:justify-start justify-center">
-            <Button variant="ppg" size="3xl" href={data.hero.btns[0].url}>
-              <span>{data.hero.btns[0].label}</span>
-              {data.hero.btns[0].icon && (
-                <i className={cn("ml-2", data.hero.btns[0].icon)} />
-              )}
-            </Button>
-            <Button
-              variant="default-stronger"
-              size="3xl"
-              href={data.hero.btns[1].url}
-            >
-              <span>{data.hero.btns[1].label}</span>
-              {data.hero.btns[1].icon && (
-                <i className={cn("ml-2", data.hero.btns[1].icon)} />
-              )}
-            </Button>
-          </div>
+          <div className="flex gap-4 md:justify-start justify-center">
+            {data.hero.btns.map((btn, idx) => (
+              <Button
+                key={`${btn.label}-${btn.url}`}
+                variant={idx === 0 ? "ppg" : "default-stronger"}
+                size="3xl"
+                href={btn.url}
+              >
+                <span>{btn.label}</span>
+                {btn.icon && <i className={cn("ml-2", btn.icon)} />}
+              </Button>
+            ))}
+          </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/app/`(prisma-with)/nextjs/page.tsx around lines 79 - 95, The
hard-coded two-Button render assumes data.hero.btns has exactly two items;
change the JSX in the hero section to map over data.hero.btns and render a
Button for each item (use data.hero.btns.map((btn, i) => ...)), supplying key
(e.g. btn.url or btn.label), href={btn.url}, size="3xl", and determine variant
by preferring btn.variant if present otherwise use i === 0 ? "ppg" :
"default-stronger"; preserve the icon rendering (btn.icon => <i
className={cn("ml-2", btn.icon)} />) and label span so any number of CTAs in
data.hero.btns are rendered safely.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/site/src/app/`(prisma-with)/nextjs/page.tsx:
- Around line 241-243: The imageAlt value is hardcoded to "Post image" for each
card; update the card rendering (where imageSrc: card.image, imageAlt: "Post
image", badge: card.badge is set) to use a meaningful alt from the card data
(e.g., imageAlt: card.alt || card.title) and fall back to an empty string when
the image is purely decorative (e.g., imageAlt: card.alt ?? "") so each card
either provides descriptive alt text or an empty alt for decorative images.
- Around line 189-208: The wrapper div is rendered even when no snippet exists
for the active tab because the guard checks
Object.keys(code_obj).includes(body.value) only inside the padded/bordered
container; move that guard up to wrap the entire block so the container (and
CodeBlock) is not rendered when code_obj lacks body.value, i.e. check presence
before rendering the outer <div> that contains CodeBlock (references: code_obj,
body.value, CodeBlock, prisma_highlighter.codeToHtml), or alternatively
validate/throw earlier if every tab must have a snippet.
- Around line 35-39: The Page component currently treats params as a synchronous
object; update it to accept and await the async params pattern used by the App
Router by changing the prop type to { params: Promise<{ slug: string }> } (or
similar), then await the params inside the function (e.g., const { slug } =
await params) and pass slug to prisma.post.findUnique({ where: { slug } });
adjust the Page signature and the const post lookup accordingly in the Page
function.

---

Nitpick comments:
In `@apps/site/src/app/`(prisma-with)/nextjs/page.tsx:
- Around line 79-95: The hard-coded two-Button render assumes data.hero.btns has
exactly two items; change the JSX in the hero section to map over data.hero.btns
and render a Button for each item (use data.hero.btns.map((btn, i) => ...)),
supplying key (e.g. btn.url or btn.label), href={btn.url}, size="3xl", and
determine variant by preferring btn.variant if present otherwise use i === 0 ?
"ppg" : "default-stronger"; preserve the icon rendering (btn.icon => <i
className={cn("ml-2", btn.icon)} />) and label span so any number of CTAs in
data.hero.btns are rendered safely.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0d40df2b-c68a-44f2-8599-c4c3c3e9ef2d

📥 Commits

Reviewing files that changed from the base of the PR and between 044101d and 4a3ebdf.

⛔ Files ignored due to path filters (1)
  • apps/site/public/photos/people/guillermo-rauch.jpeg is excluded by !**/*.jpeg
📒 Files selected for processing (2)
  • apps/site/src/app/(prisma-with)/nextjs/page.tsx
  • apps/site/src/data/prisma-with/nextjs.json
✅ Files skipped from review due to trivial changes (1)
  • apps/site/src/data/prisma-with/nextjs.json

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: 4

🧹 Nitpick comments (1)
apps/site/src/components/prisma-with/community-section.tsx (1)

31-32: Simplify redundant index conditions for class assignment.

idx >= 3 && idx === 3 and idx >= 3 && idx === 4 can be reduced to direct equality checks.

♻️ Suggested cleanup
-                idx >= 3 && idx === 3 && "md:col-start-2",
-                idx >= 3 && idx === 4 && "md:col-start-4",
+                idx === 3 && "md:col-start-2",
+                idx === 4 && "md:col-start-4",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/components/prisma-with/community-section.tsx` around lines 31 -
32, The class assignment uses redundant checks like "idx >= 3 && idx === 3" and
"idx >= 3 && idx === 4"; simplify these to direct equality checks by replacing
them with "idx === 3" and "idx === 4" respectively wherever the conditional
class logic for idx is applied (look for the JSX/array of class names that
includes those expressions in the community-section component).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/site/src/app/`(prisma-with)/nestjs/page.tsx:
- Around line 5-36: The codeExamples map only contains the "static-data" key, so
tabs that expect other examples render empty; update the codeExamples constant
to include entries for every tab key used by the tabbed UI (add keys matching
the tab body values such as the other example names used in the UI), keeping the
same string value shape as the existing "static-data" entry; locate the
codeExamples declaration in apps/site/src/app/(prisma-with)/nestjs/page.tsx and
add the missing keys (matching the tab identifiers) with appropriate code
strings so the tabbed section can render content for each tab.
- Around line 38-44: The page-level metadata object named metadata in page.tsx
currently references Next.js (title, description, alternates.canonical) and
should be updated to reflect NestJS instead; change the title to something like
"NestJS Database with Prisma | Next-Generation ORM for SQL Databases", adjust
the description to mention NestJS (e.g., "Prisma is a next-generation ORM for
Node.js & TypeScript and a great fit for NestJS apps..."), and update
alternates.canonical to the correct NestJS URL (replace the "/nextjs" path with
the appropriate "/nestjs" canonical path).

In `@apps/site/src/components/prisma-with/hero.tsx`:
- Around line 13-17: The Hero component assumes two CTAs but btns is typed as an
unconstrained Array — guard against missing entries or enforce a two-item tuple:
either change the btns type to a tuple like [FirstBtn, SecondBtn?] (making the
second optional) or add runtime checks before accessing data.btns[1].url /
data.btns[1].label; update all usages in hero.tsx (places accessing data.btns[1]
around the btns declaration and the render block at lines ~40-55) to use
optional chaining and conditional rendering (e.g., render second button only if
data.btns[1] exists) so no runtime crash occurs.

In `@apps/site/src/components/prisma-with/README.md`:
- Around line 11-22: In README.md update the fenced code block that lists the
prisma-with directory tree to include a language identifier (e.g., ```text) on
the opening fence so the block becomes a labeled code fence; locate the block
that begins with "prisma-with/" and replace the opening ``` with ```text to
satisfy markdown linting.

---

Nitpick comments:
In `@apps/site/src/components/prisma-with/community-section.tsx`:
- Around line 31-32: The class assignment uses redundant checks like "idx >= 3
&& idx === 3" and "idx >= 3 && idx === 4"; simplify these to direct equality
checks by replacing them with "idx === 3" and "idx === 4" respectively wherever
the conditional class logic for idx is applied (look for the JSX/array of class
names that includes those expressions in the community-section component).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 58e354b6-26ae-4ba8-b962-bb14c235dede

📥 Commits

Reviewing files that changed from the base of the PR and between 4a3ebdf and 6876053.

📒 Files selected for processing (13)
  • apps/site/src/app/(prisma-with)/nestjs/page.tsx
  • apps/site/src/app/(prisma-with)/nextjs/page.tsx
  • apps/site/src/components/prisma-with/README.md
  • apps/site/src/components/prisma-with/community-section.tsx
  • apps/site/src/components/prisma-with/hero.tsx
  • apps/site/src/components/prisma-with/how-section.tsx
  • apps/site/src/components/prisma-with/index.ts
  • apps/site/src/components/prisma-with/layout.tsx
  • apps/site/src/components/prisma-with/quote-section.tsx
  • apps/site/src/components/prisma-with/resources-section.tsx
  • apps/site/src/components/prisma-with/why-section.tsx
  • apps/site/src/data/prisma-with/nestjs.json
  • apps/site/src/data/prisma-with/remix.json
✅ Files skipped from review due to trivial changes (4)
  • apps/site/src/components/prisma-with/index.ts
  • apps/site/src/data/prisma-with/nestjs.json
  • apps/site/src/data/prisma-with/remix.json
  • apps/site/src/components/prisma-with/resources-section.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/site/src/app/(prisma-with)/nextjs/page.tsx

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: 2

🧹 Nitpick comments (2)
packages/ui/src/components/post-card.tsx (2)

27-27: Redundant variable aliasing.

isFeatured is simply assigned from featured without any transformation. You can use featured directly throughout the component to reduce cognitive overhead.

♻️ Suggested simplification
-  const isFeatured = featured;
-  const imageSizes = isFeatured ? "(min-width: 640px) 50vw, 100vw" : "384px";
+  const imageSizes = featured ? "(min-width: 640px) 50vw, 100vw" : "384px";

Then replace all isFeatured references with featured.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/post-card.tsx` at line 27, Remove the redundant
alias by deleting the const isFeatured = featured; line and replace all uses of
isFeatured in the component with the original prop/variable featured (e.g.,
update any conditional checks, classes, or JSX that reference isFeatured to use
featured instead). Ensure imports/props/destructuring that provide featured
remain unchanged and run tests/typechecks to confirm no remaining references to
isFeatured.

104-111: Heavy style overrides on Card component.

Using multiple !important overrides (rounded-none!, border-none!) to reset the Card's base styles is a design smell. If the featured layout consistently needs these resets, consider either:

  1. Adding a variant prop to the Card component (e.g., variant="flat")
  2. Using a simpler container element instead of Card when these styles aren't needed

This isn't blocking, but worth noting for future maintainability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/post-card.tsx` around lines 104 - 111, The Card
usage in the post-card component applies heavy "!important" style resets
(classes like "rounded-none!" and "border-none!") — change this by either (A)
updating the Card API to accept a new variant prop (e.g., Card variant="flat")
and map that variant to the flat styles inside the Card implementation, then
replace the inline "!important" classes on the Card component in this file with
variant="flat" and only the remaining needed layout classes via className, or
(B) if the Card base styles are not needed for this layout, swap the Card here
for a plain semantic container (e.g., a div) and move the layout classes
(cn(..., !vertical && "order-2 gap-0")) to that container; reference the Card
component usage and the local variables postBody and vertical when making the
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/ui/src/components/post-card.tsx`:
- Line 28: The computed but unused imageSizes constant should be either removed
or applied to the image element in this component (PostCard / the component in
post-card.tsx); choose one: if responsive sizes were intended, add the
sizes={imageSizes} prop to the <img> (or the Image component being rendered) so
the browser/renderer can use it, otherwise delete the imageSizes declaration to
remove dead code and update any related imports or variable references
accordingly.
- Line 44: The wrapper class string in the PostCard component contains an
invalid Tailwind utility ("cover") in the expression vertical && "order-none!
h-52 cover"; remove the "cover" token so the conditional becomes vertical &&
"order-none! h-52" (or replace it with a valid intented utility if you meant a
specific layout effect). Update the string in the component where the
conditional class is used (the expression containing "order-none! h-52 cover")
and ensure object-cover remains on the image element (used earlier) as-is.

---

Nitpick comments:
In `@packages/ui/src/components/post-card.tsx`:
- Line 27: Remove the redundant alias by deleting the const isFeatured =
featured; line and replace all uses of isFeatured in the component with the
original prop/variable featured (e.g., update any conditional checks, classes,
or JSX that reference isFeatured to use featured instead). Ensure
imports/props/destructuring that provide featured remain unchanged and run
tests/typechecks to confirm no remaining references to isFeatured.
- Around line 104-111: The Card usage in the post-card component applies heavy
"!important" style resets (classes like "rounded-none!" and "border-none!") —
change this by either (A) updating the Card API to accept a new variant prop
(e.g., Card variant="flat") and map that variant to the flat styles inside the
Card implementation, then replace the inline "!important" classes on the Card
component in this file with variant="flat" and only the remaining needed layout
classes via className, or (B) if the Card base styles are not needed for this
layout, swap the Card here for a plain semantic container (e.g., a div) and move
the layout classes (cn(..., !vertical && "order-2 gap-0")) to that container;
reference the Card component usage and the local variables postBody and vertical
when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bc9cef23-437b-4488-880f-5889a74b37be

📥 Commits

Reviewing files that changed from the base of the PR and between 6876053 and 13c43c5.

📒 Files selected for processing (3)
  • apps/site/src/app/(prisma-with)/nextjs/page.tsx
  • apps/site/src/data/prisma-with/nextjs.json
  • packages/ui/src/components/post-card.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/site/src/data/prisma-with/nextjs.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/site/src/app/(prisma-with)/nextjs/page.tsx

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.

Caution

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

⚠️ Outside diff range comments (1)
apps/blog/src/components/PostCard.tsx (1)

12-18: ⚠️ Potential issue | 🟡 Minor

Either thread authorSrc through here or remove it from PostCardItem.

The component still advertises authorSrc, but the new adapter never reads it and always re-resolves the avatar via getAuthorProfiles(). That makes the prop contract misleading and drops explicit avatar overrides if any callers rely on them.

Suggested fix
   const authorProfiles = post.author ? getAuthorProfiles([post.author]) : [];
+  const resolvedAuthorImageSrc =
+    post.authorSrc ?? authorProfiles[0]?.imageSrc ?? null;
   const author: AuthorProfile | null =
     authorProfiles.length > 0
       ? {
           name: authorProfiles[0].name,
-          imageSrc: authorProfiles[0].imageSrc
-            ? withBlogBasePathForImageSrc(authorProfiles[0].imageSrc)
+          imageSrc: resolvedAuthorImageSrc
+            ? withBlogBasePathForImageSrc(resolvedAuthorImageSrc)
             : null,
         }
       : null;

Also applies to: 34-43

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/blog/src/components/PostCard.tsx` around lines 12 - 18, PostCardItem
declares authorSrc but the PostCard component never uses it (getAuthorProfiles
always resolves the avatar), so either remove authorSrc from PostCardItem or
thread it through and prefer it over the resolved avatar; to fix, update the
PostCard component (and any helper that maps props) to check
PostCardItem.authorSrc and use that as the avatar source when present, falling
back to getAuthorProfiles(...) only when authorSrc is null/undefined, or else
delete authorSrc from the PostCardItem type if you want to force resolution via
getAuthorProfiles.
🧹 Nitpick comments (1)
apps/blog/src/components/PostCard.tsx (1)

15-15: Simplify date handling by passing the raw date string directly to formatDate().

On line 55, the code passes new Date(post.date).toISOString() to formatDate(). Since formatDate() creates a new Date() again internally, this chains unnecessary date parsing. The blog post dates in your data are already in a parseable format ("2020-06-09"), so you can pass post.date directly to formatDate().

Before and after
- date: formatDate(new Date(post.date).toISOString()),
+ date: formatDate(post.date),

This reduces unnecessary object creation and parsing in the render path while still giving formatDate() a valid input.

Also applies to: 52-56

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/blog/src/components/PostCard.tsx` at line 15, The render in the PostCard
component is creating an extra Date object and toISOString() before passing the
value to formatDate; instead, pass the raw post.date string directly to
formatDate (replace new Date(post.date).toISOString() with post.date) in the
PostCard render path so formatDate receives the parseable string and avoids
redundant date construction; update any other occurrences in the same block
(lines handling post.date in PostCard) to use post.date as well.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/blog/src/components/PostCard.tsx`:
- Around line 12-18: PostCardItem declares authorSrc but the PostCard component
never uses it (getAuthorProfiles always resolves the avatar), so either remove
authorSrc from PostCardItem or thread it through and prefer it over the resolved
avatar; to fix, update the PostCard component (and any helper that maps props)
to check PostCardItem.authorSrc and use that as the avatar source when present,
falling back to getAuthorProfiles(...) only when authorSrc is null/undefined, or
else delete authorSrc from the PostCardItem type if you want to force resolution
via getAuthorProfiles.

---

Nitpick comments:
In `@apps/blog/src/components/PostCard.tsx`:
- Line 15: The render in the PostCard component is creating an extra Date object
and toISOString() before passing the value to formatDate; instead, pass the raw
post.date string directly to formatDate (replace new
Date(post.date).toISOString() with post.date) in the PostCard render path so
formatDate receives the parseable string and avoids redundant date construction;
update any other occurrences in the same block (lines handling post.date in
PostCard) to use post.date as well.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c25d7beb-6c66-4b07-9ec4-4e866b5882c1

📥 Commits

Reviewing files that changed from the base of the PR and between 13c43c5 and 2ba3fdb.

⛔ Files ignored due to path filters (5)
  • apps/site/public/icons/technologies/nextjs-light.svg is excluded by !**/*.svg
  • apps/site/public/icons/technologies/nextjs.svg is excluded by !**/*.svg
  • apps/site/public/icons/technologies/prisma.svg is excluded by !**/*.svg
  • apps/site/public/icons/technologies/prisma_light.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/hero-grid.svg is excluded by !**/*.svg
📒 Files selected for processing (2)
  • apps/blog/src/components/PostCard.tsx
  • apps/site/package.json
✅ Files skipped from review due to trivial changes (1)
  • apps/site/package.json

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