Skip to content

light mode#4

Merged
t3dotgg merged 3 commits intomainfrom
juliusmarminge/use-base-components
Feb 9, 2026
Merged

light mode#4
t3dotgg merged 3 commits intomainfrom
juliusmarminge/use-base-components

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented Feb 9, 2026

CleanShot 2026-02-08 at 22 05 13@2x CleanShot 2026-02-08 at 22 05 17@2x

Summary by CodeRabbit

  • New Features

    • Large library of reusable UI components added (accordions, dialogs, menus, inputs, selects, command palette, toasts, sheets, tables, etc.) for richer, consistent interfaces.
  • Theme

    • Dark theme support with system detection, cross-tab sync, and a theme toggle in the sidebar.
  • Style

    • Replaced hard-coded colors with semantic design tokens and global CSS variables for consistent light/dark theming and improved visuals.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 9, 2026

Walkthrough

Adds a large set of new UI components and utilities to the renderer, introduces a CSS-variable based theme (light/dark/system) and a useTheme hook, replaces hard-coded color tokens with semantic tokens across core renderer components, adds a cn utility and components.json, adjusts deps/config and a small smoke-test script tweak.

Changes

Cohort / File(s) Summary
UI component library
apps/renderer/src/components/ui/*
Adds 30+ new UI modules (accordion, alert, autocomplete, avatar, badge, button, card, checkbox, collapsible, combobox, command, dialog, empty, field, fieldset, form, input-group, input, kbd, label, menu, popover, progress, radio-group, scroll-area, select, separator, sheet, skeleton, spinner, switch, table, tabs, textarea, toast). Each wraps @base-ui/react primitives, applies data-slot attributes, CVA variants and composed Tailwind classes. Review API shapes, typings, and consistent class/slot usage.
Core renderer components
apps/renderer/src/App.tsx, apps/renderer/src/components/ChatView.tsx, apps/renderer/src/components/ChatMarkdown.tsx, apps/renderer/src/components/DiffPanel.tsx, apps/renderer/src/components/Sidebar.tsx
Replaces hex color classes with semantic tokens; ChatView integrates new InputGroup, Select, Button components and removes previous textarea auto-resize logic; ChatMarkdown and DiffPanel styling tokens updated; Sidebar adds theme toggle and theme-aware styling. Validate behavioral changes where logic was removed (e.g., textarea resizing, model menu handling).
Theming & CSS
apps/renderer/src/index.css, apps/renderer/src/hooks/useTheme.ts
Introduces CSS variable theme system with light/dark variants and a .no-transitions helper; adds many CSS token definitions and dark overrides. Adds useTheme hook (light
Utilities & small libs
apps/renderer/src/lib/utils.ts, apps/renderer/components.json
Adds cn(...inputs) util combining clsx + twMerge. Adds components.json with UI framework config, aliases, Tailwind/tokens and registries. Confirm imports use the new alias and utility.
Config & build
apps/renderer/tsconfig.json, apps/renderer/vite.config.ts, biome.json
Adds #/* path alias and resolves # in Vite; sets exactOptionalPropertyTypes: false in tsconfig; relaxes biome a11y rule noSvgWithoutTitle.
Dependencies
apps/renderer/package.json
Adds runtime deps including @base-ui/react, class-variance-authority, clsx, lucide-react, tailwind-merge and reorders react-markdown. Verify lockfile and install.
Markup & scripts
apps/renderer/index.html, apps/desktop/scripts/smoke-test.mjs
Removes body Tailwind class in index.html. Small smoke-test script tweak: reorder imports from node:child_process and use template literal for error output. Minor script change.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'light mode' is vague and does not clearly describe the actual scope of changes, which include comprehensive UI component library implementation, theming system, styling updates, and design system token migration across the renderer application. Consider a more descriptive title that captures the main work, such as 'Add design system UI components and light/dark theme support' or 'Implement base UI component library with theming.'
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch juliusmarminge/use-base-components

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
apps/renderer/src/components/ChatView.tsx (1)

312-344: Consider using cn utility for conditional class handling.

The deeply nested ternaries for status indicator styling reduce readability. Using the cn utility with object syntax would make the phase-based styling clearer and more maintainable.

♻️ Suggested refactor using cn utility
+const statusContainerClasses: Record<string, string> = {
+  running: "border-sky-400/35 bg-sky-500/8 text-sky-700 dark:text-sky-100",
+  connecting: "border-amber-400/35 bg-amber-500/8 text-amber-700 dark:text-amber-100",
+  ready: "border-emerald-400/35 bg-emerald-500/8 text-emerald-700 dark:text-emerald-100",
+  disconnected: "border-border bg-secondary text-muted-foreground",
+};
+
+const statusDotClasses: Record<string, string> = {
+  running: "bg-sky-200",
+  connecting: "bg-amber-200",
+  ready: "bg-emerald-200",
+  disconnected: "bg-muted-foreground/40",
+};

Then use:

<div
  className={cn(
    "inline-flex items-center gap-2 rounded-full border px-2.5 py-1 text-[10px]",
    statusContainerClasses[phase] ?? statusContainerClasses.disconnected
  )}
>

Based on learnings: "Use Tailwind CSS for styling - no inline styles, use cn for conditional classes".

apps/renderer/src/components/Sidebar.tsx (1)

138-152: Prefer Coss UI for the new icon-only theme toggle.

To keep styling and interaction patterns consistent with the rest of the app, consider swapping this raw <button> for the equivalent Coss UI icon/button primitive.

Based on learnings: Applies to **/*.tsx : Use Coss UI components (https://coss.com/ui) for consistent styling.


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

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp bot commented Feb 9, 2026

Add light/dark/system theme cycling and apply token-based theming across Sidebar, ChatView, and global styles to introduce light mode

Introduce a useTheme hook with localStorage persistence and a Sidebar header button to cycle system/light/dark; switch global and app styling to CSS variables and semantic Tailwind tokens; refactor ChatView and Sidebar UI to use shared UI primitives; remove thread status badges, editor/approval flows, and keyboard shortcuts; update model selection in new project flow.

📍Where to Start

Start with the useTheme hook in useTheme.ts and its integration in the Sidebar in Sidebar.tsx, then review theme token application in index.css.


Macroscope summarized 0a535ae.

Copy link
Copy Markdown

@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: 6

🤖 Fix all issues with AI agents
In `@apps/renderer/src/components/Sidebar.tsx`:
- Around line 225-230: The button currently uses the disabled prop which
conflicts with accessibility guidance and tooltips; instead remove the disabled
attribute on the button element, add aria-disabled={isPickingFolder} to reflect
state, keep/adjust the visual "disabled" classes conditionally when
isPickingFolder, and add a click guard at the top of handlePickFolder (or inline
in the onClick wrapper) that returns early if isPickingFolder so clicks are
ignored; ensure tooltip behavior is preserved by using aria-disabled rather than
disabled.

In `@apps/renderer/src/components/ui/combobox.tsx`:
- Around line 196-214: The SVG in the Combobox component uses an incorrect xmlns
value; update the xmlns on the SVG inside ComboboxPrimitive.ItemIndicator to the
correct "http://www.w3.org/2000/svg" string so the icon renders properly (look
for the SVG element in the ComboboxPrimitive.ItemIndicator within the
combobox.tsx component and change the xmlns attribute value).

In `@apps/renderer/src/components/ui/empty.tsx`:
- Around line 94-105: The component EmptyDescription is typed as
React.ComponentProps<"p"> but renders a <div>, causing a props/semantic
mismatch; fix it by making the types and markup consistent—either change the
rendered element to <p> (keep the same props type) or change the prop type to
React.ComponentProps<"div"> (keep the <div>); update the function signature
(EmptyDescription) accordingly and ensure spreading {...props}, className and
data-slot="empty-description" remain correct for the chosen element.

In `@apps/renderer/src/components/ui/scroll-area.tsx`:
- Around line 5-35: Replace the custom use of ScrollAreaPrimitive
(ScrollAreaPrimitive.Root, ScrollAreaPrimitive.Viewport,
ScrollAreaPrimitive.Corner) and the local ScrollBar components with the Coss UI
ScrollArea wrapper: install the package via the shadcn CLI (`pnpm dlx
shadcn@latest add `@coss/scroll-area``), import Coss's ScrollArea,
ScrollAreaViewport and Corner (or the exported equivalents) and re-create this
component as a thin wrapper named ScrollArea that forwards props and children
while preserving the scrollFade and scrollbarGutter booleans by mapping them to
equivalent className masks and gutter classes on the Coss component (apply the
same mask expressions and `data-has-overflow-*` gutter classes), and ensure
data-slot attributes (scroll-area-viewport, scroll-area-corner) remain on the
mapped children so existing consumers continue to work.

In `@apps/renderer/src/components/ui/select.tsx`:
- Around line 128-142: The SVG used inside SelectPrimitive.ItemIndicator has a
typo in its xmlns attribute; update the xmlns on the SVG element within
SelectPrimitive.ItemIndicator to the correct namespace
"http://www.w3.org/2000/svg" so the checkmark renders correctly across browsers
(locate the SVG in the SelectPrimitive.ItemIndicator block and replace the
incorrect "http://www.w3.org/1500/svg" value).

In `@apps/renderer/src/components/ui/skeleton.tsx`:
- Around line 1-3: The file uses React.ComponentProps<"div"> in the Skeleton
component but doesn't import the React namespace; add an import for React (e.g.,
add "import React from 'react'" or "import type React from 'react'") at the top
of apps/renderer/src/components/ui/skeleton.tsx so the React.ComponentProps type
resolves for the Skeleton function signature.
🧹 Nitpick comments (6)
apps/renderer/src/components/ui/table.tsx (1)

36-47: Consider extracting long class strings for maintainability.

The class string on line 40 is quite long with many frame-conditional styles. While this is a common pattern in shadcn-style UI libraries, consider extracting the frame-specific styles into a separate variable or using Tailwind's @apply directive in a CSS file for better readability.

That said, this is a stylistic preference and the current implementation is functionally correct.

apps/renderer/src/components/ui/separator.tsx (1)

13-13: The CSS selector for vertical self-stretch is fragile and likely won't work as intended.

The selector not-[[class^='h-']]:not-[[class*='_h-']] checks whether the class attribute string starts with 'h-' or contains '_h-'. Since other classes (e.g., shrink-0) will appear first in the composed className, the [class^='h-'] condition will almost never match—even when a height utility like h-10 is present.

Consider simplifying by always applying self-stretch for vertical orientation and letting explicit height classes override it naturally, or document that consumers should use inline styles / CSS variables for custom heights:

♻️ Suggested simplification
-        "shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:not-[[class^='h-']]:not-[[class*='_h-']]:self-stretch",
+        "shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
apps/renderer/src/components/ui/toast.tsx (1)

220-250: Consider extracting shared toast content into a reusable component.

The toast content rendering here (icon, title, description, action button) is nearly identical to lines 128-158 in the Toasts component. Extracting this into a shared ToastContent component would reduce duplication and ensure consistency when making future changes.

♻️ Suggested extraction
// Shared component to use in both Toasts and AnchoredToasts
function ToastContentBody({ toast }: { toast: Toast.ToastObject }) {
  const Icon = toast.type
    ? TOAST_ICONS[toast.type as keyof typeof TOAST_ICONS]
    : null;

  return (
    <Toast.Content className="pointer-events-auto flex items-center justify-between gap-1.5 overflow-hidden px-3.5 py-3 text-sm ...">
      <div className="flex gap-2">
        {Icon && (
          <div
            className="[&>svg]:h-lh [&>svg]:w-4 [&_svg]:pointer-events-none [&_svg]:shrink-0"
            data-slot="toast-icon"
          >
            <Icon className="in-data-[type=loading]:animate-spin ..." />
          </div>
        )}
        <div className="flex flex-col gap-0.5">
          <Toast.Title className="font-medium" data-slot="toast-title" />
          <Toast.Description className="text-muted-foreground" data-slot="toast-description" />
        </div>
      </div>
      {toast.actionProps && (
        <Toast.Action className={buttonVariants({ size: "xs" })} data-slot="toast-action">
          {toast.actionProps.children}
        </Toast.Action>
      )}
    </Toast.Content>
  );
}
apps/renderer/src/components/ui/kbd.tsx (1)

5-26: Prefer Coss UI primitives for consistency.

These custom Kbd/KbdGroup wrappers diverge from the guideline to use Coss UI components (installed via the ShadCN CLI) for consistent styling and Base UI accessibility alignment. If a Coss kbd component exists, consider swapping to it (or document why bespoke wrappers are required).

Based on learnings: Applies to **/*.tsx : Use Coss UI components (https://coss.com/ui) for consistent styling. Install new components using the ShadCN CLI (e.g., bunx --bun shadcnlatest add coss/button). Refer to Base UI docs for accessibility guidelines on primitives.

apps/renderer/src/components/ui/textarea.tsx (1)

7-10: Consider documenting or removing the number type for size.

The size prop accepts "sm" | "default" | "lg" | number, but the internal styling logic (lines 35-38) only handles the string literals. When a number is passed, it's set on data-size but no corresponding styles are applied.

If numeric sizes are intended for custom CSS handling via data-size, consider adding a brief comment documenting this. Otherwise, consider restricting the type to the supported string literals only.

apps/renderer/src/index.css (1)

227-242: Consider using CSS variables for scrollbar colors for consistency.

The scrollbar styling uses hardcoded rgba() values while the rest of the file uses CSS variables. For better theme consistency, consider using the defined tokens:

♻️ Optional: Use CSS variables for scrollbar colors
 ::-webkit-scrollbar-thumb {
-  background: rgba(0, 0, 0, 0.15);
+  background: var(--muted-foreground);
+  opacity: 0.15;
   border-radius: 3px;
 }

 ::-webkit-scrollbar-thumb:hover {
-  background: rgba(0, 0, 0, 0.25);
+  background: var(--muted-foreground);
+  opacity: 0.25;
 }

 .dark ::-webkit-scrollbar-thumb {
-  background: rgba(255, 255, 255, 0.1);
+  background: var(--muted-foreground);
+  opacity: 0.1;
 }

 .dark ::-webkit-scrollbar-thumb:hover {
-  background: rgba(255, 255, 255, 0.18);
+  background: var(--muted-foreground);
+  opacity: 0.18;
 }

Note: Opacity on scrollbar thumbs may have limited browser support; the current approach works reliably.

Comment on lines 225 to 230
<button
type="button"
className="mb-2 flex w-full items-center justify-center rounded-md border border-white/[0.1] px-2 py-1.5 text-xs text-[#a0a0a0]/70 transition-colors duration-150 hover:bg-white/[0.04] disabled:cursor-not-allowed disabled:opacity-60"
className="mb-2 flex w-full items-center justify-center rounded-md border border-border px-2 py-1.5 text-xs text-muted-foreground transition-colors duration-150 hover:bg-secondary disabled:cursor-not-allowed disabled:opacity-60"
onClick={() => void handlePickFolder()}
disabled={isPickingFolder}
>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid the disabled prop; use aria-disabled and a click guard instead.

The current disabled usage conflicts with the repo’s accessibility guidance and can break tooltips. Use styling plus a guard in the handler.

🛠️ Suggested fix
-              className="mb-2 flex w-full items-center justify-center rounded-md border border-border px-2 py-1.5 text-xs text-muted-foreground transition-colors duration-150 hover:bg-secondary disabled:cursor-not-allowed disabled:opacity-60"
-              onClick={() => void handlePickFolder()}
-              disabled={isPickingFolder}
+              className={`mb-2 flex w-full items-center justify-center rounded-md border border-border px-2 py-1.5 text-xs text-muted-foreground transition-colors duration-150 hover:bg-secondary ${
+                isPickingFolder ? "cursor-not-allowed opacity-60" : ""
+              }`}
+              aria-disabled={isPickingFolder}
+              onClick={() => {
+                if (isPickingFolder) return;
+                void handlePickFolder();
+              }}
Based on learnings: Avoid using disabled props on buttons as they harm accessibility and break tooltips.
🤖 Prompt for AI Agents
In `@apps/renderer/src/components/Sidebar.tsx` around lines 225 - 230, The button
currently uses the disabled prop which conflicts with accessibility guidance and
tooltips; instead remove the disabled attribute on the button element, add
aria-disabled={isPickingFolder} to reflect state, keep/adjust the visual
"disabled" classes conditionally when isPickingFolder, and add a click guard at
the top of handlePickFolder (or inline in the onClick wrapper) that returns
early if isPickingFolder so clicks are ignored; ensure tooltip behavior is
preserved by using aria-disabled rather than disabled.

Comment on lines +196 to +214
<ComboboxPrimitive.ItemIndicator className="col-start-1">
<svg
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/1500/svg"
>
<path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
</svg>
</ComboboxPrimitive.ItemIndicator>
<div className="col-start-2">{children}</div>
</ComboboxPrimitive.Item>
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Invalid SVG namespace will break rendering.

Same issue as in select.tsx: the xmlns attribute has http://www.w3.org/1500/svg instead of http://www.w3.org/2000/svg.

🐛 Proposed fix
         <svg
           fill="none"
           height="24"
           stroke="currentColor"
           strokeLinecap="round"
           strokeLinejoin="round"
           strokeWidth="2"
           viewBox="0 0 24 24"
           width="24"
-          xmlns="http://www.w3.org/1500/svg"
+          xmlns="http://www.w3.org/2000/svg"
         >
           <path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
         </svg>
📝 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
<ComboboxPrimitive.ItemIndicator className="col-start-1">
<svg
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/1500/svg"
>
<path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
</svg>
</ComboboxPrimitive.ItemIndicator>
<div className="col-start-2">{children}</div>
</ComboboxPrimitive.Item>
);
}
<ComboboxPrimitive.ItemIndicator className="col-start-1">
<svg
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
</svg>
</ComboboxPrimitive.ItemIndicator>
<div className="col-start-2">{children}</div>
</ComboboxPrimitive.Item>
);
}
🤖 Prompt for AI Agents
In `@apps/renderer/src/components/ui/combobox.tsx` around lines 196 - 214, The SVG
in the Combobox component uses an incorrect xmlns value; update the xmlns on the
SVG inside ComboboxPrimitive.ItemIndicator to the correct
"http://www.w3.org/2000/svg" string so the icon renders properly (look for the
SVG element in the ComboboxPrimitive.ItemIndicator within the combobox.tsx
component and change the xmlns attribute value).

Comment on lines +94 to +105
function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
return (
<div
className={cn(
"text-muted-foreground text-sm [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4 [[data-slot=empty-title]+&]:mt-1",
className,
)}
data-slot="empty-description"
{...props}
/>
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Type mismatch: Component typed as <p> but renders <div>.

EmptyDescription accepts React.ComponentProps<"p"> but renders a <div>. This inconsistency could confuse consumers and allows <p>-specific props that won't apply to the rendered <div>.

💡 Proposed fix

Either change the rendered element to match the type:

-function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
+function EmptyDescription({ className, ...props }: React.ComponentProps<"div">) {
   return (
     <div

Or render a <p> to match the type (if semantically appropriate):

 function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
   return (
-    <div
+    <p
       className={cn(
         "text-muted-foreground text-sm [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4 [[data-slot=empty-title]+&]:mt-1",
         className,
       )}
       data-slot="empty-description"
       {...props}
-    />
+    />
   );
 }
📝 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
function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
return (
<div
className={cn(
"text-muted-foreground text-sm [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4 [[data-slot=empty-title]+&]:mt-1",
className,
)}
data-slot="empty-description"
{...props}
/>
);
}
function EmptyDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"text-muted-foreground text-sm [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4 [[data-slot=empty-title]+&]:mt-1",
className,
)}
data-slot="empty-description"
{...props}
/>
);
}
🤖 Prompt for AI Agents
In `@apps/renderer/src/components/ui/empty.tsx` around lines 94 - 105, The
component EmptyDescription is typed as React.ComponentProps<"p"> but renders a
<div>, causing a props/semantic mismatch; fix it by making the types and markup
consistent—either change the rendered element to <p> (keep the same props type)
or change the prop type to React.ComponentProps<"div"> (keep the <div>); update
the function signature (EmptyDescription) accordingly and ensure spreading
{...props}, className and data-slot="empty-description" remain correct for the
chosen element.

Comment on lines +5 to +35
function ScrollArea({
className,
children,
scrollFade = false,
scrollbarGutter = false,
...props
}: ScrollAreaPrimitive.Root.Props & {
scrollFade?: boolean;
scrollbarGutter?: boolean;
}) {
return (
<ScrollAreaPrimitive.Root
className={cn("size-full min-h-0", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport
className={cn(
"h-full overscroll-contain rounded-[inherit] outline-none transition-shadows focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-x:overscroll-x-contain",
scrollFade &&
"mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]",
scrollbarGutter &&
"data-has-overflow-y:pe-2.5 data-has-overflow-x:pb-2.5",
)}
data-slot="scroll-area-viewport"
>
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar orientation="vertical" />
<ScrollBar orientation="horizontal" />
<ScrollAreaPrimitive.Corner data-slot="scroll-area-corner" />
</ScrollAreaPrimitive.Root>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Coss UI ScrollArea component documentation installation shadcn

💡 Result:

Coss UI – ScrollArea (shadcn CLI install + docs)

  • Docs: coss.com/ui/docs/components/scroll-area (coss.com)
  • Install (shadcn CLI):
    pnpm dlx shadcn@latest add `@coss/scroll-area`
    (coss.com)
  • Use:
    import { ScrollArea } from "@/components/ui/scroll-area"
    (coss.com)

If you meant the core shadcn/ui ScrollArea (Radix/Base UI), the install command is:

pnpm dlx shadcn@latest add scroll-area

(ui.shadcn.com)

Citations:


🏁 Script executed:

# Check for existing UI component usage patterns in the repository
find apps/renderer/src/components/ui -type f -name "*.tsx" | head -20

Repository: pingdotgg/codething-mvp

Length of output: 957


🏁 Script executed:

# Check package.json to see what UI libraries are currently in use
cat package.json | grep -A 20 '"dependencies"' | head -40

Repository: pingdotgg/codething-mvp

Length of output: 49


🏁 Script executed:

# Search for existing imports of UI components to understand patterns
rg "from.*coss|from.*shadcn" apps/renderer/src/components/ui --no-heading -A 1 | head -30

Repository: pingdotgg/codething-mvp

Length of output: 49


🏁 Script executed:

# Check if ScrollAreaPrimitive is imported from `@radix-ui` or another source
head -50 apps/renderer/src/components/ui/scroll-area.tsx

Repository: pingdotgg/codething-mvp

Length of output: 2171


Replace with Coss UI ScrollArea component for consistency with codebase guidelines.

Coss UI provides a ScrollArea component that should be installed via ShadCN CLI: pnpm dlx shadcn@latest add @coss/scroll-area``. The custom extensions (scrollFade, `scrollbarGutter`) can be preserved by wrapping the Coss UI component instead of using Base UI directly. This ensures alignment with the team's component catalog and styling standards.

🤖 Prompt for AI Agents
In `@apps/renderer/src/components/ui/scroll-area.tsx` around lines 5 - 35, Replace
the custom use of ScrollAreaPrimitive (ScrollAreaPrimitive.Root,
ScrollAreaPrimitive.Viewport, ScrollAreaPrimitive.Corner) and the local
ScrollBar components with the Coss UI ScrollArea wrapper: install the package
via the shadcn CLI (`pnpm dlx shadcn@latest add `@coss/scroll-area``), import
Coss's ScrollArea, ScrollAreaViewport and Corner (or the exported equivalents)
and re-create this component as a thin wrapper named ScrollArea that forwards
props and children while preserving the scrollFade and scrollbarGutter booleans
by mapping them to equivalent className masks and gutter classes on the Coss
component (apply the same mask expressions and `data-has-overflow-*` gutter
classes), and ensure data-slot attributes (scroll-area-viewport,
scroll-area-corner) remain on the mapped children so existing consumers continue
to work.

Comment on lines +128 to +142
<SelectPrimitive.ItemIndicator className="col-start-1">
<svg
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/1500/svg"
>
<path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
</svg>
</SelectPrimitive.ItemIndicator>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Invalid SVG namespace will break rendering.

The xmlns attribute has a typo: http://www.w3.org/1500/svg should be http://www.w3.org/2000/svg. This invalid namespace may cause the checkmark SVG to fail to render in some browsers.

🐛 Proposed fix
         <svg
           fill="none"
           height="24"
           stroke="currentColor"
           strokeLinecap="round"
           strokeLinejoin="round"
           strokeWidth="2"
           viewBox="0 0 24 24"
           width="24"
-          xmlns="http://www.w3.org/1500/svg"
+          xmlns="http://www.w3.org/2000/svg"
         >
           <path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
         </svg>
📝 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
<SelectPrimitive.ItemIndicator className="col-start-1">
<svg
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/1500/svg"
>
<path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
</svg>
</SelectPrimitive.ItemIndicator>
<SelectPrimitive.ItemIndicator className="col-start-1">
<svg
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
</svg>
</SelectPrimitive.ItemIndicator>
🤖 Prompt for AI Agents
In `@apps/renderer/src/components/ui/select.tsx` around lines 128 - 142, The SVG
used inside SelectPrimitive.ItemIndicator has a typo in its xmlns attribute;
update the xmlns on the SVG element within SelectPrimitive.ItemIndicator to the
correct namespace "http://www.w3.org/2000/svg" so the checkmark renders
correctly across browsers (locate the SVG in the SelectPrimitive.ItemIndicator
block and replace the incorrect "http://www.w3.org/1500/svg" value).

Comment on lines +1 to +3
import { cn } from "#/lib/utils";

function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n apps/renderer/src/components/ui/skeleton.tsx | head -20

Repository: pingdotgg/codething-mvp

Length of output: 723


🏁 Script executed:

find . -name "tsconfig.json" -type f | head -5

Repository: pingdotgg/codething-mvp

Length of output: 160


🏁 Script executed:

cat tsconfig.json 2>/dev/null || cat ./apps/renderer/tsconfig.json 2>/dev/null || find . -name "tsconfig.json" -exec cat {} \;

Repository: pingdotgg/codething-mvp

Length of output: 388


Add React type import for ComponentProps reference.

Line 3 references React.ComponentProps<"div"> without importing the React namespace. While the modern JSX transform (jsx: "react-jsx") eliminates the need for React in JSX elements, explicit namespace references like React.ComponentProps still require the import and will cause a type-checking error.

+import type * as React from "react";
 import { cn } from "#/lib/utils";
📝 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
import { cn } from "#/lib/utils";
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
import type * as React from "react";
import { cn } from "#/lib/utils";
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
🤖 Prompt for AI Agents
In `@apps/renderer/src/components/ui/skeleton.tsx` around lines 1 - 3, The file
uses React.ComponentProps<"div"> in the Skeleton component but doesn't import
the React namespace; add an import for React (e.g., add "import React from
'react'" or "import type React from 'react'") at the top of
apps/renderer/src/components/ui/skeleton.tsx so the React.ComponentProps type
resolves for the Skeleton function signature.

Copy link
Copy Markdown

@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: 1

🤖 Fix all issues with AI agents
In `@apps/renderer/src/components/ChatView.tsx`:
- Around line 478-482: The UI currently renders effort labels by capitalizing
the first character in the map over REASONING_OPTIONS (in the SelectItem
rendering), which turns values like "xhigh" into "Xhigh"; replace this logic by
defining a display-name mapping (e.g., a constant object like
REASONING_DISPLAY_NAMES keyed by the same values in REASONING_OPTIONS) and use
that map when rendering the SelectItem label and when comparing to
DEFAULT_REASONING, falling back to a nicer formatter (e.g., full word
replacements or Title Case) only if a key is missing; update the SelectItem
render to use REASONING_DISPLAY_NAMES[effort] || fallbackFormatter(effort).
🧹 Nitpick comments (1)
apps/renderer/src/components/ChatView.tsx (1)

451-456: Minor: Redundant dark: prefixes for transparent and semantic tokens.

bg-transparent is identical in both modes, and bg-accent is a semantic token that already adapts to the theme. The dark: prefixes are unnecessary here.

♻️ Simplified styling
 <SelectTrigger
   size="sm"
-  className="w-auto min-w-0 border-0 shadow-none bg-transparent dark:bg-transparent before:hidden data-[popup-open]:bg-accent dark:data-[popup-open]:bg-accent"
+  className="w-auto min-w-0 border-0 shadow-none bg-transparent before:hidden data-[popup-open]:bg-accent"
 >

Apply to both SelectTrigger instances (lines 451-456 and 471-476).

Also applies to: 471-476

Comment on lines +478 to +482
{REASONING_OPTIONS.map((effort) => (
<SelectItem key={effort} value={effort}>
{effort.charAt(0).toUpperCase() + effort.slice(1)}
{effort === DEFAULT_REASONING ? " (default)" : ""}
</SelectItem>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Capitalization of "xhigh" produces awkward "Xhigh" in the UI.

The inline capitalization effort.charAt(0).toUpperCase() + effort.slice(1) transforms "xhigh" to "Xhigh", which isn't user-friendly. Consider a display name mapping for better readability.

💡 Suggested approach
+const EFFORT_LABELS: Record<string, string> = {
+  xhigh: "Extra High",
+  high: "High",
+  medium: "Medium",
+  low: "Low",
+};
+
 {REASONING_OPTIONS.map((effort) => (
   <SelectItem key={effort} value={effort}>
-    {effort.charAt(0).toUpperCase() + effort.slice(1)}
+    {EFFORT_LABELS[effort] ?? effort}
     {effort === DEFAULT_REASONING ? " (default)" : ""}
   </SelectItem>
 ))}
📝 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
{REASONING_OPTIONS.map((effort) => (
<SelectItem key={effort} value={effort}>
{effort.charAt(0).toUpperCase() + effort.slice(1)}
{effort === DEFAULT_REASONING ? " (default)" : ""}
</SelectItem>
const EFFORT_LABELS: Record<string, string> = {
xhigh: "Extra High",
high: "High",
medium: "Medium",
low: "Low",
};
{REASONING_OPTIONS.map((effort) => (
<SelectItem key={effort} value={effort}>
{EFFORT_LABELS[effort] ?? effort}
{effort === DEFAULT_REASONING ? " (default)" : ""}
</SelectItem>
🤖 Prompt for AI Agents
In `@apps/renderer/src/components/ChatView.tsx` around lines 478 - 482, The UI
currently renders effort labels by capitalizing the first character in the map
over REASONING_OPTIONS (in the SelectItem rendering), which turns values like
"xhigh" into "Xhigh"; replace this logic by defining a display-name mapping
(e.g., a constant object like REASONING_DISPLAY_NAMES keyed by the same values
in REASONING_OPTIONS) and use that map when rendering the SelectItem label and
when comparing to DEFAULT_REASONING, falling back to a nicer formatter (e.g.,
full word replacements or Title Case) only if a key is missing; update the
SelectItem render to use REASONING_DISPLAY_NAMES[effort] ||
fallbackFormatter(effort).

juliusmarminge and others added 3 commits February 9, 2026 01:12
Remove dark mode background bleed on select triggers and add accent
background when popup is open.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@t3dotgg t3dotgg force-pushed the juliusmarminge/use-base-components branch from 35deea6 to 0a535ae Compare February 9, 2026 09:13
@t3dotgg t3dotgg merged commit c51f252 into main Feb 9, 2026
1 check passed
t3dotgg added a commit that referenced this pull request Feb 9, 2026
This reverts commit c51f252.
jjalangtry pushed a commit to jjalangtry/t3code that referenced this pull request Mar 16, 2026
* init components

* use them

* Fix select trigger styling in dark mode and add open state highlight

Remove dark mode background bleed on select triggers and add accent
background when popup is open.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
jjalangtry pushed a commit to jjalangtry/t3code that referenced this pull request Mar 16, 2026
hameltomor added a commit to hameltomor/t3code that referenced this pull request Mar 20, 2026
Add AI usage dashboard with token tracking and rate limits
praveenperera pushed a commit to praveenperera/t3code that referenced this pull request Mar 23, 2026
BarretoDiego added a commit to BarretoDiego/t3code that referenced this pull request Mar 28, 2026
- Add CODEX_INTEGRATION_ANALYSIS.md with detailed protocol flow analysis
  * Protocol flow architecture and high-level overview
  * Request-response JSON-RPC sequence diagrams
  * Event streaming and transformation pipeline
  * Session state machine and lifecycle events
  * Provider dispatch routing analysis
  * 5 critical improvements ranked by priority
  * Failure scenarios and recovery analysis
  * Testing and deployment recommendations

- Add CODEX_IMPROVEMENTS_GUIDE.md with step-by-step implementation guide
  * Improvement pingdotgg#1: Method-specific timeout configuration
  * Improvement pingdotgg#2: Partial stream recovery buffer
  * Improvement pingdotgg#3: Circuit breaker pattern implementation
  * Improvement pingdotgg#4: Graceful shutdown with timeout
  * Improvement pingdotgg#5: Structured observability logging
  * Integration checklist and testing procedures
  * 5-week rollout strategy

Architecture grade: B+ (strong foundation, operational concerns remain)
Expected impact: 10x reduction in false timeouts, 99.9% → 99.99% availability

These guides provide actionable recommendations for improving connection
robustness, timeout strategies, error recovery, and observability in the
Codex App Server integration.
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