Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughReplaces local blog card UI with a shared PostCard, adds shared UI components (PostCard, Quote, AuthorAvatarGroup), introduces a data-driven "prisma-with" system (JSON pages, layout, sections, README), adds shiki-based highlighter and theme, updates site layout/navigation/theme init and dependencies, and adjusts button variants and global styles. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
The latest updates on your projects. Learn more about Argos notifications ↗︎
|
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (7)
packages/eclipse/src/styles/globals.css (1)
89-89: Identical--color-disabledin 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#030712background, 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.,#718096or#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-2xlandpx-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: Preferinoperator overObject.keys().includes().
Object.keys(code_obj).includes(body.value)creates an intermediate array. Using theinoperator 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 ondata.hero.btnsassumes at least two buttons exist.Lines 80 and 89 directly access
btns[0]andbtns[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 onlycompanyis provided.If
author.titleisundefinedbutauthor.companyis set, theSeparatorwill 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.dateis already astring. You're converting it to aDate, then immediately back to an ISO string viatoISOString(). Looking atformatDateinapps/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
⛔ Files ignored due to path filters (6)
apps/site/public/icons/technologies/nextjs-light.svgis excluded by!**/*.svgapps/site/public/icons/technologies/nextjs.svgis excluded by!**/*.svgapps/site/public/icons/technologies/prisma.svgis excluded by!**/*.svgapps/site/public/icons/technologies/prisma_light.svgis excluded by!**/*.svgapps/site/public/illustrations/hero-grid.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
apps/blog/src/components/PostCard.tsxapps/site/package.jsonapps/site/src/app/(index)/page.tsxapps/site/src/app/(prisma-with)/nextjs/page.tsxapps/site/src/app/global.cssapps/site/src/app/layout.tsxapps/site/src/app/og/image.png/route.tsxapps/site/src/data/prisma-with/nextjs.jsonapps/site/src/lib/cn.tsapps/site/src/lib/shiki_prisma.tsapps/site/src/lib/site-metadata.tspackages/eclipse/src/components/button.tsxpackages/eclipse/src/styles/globals.csspackages/ui/src/components/author-avatar-group.tsxpackages/ui/src/components/post-card.tsxpackages/ui/src/components/quote.tsxpackages/ui/src/styles/globals.css
| @@ -1,4 +1,4 @@ | |||
| import { SITE_HOME_DESCRIPTION, SITE_HOME_TITLE } from "@/lib/blog-metadata"; | |||
| import { SITE_HOME_DESCRIPTION, SITE_HOME_TITLE } from "@/lib/site-metadata"; | |||
There was a problem hiding this comment.
Imported constants are unused—hardcoded values are passed instead.
You import SITE_HOME_DESCRIPTION and SITE_HOME_TITLE from @/lib/site-metadata, but the PrismaOGImage component receives hardcoded strings ("Prisma Blog" and the description literal). This means changes to the metadata constants won't reflect in the OG image.
🔗 Proposed fix to use the imported constants
return new ImageResponse(
<PrismaOGImage
- title="Prisma Blog"
- description="Guides, announcements, and articles about Prisma, ORMs, databases, and the data access layer."
+ title={SITE_HOME_TITLE}
+ description={SITE_HOME_DESCRIPTION}
/>,Also applies to: 180-183
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/site/src/app/og/image.png/route.tsx` at 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.
| { | ||
| "image": "/images/blog/prisma-nextjs-orm.jpg", | ||
| "url": "/blog/post-slug", | ||
| "badge": "Release", | ||
| "date": "October 22, 2025", | ||
| "title": "How to use Prisma ORM with Next.js", | ||
| "description": "Learn how to build a fullstack Next.js 15 app with Prisma Postgres from scratch! This tutorial starts...", | ||
| "author": { | ||
| "name": "Johan Schmidt", | ||
| "avatar": "/images/authors/johan-schmidt.jpg" | ||
| } | ||
| }, | ||
| { | ||
| "image": "/images/blog/nextjs-prisma-postgres-auth.jpg", | ||
| "badge": "Release", | ||
| "date": "October 22, 2025", | ||
| "url": "/blog/post-slug", | ||
| "title": "Next.js 15 + Prisma Postgres Auth Example", | ||
| "description": "This demo for a blogging application demonstrates how to build login and functionalit...", | ||
| "author": { | ||
| "name": "Johan Schmidt", | ||
| "avatar": "/images/authors/johan-schmidt.jpg" | ||
| } | ||
| }, | ||
| { | ||
| "image": "/images/blog/nextjs-demo-app.jpg", | ||
| "badge": "Release", | ||
| "date": "October 22, 2025", | ||
| "url": "/blog/post-slug", | ||
| "title": "Next.js 15 Demo App with Prisma Postgres", | ||
| "description": "This demo for a blogging application demonstrates how to build login and functionalit...", | ||
| "author": { | ||
| "name": "Johan Schmidt", | ||
| "avatar": "/images/authors/johan-schmidt.jpg" | ||
| } | ||
| } | ||
| ] |
There was a problem hiding this comment.
Duplicate blog post URLs detected.
Lines 83, 97, and 109 all point to /blog/post-slug, which appears to be placeholder content. Ensure these are updated to actual post URLs before merging to production.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/site/src/data/prisma-with/nextjs.json` around lines 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.
| {authors.map((author, index) => | ||
| author.imageSrc ? ( | ||
| <Avatar | ||
| key={author.name} | ||
| format="image" | ||
| src={author.imageSrc} | ||
| alt={author.name} | ||
| size="lg" | ||
| className={ | ||
| index > 0 ? "-ml-1.5 border border-background-default" : "" | ||
| } | ||
| /> | ||
| ) : null, | ||
| )} |
There was a problem hiding this comment.
Using author.name as key may cause collisions.
If two authors share the same name (however unlikely), React will warn about duplicate keys and may exhibit unexpected rendering behavior. Consider using the array index or a unique identifier if available:
🔑 Proposed fix using index
{authors.map((author, index) =>
author.imageSrc ? (
<Avatar
- key={author.name}
+ key={`${author.name}-${index}`}
format="image"
src={author.imageSrc}
alt={author.name}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {authors.map((author, index) => | |
| author.imageSrc ? ( | |
| <Avatar | |
| key={author.name} | |
| format="image" | |
| src={author.imageSrc} | |
| alt={author.name} | |
| size="lg" | |
| className={ | |
| index > 0 ? "-ml-1.5 border border-background-default" : "" | |
| } | |
| /> | |
| ) : null, | |
| )} | |
| {authors.map((author, index) => | |
| author.imageSrc ? ( | |
| <Avatar | |
| key={`${author.name}-${index}`} | |
| format="image" | |
| src={author.imageSrc} | |
| alt={author.name} | |
| size="lg" | |
| className={ | |
| index > 0 ? "-ml-1.5 border border-background-default" : "" | |
| } | |
| /> | |
| ) : null, | |
| )} |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/ui/src/components/author-avatar-group.tsx` around lines 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.
There was a problem hiding this comment.
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.btnsalways 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
⛔ Files ignored due to path filters (1)
apps/site/public/photos/people/guillermo-rauch.jpegis excluded by!**/*.jpeg
📒 Files selected for processing (2)
apps/site/src/app/(prisma-with)/nextjs/page.tsxapps/site/src/data/prisma-with/nextjs.json
✅ Files skipped from review due to trivial changes (1)
- apps/site/src/data/prisma-with/nextjs.json
| export default async function Page({ params }: { params: { slug: string } }) { | ||
| // Fetch the post based on slug | ||
| const post = await prisma.post.findUnique({ | ||
| where: { slug: params.slug }, | ||
| }) |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In the official Next.js App Router docs, what is the current paramstype and access pattern for a dynamic routeapp/blog/[slug]/page.tsx page?
💡 Result:
In the official Next.js App Router documentation (as of March 2026), for a dynamic route at app/blog/[slug]/page.tsx, the params prop is typed as Promise<{ slug: string }> and must be awaited in an async Server Component page function. Example from the docs: export default async function Page({ params, }: { params: Promise<{ slug: string }> }) { const { slug } = await params; // Use slug... } You can also use the generated PageProps<'/blog/[slug]'> type helper for better inference: export default async function Page(props: PageProps<'/blog/[slug]'>) { const { slug } = await props.params; // Use slug... } This async params behavior was introduced in Next.js 15; earlier versions (14 and below) used synchronous { params: { slug: string } }. Since params is a Promise, the page component must be async and await it (or use React's use function). The value is { slug: string } for this single dynamic segment.
Citations:
- 1: https://nextjs.org/docs/app/api-reference/file-conventions/dynamic-routes
- 2: https://nextjs.org/docs/app/getting-started/layouts-and-pages
Update the embedded code example to use the current Next.js async params pattern.
This sample teaches synchronous params access, but the current Next.js App Router documentation specifies that params is a Promise that must be awaited in page.tsx. Since this is copy-paste-facing content, it should reflect the current best practice (Next.js 15+):
Suggested update
-export default async function Page({ params }: { params: { slug: string } }) {
- // Fetch the post based on slug
+export default async function Page({
+ params,
+}: {
+ params: Promise<{ slug: string }>
+}) {
+ const { slug } = await params
+
+ // Fetch the post based on slug
const post = await prisma.post.findUnique({
- where: { slug: params.slug },
+ where: { slug },
})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export default async function Page({ params }: { params: { slug: string } }) { | |
| // Fetch the post based on slug | |
| const post = await prisma.post.findUnique({ | |
| where: { slug: params.slug }, | |
| }) | |
| export default async function Page({ | |
| params, | |
| }: { | |
| params: Promise<{ slug: string }> | |
| }) { | |
| const { slug } = await params | |
| // Fetch the post based on slug | |
| const post = await prisma.post.findUnique({ | |
| where: { slug }, | |
| }) |
🤖 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 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.
| imageSrc: card.image, | ||
| imageAlt: "Post image", | ||
| badge: card.badge, |
There was a problem hiding this comment.
Use meaningful alt text for each post card image.
Every card passes the same "Post image" alt, so assistive tech gets identical, non-informative output for the whole grid. Please either source image-specific alt text from the data or pass "" when the artwork is decorative.
🤖 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 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.
There was a problem hiding this comment.
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 === 3andidx >= 3 && idx === 4can 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
📒 Files selected for processing (13)
apps/site/src/app/(prisma-with)/nestjs/page.tsxapps/site/src/app/(prisma-with)/nextjs/page.tsxapps/site/src/components/prisma-with/README.mdapps/site/src/components/prisma-with/community-section.tsxapps/site/src/components/prisma-with/hero.tsxapps/site/src/components/prisma-with/how-section.tsxapps/site/src/components/prisma-with/index.tsapps/site/src/components/prisma-with/layout.tsxapps/site/src/components/prisma-with/quote-section.tsxapps/site/src/components/prisma-with/resources-section.tsxapps/site/src/components/prisma-with/why-section.tsxapps/site/src/data/prisma-with/nestjs.jsonapps/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
| const codeExamples: Record<string, string> = { | ||
| "static-data": `// app/blog/[slug]/page.tsx | ||
| import { PrismaClient } from '@prisma/client' | ||
|
|
||
| const prisma = new PrismaClient() | ||
|
|
||
| // Return a list of 'params' to populate the [slug] dynamic segment | ||
| export async function generateStaticParams() { | ||
| const posts = await prisma.post.findMany() | ||
|
|
||
| return posts.map((post) => ({ | ||
| slug: post.slug, | ||
| })) | ||
| } | ||
|
|
||
| // Multiple versions of this page will be statically generated | ||
| // using the 'params' returned by 'generateStaticParams' | ||
| export default async function Page({ params }: { params: { slug: string } }) { | ||
| // Fetch the post based on slug | ||
| const post = await prisma.post.findUnique({ | ||
| where: { slug: params.slug }, | ||
| }) | ||
|
|
||
| // Simple demo rendering | ||
| return ( | ||
| <div> | ||
| <h1>{post?.title || 'Post not found'}</h1> | ||
| <p>{post?.content || 'No content available'}</p> | ||
| </div> | ||
| ) | ||
| }`, | ||
| }; |
There was a problem hiding this comment.
codeExamples is incomplete for the tab set, causing empty code areas.
This map only defines "static-data", but the tabbed section expects keys matching all tab body values. Unmatched tabs render without code content, which degrades the core walkthrough UX.
💡 Suggested fix
const codeExamples: Record<string, string> = {
"static-data": `...`,
+ "dynamic-data": `...`,
+ "server-actions": `...`,
+ "api-routes": `...`,
+ "client-components": `...`,
};🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/site/src/app/`(prisma-with)/nestjs/page.tsx around lines 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.
| export const metadata: Metadata = { | ||
| title: "Next.js Database with Prisma | Next-Generation ORM for SQL Databases", | ||
| description: | ||
| "Prisma is a next-generation ORM for Node.js & TypeScript. It's the easiest way to build Next.js apps with MySQL, PostgreSQL & SQL Server databases.", | ||
| alternates: { | ||
| canonical: "https://www.prisma.io/nextjs", | ||
| }, |
There was a problem hiding this comment.
Metadata appears copied from Next.js page instead of NestJS page.
Title and canonical currently reference Next.js (/nextjs), which is incorrect for this route and can hurt SEO/canonicalization.
💡 Suggested fix
export const metadata: Metadata = {
- title: "Next.js Database with Prisma | Next-Generation ORM for SQL Databases",
+ title: "NestJS Database with Prisma | Next-Generation ORM for SQL Databases",
description:
- "Prisma is a next-generation ORM for Node.js & TypeScript. It's the easiest way to build Next.js apps with MySQL, PostgreSQL & SQL Server databases.",
+ "Prisma is a next-generation ORM for Node.js & TypeScript. It's the easiest way to build NestJS apps with MySQL, PostgreSQL & SQL Server databases.",
alternates: {
- canonical: "https://www.prisma.io/nextjs",
+ canonical: "https://www.prisma.io/nestjs",
},
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const metadata: Metadata = { | |
| title: "Next.js Database with Prisma | Next-Generation ORM for SQL Databases", | |
| description: | |
| "Prisma is a next-generation ORM for Node.js & TypeScript. It's the easiest way to build Next.js apps with MySQL, PostgreSQL & SQL Server databases.", | |
| alternates: { | |
| canonical: "https://www.prisma.io/nextjs", | |
| }, | |
| export const metadata: Metadata = { | |
| title: "NestJS Database with Prisma | Next-Generation ORM for SQL Databases", | |
| description: | |
| "Prisma is a next-generation ORM for Node.js & TypeScript. It's the easiest way to build NestJS apps with MySQL, PostgreSQL & SQL Server databases.", | |
| alternates: { | |
| canonical: "https://www.prisma.io/nestjs", | |
| }, | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/site/src/app/`(prisma-with)/nestjs/page.tsx around lines 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).
| btns: Array<{ | ||
| label: string; | ||
| icon?: string; | ||
| url: string; | ||
| }>; |
There was a problem hiding this comment.
Guard CTA access or enforce tuple length to prevent runtime crashes.
The code assumes two buttons always exist, but btns is typed as an unconstrained array. Accessing data.btns[1].url/label will throw if only one CTA is provided.
🛠️ Suggested fix
type HeroData = {
@@
- btns: Array<{
- label: string;
- icon?: string;
- url: string;
- }>;
+ btns: [
+ {
+ label: string;
+ icon?: string;
+ url: string;
+ },
+ ...Array<{
+ label: string;
+ icon?: string;
+ url: string;
+ }>,
+ ];
};
@@
- <Button
- variant="default-stronger"
- size="3xl"
- href={data.btns[1].url}
- >
- <span>{data.btns[1].label}</span>
- {data.btns[1].icon && (
- <i className={cn("ml-2", data.btns[1].icon)} />
- )}
- </Button>
+ {data.btns[1] && (
+ <Button
+ variant="default-stronger"
+ size="3xl"
+ href={data.btns[1].url}
+ >
+ <span>{data.btns[1].label}</span>
+ {data.btns[1].icon && (
+ <i className={cn("ml-2", data.btns[1].icon)} />
+ )}
+ </Button>
+ )}Also applies to: 40-55
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/site/src/components/prisma-with/hero.tsx` around lines 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.
| ``` | ||
| prisma-with/ | ||
| ├── layout.tsx # Main layout component | ||
| ├── hero.tsx # Hero section with tech logos | ||
| ├── why-section.tsx # "Why Prisma + Tech?" card grid | ||
| ├── how-section.tsx # "How they fit together" with tabs & code | ||
| ├── resources-section.tsx # Blog posts/resources cards | ||
| ├── quote-section.tsx # Customer testimonial | ||
| ├── community-section.tsx # Community examples | ||
| ├── index.ts # Barrel exports | ||
| └── README.md # This file | ||
| ``` |
There was a problem hiding this comment.
Add a language identifier to the fenced code block.
The block starting at Line 11 should specify a language (for example text) to satisfy markdown linting.
📝 Suggested fix
-```
+```text
prisma-with/
├── layout.tsx # Main layout component
...
└── README.md # This file</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 11-11: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/site/src/components/prisma-with/README.md` around lines 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.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
packages/ui/src/components/post-card.tsx (2)
27-27: Redundant variable aliasing.
isFeaturedis simply assigned fromfeaturedwithout any transformation. You can usefeatureddirectly 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
isFeaturedreferences withfeatured.🤖 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
!importantoverrides (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:
- Adding a
variantprop to the Card component (e.g.,variant="flat")- 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
📒 Files selected for processing (3)
apps/site/src/app/(prisma-with)/nextjs/page.tsxapps/site/src/data/prisma-with/nextjs.jsonpackages/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
| vertical?: boolean; | ||
| }) { | ||
| const isFeatured = featured; | ||
| const imageSizes = isFeatured ? "(min-width: 640px) 50vw, 100vw" : "384px"; |
There was a problem hiding this comment.
Unused variable imageSizes.
The imageSizes variable is computed but never used in the component. If this was intended for the <img> tag's sizes attribute (for responsive images), it's missing. Otherwise, this dead code should be removed.
🔧 Either use it or remove it
Option A: Remove if not needed
- const imageSizes = isFeatured ? "(min-width: 640px) 50vw, 100vw" : "384px";Option B: Add to img tag if responsive sizing was intended
<img
src={post.imageSrc}
alt={post.imageAlt ?? post.title}
className={imageClassName}
loading={isFeatured ? "eager" : "lazy"}
+ sizes={imageSizes}
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const imageSizes = isFeatured ? "(min-width: 640px) 50vw, 100vw" : "384px"; | |
| // Line 28 removed - imageSizes variable is deleted |
| const imageSizes = isFeatured ? "(min-width: 640px) 50vw, 100vw" : "384px"; | |
| <img | |
| src={post.imageSrc} | |
| alt={post.imageAlt ?? post.title} | |
| className={imageClassName} | |
| loading={isFeatured ? "eager" : "lazy"} | |
| sizes={imageSizes} | |
| /> |
🤖 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 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.
| const imageWrapperClassName = cn( | ||
| "relative aspect-video w-full h-full", | ||
| isFeatured ? "order-1" : "order-2 max-w-96 hidden sm:block", | ||
| vertical && "order-none! h-52 cover", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if 'cover' is defined as a custom utility class anywhere in the codebase
rg -n "\.cover\s*\{" --type css
rg -n "'cover'|\"cover\"" --glob "tailwind.config.*"Repository: prisma/web
Length of output: 202
🏁 Script executed:
# First, let's look at the actual code in post-card.tsx around line 44
cat -n packages/ui/src/components/post-card.tsx | head -60Repository: prisma/web
Length of output: 2277
🏁 Script executed:
# Search for cover class definition more broadly (without type restrictions)
rg -n "cover\s*\{" --type-list | head -20
rg -in "cover\s*:" packages/ui/src --type css --type scss --type postcssRepository: prisma/web
Length of output: 472
🏁 Script executed:
# Check tailwind config files
fd -name "tailwind.config.*" -o -name "tailwind.js"Repository: prisma/web
Length of output: 284
🏁 Script executed:
# Search for any custom utility definitions that might include 'cover'
rg -n "addUtilities|addComponents|addBase" packages/ui --type typescript --type javascript --type jsxRepository: prisma/web
Length of output: 88
🏁 Script executed:
# Find tailwind config files
find . -name "tailwind.config*" -type f 2>/dev/null | head -20Repository: prisma/web
Length of output: 36
🏁 Script executed:
# Search for 'cover' class definition in CSS/PostCSS files
rg "cover" --type css --type json 2>/dev/null | grep -i "cover\s*[:{]" | head -20Repository: prisma/web
Length of output: 36
🏁 Script executed:
# Broader search for custom utility setup with 'cover'
rg "cover" packages/ui --type json --type css 2>/dev/null | head -30Repository: prisma/web
Length of output: 36
🏁 Script executed:
# Search for any plugin or utility configuration that might define 'cover'
rg "addUtilities|addComponents|extend.*colors|extend.*" --type json packages/ 2>/dev/null | head -40Repository: prisma/web
Length of output: 115
🏁 Script executed:
# Check root directory
ls -la | grep -i tailwind
cat tailwind.config.* 2>/dev/null | head -50Repository: prisma/web
Length of output: 36
🏁 Script executed:
# Check packages directory structure
ls -la packages/Repository: prisma/web
Length of output: 269
🏁 Script executed:
# Look for CSS files that might define utilities
find packages/ui/src -name "*.css" -o -name "*.postcss" 2>/dev/nullRepository: prisma/web
Length of output: 88
🏁 Script executed:
# Check the eclipse package for component definitions
find packages -name "eclipse" -type d 2>/dev/nullRepository: prisma/web
Length of output: 70
🏁 Script executed:
# Search for 'cover' in all file types across the entire packages/ui
rg "cover" packages/ui/ 2>/dev/null | head -40Repository: prisma/web
Length of output: 256
🏁 Script executed:
# Check globals.css for any custom utilities
cat packages/ui/src/styles/globals.cssRepository: prisma/web
Length of output: 4100
🏁 Script executed:
# Look for all CSS files in the project
find . -name "*.css" -type f 2>/dev/null | grep -v node_modules | head -20Repository: prisma/web
Length of output: 339
🏁 Script executed:
# Check package.json to understand tailwind setup
cat packages/ui/package.json | grep -A 10 -B 5 "tailwind\|@tailwindcss"Repository: prisma/web
Length of output: 554
🏁 Script executed:
# Search for .cover class definition in all CSS files
rg "\.cover\s*\{" --type css 2>/dev/nullRepository: prisma/web
Length of output: 36
🏁 Script executed:
# Check eclipse package for any utility definitions
ls -la packages/eclipse/src/Repository: prisma/web
Length of output: 495
🏁 Script executed:
# Check if there's a tailwind config in apps or root
find . -maxdepth 3 -name "tailwind.config*" -o -name "postcss.config*" 2>/dev/null | grep -v node_modulesRepository: prisma/web
Length of output: 251
🏁 Script executed:
# Search in eclipse package for any cover definition
rg "cover" packages/eclipse/src/ 2>/dev/nullRepository: prisma/web
Length of output: 148
🏁 Script executed:
# Check if there's any CSS that might be defining cover as a utility
rg "@apply.*cover|\.cover\s*\{|\bcover\b.*@apply" . 2>/dev/null | grep -v node_modules | head -20Repository: prisma/web
Length of output: 36
🏁 Script executed:
# Final check: search all CSS/PostCSS in the entire repo for 'cover'
find . -name "*.css" -o -name "*.postcss" 2>/dev/null | grep -v node_modules | xargs grep -l "cover" 2>/dev/nullRepository: prisma/web
Length of output: 38
🏁 Script executed:
# Check postcss.config to see if there's any custom configuration that might define 'cover'
cat packages/ui/postcss.config.mjsRepository: prisma/web
Length of output: 192
🏁 Script executed:
# Look for any custom utility definitions in the entire codebase
rg "addUtilities|addComponents" . --type typescript --type javascript 2>/dev/null | grep -v node_modulesRepository: prisma/web
Length of output: 36
🏁 Script executed:
# Search the entire codebase for patterns of 'cover' being used alone (not bg-cover or object-cover)
rg "\bcover\b['\"]" packages/ui packages/eclipse 2>/dev/nullRepository: prisma/web
Length of output: 231
Remove invalid cover utility class.
The cover class is not a standard Tailwind utility and doesn't exist as a custom utility in this codebase. This appears to be a typo on a wrapper <div> element. The object-cover utility used on line 38 is correctly applied to the image itself. Consider removing cover from line 44 unless there's a specific styling intent for the wrapper—in which case, clarify what effect you're trying to achieve with the vertical layout.
🤖 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 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.
Summary by CodeRabbit
New Features
Navigation Updates
Improvements
Chores