Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR introduces a new Prisma Client landing page featuring an interactive API explorer with code samples, showcases supported databases and frameworks, and includes feature callouts for Prisma Studio and Migrate. Minor refinements are also applied to existing card and pricing components. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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: 8
🧹 Nitpick comments (6)
apps/site/src/components/client/api.tsx (2)
148-173:CodeUIItemsis defined inside the component — recreated every render.Defining a component inside another component means it gets a new identity on each render. This can cause unnecessary unmounting/remounting of the sub-tree. Move it outside
APIor memoize it.Move component outside or convert to a function
Either move
CodeUIItemsto module scope (outsideAPI), passingfuncSelectedandsetFuncSelectedas props, or inline it as a render function (without the JSX component pattern):+const CodeUIItems = ({ + item, + blockType, + funcSelected, + setFuncSelected, +}: { + item: any; + blockType: string; + funcSelected: any; + setFuncSelected: (func: any) => void; +}) => { + const labelToDisplay = item.functions.filter( + (i: any) => i[blockType] && i[blockType].length > 0, + ); + return ( + <ul className="flex flex-wrap my-5 mx-0 gap-2 list-none p-0"> + {labelToDisplay.map((func: any, fIndex: number) => ( + <li key={fIndex}> + <div + className={cn( + "rounded-full px-3 py-2 bg-background-default border border-stroke-neutral text-base uppercase font-sans-display font-bold tracking-wide leading-4 cursor-pointer transition-colors duration-300 ease-in-out hover:bg-foreground-orm text-foreground-neutral hover:text-foreground-neutral-reverse", + funcSelected === func && + "bg-foreground-orm text-foreground-reverse-neutral", + )} + onClick={() => setFuncSelected(func)} + > + {func.name} + </div> + </li> + ))} + </ul> + ); +}; const API = () => { // ... existing code ... - const CodeUIItems = ({ item, blockType }: any) => { - // ... remove inline definition ... - };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 148 - 173, The CodeUIItems component is recreated on every render because it's defined inside API; move CodeUIItems to module scope (outside the API component) and change it to accept props for funcSelected and setFuncSelected (and item, blockType) so it no longer closes over API state, or alternatively wrap it with React.memo/useCallback to memoize it; update where CodeUIItems is used inside API to pass the props (funcSelected, setFuncSelected, item, blockType) accordingly so the sub-tree is stable across renders.
100-110: JavaScript code is highlighted as TypeScript.When the user selects JavaScript, the code is still highlighted with
lang: "typescript"(line 105). While TypeScript highlighting usually works for JS, it can occasionally produce odd results for JS-specific patterns. Consider using the selected language:Use the correct language for highlighting
for (let index = 0; index < codeBlockSelected.length; index++) { const html = await highlighter.codeToHtml( codeBlockSelected[index], { - lang: "typescript", + lang: selectedLang.value === "js" ? "javascript" : "typescript", theme: "prisma-dark", }, );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 100 - 110, The highlighter is hardcoded to lang: "typescript" in the block that checks codeBlockSelected and funcSelected; change the call to highlighter.codeToHtml to use the actual selected language (e.g., derive a language string from funcSelected or the user's selection instead of the literal "typescript") so JavaScript selections use "javascript" (or the appropriate value) — update the lang property passed to highlighter.codeToHtml and ensure the code path that checks for "prismaCodeBlock" in funcSelected still uses the dynamic language.apps/site/src/components/homepage/card-section/card-section.tsx (1)
68-71: Intentional asymmetry?noShadowonly affects desktop images.The
noShadowflag is applied to the desktop image (line 68-71) but not to the mobile image (line 81). If this is by design — perhaps mobile always needs the shadow for visual separation — then this is fine. Otherwise, you may want to apply the same conditional logic to the mobile image.If mobile should also respect noShadow
{item.mobileImageUrl && ( <img - className="w-full h-auto shadow-[0_10px_25px_-5px_rgba(0,0,0,0.1)] sm:hidden" + className={cn( + "w-full h-auto shadow-[0_10px_25px_-5px_rgba(0,0,0,0.1)] sm:hidden", + item.noShadow && "shadow-none", + )} src={Also applies to: 79-88
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/homepage/card-section/card-section.tsx` around lines 68 - 71, The desktop image className uses the item.noShadow conditional but the mobile image does not, causing asymmetry; update the mobile image's className (the one rendering with "sm:hidden" / mobile view) to include the same conditional (item.noShadow && "shadow-none") so both images respect the noShadow flag, and mirror this change for the other similar occurrence referenced around lines 79-88 in card-section.tsx.apps/site/src/lib/shiki_prisma.ts (2)
222-244: Potential race condition in highlighter initialization.If
getHighlighter()is called multiple times concurrently before the first call completes, each call will seeprisma_highlighterasnulland create a new highlighter. While not catastrophic (the last one assigned wins), it wastes resources loading the highlighter multiple times.A simple fix is to cache the promise instead of the result:
Cache the promise to prevent duplicate initialization
-let prisma_highlighter: Awaited<ReturnType<typeof createHighlighter>> | null = - null; +let highlighterPromise: ReturnType<typeof createHighlighter> | null = null; async function getHighlighter() { - if (!prisma_highlighter) { - prisma_highlighter = await createHighlighter({ + if (!highlighterPromise) { + highlighterPromise = createHighlighter({ themes: [prismaTheme], langs: [ "typescript", "javascript", "jsx", "tsx", "json", "bash", "sh", "prisma", "sql", "diff", ], }); } - return prisma_highlighter; + return highlighterPromise; }🤖 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 222 - 244, The current getHighlighter implementation can trigger multiple concurrent createHighlighter calls because prisma_highlighter is null until the first await completes; change the caching to store the initialization Promise instead of the resolved result—e.g., make prisma_highlighter hold the Promise returned by createHighlighter (or introduce prisma_highlighterPromise) and on first call assign prisma_highlighter = createHighlighter({...}) and then await it in getHighlighter before returning the resolved highlighter; update the prisma_highlighter type accordingly so subsequent concurrent calls reuse the same Promise and avoid duplicate initializations.
246-246: Confusing export alias.Exporting
getHighlighterasprisma_highlighteris misleading — consumers might expectprisma_highlighterto be the highlighter instance, not a function that returns one. Consider either:
- Export with a clearer name like
getPrismaHighlighter, or- Keep the original name
getHighlighterClearer export naming
-export { getHighlighter as prisma_highlighter }; +export { getHighlighter };Then update the import in
api.tsx:-import { prisma_highlighter as getHighlighter } from "@/lib/shiki_prisma"; +import { getHighlighter } from "@/lib/shiki_prisma";🤖 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` at line 246, The export alias prisma_highlighter is misleading because it exports the function getHighlighter rather than a highlighter instance; rename the export to a clearer function name like getPrismaHighlighter (or re-export the original getHighlighter name) and update any imports (e.g., in api.tsx) to use the new name; specifically change the export statement exporting getHighlighter as prisma_highlighter to export it as getPrismaHighlighter (or export { getHighlighter }) and then update all usages/imports that reference prisma_highlighter to the new identifier.apps/site/src/components/client/technology.tsx (1)
9-9: Remove unuseduseStateimport.The
useStatehook is imported but never used in this component. This is dead code that should be cleaned up.Remove unused import
-import { useState } from "react";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/technology.tsx` at line 9, Remove the unused React hook import by deleting the named import "useState" (the import statement `import { useState } from "react";`) from the component file so there is no dead code; if other React imports are needed, keep only the necessary ones, otherwise remove the entire import line.
🤖 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/client/page.tsx`:
- Around line 169-173: The hero heading in apps/site/src/app/client/page.tsx
contains the incorrect second line "Database Migrations" inside the <h1> (the
element with className "stretch-display text-6xl font-bold text-center
font-sans-display z-2 relative max-w-223 mx-auto"); replace or remove that stray
text so the hero copy matches the Prisma Client page (e.g., remove "Database
Migrations" or change it to a Client-relevant phrase) and ensure the <h1>
content only contains accurate Prisma Client messaging.
- Around line 297-300: The button in the Migrate section has incorrect copy:
locate the Button element (the JSX element with variant="orm" size="3xl" and
className="w-fit") and update its inner span text from "Learn more about Prisma
Studio" to "Learn more about Prisma Migrate" (or equivalent migrate-specific
copy) so the CTA matches the Prisma Migrate section.
- Around line 239-251: The mapped list is missing a React key on the outer
Technology component causing reconciliation issues; move the key prop from the
inner Action to the Technology element in the frameworks.list.map callback
(e.g., set key={fw.name} or key={fw.id} on <Technology ...>) and remove it from
<Action> so each Technology child has a stable unique key during rendering.
- Around line 216-227: The map rendering uses databases.list.map with the outer
component Technology but the key prop is incorrectly placed on the inner Action;
move the unique key (e.g., key={db.name} or a more robust unique id) from the
Action component to the Technology component so the Technology element is the
keyed list item, and remove the duplicate key from Action (update the JSX where
Technology and Action are rendered).
In `@apps/site/src/components/client/api-data.ts`:
- Line 146: The example transaction snippet is truncated and starts mid-function
(showing locate, geo, tx.user.update) so update the source in ui/explore to
produce a complete interactive transaction example: ensure the snippet includes
the opening prisma.$transaction(async (tx) => { ... }), creation or lookup of
bob (e.g., await tx.user.create or await tx.user.findUnique to set bob), the
locate function definition (locate) and the final tx.user.update call so the
flow is contiguous; then regenerate the auto-generated file
(apps/site/src/components/client/api-data.ts) so the rendered snippet contains
the full transaction sequence (prisma.$transaction, bob, locate, geo,
tx.user.update).
- Line 56: The variable prolificAuthors is typed incorrectly: the result of
prisma.user.findMany(...) is annotated as Category[] but should be User[];
update the type annotation for prolificAuthors (and any related declarations)
from Category[] to User[] to match the return type of prisma.user.findMany and
avoid confusing mismatched types in the example.
In `@apps/site/src/components/client/api.tsx`:
- Around line 231-236: The onValueChange handler calls
handleCodeBlockChange(apiItems.find(...)) without checking the find result;
since Array.prototype.find can return undefined and handleCodeBlockChange
assumes a valid item (it accesses item.functions[0]), guard this by storing the
result of apiItems.find(...) in a local variable, check that it is not undefined
(and optionally that item.functions?.length > 0) before calling
handleCodeBlockChange, and only call handleCodeBlockChange with a valid item or
handle the missing-case (e.g., no-op or show fallback).
In `@apps/site/src/components/client/technology.tsx`:
- Line 27: The className on the JSX element in
apps/site/src/components/client/technology.tsx contains conflicting font utility
classes (font-sans-display! and font-mono!); pick the intended font for this
component (e.g., if you want the display font keep font-sans-display! and remove
font-mono!, or vice versa) and update the className on the element (the
className prop in the Technology component) so only the chosen font utility
remains.
---
Nitpick comments:
In `@apps/site/src/components/client/api.tsx`:
- Around line 148-173: The CodeUIItems component is recreated on every render
because it's defined inside API; move CodeUIItems to module scope (outside the
API component) and change it to accept props for funcSelected and
setFuncSelected (and item, blockType) so it no longer closes over API state, or
alternatively wrap it with React.memo/useCallback to memoize it; update where
CodeUIItems is used inside API to pass the props (funcSelected, setFuncSelected,
item, blockType) accordingly so the sub-tree is stable across renders.
- Around line 100-110: The highlighter is hardcoded to lang: "typescript" in the
block that checks codeBlockSelected and funcSelected; change the call to
highlighter.codeToHtml to use the actual selected language (e.g., derive a
language string from funcSelected or the user's selection instead of the literal
"typescript") so JavaScript selections use "javascript" (or the appropriate
value) — update the lang property passed to highlighter.codeToHtml and ensure
the code path that checks for "prismaCodeBlock" in funcSelected still uses the
dynamic language.
In `@apps/site/src/components/client/technology.tsx`:
- Line 9: Remove the unused React hook import by deleting the named import
"useState" (the import statement `import { useState } from "react";`) from the
component file so there is no dead code; if other React imports are needed, keep
only the necessary ones, otherwise remove the entire import line.
In `@apps/site/src/components/homepage/card-section/card-section.tsx`:
- Around line 68-71: The desktop image className uses the item.noShadow
conditional but the mobile image does not, causing asymmetry; update the mobile
image's className (the one rendering with "sm:hidden" / mobile view) to include
the same conditional (item.noShadow && "shadow-none") so both images respect the
noShadow flag, and mirror this change for the other similar occurrence
referenced around lines 79-88 in card-section.tsx.
In `@apps/site/src/lib/shiki_prisma.ts`:
- Around line 222-244: The current getHighlighter implementation can trigger
multiple concurrent createHighlighter calls because prisma_highlighter is null
until the first await completes; change the caching to store the initialization
Promise instead of the resolved result—e.g., make prisma_highlighter hold the
Promise returned by createHighlighter (or introduce prisma_highlighterPromise)
and on first call assign prisma_highlighter = createHighlighter({...}) and then
await it in getHighlighter before returning the resolved highlighter; update the
prisma_highlighter type accordingly so subsequent concurrent calls reuse the
same Promise and avoid duplicate initializations.
- Line 246: The export alias prisma_highlighter is misleading because it exports
the function getHighlighter rather than a highlighter instance; rename the
export to a clearer function name like getPrismaHighlighter (or re-export the
original getHighlighter name) and update any imports (e.g., in api.tsx) to use
the new name; specifically change the export statement exporting getHighlighter
as prisma_highlighter to export it as getPrismaHighlighter (or export {
getHighlighter }) and then update all usages/imports that reference
prisma_highlighter to the new identifier.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: faa94581-bd12-4e50-b6a2-68091d7d5c68
⛔ Files ignored due to path filters (8)
apps/site/public/icons/technologies/mariadb.svgis excluded by!**/*.svgapps/site/public/icons/technologies/mongodbsimple.svgis excluded by!**/*.svgapps/site/public/icons/technologies/mysqlsimple.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_0.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_0_light.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_1.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_1_light.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
apps/site/package.jsonapps/site/src/app/client/page.tsxapps/site/src/app/layout.tsxapps/site/src/components/client/api-data.tsapps/site/src/components/client/api.tsxapps/site/src/components/client/technology.tsxapps/site/src/components/homepage/card-section/card-section.tsxapps/site/src/lib/shiki_prisma.ts
|
Nice one also! A few comments: when clicking on the dropdown to select the stack we have a horizontal window width jump due to scrollbar being hide/shown. Same behaviour with the second dropdown |
2779863 to
adbf0ec
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
apps/site/src/components/client/api.tsx (2)
60-62: Consider adding proper types instead ofany.Using
anyhere bypasses TypeScript's type checking. SinceapiItemshas a defined structure, you could derive proper types from it or define an interface for the function objects.Example type definition
interface APIFunction { name: string; jsCodeBlocks?: string[]; tsCodeBlocks?: string[]; prismaCodeBlock?: string; } const [funcSelected, setFuncSelected] = useState<APIFunction>( apiItems[0].functions[0], );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 60 - 62, Replace the use of the unsafe any type for funcSelected/setFuncSelected by defining or deriving a concrete function type and use it as the generic for useState; e.g., create an APIFunction interface (or derive via typeof apiItems[number]['functions'][number]) that includes name, jsCodeBlocks?, tsCodeBlocks?, prismaCodeBlock? and then change the declaration of funcSelected/setFuncSelected to use useState<APIFunction>(apiItems[0].functions[0]) so TypeScript can type-check usages of funcSelected throughout the component.
148-173: Consider extractingCodeUIItemsoutside the component.This inner component is recreated on every render of
API. While it works, extracting it to the module level would be more efficient and is a React best practice for components that don't need closure over parent state (which this one does need viafuncSelectedandsetFuncSelected).Given it depends on parent state via closure, an alternative is to memoize it with
useCallbackfor the click handler, but frankly the current approach is fine for this use case—just something to be aware of for larger components.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 148 - 173, CodeUIItems is declared inside the API component causing it to be recreated each render; extract CodeUIItems to module scope and convert it to a pure component that accepts props (at minimum: item, blockType, funcSelected, setFuncSelected) so it no longer closes over API state, or alternatively keep it inside but memoize the click handler with useCallback to avoid recreating handlers; update all usages in API to pass funcSelected and setFuncSelected into the relocated CodeUIItems component (refer to the CodeUIItems name and the funcSelected/setFuncSelected symbols to implement the prop changes).
🤖 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/client/page.tsx`:
- Around line 279-282: The Button rendered in page.tsx (the <Button> component
with className "w-fit" that contains "Learn more about Prisma Studio" and the
fa-arrow-right icon) lacks an href/destination; update that Button to provide a
proper link to the Prisma Studio docs (e.g. https://www.prisma.io/studio) by
passing the href prop or wrapping it with your router/link component as
appropriate (or using an anchorVariant of the Button) so clicking "Learn more
about Prisma Studio" navigates to the documentation.
- Around line 12-15: The metadata object currently uses generic SITE_HOME_TITLE
and SITE_HOME_DESCRIPTION; update it to Prisma Client–specific values by
replacing SITE_HOME_TITLE and SITE_HOME_DESCRIPTION with client-focused
constants or string literals (e.g., PRISMA_CLIENT_TITLE,
PRISMA_CLIENT_DESCRIPTION or appropriate text) so the exported metadata in
page.tsx reflects the Prisma Client page; ensure any new constants are
defined/imported where metadata is declared (or inline the strings) and keep the
exported symbol name metadata unchanged.
- Around line 254-263: The two CTA Buttons (the Button elements with
variant="default-stronger" size="3xl" and variant="orm" size="3xl") are styled
like links but lack href props; add appropriate href values so they navigate:
set the first Button's href to your GitHub examples URL (e.g. your repo or
examples page) and set the second Button's href to the "Prisma in your stack"
destination (e.g. the internal stack/guides route such as "/guides" or the exact
page route used in the app); keep the same Button props and children so only the
href attribute is added.
- Around line 17-61: The databases object uses placeholder urls (url: "/") for
every entry; update each entry in the databases.list array so each database
(e.g., "PostgreSQL", "MySQL", "MariaDB", "SQLite", "SQL Server", "CockroachDB",
"PlanetScale", "MongoDB") points to the correct documentation or site page
instead of "/", for example "/postgres", "/mysql", "/mariadb", "/sqlite",
"/sqlserver", "/cockroachdb", "/planetscale", "/mongodb" (or other canonical
paths your app uses); edit the databases constant in
apps/site/src/app/client/page.tsx (the databases object and its list entries) to
replace the placeholder urls with the appropriate real routes or doc links.
In `@apps/site/src/components/client/api.tsx`:
- Around line 100-111: The code hardcodes lang: "typescript" when calling
highlighter.codeToHtml inside the block that checks codeBlockSelected and
funcSelected; change it to use the actual selected language (e.g., use
selectedLang or a small mapping such as selectedLang === "js" ? "javascript" :
selectedLang === "ts" ? "typescript" : selectedLang) so
highlighter.codeToHtml(codeBlockSelected[index], { lang: chosenLang, theme:
"prisma-dark" }) uses the correct language; update the call site where
highlighter.codeToHtml is invoked and ensure chosenLang falls back to
"typescript" only if no selection exists.
- Around line 197-202: The onValueChange handler currently calls handleChange
with the result of langOptions.find which may be undefined; modify the handler
(the onValueChange arrow inside the select logic) to guard the find result
before calling handleChange—only call handleChange when langOptions.find(...)
returns a truthy value (or fall back to a safe default object), so selectedLang
is never set to undefined and the render that uses selectedLang remains safe.
---
Nitpick comments:
In `@apps/site/src/components/client/api.tsx`:
- Around line 60-62: Replace the use of the unsafe any type for
funcSelected/setFuncSelected by defining or deriving a concrete function type
and use it as the generic for useState; e.g., create an APIFunction interface
(or derive via typeof apiItems[number]['functions'][number]) that includes name,
jsCodeBlocks?, tsCodeBlocks?, prismaCodeBlock? and then change the declaration
of funcSelected/setFuncSelected to use
useState<APIFunction>(apiItems[0].functions[0]) so TypeScript can type-check
usages of funcSelected throughout the component.
- Around line 148-173: CodeUIItems is declared inside the API component causing
it to be recreated each render; extract CodeUIItems to module scope and convert
it to a pure component that accepts props (at minimum: item, blockType,
funcSelected, setFuncSelected) so it no longer closes over API state, or
alternatively keep it inside but memoize the click handler with useCallback to
avoid recreating handlers; update all usages in API to pass funcSelected and
setFuncSelected into the relocated CodeUIItems component (refer to the
CodeUIItems name and the funcSelected/setFuncSelected symbols to implement the
prop changes).
🪄 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: b6573bd2-4882-4326-91ba-1ac01182381f
⛔ Files ignored due to path filters (8)
apps/site/public/icons/technologies/mariadb.svgis excluded by!**/*.svgapps/site/public/icons/technologies/mongodbsimple.svgis excluded by!**/*.svgapps/site/public/icons/technologies/mysqlsimple.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_0.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_0_light.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_1.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_1_light.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
apps/site/package.jsonapps/site/src/app/client/page.tsxapps/site/src/app/layout.tsxapps/site/src/components/client/api-data.tsapps/site/src/components/client/api.tsxapps/site/src/components/client/technology.tsxapps/site/src/components/homepage/card-section/card-section.tsxapps/site/src/lib/shiki_prisma.ts
✅ Files skipped from review due to trivial changes (4)
- apps/site/package.json
- apps/site/src/app/layout.tsx
- apps/site/src/components/client/technology.tsx
- apps/site/src/components/client/api-data.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/site/src/components/homepage/card-section/card-section.tsx
- apps/site/src/lib/shiki_prisma.ts
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
apps/site/src/components/client/api.tsx (2)
198-202:⚠️ Potential issue | 🟡 MinorGuard the
find()result before calling the setters.Both selects pass
find(...)straight into handlers that later dereference.valueor.functions[0]. If either lookup misses, the next render fails at Line 75 or Line 177.🛡️ Proposed fix
onValueChange={(value: string | null) => { if (value) { - handleChange( - langOptions.find((lang: any) => lang.value === value), - ); + const lang = langOptions.find((option) => option.value === value); + if (lang) { + handleChange(lang); + } } }} ... onValueChange={(value: string | null) => { if (value) { - handleCodeBlockChange( - apiItems.find((item: any) => item.value === value), - ); + const item = apiItems.find((option) => option.value === value); + if (item) { + handleCodeBlockChange(item); + } } }}Also applies to: 232-236
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 198 - 202, The onValueChange callbacks pass langOptions.find(...) directly into handleChange (and similarly in the other select) which can return undefined and later cause dereferences of .value or .functions[0]; update the onValueChange handlers to first store the result of langOptions.find(...) in a local (e.g., selectedLang), check that selectedLang is non-null/undefined, and only then call handleChange or the other setter; if the find misses, either bail early or call the setter with a safe fallback (null/default) so downstream code that expects .value or .functions[0] cannot crash.
100-106:⚠️ Potential issue | 🟡 MinorUse the selected grammar when highlighting JS examples.
When
selectedLang.value === "js", Line 105 still sends"typescript"to Shiki, so the JavaScript tab can render with the wrong grammar.💡 Proposed fix
+ const shikiLang = + selectedLang.value === "js" ? "javascript" : "typescript"; + if (codeBlockSelected && !("prismaCodeBlock" in funcSelected)) { for (let index = 0; index < codeBlockSelected.length; index++) { const html = await highlighter.codeToHtml( codeBlockSelected[index], { - lang: "typescript", + lang: shikiLang, theme: "prisma-dark", }, );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 100 - 106, The highlighter call hardcodes lang: "typescript" causing JS examples to be highlighted incorrectly; change the lang passed to highlighter.codeToHtml to derive from selectedLang.value (mapping "js" to "javascript" if needed) and use that variable instead of the literal "typescript" in the block where codeBlockSelected, funcSelected and highlighter.codeToHtml are used so the JS tab renders with the correct grammar.
🤖 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/components/client/api.tsx`:
- Around line 206-224: The SelectTrigger is using a custom height/padding that
doesn't match the adjacent Button (Button size="2xl"), causing a visual height
mismatch; update the SelectTrigger to use the same height token as the
Button—either pass the same size prop if SelectTrigger supports it or adjust its
className padding/height to match the Button's size="2xl" token (make
SelectTrigger's height/padding match Button) so both controls sit on the same
height scale; refer to SelectTrigger and Button(size="2xl") in the component to
locate and change the styling.
- Around line 157-165: The clickable function chip is a non-focusable div;
replace it with a semantic button element (the element using cn and onClick
calling setNewBlocks) so it is keyboard-focusable and accessible, add an
appropriate ARIA state like aria-pressed or aria-selected that reflects
(funcSelected === func), preserve the current className logic and event handler
(onClick={() => setNewBlocks()}) for the button, and ensure any focus/hover
styles remain intact; update any surrounding markup or imports if necessary to
handle a button instead of a div.
---
Duplicate comments:
In `@apps/site/src/components/client/api.tsx`:
- Around line 198-202: The onValueChange callbacks pass langOptions.find(...)
directly into handleChange (and similarly in the other select) which can return
undefined and later cause dereferences of .value or .functions[0]; update the
onValueChange handlers to first store the result of langOptions.find(...) in a
local (e.g., selectedLang), check that selectedLang is non-null/undefined, and
only then call handleChange or the other setter; if the find misses, either bail
early or call the setter with a safe fallback (null/default) so downstream code
that expects .value or .functions[0] cannot crash.
- Around line 100-106: The highlighter call hardcodes lang: "typescript" causing
JS examples to be highlighted incorrectly; change the lang passed to
highlighter.codeToHtml to derive from selectedLang.value (mapping "js" to
"javascript" if needed) and use that variable instead of the literal
"typescript" in the block where codeBlockSelected, funcSelected and
highlighter.codeToHtml are used so the JS tab renders with the correct grammar.
🪄 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: 4d2b61d3-5202-4987-9e6c-7dd179862fcb
📒 Files selected for processing (2)
apps/site/src/app/pricing/pricing-hero-plans.tsxapps/site/src/components/client/api.tsx
✅ Files skipped from review due to trivial changes (1)
- apps/site/src/app/pricing/pricing-hero-plans.tsx
5c95689 to
e7bf524
Compare
e7bf524 to
a9ba05f
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (4)
apps/site/src/components/client/api.tsx (4)
197-201:⚠️ Potential issue | 🟡 MinorGuard
find()before updating selected language.On Line 200,
langOptions.find(...)may returnundefined; guard before callinghandleChange.Suggested fix
- handleChange( - langOptions.find((lang: any) => lang.value === value), - ); + const lang = langOptions.find((l: any) => l.value === value); + if (lang) handleChange(lang);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 197 - 201, The callback onValueChange should guard the result of langOptions.find(...) before invoking handleChange to avoid passing undefined; update the onValueChange handler to store the result of langOptions.find((lang) => lang.value === value) in a variable, check that it is truthy (or provide a safe fallback object) and only then call handleChange(foundLang), otherwise return or handle the missing option case. This change touches the onValueChange anonymous function and the call site of handleChange/langOptions.find.
100-106:⚠️ Potential issue | 🟡 MinorUse the selected language when calling the highlighter.
On Line 105,
langis hardcoded to"typescript", so JavaScript examples are still highlighted as TS whenselectedLang.value === "js".Suggested fix
- lang: "typescript", + lang: selectedLang.value === "js" ? "javascript" : "typescript",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 100 - 106, The highlighter is using a hardcoded lang "typescript" when calling highlighter.codeToHtml for codeBlockSelected (inside the block guarded by codeBlockSelected and !("prismaCodeBlock" in funcSelected)); change the call to pass the actual selected language (e.g., selectedLang.value or a small mapping from "js" to "javascript"/"typescript" as your highlighter expects) instead of the hardcoded "typescript" so JS examples are highlighted correctly; update the lang argument in the highlighter.codeToHtml call accordingly.
231-235:⚠️ Potential issue | 🟡 MinorGuard
apiItems.find()result before use.On Line 234,
findcan returnundefined, andhandleCodeBlockChangeassumes a valid item (item.functions[0]).Suggested fix
- handleCodeBlockChange( - apiItems.find((item: any) => item.value === value), - ); + const item = apiItems.find((i: any) => i.value === value); + if (item) handleCodeBlockChange(item);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 231 - 235, The result of apiItems.find in the onValueChange handler can be undefined; before calling handleCodeBlockChange you must guard the found item (from apiItems.find(...)) and only call handleCodeBlockChange when the item is non-null, or provide a safe fallback (e.g., return early or pass a default object) so that handleCodeBlockChange (which accesses item.functions[0]) never receives undefined; update the onValueChange callback to check the find result and handle the undefined case appropriately.
158-167:⚠️ Potential issue | 🟠 MajorUse a semantic button for function chips.
This interactive control is a clickable
<div>, which hurts keyboard accessibility and state semantics. Please use a<button type="button">witharia-pressed.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/client/api.tsx` around lines 158 - 167, Replace the interactive <div> used for function chips with a semantic <button type="button">: keep the className logic currently using cn(...) and the onClick handler that calls setNewBlocks(), but move it onto the button element and add aria-pressed={funcSelected === func} so assistive tech sees toggle state; ensure the same conditional styling that depends on funcSelected === func (and uses func.name for label) is preserved and that keyboard focus/activation now works natively via the button element.
🧹 Nitpick comments (1)
apps/site/src/components/homepage/card-section/card-section.tsx (1)
66-69: Desktop shadow logic looks good.The use of
cn()to conditionally appendshadow-noneis the right approach—tailwind-mergewill correctly resolve the conflicting shadow utilities.One thing to consider: the mobile image (line 79) still applies the shadow unconditionally. If a consumer sets
noShadow: true, they might expect it to apply to both breakpoints. If this is intentional (different mobile visual treatment), you're all set. If not, you may want to apply the same pattern to the mobile<img>:♻️ Optional: apply noShadow to mobile image as well
<img - className="w-full h-auto shadow-[0_10px_25px_-5px_rgba(0,0,0,0.1)] sm:hidden" + className={cn( + "w-full h-auto shadow-[0_10px_25px_-5px_rgba(0,0,0,0.1)] sm:hidden", + item.noShadow && "shadow-none", + )} src={🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/components/homepage/card-section/card-section.tsx` around lines 66 - 69, The mobile <img> currently always has the shadow class while the desktop image uses cn(...) with item.noShadow to conditionally add "shadow-none"; update the mobile image's className to use the same cn(...) pattern (referencing cn and item.noShadow) so that when item.noShadow is true the mobile image also gets "shadow-none" and tailwind-merge resolves the conflicting shadow utilities.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@apps/site/src/components/client/api.tsx`:
- Around line 197-201: The callback onValueChange should guard the result of
langOptions.find(...) before invoking handleChange to avoid passing undefined;
update the onValueChange handler to store the result of langOptions.find((lang)
=> lang.value === value) in a variable, check that it is truthy (or provide a
safe fallback object) and only then call handleChange(foundLang), otherwise
return or handle the missing option case. This change touches the onValueChange
anonymous function and the call site of handleChange/langOptions.find.
- Around line 100-106: The highlighter is using a hardcoded lang "typescript"
when calling highlighter.codeToHtml for codeBlockSelected (inside the block
guarded by codeBlockSelected and !("prismaCodeBlock" in funcSelected)); change
the call to pass the actual selected language (e.g., selectedLang.value or a
small mapping from "js" to "javascript"/"typescript" as your highlighter
expects) instead of the hardcoded "typescript" so JS examples are highlighted
correctly; update the lang argument in the highlighter.codeToHtml call
accordingly.
- Around line 231-235: The result of apiItems.find in the onValueChange handler
can be undefined; before calling handleCodeBlockChange you must guard the found
item (from apiItems.find(...)) and only call handleCodeBlockChange when the item
is non-null, or provide a safe fallback (e.g., return early or pass a default
object) so that handleCodeBlockChange (which accesses item.functions[0]) never
receives undefined; update the onValueChange callback to check the find result
and handle the undefined case appropriately.
- Around line 158-167: Replace the interactive <div> used for function chips
with a semantic <button type="button">: keep the className logic currently using
cn(...) and the onClick handler that calls setNewBlocks(), but move it onto the
button element and add aria-pressed={funcSelected === func} so assistive tech
sees toggle state; ensure the same conditional styling that depends on
funcSelected === func (and uses func.name for label) is preserved and that
keyboard focus/activation now works natively via the button element.
---
Nitpick comments:
In `@apps/site/src/components/homepage/card-section/card-section.tsx`:
- Around line 66-69: The mobile <img> currently always has the shadow class
while the desktop image uses cn(...) with item.noShadow to conditionally add
"shadow-none"; update the mobile image's className to use the same cn(...)
pattern (referencing cn and item.noShadow) so that when item.noShadow is true
the mobile image also gets "shadow-none" and tailwind-merge resolves the
conflicting shadow utilities.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: cf62a6dc-6025-48e7-88fe-03703399d474
⛔ Files ignored due to path filters (7)
apps/site/public/icons/technologies/mariadb.svgis excluded by!**/*.svgapps/site/public/icons/technologies/mongodbsimple.svgis excluded by!**/*.svgapps/site/public/icons/technologies/mysqlsimple.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_0.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_0_light.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_1.svgis excluded by!**/*.svgapps/site/public/illustrations/client/client_1_light.svgis excluded by!**/*.svg
📒 Files selected for processing (6)
apps/site/src/app/client/page.tsxapps/site/src/app/pricing/pricing-hero-plans.tsxapps/site/src/components/client/api-data.tsapps/site/src/components/client/api.tsxapps/site/src/components/client/technology.tsxapps/site/src/components/homepage/card-section/card-section.tsx
✅ Files skipped from review due to trivial changes (1)
- apps/site/src/components/client/api-data.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/site/src/components/client/technology.tsx
- apps/site/src/app/client/page.tsx
a9ba05f to
aa8967f
Compare
Summary by CodeRabbit
New Features
Style