Skip to content

feat: DR-7667 ORM page#7707

Open
carlagn wants to merge 6 commits intomainfrom
feat/DR-7667-orm
Open

feat: DR-7667 ORM page#7707
carlagn wants to merge 6 commits intomainfrom
feat/DR-7667-orm

Conversation

@carlagn
Copy link
Contributor

@carlagn carlagn commented Mar 26, 2026

Summary by CodeRabbit

  • New Features

    • Added Prisma ORM landing page featuring hero section, animated statistics, feature showcase cards, and customer testimonials
    • Added YouTube player component with thumbnail preview, autoplay controls, and play-on-scroll functionality
  • Style

    • Introduced ORM-themed color styling and variants for buttons and interactive elements

@vercel
Copy link

vercel bot commented Mar 26, 2026

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

Project Deployment Actions Updated (UTC)
blog Ready Ready Preview, Comment Mar 26, 2026 4:39pm
docs Error Error Mar 26, 2026 4:39pm
eclipse Ready Ready Preview, Comment Mar 26, 2026 4:39pm
site Ready Ready Preview, Comment Mar 26, 2026 4:39pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 26, 2026

Walkthrough

This PR introduces ORM-themed landing page features for Prisma documentation. Changes include a new ORM page component, CSS styling for ORM-branded elements, new dependencies for animated numbers and video players, new utility components, and systematic color variant support propagated through existing component libraries.

Changes

Cohort / File(s) Summary
Dependencies
apps/site/package.json, packages/ui/package.json, pnpm-workspace.yaml
Added react-animated-numbers and react-intersection-observer dependencies to enable animated counters and viewport-triggered playback.
ORM Page and Styling
apps/site/src/app/orm/page.tsx, apps/site/src/app/global.css
New ORM landing page with hero, stats, card sections, testimonials, and enterprise CTAs; extended global CSS with .box.orm gradient overrides and .link-btn styling.
New ORM Components
apps/site/src/components/orm/info-stats.tsx, packages/ui/src/components/youtube-player.tsx
InfoStats renders animated numbers with optional links; YouTubePlayer handles autoplay, thumbnail overlays, and viewport-triggered playback via intersection observer.
Color Variant Extensions
packages/eclipse/src/components/action.tsx, packages/eclipse/src/components/button.tsx
Added orm-reverse color variant to Action and Button components, supporting ORM-themed styling alongside existing variants.
Component Enhancements for Color Props
apps/site/src/components/homepage/bento.tsx, apps/site/src/components/homepage/card-section/card-section.tsx, apps/site/src/components/homepage/card-section/logo-grid.tsx, apps/site/src/components/homepage/testimonials/index.tsx, apps/site/src/components/homepage/testimonials/testimonial-item.tsx
Systematically added optional `color?: "orm"

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: DR-7667 ORM page' directly corresponds to the main changeset—a new ORM landing page implementation with supporting components and styling.

✏️ 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

argos-ci bot commented Mar 26, 2026

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

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Mar 26, 2026, 4:42 PM

Copy link
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: 5

Caution

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

⚠️ Outside diff range comments (1)
apps/site/src/components/homepage/bento.tsx (1)

172-178: ⚠️ Potential issue | 🔴 Critical

The .ppg CSS class is missing from the codebase.

The color prop accepts both "orm" and "ppg" as valid TypeScript values, but only the .box.orm CSS class is defined in global.css. If color="ppg" is passed to a Card component, the corresponding CSS styling will not be applied. Either implement the missing .box.ppg CSS class or remove "ppg" from the type definition if it's not currently in use.

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

In `@apps/site/src/components/homepage/bento.tsx` around lines 172 - 178, The
component uses a color variable passed into className via cn(...) (see the color
prop usage in the Card/Bento component) but the corresponding CSS selector
.box.ppg is missing; either add a .box.ppg rule in global.css mirroring the
styles in .box.orm (so color="ppg" gets styled), or remove "ppg" from the color
prop type/union (e.g., the CardProps or color type) so it cannot be passed;
locate the color type definition and the className usage in the Bento/Card
component to apply one of these fixes.
🧹 Nitpick comments (8)
apps/site/src/components/homepage/testimonials/index.tsx (1)

11-18: Consider reusing a typed color union here too.

color?: string in TestimonialsType and TestimonialColProps weakens compile-time guarantees. Reusing the same union type used by testimonial items would keep the API safer and consistent.

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

In `@apps/site/src/components/homepage/testimonials/index.tsx` around lines 11 -
18, Replace the loose string-typed color props with the shared color union used
by testimonial items: change the color?: string on TestimonialsType and
TestimonialColProps to the same typed union used by TestimonialItemType (e.g.,
TestimonialColor or whatever union/type is declared for item colors) so the
component API is consistent and type-safe; update any imports or exported types
as needed to reference that union and run type checks to ensure no other call
sites need adjustment.
apps/site/src/app/global.css (2)

186-210: Consider reducing hover-gradient duplication for ORM/PPG variants.

These blocks repeat the same conic-gradient structure with only accent differences, which can drift over time. A shared rule with variant-level CSS variables would be easier to maintain.

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

In `@apps/site/src/app/global.css` around lines 186 - 210, The two conic-gradient
rules for .box.orm:hover::before and [data-theme="light"] .box.orm:hover::before
are duplicated; extract a single shared rule for .box.orm:hover::before that
uses CSS variables for the differing stops (e.g., --hover-accent,
--hover-overlay-1, --hover-overlay-2, --angle) and then set those variables in
the theme-specific selector ([data-theme="light"] .box.orm and .box.orm or a
dark-theme selector) to the light/dark-specific color values so you maintain one
conic-gradient declaration and only override the per-theme variables.

126-132: Avoid !important in .box.orm background override.

Line 131 uses !important, but .box.orm already out-specifics .box. Keeping it makes future state/theme overrides harder.

♻️ Proposed fix
 .box.orm {
     background: linear-gradient(
         180deg,
         var(--color-background-default) 0%,
         var(--color-background-orm) 262.5%
-    ) !important;
+    );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/app/global.css` around lines 126 - 132, Remove the unnecessary
"!important" from the .box.orm background rule so the selector's specificity
(which already out-specifics .box) controls the style; update the .box.orm CSS
block to set the background gradient without "!important" and rely on the
selector specificity (or, if you need stronger precedence in future, use a more
specific selector like .box.orm.active rather than "!important").
apps/site/src/components/homepage/testimonials/testimonial-item.tsx (1)

15-16: Tighten color to a union type instead of string.

Line 15 allows any string, but Line 83 only supports the "orm" branch with fallback behavior. Narrowing the type prevents typo-driven styling bugs.

♻️ Proposed fix
+type TestimonialColor = "orm" | "ppg";
+
 export type TestimonialItemType = {
   text: string | React.ReactNode;
@@
-  color?: string;
+  color?: TestimonialColor;
 };

Also applies to: 26-27

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

In `@apps/site/src/components/homepage/testimonials/testimonial-item.tsx` around
lines 15 - 16, The prop type for color is too broad; replace color?: string on
the TestimonialItem props (and the similar prop type at the other occurrence)
with a narrowed union that includes the only supported variant used in
rendering—e.g. change to color?: "orm" | "default" (or the actual variant names
used across the component) so typos are caught by the typechecker; update both
the declaration at color?: string and the other prop/interface at the other
occurrence (lines 26-27) to the same union.
apps/site/src/components/orm/info-stats.tsx (1)

5-10: Consider stronger typing for the icon prop.

The icon prop is typed as any, but since it's used as a className string passed to cn(), a more precise type like string would improve clarity and catch type errors at compile time.

🔧 Suggested fix
 export const InfoStats: FunctionComponent<{
-  icon?: any;
+  icon?: string;
   number?: string;
   text?: string;
   link?: string;
 }> = ({ icon, number, text, link }) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/components/orm/info-stats.tsx` around lines 5 - 10, The icon
prop on the InfoStats component is currently typed as any; change its type to
string since it is passed into cn() as a className. Update the component
signature (InfoStats) to use icon?: string and adjust any usages that rely on
icon being a string (e.g., where cn(icon, ...) is called) so TS type-checking
will catch non-string values.
apps/site/src/app/orm/page.tsx (1)

265-268: Consider ORM-specific metadata.

The page uses generic SITE_HOME_TITLE and SITE_HOME_DESCRIPTION for metadata. For better SEO and clarity, consider creating ORM-specific title and description constants.

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

In `@apps/site/src/app/orm/page.tsx` around lines 265 - 268, The page metadata
currently uses generic SITE_HOME_TITLE and SITE_HOME_DESCRIPTION; replace these
with ORM-specific constants (e.g., ORM_HOME_TITLE and ORM_HOME_DESCRIPTION) and
update the exported metadata object (export const metadata) to reference the new
constants; add the new constants near other site constants or at top of
apps/site/src/app/orm/page.tsx and ensure any imports or references are adjusted
so the ORM page has distinct title/description for SEO.
packages/ui/src/components/youtube-player.tsx (2)

74-76: Consider a more descriptive alt text.

The generic alt="thumbnail" doesn't convey meaningful information to screen reader users. Consider accepting an optional alt or title prop to provide context about the video content.

🔧 Suggested enhancement
 export const YouTubePlayer = ({
   video,
   thumbnail,
+  thumbnailAlt = "Video thumbnail",
   className,
   ...
 }: {
   ...
+  thumbnailAlt?: string;
 }) => {

Then use:

-          alt="thumbnail"
+          alt={thumbnailAlt}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/youtube-player.tsx` around lines 74 - 76, The
image uses a non-descriptive alt ("thumbnail"); update the YouTubePlayer
component to accept an optional alt (or title) prop (e.g., altText?: string) in
its props interface, use that prop for the img alt attribute (falling back to a
sensible default like "Video thumbnail" or an empty string for decorative
images), and update any places that construct/return the thumbnail to pass the
new prop through; modify the function/component signature (YouTubePlayer) and
its prop type definition accordingly so screen readers receive meaningful
context.

94-104: Consider adding loading="lazy" for iframe performance.

For videos that aren't immediately visible or autoplaying, adding loading="lazy" can improve initial page load performance by deferring iframe loading until needed.

🔧 Suggested enhancement
           <iframe
             className={cn(
               "w-full border-0 rounded-[10px]",
               serverlessTalk && "absolute top-0 left-0 w-full h-full",
             )}
             height="287"
             src={`https://www.youtube.com/embed/${video}${getAutoplayParams()}`}
             title="YouTube Video"
+            loading="lazy"
             allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; autoplay"
             allowFullScreen
           />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/youtube-player.tsx` around lines 94 - 104, The
iframe in the YouTubePlayer component should include loading="lazy" to improve
page performance; update the iframe JSX in
packages/ui/src/components/youtube-player.tsx (the element using video,
getAutoplayParams(), serverlessTalk and cn) by adding loading="lazy", but avoid
adding lazy when autoplay is requested (detect via getAutoplayParams()
containing "autoplay=1" or by using the same autoplay flag you already use) so
autoplay behavior is preserved.
🤖 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/orm/page.tsx`:
- Around line 284-303: Two hero Button instances both render the label "Create
database" which is confusing; update the text content for the Button with
href="/docs/getting-started/quickstart-prismaPostgres" (variant="orm") to
something like "Get started" or "Quickstart" and change the Button with
href="https://console.prisma.io/..." (variant="default-stronger") to a distinct
label like "Create database" or "Open Prisma Console" so users can clearly see
one leads to docs/quickstart and the other opens the Prisma console.
- Around line 391-410: The current use of dangerouslySetInnerHTML with
review.title is an XSS risk; if review.title is static from homepage.json,
replace the dangerouslySetInnerHTML usage and render the title directly (e.g.,
output review.title as text inside the h5) to avoid injecting HTML, otherwise
sanitize the value before injecting by integrating a sanitizer (e.g., DOMPurify)
and applying it to review.title before passing to dangerouslySetInnerHTML;
update the h5 in page.tsx where review.title is used and ensure any import/usage
of Testimonials remains unchanged.
- Around line 102-108: The YouTubePlayer is being passed an invalid 12-character
video ID ("EEDGwLB55bIo") which causes YouTube to return HTTP 400; update the
video prop on the YouTubePlayer component to the correct 11-character YouTube
video ID for the intended video (ensure no extra characters/typos), then verify
the component loads properly and the thumbnail/preview still match; the change
will be in the JSX where YouTubePlayer's video prop is set.

In `@apps/site/src/components/orm/info-stats.tsx`:
- Around line 25-30: The <i> element in info-stats contains duplicate top margin
declarations: the Tailwind class "mt-1" and an inline style marginTop: '4px';
remove the redundancy by deleting the inline style object (or alternatively
remove "mt-1") so only one source of truth remains—update the <i> element's
className/props where the className={cn("mt-1 mr-4 max-w-8.5 h-9.5", icon)} and
style={{ marginTop: `4px` }} are set to keep just the Tailwind class.

In `@packages/eclipse/src/components/action.tsx`:
- Line 13: The "orm-reverse" color variant is missing a compoundVariants entry
to add a framed border when isFramed is true; add a compoundVariants object
entry that checks { color: "orm-reverse", isFramed: true } and returns the class
"border-stroke-orm-reverse" so the component (the CVA/variants definition in
components/action.tsx referencing the "orm-reverse" variant) applies the correct
border styling when isFramed is true.

---

Outside diff comments:
In `@apps/site/src/components/homepage/bento.tsx`:
- Around line 172-178: The component uses a color variable passed into className
via cn(...) (see the color prop usage in the Card/Bento component) but the
corresponding CSS selector .box.ppg is missing; either add a .box.ppg rule in
global.css mirroring the styles in .box.orm (so color="ppg" gets styled), or
remove "ppg" from the color prop type/union (e.g., the CardProps or color type)
so it cannot be passed; locate the color type definition and the className usage
in the Bento/Card component to apply one of these fixes.

---

Nitpick comments:
In `@apps/site/src/app/global.css`:
- Around line 186-210: The two conic-gradient rules for .box.orm:hover::before
and [data-theme="light"] .box.orm:hover::before are duplicated; extract a single
shared rule for .box.orm:hover::before that uses CSS variables for the differing
stops (e.g., --hover-accent, --hover-overlay-1, --hover-overlay-2, --angle) and
then set those variables in the theme-specific selector ([data-theme="light"]
.box.orm and .box.orm or a dark-theme selector) to the light/dark-specific color
values so you maintain one conic-gradient declaration and only override the
per-theme variables.
- Around line 126-132: Remove the unnecessary "!important" from the .box.orm
background rule so the selector's specificity (which already out-specifics .box)
controls the style; update the .box.orm CSS block to set the background gradient
without "!important" and rely on the selector specificity (or, if you need
stronger precedence in future, use a more specific selector like .box.orm.active
rather than "!important").

In `@apps/site/src/app/orm/page.tsx`:
- Around line 265-268: The page metadata currently uses generic SITE_HOME_TITLE
and SITE_HOME_DESCRIPTION; replace these with ORM-specific constants (e.g.,
ORM_HOME_TITLE and ORM_HOME_DESCRIPTION) and update the exported metadata object
(export const metadata) to reference the new constants; add the new constants
near other site constants or at top of apps/site/src/app/orm/page.tsx and ensure
any imports or references are adjusted so the ORM page has distinct
title/description for SEO.

In `@apps/site/src/components/homepage/testimonials/index.tsx`:
- Around line 11-18: Replace the loose string-typed color props with the shared
color union used by testimonial items: change the color?: string on
TestimonialsType and TestimonialColProps to the same typed union used by
TestimonialItemType (e.g., TestimonialColor or whatever union/type is declared
for item colors) so the component API is consistent and type-safe; update any
imports or exported types as needed to reference that union and run type checks
to ensure no other call sites need adjustment.

In `@apps/site/src/components/homepage/testimonials/testimonial-item.tsx`:
- Around line 15-16: The prop type for color is too broad; replace color?:
string on the TestimonialItem props (and the similar prop type at the other
occurrence) with a narrowed union that includes the only supported variant used
in rendering—e.g. change to color?: "orm" | "default" (or the actual variant
names used across the component) so typos are caught by the typechecker; update
both the declaration at color?: string and the other prop/interface at the other
occurrence (lines 26-27) to the same union.

In `@apps/site/src/components/orm/info-stats.tsx`:
- Around line 5-10: The icon prop on the InfoStats component is currently typed
as any; change its type to string since it is passed into cn() as a className.
Update the component signature (InfoStats) to use icon?: string and adjust any
usages that rely on icon being a string (e.g., where cn(icon, ...) is called) so
TS type-checking will catch non-string values.

In `@packages/ui/src/components/youtube-player.tsx`:
- Around line 74-76: The image uses a non-descriptive alt ("thumbnail"); update
the YouTubePlayer component to accept an optional alt (or title) prop (e.g.,
altText?: string) in its props interface, use that prop for the img alt
attribute (falling back to a sensible default like "Video thumbnail" or an empty
string for decorative images), and update any places that construct/return the
thumbnail to pass the new prop through; modify the function/component signature
(YouTubePlayer) and its prop type definition accordingly so screen readers
receive meaningful context.
- Around line 94-104: The iframe in the YouTubePlayer component should include
loading="lazy" to improve page performance; update the iframe JSX in
packages/ui/src/components/youtube-player.tsx (the element using video,
getAutoplayParams(), serverlessTalk and cn) by adding loading="lazy", but avoid
adding lazy when autoplay is requested (detect via getAutoplayParams()
containing "autoplay=1" or by using the same autoplay flag you already use) so
autoplay behavior is preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cee9e71e-cf9e-4927-a7a0-d3febed41a92

📥 Commits

Reviewing files that changed from the base of the PR and between edda9c3 and 3779ae2.

⛔ Files ignored due to path filters (15)
  • apps/site/public/icons/technologies/vscode.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/collaborative.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/collaborative_light.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/data.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/data_light.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/ide.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/ide_light.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/orm_1.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/orm_1_light.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/orm_2.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/orm_2_light.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/thumbnail.png is excluded by !**/*.png
  • apps/site/public/illustrations/orm/typesafe.svg is excluded by !**/*.svg
  • apps/site/public/illustrations/orm/typesafe_light.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • apps/site/package.json
  • apps/site/src/app/global.css
  • apps/site/src/app/orm/page.tsx
  • apps/site/src/components/homepage/bento.tsx
  • apps/site/src/components/homepage/card-section/card-section.tsx
  • apps/site/src/components/homepage/card-section/logo-grid.tsx
  • apps/site/src/components/homepage/testimonials/index.tsx
  • apps/site/src/components/homepage/testimonials/testimonial-item.tsx
  • apps/site/src/components/orm/info-stats.tsx
  • packages/eclipse/src/components/action.tsx
  • packages/eclipse/src/components/button.tsx
  • packages/ui/package.json
  • packages/ui/src/components/youtube-player.tsx
  • pnpm-workspace.yaml

Comment on lines +102 to +108
other: (
<YouTubePlayer
autoplay={false}
video="EEDGwLB55bIo"
thumbnail={"/illustrations/orm/thumbnail.png"}
/>
),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if the YouTube video ID is valid by querying the oembed endpoint
# Expect: HTTP 200 if valid, 4xx if invalid

curl -s -o /dev/null -w "%{http_code}" "https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=EEDGwLB55bIo&format=json"

Repository: prisma/web

Length of output: 57


Fix the invalid YouTube video ID.

The video ID EEDGwLB55bIo is 12 characters and fails YouTube's validation (HTTP 400 response). Standard YouTube video IDs are 11 characters. Correct the ID so the video component loads properly.

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

In `@apps/site/src/app/orm/page.tsx` around lines 102 - 108, The YouTubePlayer is
being passed an invalid 12-character video ID ("EEDGwLB55bIo") which causes
YouTube to return HTTP 400; update the video prop on the YouTubePlayer component
to the correct 11-character YouTube video ID for the intended video (ensure no
extra characters/typos), then verify the component loads properly and the
thumbnail/preview still match; the change will be in the JSX where
YouTubePlayer's video prop is set.

Comment on lines +284 to +303
<Button
variant="orm"
href="/docs/getting-started/quickstart-prismaPostgres"
size="3xl"
className="font-sans-display! font-[650]"
>
<span>Create database</span>
<i className="fa-regular fa-database ml-2" />
</Button>
<Button
variant="default-stronger"
href="https://console.prisma.io/sign-up?utm_source=website&utm_medium=index&utm_campaign=cta"
size="3xl"
target="_blank"
rel="noopener noreferrer"
className="font-sans-display! font-[650]"
>
<span>Create database</span>
<i className="fa-regular fa-database ml-2" />
</Button>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Both buttons have the same label "Create database".

The two hero buttons both display "Create database" but link to different destinations (one internal, one to console.prisma.io). Consider differentiating the labels to clarify the user journey—perhaps "Get Started" vs "Create database" or similar.

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

In `@apps/site/src/app/orm/page.tsx` around lines 284 - 303, Two hero Button
instances both render the label "Create database" which is confusing; update the
text content for the Button with
href="/docs/getting-started/quickstart-prismaPostgres" (variant="orm") to
something like "Get started" or "Quickstart" and change the Button with
href="https://console.prisma.io/..." (variant="default-stronger") to a distinct
label like "Create database" or "Open Prisma Console" so users can clearly see
one leads to docs/quickstart and the other opens the Prisma console.

Comment on lines +391 to +410
{review?.testimonials?.length > 0 && (
<div>
<div className="my-12">
<div className="px-4 py-10">
<div className="max-w-[1240px] mx-auto">
<h5
className="[&>b]:text-background-orm-reverse-strong font-sans-display stretch-display text-center text-base mb-12"
dangerouslySetInnerHTML={{ __html: review.title }}
/>
<Testimonials
noShadow
color="orm"
list={review.testimonials}
mask="linear-gradient(to bottom, transparent, black 15%, black 85%, transparent)"
/>
</div>
</div>
</div>
</div>
)}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

XSS risk with dangerouslySetInnerHTML.

The static analysis tool flagged this usage. While review.title comes from a local JSON file (homepage.json), which significantly reduces the risk, it's worth noting that any future changes to how this data is sourced could introduce vulnerabilities. If the content is truly static, consider rendering it directly or using a sanitization library like DOMPurify as a defensive measure.

🧰 Tools
🪛 ast-grep (0.41.1)

[warning] 397-397: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

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

In `@apps/site/src/app/orm/page.tsx` around lines 391 - 410, The current use of
dangerouslySetInnerHTML with review.title is an XSS risk; if review.title is
static from homepage.json, replace the dangerouslySetInnerHTML usage and render
the title directly (e.g., output review.title as text inside the h5) to avoid
injecting HTML, otherwise sanitize the value before injecting by integrating a
sanitizer (e.g., DOMPurify) and applying it to review.title before passing to
dangerouslySetInnerHTML; update the h5 in page.tsx where review.title is used
and ensure any import/usage of Testimonials remains unchanged.

Comment on lines +25 to +30
<i
className={cn("mt-1 mr-4 max-w-8.5 h-9.5", icon)}
style={{
marginTop: `4px`,
}}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Duplicate marginTop styling.

The <i> element has both the Tailwind class mt-1 (4px) and an inline style marginTop: '4px'. These are redundant. Remove one to avoid confusion.

🛠️ Proposed fix
           <i
             className={cn("mt-1 mr-4 max-w-8.5 h-9.5", icon)}
-            style={{
-              marginTop: `4px`,
-            }}
           />
📝 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.

Suggested change
<i
className={cn("mt-1 mr-4 max-w-8.5 h-9.5", icon)}
style={{
marginTop: `4px`,
}}
/>
<i
className={cn("mt-1 mr-4 max-w-8.5 h-9.5", icon)}
/>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/site/src/components/orm/info-stats.tsx` around lines 25 - 30, The <i>
element in info-stats contains duplicate top margin declarations: the Tailwind
class "mt-1" and an inline style marginTop: '4px'; remove the redundancy by
deleting the inline style object (or alternatively remove "mt-1") so only one
source of truth remains—update the <i> element's className/props where the
className={cn("mt-1 mr-4 max-w-8.5 h-9.5", icon)} and style={{ marginTop: `4px`
}} are set to keep just the Tailwind class.

color: {
ppg: "bg-background-ppg text-foreground-ppg",
orm: "bg-background-orm text-foreground-orm",
"orm-reverse": "bg-background-orm-reverse text-foreground-orm-reverse",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether orm-reverse is used with isFramed and whether reverse stroke tokens/classes exist.
rg -nP --type=tsx 'color=["'"'"']orm-reverse["'"'"']' -C3
rg -nP --type=tsx 'isFramed(\s*=|\s|:)' -C3
rg -nP 'border-stroke-orm-reverse|--color-stroke-orm-reverse' -C2

Repository: prisma/web

Length of output: 109


🏁 Script executed:

# Check if the file exists and read the relevant section
head -100 packages/eclipse/src/components/action.tsx | tail -50

Repository: prisma/web

Length of output: 1126


🏁 Script executed:

# Search for orm-reverse usage patterns (without --type flag)
rg -n "orm-reverse" packages/eclipse/src/components/

Repository: prisma/web

Length of output: 541


🏁 Script executed:

# Search for compoundVariants structure to understand the pattern
rg -n "compoundVariants" packages/eclipse/src/components/action.tsx -A 30

Repository: prisma/web

Length of output: 854


🏁 Script executed:

# Search for border-stroke classes
rg -n "border-stroke-orm" packages/

Repository: prisma/web

Length of output: 297


🏁 Script executed:

# Check for isFramed usage in the same file
rg -n "isFramed" packages/eclipse/src/components/action.tsx -B 2 -A 2

Repository: prisma/web

Length of output: 2464


Add framed border mapping for orm-reverse.

The orm-reverse variant introduced on line 13 lacks a corresponding compoundVariants entry for isFramed: true. Looking at the pattern, every other color variant (ppg, orm, error, success, etc.) has a compound variant that applies border-stroke-{color} when framed. Without this entry, orm-reverse won't receive the appropriate border styling when the component is rendered with isFramed={true}, creating an inconsistency.

♻️ Proposed fix
     compoundVariants: [
+      {
+        color: "orm-reverse",
+        isFramed: true,
+        className: "border-stroke-orm",
+      },
       // Framed border colors for each color variant
       {
         color: "ppg",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/eclipse/src/components/action.tsx` at line 13, The "orm-reverse"
color variant is missing a compoundVariants entry to add a framed border when
isFramed is true; add a compoundVariants object entry that checks { color:
"orm-reverse", isFramed: true } and returns the class
"border-stroke-orm-reverse" so the component (the CVA/variants definition in
components/action.tsx referencing the "orm-reverse" variant) applies the correct
border styling when isFramed is true.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant