Skip to content

Conversation

@ariflogs
Copy link
Member

@ariflogs ariflogs commented Sep 5, 2025

Summary by CodeRabbit

  • New Features

    • Added a Themes playground with selectable palettes and radius option.
    • Added a Copy Theme dialog, preview components (Course card, Sign-in, Team members), and “Themes” to top navigation.
  • Style

    • New multi-theme system (light/dark), updated muted colors, radius tokens, themed scrollbars, and expanded code highlighting.
    • Rounded corners across UI, darker dialog backdrop, sticky top navigation, and reduced top spacing for line charts.
    • Updated GitHub stars text to 700+.
  • Documentation

    • Improved Install page layout on large screens.
  • Chores

    • Updated homepage CTA to point to Themes; removed Product Hunt embed.

@vercel
Copy link

vercel bot commented Sep 5, 2025

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

Project Deployment Preview Comments Updated (UTC)
retro-ui Ready Ready Preview Comment Sep 5, 2025 10:48am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 5, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a multi-theme system with radius control, a new Themes playground and CopyTheme dialog, extensive global CSS theme palettes, UI styling updates (rounded/token alignment), preview blocks, navigation/layout tweaks, and a marketing CTA update linking to /themes.

Changes

Cohort / File(s) Summary of changes
Marketing pages
app/(marketing)/page.tsx, app/(marketing)/themes/page.tsx
Replaced Product Hunt CTA with a link to /themes (badge + PaintbrushIcon); added new client-side Themes page with theme & variant selectors, preview grid, and CopyTheme integration.
Global theming & tokens
app/global.css, config/theme.ts
Added multi-theme palettes (purple, lime, red, lavender, orange, green) with dark variants, introduced --radius token and .with-radius, added --chart-1..--chart-5 tokens, expanded hljs styles, and added Theme enum + themeConfig() + themes list.
Navigation & layout
config/navigation.ts, components/TopNav.tsx, app/layout.tsx
Added "Themes" to top nav; TopNav changed from fixed to sticky (z-10); removed wrapper div formerly around TopNav in RootLayout.
New utility component
components/CopyTheme.tsx
New dialog component that renders/copies generated CSS for the selected theme and optional radius (props: theme, hasRadius?).
UI primitives styling sweep
components/retroui/* (Accordion, Alert, Badge, Button, Card, Checkbox, Command, Dialog, Input, Select, Textarea, charts/LineChart.tsx)
Visual-only updates across primitives: added rounded to many components, adjusted variant token usage (e.g., primary-foreground, muted), Dialog overlay darker and layout simplified, removed some dialog transitions, reduced LineChart top margin from 10→0.
Preview blocks
preview/blocks/course-card.tsx, preview/blocks/team-members.tsx, preview/blocks/sign-in.tsx
Added CourseCard, TeamMembersBlock, and SignInBlock components used in the Themes preview; SignInBlock includes password visibility toggle.
Preview demo tweak
preview/components/command-style-default.tsx
Removed rounded-lg from the Command demo styling.
Docs layout
content/docs/install/index.mdx
Changed large-screen grid from 3 to 2 columns.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Browser
  participant ThemesPage as "Themes Page"
  participant UI as "Preview UI"
  participant CopyTheme as "CopyTheme Dialog"
  participant ThemeCfg as "themeConfig()"

  User->>Browser: Navigate to /themes
  Browser->>ThemesPage: Load page
  ThemesPage->>UI: Render preview grid with class "theme-{name}" (+".with-radius" if set)
  User->>UI: Select Theme / Variant
  UI->>ThemesPage: onValueChange(theme, variant)
  ThemesPage->>UI: Update root classNames -> re-render previews

  User->>CopyTheme: Click "Copy Theme"
  CopyTheme->>ThemeCfg: Request CSS for selected theme (hasRadius?)
  ThemeCfg-->>CopyTheme: Return CSS string
  CopyTheme->>Browser: Show dialog with copyable code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Added Chart components #73 — Adds chart components and chart CSS variables; directly overlaps with new chart tokens and preview usage.
  • V1.2 #56 — Prior theming sweep touching app/global.css and layout; overlaps with token and layout changes here.
  • Command component #76 — Modifies components/retroui/Command.tsx; related to the Command styling edits in this PR.

Poem

I nibble tokens, paint and paste,
New themes to dress each UI taste.
A copy click, a sticky top,
Rounded corners, charts that pop.
Hopping off — the demo glows. 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 730d4d3 and 877c9b4.

📒 Files selected for processing (2)
  • app/(marketing)/page.tsx (3 hunks)
  • app/(marketing)/themes/page.tsx (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch themes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@ariflogs ariflogs merged commit b6ba9b8 into main Sep 5, 2025
2 checks passed
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: 7

Caution

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

⚠️ Outside diff range comments (4)
app/(marketing)/page.tsx (1)

209-213: Fix typo in alt text: “shotting” → “shooting”

User-facing copy. Correct the alt text in both images.

-              alt="shotting stars"
+              alt="shooting stars"

Also applies to: 224-229

components/retroui/Dialog.tsx (3)

13-25: Overlay “none” variant doesn’t cover the viewport.

inset-0 z-50 are only on the default variant; “none” yields a zero-size overlay that won’t capture interactions.

-const overlayVariants = cva(
-  ` fixed bg-black/80 font-head
+const overlayVariants = cva(
+  ` fixed inset-0 z-50 bg-black/80 font-head
     data-[state=open]:fade-in-0
     data-[state=open]:animate-in 
     data-[state=closed]:animate-out 
     data-[state=closed]:fade-out-0 
   `,
   {
     variants: {
       variant: {
-        default: "inset-0 z-50 bg-black/85",
+        default: "bg-black/85",
         none: "fixed bg-transparent",
       },
     },

104-107: Dialog lacks an accessible title; replace empty Title with a real Title.

You render an empty <Dialog.Title /> and the header is a plain div, so screen readers get no name.

-          <VisuallyHidden>
-            <ReactDialog.Title />
-          </VisuallyHidden>
+          {/* Title is provided by DialogHeader below via ReactDialog.Title */}
-const DialogHeaderDefaultLayout = ({ children }: { children: ReactNode }) => {
+const DialogHeaderDefaultLayout = ({ children }: { children: ReactNode }) => {
   return (
     <>
       {children}
-      <DialogTrigger title="Close pop-up" className="cursor-pointer" asChild>
-        <X />
-      </DialogTrigger>
+      <ReactDialog.Close asChild>
+        <button aria-label="Close dialog" className="cursor-pointer p-2">
+          <X />
+        </button>
+      </ReactDialog.Close>
     </>
   );
};
-  return (
-    <div
-      className={cn(dialogHeaderVariants({ position, variant }), className)}
-      {...props}
-    >
+  return (
+    <ReactDialog.Title
+      className={cn(dialogHeaderVariants({ position, variant }), className)}
+      {...props}
+    >
       {asChild ? (
         children
       ) : (
         <DialogHeaderDefaultLayout>{children}</DialogHeaderDefaultLayout>
       )}
-    </div>
+    </ReactDialog.Title>
   );

Also applies to: 167-183, 202-221


186-194: Use Close instead of Trigger for the header X.

Trigger toggles; Close always closes and is the intended control inside content.

🧹 Nitpick comments (38)
components/retroui/charts/LineChart.tsx (1)

54-54: Avoid line/dot tooltip clipping by restoring headroom (dynamic top margin)

top: 0 risks clipping stroke/active dots and tooltips. Compute a small top margin from strokeWidth/dotSize.

Apply this diff:

-          <RechartsLineChart data={data} margin={{ top: 0, right: 30, left: 0, bottom: 0 }}>
+          <RechartsLineChart data={data} margin={{ top: topMargin, right: 30, left: 0, bottom: 0 }}>

Add inside the component before the return:

const topMargin = Math.max(strokeWidth + (dotSize ?? 0), 8);

Quick check: verify no clipping at small container heights (e.g., h-40) and with larger dotSize (6–8).

components/retroui/Alert.tsx (2)

7-7: Use the shared radius token utility instead of fixed rounded

Keeps radius consistent with the new theme “Variant” toggle.

-const alertVariants = cva("relative w-full rounded border-2 p-4", {
+const alertVariants = cva("relative w-full with-radius border-2 p-4", {

14-18: Align status colors with theme tokens

Hard-coded Tailwind palette locks colors and fights theming. Consider mapping status to tokenized classes (e.g., bg-[var(--success)], text-[var(--success-foreground)], etc.) or theme-aware variants.

Would you like a follow-up patch that introduces token-backed status variants?

components/retroui/Accordion.tsx (1)

18-18: Gate radius with theme utility (not fixed rounded)

Keeps Accordion aligned with the theme’s radius toggle.

-      "border-2 bg-background rounded text-foreground shadow-md hover:shadow-sm data-[state=open]:shadow-sm transition-all overflow-hidden",
+      "border-2 bg-background with-radius text-foreground shadow-md hover:shadow-sm data-[state=open]:shadow-sm transition-all overflow-hidden",
config/navigation.ts (1)

11-11: Top-nav addition looks good

The item matches INavItem and the route is consistent with the new page. Optionally add a temporary "New" tag to highlight it.

-    { title: "Themes", href: "/themes" },
+    { title: "Themes", href: "/themes", tag: "New" },
components/retroui/Textarea.tsx (2)

5-5: Remove unused/invalid type prop

textarea doesn’t accept a type attribute. The prop is unused and can confuse consumers.

-export function Textarea({
-  type = "text",
+export function Textarea({
   placeholder = "Enter text...",
   className = "",
   ...props
 }) {

15-16: Use design token for border radius (optional)
Consider replacing the fixed rounded class with your radius token utility—e.g. rounded-[var(--radius)]—or add the existing with-radius class to stay aligned with your theming.

components/retroui/Badge.tsx (1)

11-12: Stray outline-2 on surface variant

outline-2 has no effect without outline style. Remove it (or add outline), to avoid dead CSS.

-      surface: "outline-2 bg-primary text-primary-foreground",
+      surface: "bg-primary text-primary-foreground",
app/(marketing)/page.tsx (1)

206-206: Avoid hard-coding stars; fetch dynamically (optional)

The “700+” count will drift. Consider fetching stargazers_count from GitHub with revalidation.

-              700+
+              {stars.toLocaleString()}+

Add (outside this hunk) and call it in the page:

async function getRepoStats() {
  const res = await fetch(
    "https://api.github.com/repos/Logging-Stuff/RetroUI",
    { next: { revalidate: 3600 } } // 1h
  );
  const json = await res.json();
  return { stars: json?.stargazers_count ?? 0 };
}

// usage
const { stars } = await getRepoStats();
preview/blocks/sign-in.tsx (7)

24-26: Add names and autocomplete for better a11y and UX.

Helps autofill and screen readers; harmless in a preview.

-              <Input id="email" type="email" placeholder="you@example.com" />
+              <Input id={emailId} name="email" autoComplete="email" type="email" placeholder="you@example.com" required />
...
-                <Input
-                  id="password"
+                <Input
+                  id={passwordId}
+                  name="password"
+                  autoComplete="current-password"
                   type={showPassword ? "text" : "password"}
                   placeholder="••••••••"
+                  required
                 />

Also applies to: 39-42


11-11: Avoid ID collisions across multiple previews with useId.

Hard-coded ids can duplicate when multiple blocks render.

 import { useState } from "react";
+import { useId } from "react";
...
-  const [showPassword, setShowPassword] = useState(false);
+  const [showPassword, setShowPassword] = useState(false);
+  const emailId = useId();
+  const passwordId = useId();
+  const rememberId = useId();
...
-              <Label htmlFor="email">Email</Label>
-              <Input id="email" type="email" placeholder="you@example.com" />
+              <Label htmlFor={emailId}>Email</Label>
+              <Input id={emailId} type="email" placeholder="you@example.com" />
...
-                <Label htmlFor="password">Password</Label>
+                <Label htmlFor={passwordId}>Password</Label>
...
-              <Checkbox id="remember" />
+              <Checkbox id={rememberId} />
-              <label
-                htmlFor="remember"
+              <label
+                htmlFor={rememberId}

Also applies to: 24-26, 39-42, 60-67


43-56: Improve password toggle accessibility.

Expose pressed state and control relationship.

-                <button
+                <button
                   type="button"
                   className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
-                  onClick={() => setShowPassword(!showPassword)}
+                  aria-pressed={showPassword}
+                  aria-controls={passwordId}
+                  onClick={() => setShowPassword(!showPassword)}
                 >

73-80: Use theme tokens instead of hard-coded grays/white.

Ensures proper theming in dark/alt themes.

-              <div className="absolute inset-0 flex items-center">
-                <span className="w-full border-t border-gray-300" />
+              <div className="absolute inset-0 flex items-center">
+                <span className="w-full border-t border-border" />
               </div>
               <div className="relative flex justify-center text-xs uppercase">
-                <span className="bg-white px-2 text-gray-500">
+                <span className="bg-card px-2 text-muted-foreground">
                   Or continue with
                 </span>
               </div>

87-89: Brand capitalization: GitHub.

-                Github
+                GitHub

94-96: Icon mismatch for Google.

Mail icon suggests email sign-in; consider a Google “G” icon (e.g., react-icons/fc) or omit the icon.


30-36: Prefer Next.js Link for internal routes.

Prevents full page reloads; safe even in previews.

-                <a
-                  href="/forgot-password"
+                <Link
+                  href="/forgot-password"
                   className="text-sm font-medium underline underline-offset-4"
                 >
                   Forgot password?
-                </a>
+                </Link>
...
-            <a
-              href="/sign-up"
+            <Link
+              href="/sign-up"
               className="font-bold underline underline-offset-4"
             >
               Sign up
-            </a>
+            </Link>

Note: add import Link from "next/link";.

Also applies to: 101-106

config/theme.ts (2)

13-15: Unify display names (name field) casing.

Mix of "default"/"purple" vs "Red"/"Green". Pick one convention (Title Case recommended).

-        name: "default",
+        name: "Default",
...
-        name: "purple",
+        name: "Purple",
...
-        name: "Lime",
+        name: "Lime",
...
-        name: "Red",
+        name: "Red",
...
-        name: "Lavender",
+        name: "Lavender",
...
-        name: "Orange",
+        name: "Orange",
...
-        name: "Green",
+        name: "Green",

Also applies to: 56-58, 99-101, 146-148, 197-199, 249-251, 300-302


353-353: Avoid recomputing config for keys.

Minor: cache const CONFIG = themeConfig({ hasRadius: false }) and export both CONFIG and Object.keys(CONFIG). Cleaner and avoids duplicate construction.

app/global.css (4)

371-375: Improve Firefox scrollbar theming (track should not be foreground).

Using the foreground as the track color can look inverted and noisy in both themes. Prefer a transparent or background track.

-html {
-  scrollbar-width: auto;
-  scrollbar-color: var(--muted) var(--foreground);
-}
+html {
+  scrollbar-width: auto;
+  /* thumb, track */
+  scrollbar-color: var(--muted) transparent;
+}

66-89: Advertise color scheme to the browser for native UI (forms/scrollbars).

Setting color-scheme improves native controls rendering in light/dark.

 :root {
+  color-scheme: light;
   --radius: 0;
   /* ... */
 }

 .dark {
+  color-scheme: dark;
   --background: #1a1a1a;
   /* ... */
 }

Also applies to: 40-64


480-494: Add hover style for WebKit scrollbars to match Firefox behavior.

Currently only Firefox thumb color changes on hover.

 .sidebar-scroll::-webkit-scrollbar-thumb {
   background: transparent;
   border-radius: 2px;
   transition: background 0.3s ease;
 }
+
+.sidebar-scroll:hover::-webkit-scrollbar-thumb {
+  background: var(--color-primary);
+}

139-180: Unify token surface across themes.

Several themes define extra tokens (--input, --ring, --popover*) while others don’t. If components read these tokens, missing definitions will fall back unexpectedly. Consider defining a consistent set across all themes (or provide safe fallbacks in component styles).

Also applies to: 182-226, 228-272, 274-318, 320-364

components/TopNav.tsx (3)

39-39: Use themed border color and drop redundant right-0 on a sticky element.

right-0 has no effect on position: sticky. Also specify border-border to use the tokenized border color.

-    <nav className="sticky z-10 top-0 right-0 w-full border-b-2 bg-background">
+    <nav className="sticky top-0 z-10 w-full border-b-2 border-border bg-background">

13-23: Avoid duplicating theme toggle logic (layout already sets dark class).

You set dark mode in RootLayout before paint and again here after mount. This is harmless but redundant and can cause brief icon flicker. Consider reading the initial state from document.documentElement.classList.contains('dark') and skipping the first-effect logic, or remove one of the two.

Also applies to: 110-113


40-55: Consider theming the promo bar.

Hardcoded bg-black text-white ignores selected themes. If intentional, ignore; otherwise swap to tokens (bg-secondary text-secondary-foreground or similar).

app/layout.tsx (1)

48-66: Respect OS preference when no saved theme exists.

If localStorage.theme is unset, you can default to prefers-color-scheme to reduce surprises for first-time visitors.

-                  const theme = localStorage.getItem('theme');
-                  if (theme === 'dark') {
+                  const theme = localStorage.getItem('theme');
+                  const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
+                  if (theme === 'dark' || (!theme && prefersDark)) {
                     document.documentElement.classList.add('dark');
                   } else {
                     document.documentElement.classList.remove('dark');
                   }
preview/blocks/course-card.tsx (2)

31-44: Use themed border color instead of hardcoded black tint.

border-black/10 will be too light/dark depending on theme. Use the border token.

-                    <div className="flex text-sm justify-between gap-4 py-4 border-y-2 border-black/10 mb-4">
+                    <div className="flex text-sm justify-between gap-4 py-4 border-y border-border mb-4">

46-48: Non-submit intent: set type="button" on button.

Prevents accidental form submission if this block is ever placed inside a form.

-                    <Button className="w-full font-bold font-sans justify-center">
+                    <Button type="button" className="w-full font-bold font-sans justify-center">
components/CopyTheme.tsx (3)

13-13: Harden dynamic classes and avoid stray spaces.

Use a classnames helper and ensure theme is a string name (not a numeric enum) to avoid theme-0 classes.

-import { CodeBlock } from "./CodeBlock";
+import { CodeBlock } from "./CodeBlock";
+import { cn } from "@/lib/utils";
@@
-            <Dialog.Content className={`theme-${theme} ${hasRadius ? "with-radius" : ""}`}>
+            <Dialog.Content className={cn(`theme-${String(theme)}`, hasRadius && "with-radius")}>

11-12: Non-submit intent: set type="button" on trigger button.

-                <Button>Copy Theme</Button>
+                <Button type="button">Copy Theme</Button>

20-22: Large code blocks: consider white-space: pre and font-mono.

For long CSS strings, ensure code wraps correctly and uses monospaced font. Your CodeBlock probably handles this, but if not, add classes here.

preview/blocks/team-members.tsx (4)

4-4: Remove unused import.

Clock isn’t used.

-import { Clock, User } from "lucide-react";
+import { User } from "lucide-react";

10-11: Align borders with theme tokens.

Use token-aware border utilities for consistent theming.

- className="border-2 p-4 flex items-center justify-between gap-3 bg-card rounded"
+ className="border border-muted p-4 flex items-center justify-between gap-3 bg-card rounded"

Also applies to: 32-33, 53-54


15-17: Use descriptive alt text (accessibility).

Alt should reflect the person’s name.

-                            alt="Person A"
+                            alt="Alex Johnson"
...
-                            alt="Person B"
+                            alt="John Doe"
...
-                            alt="Person C"
+                            alt="Jane Smith"

Also applies to: 36-38, 57-59


9-75: De-duplicate the three cards.

Consider mapping over a small data array to reduce repetition and ease future edits.

Example:

const members = [
  { name: "Alex Johnson", email: "alex@example.com", avatar: "…person_a.png", badge: { label: "Admin", variant: "solid" as const } },
  { name: "John Doe", email: "john@example.com", avatar: "…person_b.png", badge: { label: "Member", variant: "solid" as const } },
  { name: "Jane Smith", email: "jane@example.com", avatar: "…person_c.png", badge: { label: "Pending", variant: "surface" as const } },
];

Then render with members.map(...).

app/(marketing)/themes/page.tsx (3)

17-46: Avoid name shadowing and future drift: rename option arrays.

Prevents confusion with exported themes from config and avoids shadowing state vars inside maps.

-const themes: {value: Theme, label: string}[] = [
+const themeOptions: {value: Theme, label: string}[] = [
@@
-const variants = [
+const variantOptions = [
@@
-    const [theme, setTheme] = useState<Theme>(themes[0].value);
-    const [variant, setVariant] = useState(variants[0].value);
+    const [theme, setTheme] = useState<Theme>(themeOptions[0].value);
+    const [variant, setVariant] = useState(variantOptions[0].value);
@@
-                                        themes.map((theme) => (
-                                            <Select.Item key={theme.value} value={theme.value}>
-                                                {theme.label}
+                                        themeOptions.map((opt) => (
+                                            <Select.Item key={opt.value} value={opt.value}>
+                                                {opt.label}
                                             </Select.Item>
                                         ))
@@
-                                        variants.map((variant) => (
-                                            <Select.Item key={variant.value} value={variant.value}>
-                                                {variant.label}
+                                        variantOptions.map((opt) => (
+                                            <Select.Item key={opt.value} value={opt.value}>
+                                                {opt.label}
                                             </Select.Item>
                                         ))

Also applies to: 60-61, 75-80, 48-57, 61-61, 93-97


70-73: Add accessible names to Select triggers.

Improves a11y for screen readers.

-                            <Select.Trigger>
+                            <Select.Trigger aria-label="Theme">
@@
-                            <Select.Trigger>
+                            <Select.Trigger aria-label="Variant">

Also applies to: 87-90


107-107: Make the grid responsive.

Prevents cramped layout on small screens.

-                <div className="grid grid-cols-3 w-full gap-6">
+                <div className="grid grid-cols-1 md:grid-cols-3 w-full gap-6">
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 66d69bb and 730d4d3.

📒 Files selected for processing (25)
  • app/(marketing)/page.tsx (2 hunks)
  • app/(marketing)/themes/page.tsx (1 hunks)
  • app/global.css (8 hunks)
  • app/layout.tsx (1 hunks)
  • components/CopyTheme.tsx (1 hunks)
  • components/TopNav.tsx (1 hunks)
  • components/retroui/Accordion.tsx (1 hunks)
  • components/retroui/Alert.tsx (1 hunks)
  • components/retroui/Badge.tsx (1 hunks)
  • components/retroui/Button.tsx (1 hunks)
  • components/retroui/Card.tsx (1 hunks)
  • components/retroui/Checkbox.tsx (1 hunks)
  • components/retroui/Command.tsx (4 hunks)
  • components/retroui/Dialog.tsx (3 hunks)
  • components/retroui/Input.tsx (1 hunks)
  • components/retroui/Select.tsx (1 hunks)
  • components/retroui/Textarea.tsx (1 hunks)
  • components/retroui/charts/LineChart.tsx (1 hunks)
  • config/navigation.ts (1 hunks)
  • config/theme.ts (1 hunks)
  • content/docs/install/index.mdx (1 hunks)
  • preview/blocks/course-card.tsx (1 hunks)
  • preview/blocks/sign-in.tsx (1 hunks)
  • preview/blocks/team-members.tsx (1 hunks)
  • preview/components/command-style-default.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (19)
components/retroui/Button.tsx (3)
preview/components/dialog-style-width-variant.tsx (1)
  • singleVariant (45-54)
preview/components/button-style-outline.tsx (1)
  • ButtonStyleOutline (3-5)
preview/components/tooltip-style-primary.tsx (1)
  • TooltipStylePrimary (5-16)
content/docs/install/index.mdx (1)
app/(docs)/docs/layout.tsx (1)
  • ComponentLayout (8-18)
components/retroui/Input.tsx (1)
preview/components/input-style-error.tsx (1)
  • InputStyleError (4-18)
components/retroui/charts/LineChart.tsx (2)
components/retroui/charts/AreaChart.tsx (1)
  • value (32-151)
components/retroui/charts/BarChart.tsx (1)
  • value (32-157)
components/retroui/Accordion.tsx (1)
preview/components/accordion-style-default.tsx (1)
  • AccordionStyleDefault (5-28)
preview/blocks/course-card.tsx (3)
components/retroui/Badge.tsx (1)
  • Badge (29-44)
components/retroui/Text.tsx (1)
  • Text (30-37)
components/retroui/Button.tsx (1)
  • Button (39-62)
components/retroui/Alert.tsx (4)
preview/components/alert-style-solid.tsx (1)
  • AlertStyleDefault (3-12)
preview/components/alert-style-default.tsx (1)
  • AlertStyleDefault (3-12)
preview/components/alert-style-all-status.tsx (1)
  • AlertAllStatus (4-25)
preview/components/alert-style-with-icon.tsx (1)
  • AlertStyleDefaultIcon (4-16)
app/layout.tsx (3)
components/TopNav.tsx (1)
  • TopNav (10-118)
app/(marketing)/blogs/layout.tsx (1)
  • BlogsLayout (7-18)
app/(docs)/docs/layout.tsx (1)
  • ComponentLayout (8-18)
preview/blocks/team-members.tsx (3)
components/retroui/Text.tsx (1)
  • Text (30-37)
components/retroui/Badge.tsx (1)
  • Badge (29-44)
preview/components/badge-style-variants.tsx (1)
  • BadgeStyleVariants (3-12)
components/CopyTheme.tsx (4)
components/retroui/Button.tsx (1)
  • Button (39-62)
components/retroui/Text.tsx (1)
  • Text (30-37)
components/CodeBlock.tsx (1)
  • CodeBlock (16-55)
config/theme.ts (1)
  • themeConfig (12-351)
config/navigation.ts (1)
types/index.d.ts (3)
  • INavigationConfig (12-15)
  • INavItem (1-5)
  • INavItemWithChildren (7-10)
components/retroui/Badge.tsx (4)
preview/components/badge-style-variants.tsx (1)
  • BadgeStyleVariants (3-12)
preview/components/badge-style-sizes.tsx (1)
  • BadgeStyleVariants (3-11)
preview/components/badge-style-rounded.tsx (1)
  • BadgeStyleRounded (3-14)
preview/components/badge-style-default.tsx (1)
  • BadgeStyleDefault (3-5)
components/retroui/Card.tsx (3)
preview/components/card-style-default.tsx (1)
  • BasicCard (3-15)
components/retroui/BasicCard.tsx (1)
  • BasicCard (3-12)
preview/components/card-style-commerce.tsx (1)
  • CommerceCard (4-23)
app/(marketing)/themes/page.tsx (3)
config/theme.ts (1)
  • themes (353-353)
components/retroui/Text.tsx (1)
  • Text (30-37)
components/CopyTheme.tsx (1)
  • CopyTheme (7-27)
components/retroui/Textarea.tsx (1)
preview/components/textarea-style-default.tsx (1)
  • TextareaStyleDefault (3-11)
components/retroui/Command.tsx (1)
preview/components/command-style-dialog.tsx (1)
  • Component (15-78)
preview/blocks/sign-in.tsx (5)
components/retroui/Text.tsx (1)
  • Text (30-37)
components/retroui/Label.tsx (1)
  • Label (11-16)
components/retroui/Input.tsx (1)
  • Input (7-25)
components/retroui/Checkbox.tsx (1)
  • Checkbox (30-50)
components/retroui/Button.tsx (1)
  • Button (39-62)
app/(marketing)/page.tsx (1)
components/retroui/Badge.tsx (1)
  • Badge (29-44)
components/retroui/Dialog.tsx (2)
preview/components/dialog-style-width-variant.tsx (1)
  • DialogStyleWidthVariant (17-61)
preview/components/dialog-style-default.tsx (1)
  • DialogStyleDefault (5-29)
🪛 ESLint
app/(marketing)/themes/page.tsx

[error] 65-65: ' can be escaped with &apos;, &lsquo;, &#39;, &rsquo;.

(react/no-unescaped-entities)

preview/blocks/sign-in.tsx

[error] 100-100: ' can be escaped with &apos;, &lsquo;, &#39;, &rsquo;.

(react/no-unescaped-entities)

🔇 Additional comments (12)
components/retroui/Select.tsx (1)

18-18: Use with-radius utility, consolidate border classes, fix width, add accessible focus ring

  • Replace rounded with existing with-radius utility (defined in global.css).
  • Remove border-input; retain only border-border.
  • Swap non-default min-w-40 for min-w-[10rem] (or extend minWidth in tailwind.config).
  • Introduce an accessible focus state: use focus-visible:ring-2 ring-ring ring-offset-2 instead of hiding all outlines.

Apply this diff:

-        "flex h-10 rounded min-w-40 items-center shadow-md justify-between border-2 border-input border-border bg-transparent px-4 py-2 placeholder:text-muted-foreground outline-none focus:outline-none focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
+        "flex h-10 with-radius min-w-[10rem] items-center shadow-md justify-between border-2 border-border bg-transparent px-4 py-2 placeholder:text-muted-foreground outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",

Confirm your tailwind.config includes the with-radius utility and any minWidth extensions.

components/retroui/Checkbox.tsx (1)

6-6: Confirm Tailwind DEFAULT borderRadius mapping (optional): I couldn’t locate a tailwind.config.* file to verify if DEFAULT border radius is tied to var(--radius). Please confirm your Tailwind config—and if it isn’t mapped, consider changing the variant from rounded to rounded-[var(--radius)] to bind rounding to your theme’s radius token.

preview/components/command-style-default.tsx (1)

17-17: LGTM: rely on component default radius.

Removing redundant rounded-lg lets the base Command radius control visuals uniformly across themes.

content/docs/install/index.mdx (1)

12-12: LGTM: grid columns now match item count.

lg:grid-cols-2 correctly places the two cards in one row on large screens.

components/retroui/Button.tsx (1)

7-13: Rounded + token-based foreground: good alignment with theming

The base rounded and text-primary-foreground for the default variant align with the new theme tokens.

Please confirm there’s a visible keyboard focus style across themes since outline-hidden suppresses the default outline (e.g., via focus-visible:ring-* or equivalent).

components/retroui/Badge.tsx (1)

5-9: Theme-token adoption looks good

Base rounded and bg-muted text-muted-foreground for the default variant match the palette shift.

app/(marketing)/page.tsx (1)

57-63: Nice CTA

Enabling the charts CTA via Badge + Link is clean and unobtrusive.

config/theme.ts (1)

124-144: Verify Lime dark palette (white background in .dark).

.white backgrounds in dark mode may be intentional, but it breaks expectations and contrast in many components. Confirm design intent.

components/retroui/Dialog.tsx (1)

52-59: Content animations simplified — LGTM.

The new layout is simpler and still provides adequate motion without the slide-in quirks.

app/layout.tsx (1)

75-76: Verify top spacing after removing the old wrapper.

The previous wrapper added bottom padding; with a sticky (not fixed) nav this is likely fine, but please sanity-check pages with hero sections to ensure no overlap/regression.

app/(marketing)/themes/page.tsx (2)

104-105: LGTM: CopyTheme wiring.

Prop derivation of hasRadius from variant is correct.


59-61: No changes required: Theme is a string enum
Theme is defined as a string enum ("default", "purple", "lime"), so both slice operations and the Select callback receiving string values are safe.

const [variant, setVariant] = useState(variants[0].value);

return (
<section className={`theme-${theme} ${variant} container max-w-8xl mx-auto py-12`}>
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Verify Tailwind support for max-w-8xl.

Ensure 8xl is defined; default Tailwind stops at 7xl.


🏁 Script executed:

#!/bin/bash
# Check Tailwind config for custom '8xl' size
rg -nP "maxWidth|extend\s*:\s*{[^}]*maxWidth" -C3 -- tailwind.config.* tailwind.config.*.* 2>/dev/null
rg -nP "8xl" -- tailwind.config.* tailwind.config.*.* 2>/dev/null

Length of output: 154


Add custom 8xl max-width or switch to 7xl. Default Tailwind defines max-w only up to 7xl; no 8xl entry was found in theme.extend.maxWidth. Either add an 8xl value in your tailwind.config.(js|ts) or update this class to max-w-7xl.

🤖 Prompt for AI Agents
In app/(marketing)/themes/page.tsx around line 64, the class uses a non-existent
Tailwind utility "max-w-8xl"; either change the class to use the existing
"max-w-7xl" or add a custom "8xl" entry in your Tailwind config. If you choose
to add the custom size, open tailwind.config.js/ts and under
theme.extend.maxWidth define an "8xl" key with your desired width value, then
rebuild; otherwise update the JSX class from max-w-8xl to max-w-7xl.

Comment on lines +95 to 118
.theme-purple {
--background: #f5f5f5;
--foreground: #1a1a1a;
--card: #FFFFFF;
--card-foreground: #f5f5f5;
--primary: #5F4FE6;
--primary-hover: #4938C2;
--primary-foreground: #fff;
--secondary: #3a3a3a;
--secondary-foreground: #f5f5f5;
--muted: #CFCCEA;
--muted-foreground: #5B5686;
--accent: #FED13B;
--accent-foreground: #000000;
--destructive: #EF4444;
--destructive-foreground: #fff;
--border: #3a3a3a;
--background-image: url("/images/bg_void_3.svg"); /* Optional: A different image for dark mode */
--background-image: url("/images/bg_void_3.svg");
--chart-1: #ffdb33;
--chart-2: #000;
--chart-3: #aeaeae;
--chart-4: #fae583;
--chart-5: #e63946;
}
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

Fix low-contrast text: card foreground is white on white in theme-purple (accessibility bug).

In light mode, --card: #FFFFFF and --card-foreground: #f5f5f5 produce near-invisible text. Switch the foreground to a dark tone for adequate contrast.

Apply:

-  --card-foreground: #f5f5f5;
+  --card-foreground: #1a1a1a;
📝 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
.theme-purple {
--background: #f5f5f5;
--foreground: #1a1a1a;
--card: #FFFFFF;
--card-foreground: #f5f5f5;
--primary: #5F4FE6;
--primary-hover: #4938C2;
--primary-foreground: #fff;
--secondary: #3a3a3a;
--secondary-foreground: #f5f5f5;
--muted: #CFCCEA;
--muted-foreground: #5B5686;
--accent: #FED13B;
--accent-foreground: #000000;
--destructive: #EF4444;
--destructive-foreground: #fff;
--border: #3a3a3a;
--background-image: url("/images/bg_void_3.svg"); /* Optional: A different image for dark mode */
--background-image: url("/images/bg_void_3.svg");
--chart-1: #ffdb33;
--chart-2: #000;
--chart-3: #aeaeae;
--chart-4: #fae583;
--chart-5: #e63946;
}
.theme-purple {
--background: #f5f5f5;
--foreground: #1a1a1a;
--card: #FFFFFF;
--card-foreground: #1a1a1a;
--primary: #5F4FE6;
--primary-hover: #4938C2;
--primary-foreground: #fff;
--secondary: #3a3a3a;
--secondary-foreground: #f5f5f5;
--muted: #CFCCEA;
--muted-foreground: #5B5686;
--accent: #FED13B;
--accent-foreground: #000000;
--destructive: #EF4444;
--destructive-foreground: #fff;
--border: #3a3a3a;
--background-image: url("/images/bg_void_3.svg");
--chart-1: #ffdb33;
--chart-2: #000;
--chart-3: #aeaeae;
--chart-4: #fae583;
--chart-5: #e63946;
}
🤖 Prompt for AI Agents
In app/global.css around lines 95 to 118, the theme-purple definition sets
--card: #FFFFFF and --card-foreground: #f5f5f5 which results in very
low-contrast (white-on-white) text; change --card-foreground to a dark color
(for example reuse --foreground: #1a1a1a or a similar dark hex) so card text
meets contrast requirements and remains consistent with the theme’s foreground
variable.

<div
className={cn(
"inline-block border-2 shadow-md transition-all hover:shadow-xs bg-card",
"inline-block border-2 rounded shadow-md transition-all hover:shadow-nonw bg-card",
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

Typo breaks hover shadow.

hover:shadow-nonw isn’t a Tailwind class; likely meant hover:shadow-none.

Fix:

- "inline-block border-2 rounded shadow-md transition-all hover:shadow-nonw bg-card",
+ "inline-block border-2 rounded shadow-md transition-all hover:shadow-none bg-card",
📝 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
"inline-block border-2 rounded shadow-md transition-all hover:shadow-nonw bg-card",
"inline-block border-2 rounded shadow-md transition-all hover:shadow-none bg-card",
🤖 Prompt for AI Agents
In components/retroui/Card.tsx around line 13, the class string contains a typo
"hover:shadow-nonw" which is not a valid Tailwind class and prevents the
intended hover shadow behavior; replace it with the correct class
"hover:shadow-none" (or another valid Tailwind shadow utility as intended) so
the hover state works properly.

Comment on lines +17 to 21
className={`px-4 py-2 w-full rounded border-2 shadow-md transition focus:outline-hidden focus:shadow-xs ${
props["aria-invalid"]
? "border-red-500 text-red-500 shadow-xs shadow-red-600"
? "border-destructive text-destructive shadow-xs shadow-destructive"
: ""
} ${className}`}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Radius via token; verify custom utilities; simplify error visuals

  • Swap rounded for your radius utility.
  • focus:outline-hidden and shadow-destructive look custom; verify they’re defined.
  • Error state mixes shadow-md (base) and shadow-xs; pick one and prefer a focus ring for accessibility.
-      className={`px-4 py-2 w-full rounded border-2 shadow-md transition focus:outline-hidden focus:shadow-xs ${
-        props["aria-invalid"]
-          ? "border-destructive text-destructive shadow-xs shadow-destructive"
-          : ""
-      } ${className}`}
+      className={`px-4 py-2 w-full with-radius border-2 shadow-md transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ${
+        props["aria-invalid"]
+          ? "border-destructive text-destructive"
+          : ""
+      } ${className}`}

Verification script:


🏁 Script executed:

#!/bin/bash
# Confirm presence of custom utilities and avoid accidental no-ops
rg -n 'outline-hidden|shadow-destructive|with-radius' -S -g '!node_modules/**'
fd -HI 'global.css' -x rg -n 'with-radius|outline-hidden|shadow-destructive' {}

Length of output: 23954


🏁 Script executed:

#!/bin/bash
echo "== app/global.css lines 80-120 =="
sed -n '80,120p' app/global.css || echo "app/global.css not found"

echo "== tailwind config files =="
fd -t f -HI 'tailwind.config.*'

for cfg in $(fd -t f -HI 'tailwind.config.*'); do
  echo "== $cfg =="
  sed -n '1,200p' "$cfg"
  echo "..."
done

Length of output: 1146


Swap to design tokens and remove undefined utilities

  • Replace rounded with with-radius (components/retroui/Input.tsx:17) and verify your global CSS or Tailwind config actually uses --radius for border-radius.
  • Remove focus:outline-hidden and shadow-destructive (not defined in global.css) and use core Tailwind classes (focus:outline-none + focus-visible:ring-2 focus-visible:ring-offset-2) for accessible focus.
  • Don’t mix shadow-md and shadow-xs; pick one or lean on a focus ring for error states.
🤖 Prompt for AI Agents
components/retroui/Input.tsx lines 17-21: replace non-token/undefined utilities
by swapping `rounded` for the design-token class `with-radius` (ensure your
global CSS/Tailwind uses --radius for border-radius), remove
`focus:outline-hidden` and `shadow-destructive` and instead use core Tailwind
focus utilities like `focus:outline-none` plus `focus-visible:ring-2
focus-visible:ring-offset-2` for accessible focus, stop mixing `shadow-md` and
`shadow-xs` (choose one consistent shadow or remove shadows and rely on focus
ring for error state), and update the conditional error classes to apply a
visible ring/border color (e.g., error border or ring) rather than undefined
shadow utilities.

Comment on lines +13 to +55
[Theme.Default]: {
name: "default",
color:
`:root {
--radius: ${hasRadius ? "0.5rem" : "0"};
--background: #fff;
--foreground: #000;
--card: #fff;
--card-foreground: #000;
--primary: #ffdb33;
--primary-hover: #ffcc00;
--primary-foreground: #000;
--secondary: #000;
--secondary-foreground: #fff;
--muted: #cccccc;
--muted-foreground: #5a5a5a;
--accent: #fae583;
--accent-foreground: #000;
--destructive: #e63946;
--destructive-foreground: #fff;
--border: #000;
}
.dark {
--background: #1a1a1a;
--foreground: #f5f5f5;
--card: #242424;
--card-foreground: #f5f5f5;
--primary: #ffdb33;
--primary-hover: #ffcc00;
--primary-foreground: #000;
--secondary: #3a3a3a;
--secondary-foreground: #f5f5f5;
--muted: #3f3f46;
--muted-foreground: #a0a0a0;
--accent: #fae583;
--accent-foreground: #000;
--destructive: #e63946;
--destructive-foreground: #fff;
--border: #5c5c5c;
}
`,
},
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Normalize token coverage across themes.

Default lacks tokens present elsewhere (e.g., --input, --ring, --popover); Purple also omits some. Missing vars can cause inconsistent UI when components rely on them. Recommend ensuring each theme defines a complete, identical token set.

I can generate a consolidated token schema and a validation script to assert presence across all themes if you want.

Also applies to: 56-98, 99-145, 146-196, 197-248, 249-299, 300-351


🏁 Script executed:

#!/bin/bash
python3 - << 'EOF'
import re,sys
try:
    data = open('config/theme.ts', 'r').read()
except FileNotFoundError:
    sys.stderr.write('ERROR: config/theme.ts not found\n')
    sys.exit(1)
# Extract each theme's CSS variable tokens
themes = re.findall(r'\[Theme\.(\w+)\]:\s*{[^}]*color:\s*`([^`]*)`', data, re.DOTALL)
if not themes:
    sys.stderr.write('ERROR: No theme definitions found\n')
    sys.exit(1)
for name, color in themes:
    vars = re.findall(r'--([\w-]+):', color)
    print(f"{name}: {sorted(set(vars))}")
EOF

Length of output: 2129


Normalize tokens across all themes
Default and Purple are missing CSS vars (--input, --ring, --popover, --popover-foreground) present in other themes; ensure every theme defines the complete token set and add a validation check (script or unit test) to enforce consistency.

🤖 Prompt for AI Agents
In config/theme.ts around lines 13 to 55, the Default theme is missing several
CSS token variables (--input, --ring, --popover, --popover-foreground) that
other themes include; update the Default (and Purple if applicable) theme CSS
string to define those missing vars for both light and .dark blocks to match the
full token set used across themes, and then add a validation step (either a
small script or unit test) that loads all theme objects, extracts the CSS
variable names from each theme string, compares them to a canonical set (e.g.,
from the most complete theme), and fails the build/test if any theme is missing
or has extra tokens so future changes are enforced.

Comment on lines +100 to +107
Don't have an account?{" "}
<a
href="/sign-up"
className="font-bold underline underline-offset-4"
>
Sign up
</a>
</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

Fix ESLint: escape the apostrophe in “Don't”.

react/no-unescaped-entities flags this and can fail CI.

-            Don't have an account?{" "}
+            Don&apos;t have an account?{" "}
📝 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
Don't have an account?{" "}
<a
href="/sign-up"
className="font-bold underline underline-offset-4"
>
Sign up
</a>
</div>
Don&apos;t have an account?{" "}
<a
href="/sign-up"
className="font-bold underline underline-offset-4"
>
Sign up
</a>
</div>
🧰 Tools
🪛 ESLint

[error] 100-100: ' can be escaped with &apos;, &lsquo;, &#39;, &rsquo;.

(react/no-unescaped-entities)

🤖 Prompt for AI Agents
In preview/blocks/sign-in.tsx around lines 100 to 107, the string "Don't have an
account?" triggers react/no-unescaped-entities; replace the apostrophe with an
escaped entity (e.g., Don&apos;t) or otherwise escape the apostrophe in the JSX
so the text becomes Don&apos;t have an account? to satisfy ESLint and avoid CI
failures.

@coderabbitai coderabbitai bot mentioned this pull request Sep 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants