refactor: replace shadcn color vocabulary with semantic tokens

Remove the shadcn/ui color tokens (background, foreground, card, popover,
muted, accent, secondary, destructive, input) and migrate every usage to
LibreChat semantic surface/text/border tokens.

Add surface-inverted/text-inverted for the neutral inverted CTA and
surface-fixed/text-fixed for controls that must not flip with the theme
(favicon chips, QR container, carousel arrows). New tokens are defined once
in style.css (light + dark), createTailwindColors, the theme types,
applyTheme and the default/dark theme objects so they stay overridable at
runtime.

Collapse paired dark: color variants into the dark-aware tokens and tokenize
the remaining raw palette and white/black utilities, mapping status colors to
the status-* tokens and legacy ring-black/ring-white focus rings to
ring-text-primary.

Retain the background, primary and ring tokens, which are still referenced by
the SidePanel/Agents and SidePanel/Builder panels (excluded from this pass).
This commit is contained in:
Marco Beretta 2026-06-21 00:20:54 +02:00
parent 6a666aeabd
commit fefaa45b70
No known key found for this signature in database
GPG key ID: D918033D8E74CC11
141 changed files with 379 additions and 455 deletions

View file

@ -36,7 +36,7 @@ const AccordionTrigger: React.ForwardRefExoticComponent<
{...props}
>
{children}
<ChevronDownIcon className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
<ChevronDownIcon className="h-4 w-4 shrink-0 text-text-secondary transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));

View file

@ -47,8 +47,7 @@ const AlertDialogContent: React.ForwardRefExoticComponent<
<AlertDialogPrimitive.Content
ref={ref}
className={cn(
'fixed z-50 grid w-full max-w-lg scale-100 gap-4 bg-white p-6 opacity-100 animate-in fade-in-90 slide-in-from-bottom-10 sm:rounded-lg sm:zoom-in-90 sm:slide-in-from-bottom-0 md:w-full',
'dark:bg-gray-900',
'fixed z-50 grid w-full max-w-lg scale-100 gap-4 bg-surface-dialog p-6 opacity-100 animate-in fade-in-90 slide-in-from-bottom-10 sm:rounded-lg sm:zoom-in-90 sm:slide-in-from-bottom-0 md:w-full',
className,
)}
{...props}
@ -88,7 +87,7 @@ const AlertDialogTitle: React.ForwardRefExoticComponent<
>(({ className = '', ...props }, ref) => (
<AlertDialogPrimitive.Title
ref={ref}
className={cn('text-lg font-semibold text-gray-900', 'dark:text-gray-50', className)}
className={cn('text-lg font-semibold text-text-primary', className)}
{...props}
/>
));
@ -106,7 +105,7 @@ const AlertDialogDescription: React.ForwardRefExoticComponent<
>(({ className = '', ...props }, ref) => (
<AlertDialogPrimitive.Description
ref={ref}
className={cn('text-sm text-gray-500', 'dark:text-gray-400', className)}
className={cn('text-sm text-text-secondary', className)}
{...props}
/>
));
@ -125,7 +124,7 @@ const AlertDialogAction: React.ForwardRefExoticComponent<
<AlertDialogPrimitive.Action
ref={ref}
className={cn(
'inline-flex h-10 items-center justify-center rounded-md bg-gray-900 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-100 dark:focus:ring-gray-400 dark:focus:ring-offset-gray-900',
'inline-flex h-10 items-center justify-center rounded-md bg-surface-inverted px-4 py-2 text-sm font-semibold text-text-inverted transition-colors hover:bg-surface-inverted-hover focus:outline-none focus:ring-2 focus:ring-text-primary focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
@ -146,7 +145,7 @@ const AlertDialogCancel: React.ForwardRefExoticComponent<
<AlertDialogPrimitive.Cancel
ref={ref}
className={cn(
'mt-2 inline-flex h-10 items-center justify-center rounded-md border border-gray-200 bg-transparent px-4 py-2 text-sm font-semibold text-gray-900 transition-colors hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:text-gray-100 dark:hover:bg-gray-800 dark:focus:ring-gray-400 dark:focus:ring-offset-gray-900 sm:mt-0',
'mt-2 inline-flex h-10 items-center justify-center rounded-md border border-border-light bg-transparent px-4 py-2 text-sm font-semibold text-text-primary transition-colors hover:bg-surface-hover focus:outline-none focus:ring-2 focus:ring-text-primary focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 sm:mt-0',
className,
)}
{...props}

View file

@ -28,7 +28,7 @@ const AnimatedSearchInput = ({
<Search
className={cn(
`h-4 w-4 transition-all duration-500 ease-in-out`,
isSearching && hasValue ? 'text-blue-400' : 'text-gray-500',
isSearching && hasValue ? 'text-blue-400' : 'text-text-secondary',
)}
/>
</div>
@ -40,7 +40,7 @@ const AnimatedSearchInput = ({
onChange={onChange}
placeholder={placeholder}
aria-label={localize('com_ui_search')}
className={`peer relative z-20 w-full rounded-lg bg-surface-secondary py-2 pl-10 outline-none backdrop-blur-sm transition-all duration-500 ease-in-out placeholder:text-gray-500 focus:ring-ring`}
className={`peer relative z-20 w-full rounded-lg bg-surface-secondary py-2 pl-10 outline-none backdrop-blur-sm transition-all duration-500 ease-in-out placeholder:text-text-secondary focus:ring-text-primary`}
/>
{/* Gradient overlay */}

View file

@ -24,7 +24,7 @@ const BreadcrumbList: React.ForwardRefExoticComponent<
<ol
ref={ref}
className={cn(
'flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5',
'flex flex-wrap items-center gap-1.5 break-words text-sm text-text-secondary sm:gap-2.5',
className,
)}
{...props}
@ -61,7 +61,7 @@ const BreadcrumbLink: React.ForwardRefExoticComponent<
return (
<Comp
ref={ref}
className={cn('transition-colors hover:text-foreground', className)}
className={cn('transition-colors hover:text-text-primary', className)}
{...props}
/>
);
@ -78,7 +78,7 @@ const BreadcrumbPage: React.ForwardRefExoticComponent<
role="link"
aria-disabled="true"
aria-current="page"
className={cn('font-normal text-foreground', className)}
className={cn('font-normal text-text-primary', className)}
{...props}
/>
),

View file

@ -21,18 +21,17 @@ const buttonVariants: (
} & ClassProp)
| undefined,
) => string = cva(
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium ring-offset-surface-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive:
'bg-surface-destructive text-destructive-foreground hover:bg-surface-destructive-hover',
default: 'bg-surface-inverted text-text-inverted hover:bg-surface-inverted-hover',
destructive: 'bg-surface-destructive text-white hover:bg-surface-destructive-hover',
outline:
'text-text-primary border border-border-light bg-transparent hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-surface-hover hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
'text-text-primary border border-border-light bg-transparent hover:bg-surface-hover hover:text-text-primary',
secondary: 'bg-surface-secondary text-text-primary hover:bg-surface-hover',
ghost: 'hover:bg-surface-hover hover:text-text-primary',
link: 'text-text-primary underline-offset-4 hover:underline',
// hardcoded text color because of WCAG contrast issues (text-white)
submit: 'bg-surface-submit text-white hover:bg-surface-submit-hover',
},

View file

@ -27,7 +27,7 @@ const Checkbox: React.ForwardRefExoticComponent<
<CheckboxPrimitive.Root
ref={ref}
className={cn(
'peer h-4 w-4 shrink-0 rounded-sm border border-border-xheavy ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
'peer h-4 w-4 shrink-0 rounded-sm border border-border-xheavy ring-offset-surface-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-surface-inverted data-[state=checked]:text-text-inverted',
className,
)}
{...props}

View file

@ -82,7 +82,7 @@ export default function ComboboxComponent({
isCollapsed
? 'flex h-9 w-9 shrink-0 items-center justify-center p-0 [&>span]:w-auto [&>svg]:hidden'
: '',
'bg-white text-black hover:bg-gray-50 focus-visible:ring-2 focus-visible:ring-gray-500 dark:bg-gray-850 dark:text-white',
'bg-surface-secondary text-text-primary hover:bg-surface-hover focus-visible:ring-2 focus-visible:ring-text-primary',
)}
>
<SelectValue placeholder={selectPlaceholder}>
@ -105,18 +105,18 @@ export default function ComboboxComponent({
aria-label={ariaLabel + 's'}
position="popper"
className={cn(
'bg-popover text-popover-foreground relative z-40 max-h-[52vh] min-w-[8rem] overflow-hidden rounded-md border border-gray-200 shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-gray-600',
'relative z-40 max-h-[52vh] min-w-[8rem] overflow-hidden rounded-md border border-border-light bg-surface-secondary text-text-primary shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
'bg-white dark:bg-gray-700',
'bg-surface-secondary',
)}
>
<RadixSelect.Viewport className="mb-5 h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]">
<div className="group sticky left-0 top-0 z-10 flex h-12 items-center gap-2 bg-white px-3 py-2 text-black duration-300 dark:bg-gray-700 dark:text-white">
<SearchIcon className="h-4 w-4 text-gray-500 transition-colors duration-300 dark:group-focus-within:text-gray-300 dark:group-hover:text-gray-300" />
<div className="group sticky left-0 top-0 z-10 flex h-12 items-center gap-2 bg-surface-secondary px-3 py-2 text-text-primary duration-300">
<SearchIcon className="h-4 w-4 text-text-secondary transition-colors duration-300 group-focus-within:text-text-primary group-hover:text-text-primary" />
<Combobox
autoSelect
placeholder={searchPlaceholder}
className="flex-1 rounded-md border-none bg-transparent px-2.5 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-gray-700/10 dark:focus:ring-gray-200/10"
className="flex-1 rounded-md border-none bg-transparent px-2.5 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-border-medium"
// Ariakit's Combobox manually triggers a blur event on virtually
// blurred items, making them work as if they had actual DOM
// focus. These blur events might happen after the corresponding
@ -133,7 +133,7 @@ export default function ComboboxComponent({
/>
<ComboboxCancel
hideWhenEmpty={true}
className="relative flex h-5 w-5 items-center justify-end text-gray-500 transition-colors duration-300 dark:group-focus-within:text-gray-300 dark:group-hover:text-gray-300"
className="relative flex h-5 w-5 items-center justify-end text-text-secondary transition-colors duration-300 group-focus-within:text-text-primary group-hover:text-text-primary"
/>
</div>
<ComboboxList className="overflow-y-auto p-1 py-2">
@ -141,8 +141,8 @@ export default function ComboboxComponent({
<RadixSelect.Item key={value} value={`${value ?? ''}`} asChild>
<ComboboxItem
className={cn(
'relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'rounded-lg hover:bg-gray-100/50 hover:bg-gray-50 dark:text-white dark:hover:bg-gray-600',
'relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-surface-hover focus:text-text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'rounded-lg hover:bg-surface-hover',
)}
/** Hacky fix for radix-ui Android issue: https://github.com/radix-ui/primitives/issues/1658 */
onTouchEnd={() => {
@ -156,7 +156,7 @@ export default function ComboboxComponent({
</RadixSelect.ItemIndicator>
</span>
<RadixSelect.ItemText>
<div className="flex items-center justify-center gap-3 dark:text-white [&_svg]:h-4 [&_svg]:w-4 [&_svg]:shrink-0 [&_svg]:text-foreground">
<div className="flex items-center justify-center gap-3 [&_svg]:h-4 [&_svg]:w-4 [&_svg]:shrink-0 [&_svg]:text-text-primary">
<div className="assistant-item overflow-hidden rounded-full">
{icon && icon}
</div>

View file

@ -198,7 +198,7 @@ const DeleteButton = memo(
<Spinner className="size-4" />
) : (
<>
<TrashIcon className="size-3.5 text-red-400 sm:size-4" />
<TrashIcon className="size-3.5 text-text-destructive sm:size-4" />
{!isSmallScreen && <span className="ml-2">Delete</span>}
</>
)}
@ -429,7 +429,7 @@ export default function DataTable<TData, TValue>({
<div
ref={tableContainerRef}
className={cn(
'relative min-h-0 max-w-full flex-1 overflow-x-auto overflow-y-auto rounded-md border border-black/10 dark:border-white/10',
'relative min-h-0 max-w-full flex-1 overflow-x-auto overflow-y-auto rounded-md border border-border-light',
'transition-all duration-300 ease-out',
isSearching && 'bg-surface-secondary/50',
className,

View file

@ -436,7 +436,7 @@ function DataTable<TData extends Record<string, unknown>, TValue>({
return (
<div
className={cn(
'relative flex w-full flex-col overflow-hidden rounded-lg border border-border-light bg-background',
'relative flex w-full flex-col overflow-hidden rounded-lg border border-border-light bg-surface-primary',
'h-[calc(100vh-8rem)] max-h-[80vh]',
className,
)}

View file

@ -73,7 +73,7 @@ class DataTableErrorBoundaryInner extends Component<
aria-labelledby="datatable-error-title"
aria-describedby="datatable-error-desc"
tabIndex={-1}
className="before:bg-surface-destructive/80 relative w-full max-w-md overflow-hidden rounded-lg border border-border-light bg-surface-primary-alt p-6 shadow-sm outline-none before:absolute before:left-0 before:top-0 before:h-full before:w-1 focus:ring-2 focus:ring-ring focus:ring-offset-2 dark:border-border-medium dark:bg-surface-secondary"
className="before:bg-surface-destructive/80 relative w-full max-w-md overflow-hidden rounded-lg border border-border-light bg-surface-primary-alt p-6 shadow-sm outline-none before:absolute before:left-0 before:top-0 before:h-full before:w-1 focus:ring-2 focus:ring-text-primary focus:ring-offset-2"
>
<div className="flex items-center gap-2">
<RefreshCw className="h-4 w-4 text-surface-destructive" />
@ -98,7 +98,7 @@ class DataTableErrorBoundaryInner extends Component<
</div>
{import.meta.env.MODE === 'development' && this.state.error && (
<details className="mt-4 max-w-md rounded-md bg-surface-secondary p-3 text-xs dark:bg-surface-tertiary">
<details className="mt-4 max-w-md rounded-md bg-surface-secondary p-3 text-xs">
<summary className="cursor-pointer font-medium text-text-primary">
{this.props.localize('com_ui_error_details')}
</summary>

View file

@ -60,10 +60,9 @@ const DialogContent: React.ForwardRefExoticComponent<
<DialogPrimitive.Content
ref={ref}
className={cn(
'fixed z-[999] grid w-full gap-4 rounded-b-lg bg-white pb-6 animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:rounded-lg',
'dark:bg-gray-700',
'fixed z-[999] grid w-full gap-4 rounded-b-lg bg-surface-dialog pb-6 animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:rounded-lg',
isSmallScreen
? 'fixed left-1/2 top-1/2 z-[999] m-auto grid w-11/12 -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-white pb-6'
? 'fixed left-1/2 top-1/2 z-[999] m-auto grid w-11/12 -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-surface-dialog pb-6'
: '',
disableScroll ? 'overflow-hidden' : '',
className ?? '',
@ -72,8 +71,8 @@ const DialogContent: React.ForwardRefExoticComponent<
>
{children}
{showCloseButton && (
<DialogPrimitive.Close className="absolute right-6 top-[1.6rem] rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 dark:focus:ring-white dark:focus:ring-offset-gray-700 dark:data-[state=open]:bg-gray-800">
<X className="h-5 w-5 text-black dark:text-white" aria-hidden="true" />
<DialogPrimitive.Close className="absolute right-6 top-[1.6rem] rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-text-primary focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-surface-hover">
<X className="h-5 w-5 text-text-primary" aria-hidden="true" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
)}
@ -90,7 +89,7 @@ const DialogHeader: {
} = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): JSX.Element => (
<div
className={cn(
'flex flex-col space-y-2 border-b border-black/10 p-6 pb-4 text-left dark:border-white/10',
'flex flex-col space-y-2 border-b border-border-light p-6 pb-4 text-left',
className ?? '',
)}
{...props}
@ -118,7 +117,7 @@ const DialogTitle: React.ForwardRefExoticComponent<
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn('text-lg font-semibold text-gray-900', 'dark:text-gray-50', className ?? '')}
className={cn('text-lg font-semibold text-text-primary', className ?? '')}
{...props}
/>
));
@ -133,7 +132,7 @@ const DialogDescription: React.ForwardRefExoticComponent<
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn('text-sm text-gray-500', 'dark:text-gray-400', className ?? '')}
className={cn('text-sm text-text-secondary', className ?? '')}
{...props}
/>
));
@ -149,10 +148,10 @@ const DialogClose: React.ForwardRefExoticComponent<
<DialogPrimitive.Close
ref={ref}
className={cn(
'mt-2 inline-flex h-10 items-center justify-center rounded-lg border border-gray-200 bg-transparent px-4 py-2 text-sm font-semibold text-gray-900 transition-colors hover:bg-gray-100 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:text-gray-100 dark:hover:bg-gray-800 sm:mt-0',
'mt-2 inline-flex h-10 items-center justify-center rounded-lg border border-border-light bg-transparent px-4 py-2 text-sm font-semibold text-text-primary transition-colors hover:bg-surface-hover focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 sm:mt-0',
className ?? '',
/* Important: for accessibility */
'focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 dark:focus:ring-gray-400 dark:focus:ring-offset-gray-900',
'focus:ring-2 focus:ring-text-primary focus:ring-offset-2',
)}
{...props}
/>
@ -170,10 +169,10 @@ const DialogButton: React.ForwardRefExoticComponent<
ref={ref}
variant="outline"
className={cn(
'mt-2 inline-flex h-10 items-center justify-center rounded-lg border border-gray-200 bg-transparent px-4 py-2 text-sm font-semibold text-gray-900 transition-colors hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:text-gray-100 dark:hover:bg-gray-800 dark:focus:ring-gray-400 dark:focus:ring-offset-gray-900 sm:mt-0',
'mt-2 inline-flex h-10 items-center justify-center rounded-lg border border-border-light bg-transparent px-4 py-2 text-sm font-semibold text-text-primary transition-colors hover:bg-surface-hover focus:outline-none focus:ring-2 focus:ring-text-primary focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 sm:mt-0',
className ?? '',
/* Important: for accessibility */
'focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 dark:focus:ring-gray-400 dark:focus:ring-offset-gray-900',
'focus:ring-2 focus:ring-text-primary focus:ring-offset-2',
)}
{...props}
/>

View file

@ -49,22 +49,20 @@ const DialogTemplate: ForwardRefExoticComponent<
const Cancel = 'cancel';
const defaultSelect =
'bg-gray-800 text-white transition-colors hover:bg-gray-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-200 dark:text-gray-800 dark:hover:bg-gray-200';
'bg-surface-inverted text-text-inverted transition-colors hover:bg-surface-inverted-hover disabled:cursor-not-allowed disabled:opacity-50';
return (
<DialogContent
showCloseButton={showCloseButton}
ref={ref}
className={cn('shadow-2xl dark:bg-gray-700', className || '')}
className={cn('bg-surface-dialog shadow-2xl', className || '')}
onClick={(e) => e.stopPropagation()}
>
<DialogHeader className={cn(headerClassName ?? '')}>
<DialogTitle className="text-lg font-medium leading-6 text-gray-800 dark:text-gray-200">
<DialogTitle className="text-lg font-medium leading-6 text-text-primary">
{title}
</DialogTitle>
{description && (
<DialogDescription className="text-gray-600 dark:text-gray-300">
{description}
</DialogDescription>
<DialogDescription className="text-text-secondary">{description}</DialogDescription>
)}
</DialogHeader>
<div className="px-6">{main ? main : null}</div>
@ -72,7 +70,7 @@ const DialogTemplate: ForwardRefExoticComponent<
<div>{leftButtons ? leftButtons : null}</div>
<div className="flex h-auto gap-3">
{showCancelButton && (
<DialogClose className="border-gray-100 hover:bg-gray-100 dark:border-gray-600 dark:hover:bg-gray-600">
<DialogClose className="border-border-light hover:bg-surface-hover">
{Cancel}
</DialogClose>
)}

View file

@ -137,8 +137,8 @@ const Dropdown: React.FC<DropdownProps> = ({
store={selectProps}
disabled={disabled}
className={cn(
'focus:ring-offset-ring-offset relative inline-flex items-center justify-between rounded-xl border border-input bg-background px-3 py-2 text-sm text-text-primary transition-all duration-200 ease-in-out hover:bg-accent hover:text-accent-foreground focus:ring-ring-primary',
'disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-background disabled:hover:text-text-primary',
'focus:ring-offset-ring-offset relative inline-flex items-center justify-between rounded-xl border border-border-medium bg-surface-primary px-3 py-2 text-sm text-text-primary transition-all duration-200 ease-in-out hover:bg-surface-hover hover:text-text-primary focus:ring-ring-primary',
'disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-surface-primary disabled:hover:text-text-primary',
iconOnly ? 'size-10' : 'w-fit gap-2',
className,
)}
@ -176,7 +176,7 @@ const Dropdown: React.FC<DropdownProps> = ({
>
{searchable ? (
<>
<div className="sticky -top-2 z-10 -mx-2 -mt-2 mb-1 bg-surface-primary px-2 pb-1.5 pt-2 dark:bg-surface-secondary">
<div className="sticky -top-2 z-10 -mx-2 -mt-2 mb-1 bg-surface-primary px-2 pb-1.5 pt-2">
<div className="relative">
<Search
className="pointer-events-none absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary"

View file

@ -63,7 +63,7 @@ function DropdownMenuItem({
data-inset={inset}
data-variant={variant}
className={cn(
"data-[variant=destructive]:*:[svg]:!text-destructive outline-hidden relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[disabled]:opacity-50 data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0",
"data-[variant=destructive]:*:[svg]:!text-text-destructive outline-hidden relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm focus:bg-surface-hover focus:text-text-primary data-[disabled]:pointer-events-none data-[inset]:pl-8 data-[variant=destructive]:text-text-destructive data-[disabled]:opacity-50 data-[variant=destructive]:focus:bg-status-error-subtle data-[variant=destructive]:focus:text-text-destructive [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-text-secondary [&_svg]:pointer-events-none [&_svg]:shrink-0",
className,
)}
{...props}
@ -81,7 +81,7 @@ function DropdownMenuCheckboxItem({
<DropdownMenuPrimitive.CheckboxItem
data-slot="dropdown-menu-checkbox-item"
className={cn(
"outline-hidden relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"outline-hidden relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm focus:bg-surface-hover focus:text-text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className,
)}
checked={checked}
@ -112,7 +112,7 @@ function DropdownMenuRadioItem({
<DropdownMenuPrimitive.RadioItem
data-slot="dropdown-menu-radio-item"
className={cn(
"outline-hidden relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"outline-hidden relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm focus:bg-surface-hover focus:text-text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className,
)}
{...props}
@ -161,7 +161,7 @@ function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'spa
return (
<span
data-slot="dropdown-menu-shortcut"
className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}
className={cn('ml-auto text-xs tracking-widest text-text-secondary', className)}
{...props}
/>
);
@ -186,7 +186,7 @@ function DropdownMenuSubTrigger({
data-slot="dropdown-menu-sub-trigger"
data-inset={inset}
className={cn(
'outline-hidden flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[inset]:pl-8 data-[state=open]:text-accent-foreground',
'outline-hidden flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm focus:bg-surface-hover focus:text-text-primary data-[state=open]:bg-surface-hover data-[inset]:pl-8 data-[state=open]:text-text-primary',
className,
)}
{...props}

View file

@ -53,7 +53,7 @@ const Dropdown: FC<DropdownProps> = ({
<ListboxButton
data-testid={testId}
className={cn(
'relative inline-flex items-center justify-between rounded-md border-gray-50 bg-white py-2 pl-3 pr-8 text-black transition-all duration-100 ease-in-out hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 dark:focus:ring-white dark:focus:ring-offset-gray-700',
'relative inline-flex items-center justify-between rounded-md border-border-light bg-surface-secondary py-2 pl-3 pr-8 text-text-primary transition-all duration-100 ease-in-out hover:bg-surface-hover',
'w-auto',
className,
)}
@ -70,7 +70,7 @@ const Dropdown: FC<DropdownProps> = ({
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
className="h-4 w-5 rotate-0 transform text-black transition-transform duration-300 ease-in-out dark:text-gray-50"
className="h-4 w-5 rotate-0 transform text-text-primary transition-transform duration-300 ease-in-out"
>
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
@ -83,7 +83,7 @@ const Dropdown: FC<DropdownProps> = ({
>
<ListboxOptions
className={cn(
'absolute z-50 mt-1 flex flex-col items-start gap-1 overflow-auto rounded-lg border border-gray-300 bg-white p-1.5 text-gray-700 shadow-lg transition-opacity focus:outline-none dark:border-gray-600 dark:bg-gray-700 dark:text-white',
'absolute z-50 mt-1 flex flex-col items-start gap-1 overflow-auto rounded-lg border border-border-medium bg-surface-secondary p-1.5 text-text-primary shadow-lg transition-opacity focus:outline-none',
sizeClasses,
className,
)}
@ -94,7 +94,7 @@ const Dropdown: FC<DropdownProps> = ({
key={index}
value={item}
className={cn(
'relative cursor-pointer select-none rounded border-gray-300 bg-white py-2.5 pl-3 pr-3 text-sm text-gray-700 hover:bg-gray-100 dark:border-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600',
'relative cursor-pointer select-none rounded border-border-medium bg-surface-secondary py-2.5 pl-3 pr-3 text-sm text-text-primary hover:bg-surface-hover',
)}
style={{ width: '100%' }}
data-theme={getValue(item)}

View file

@ -169,7 +169,7 @@ const Menu: React.FC<MenuProps> = ({
)}
{item.label}
{item.kbd != null && (
<kbd className="ml-auto hidden font-sans text-xs text-black/50 group-hover:inline group-focus:inline dark:text-white/50">
<kbd className="ml-auto hidden font-sans text-xs text-text-tertiary group-hover:inline group-focus:inline">
{item.kbd}
</kbd>
)}

View file

@ -35,14 +35,14 @@ const FilterInput: React.ForwardRefExoticComponent<
placeholder=" "
aria-label={label}
className={cn(
'peer flex h-9 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
'peer flex h-9 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm ring-offset-surface-primary placeholder:text-text-secondary focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
/>
<label
htmlFor={inputId}
className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-sm text-text-secondary transition-all duration-200 peer-focus:top-0 peer-focus:bg-background peer-focus:px-1 peer-focus:text-xs peer-[:not(:placeholder-shown)]:top-0 peer-[:not(:placeholder-shown)]:bg-background peer-[:not(:placeholder-shown)]:px-1 peer-[:not(:placeholder-shown)]:text-xs"
className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-sm text-text-secondary transition-all duration-200 peer-focus:top-0 peer-focus:bg-surface-primary peer-focus:px-1 peer-focus:text-xs peer-[:not(:placeholder-shown)]:top-0 peer-[:not(:placeholder-shown)]:bg-surface-primary peer-[:not(:placeholder-shown)]:px-1 peer-[:not(:placeholder-shown)]:text-xs"
>
{label}
</label>

View file

@ -8,7 +8,7 @@ const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HT
return (
<input
className={cn(
'flex h-10 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
'flex h-10 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm ring-offset-surface-primary placeholder:text-text-secondary focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
className ?? '',
)}
ref={ref}

View file

@ -18,7 +18,7 @@ const InputNumber: React.ForwardRefExoticComponent<
return (
<RCInputNumber
className={cn(
'flex max-h-5 w-full rounded-md border border-gray-300 bg-transparent px-3 py-2 text-sm placeholder:text-gray-400 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:text-gray-50',
'flex max-h-5 w-full rounded-md border border-border-medium bg-transparent px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:outline-none disabled:cursor-not-allowed disabled:opacity-50',
className ?? '',
)}
ref={ref}

View file

@ -109,8 +109,8 @@ const InputOTPSlot: React.ForwardRefExoticComponent<
<div
ref={ref}
className={cn(
'text-md relative flex h-11 w-11 items-center justify-center border-y border-r border-input shadow-sm transition-all first:rounded-l-xl first:border-l last:rounded-r-xl',
isActive && 'z-10 ring-1 ring-ring',
'text-md relative flex h-11 w-11 items-center justify-center border-y border-r border-border-medium shadow-sm transition-all first:rounded-l-xl first:border-l last:rounded-r-xl',
isActive && 'z-10 ring-1 ring-text-primary',
className,
)}
{...props}
@ -118,7 +118,7 @@ const InputOTPSlot: React.ForwardRefExoticComponent<
{char}
{hasFakeCaret && (
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div className="animate-caret-blink h-4 w-px bg-foreground duration-1000" />
<div className="animate-caret-blink h-4 w-px bg-text-primary duration-1000" />
</div>
)}
</div>

View file

@ -97,7 +97,7 @@ const InputWithDropdown: React.ForwardRefExoticComponent<
/>
<button
type="button"
className="text-tertiary absolute inset-y-0 right-0 flex items-center rounded-md px-2 hover:text-secondary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring-primary"
className="text-tertiary absolute inset-y-0 right-0 flex items-center rounded-md px-2 hover:text-text-secondary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring-primary"
onClick={() => setIsOpen(!isOpen)}
aria-label={isOpen ? 'Close dropdown' : 'Open dropdown'}
>
@ -132,8 +132,8 @@ const InputWithDropdown: React.ForwardRefExoticComponent<
'cursor-pointer rounded-md px-3 py-2',
'focus:bg-surface-tertiary focus:outline-none focus:ring-1 focus:ring-inset focus:ring-ring-primary',
index === highlightedIndex
? 'bg-surface-active text-primary'
: 'text-secondary hover:bg-surface-tertiary',
? 'bg-surface-active text-text-primary'
: 'text-text-secondary hover:bg-surface-tertiary',
)}
onClick={() => handleSelect(option)}
onKeyDown={(e) => {

View file

@ -17,7 +17,7 @@ const Label: React.ForwardRefExoticComponent<
{...props}
{...{
className: cn(
'block w-full break-all text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-200',
'block w-full break-all text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-text-primary',
className,
),
}}

View file

@ -114,7 +114,7 @@ export default function MultiSelect<T extends string>({
className={cn(
'flex items-center justify-between gap-2 rounded-xl px-3 py-2 text-sm',
'bg-surface-tertiary text-text-primary shadow-sm hover:cursor-pointer hover:bg-surface-hover',
'outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white',
'outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary',
selectClassName,
selectedValues.length > 0 && selectItemsClassName != null && selectItemsClassName,
)}
@ -151,7 +151,7 @@ export default function MultiSelect<T extends string>({
const label = getItemLabel(item);
const defaultContent = (
<>
<SelectItemCheck className="mr-0.5 text-primary" />
<SelectItemCheck className="mr-0.5 text-text-primary" />
<span className="truncate">{label}</span>
</>
);
@ -163,8 +163,8 @@ export default function MultiSelect<T extends string>({
className={cn(
'flex items-center gap-2 rounded-lg px-2 py-1.5 hover:cursor-pointer',
'scroll-m-1 outline-none transition-colors',
'hover:bg-black/[0.075] dark:hover:bg-white/10',
'data-[active-item]:bg-black/[0.075] dark:data-[active-item]:bg-white/10',
'hover:bg-surface-hover',
'data-[active-item]:bg-surface-active',
'w-full min-w-0 text-sm',
itemClassName,
)}

View file

@ -93,7 +93,7 @@ const OGDialogTemplate: ForwardRefExoticComponent<
const { selectHandler, selectClasses, selectText, isLoading } = legacySelection ?? {};
const defaultSelect =
'bg-gray-800 text-white transition-colors hover:bg-gray-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-200 dark:text-gray-800 dark:hover:bg-gray-200';
'bg-surface-inverted text-text-inverted transition-colors hover:bg-surface-inverted-hover disabled:cursor-not-allowed disabled:opacity-50';
let selectionContent = null;
if (isLegacySelection) {
@ -121,7 +121,7 @@ const OGDialogTemplate: ForwardRefExoticComponent<
overlayClassName={overlayClassName}
showCloseButton={showCloseButton}
ref={ref}
className={cn('w-11/12 border-none bg-background text-foreground', className ?? '')}
className={cn('w-11/12 border-none bg-surface-primary text-text-primary', className ?? '')}
onClick={(e) => e.stopPropagation()}
>
<OGDialogHeader className={cn(headerClassName ?? '')}>

View file

@ -154,14 +154,14 @@ const DialogContent: React.ForwardRefExoticComponent<
style={{ ...style, zIndex: contentZIndex }}
onEscapeKeyDown={handleEscapeKeyDown}
className={cn(
'max-w-11/12 fixed left-[50%] top-[50%] grid max-h-[90vh] w-full translate-x-[-50%] translate-y-[-50%] gap-4 overflow-y-auto rounded-2xl bg-background p-6 text-text-primary shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
'max-w-11/12 fixed left-[50%] top-[50%] grid max-h-[90vh] w-full translate-x-[-50%] translate-y-[-50%] gap-4 overflow-y-auto rounded-2xl bg-surface-primary p-6 text-text-primary shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
className,
)}
{...props}
>
{children}
{showCloseButton && (
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-ring-primary ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-ring-primary ring-offset-surface-primary transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-text-primary focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-surface-hover data-[state=open]:text-text-secondary">
<X className="h-6 w-6" aria-hidden="true" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>

View file

@ -11,11 +11,14 @@ const Progress: React.ForwardRefExoticComponent<
>(({ className, value, ...props }, ref) => (
<ProgressPrimitive.Root
ref={ref}
className={cn('relative h-2 w-full overflow-hidden rounded-full bg-primary/20', className)}
className={cn(
'relative h-2 w-full overflow-hidden rounded-full bg-surface-tertiary',
className,
)}
{...props}
>
<ProgressPrimitive.Indicator
className="h-full w-full flex-1 bg-primary transition-all"
className="h-full w-full flex-1 bg-surface-inverted transition-all"
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</ProgressPrimitive.Root>

View file

@ -81,11 +81,11 @@ const Radio: React.NamedExoticComponent<RadioProps> = memo(function Radio({
if (options.length === 0) {
return (
<div
className="relative inline-flex items-center rounded-lg bg-muted p-1 opacity-50"
className="relative inline-flex items-center rounded-lg bg-surface-tertiary p-1 opacity-50"
role="radiogroup"
aria-labelledby={ariaLabelledBy}
>
<span className="px-4 py-2 text-xs text-muted-foreground">
<span className="px-4 py-2 text-xs text-text-secondary">
{localize('com_ui_no_options')}
</span>
</div>
@ -96,13 +96,13 @@ const Radio: React.NamedExoticComponent<RadioProps> = memo(function Radio({
return (
<div
className={`relative ${fullWidth ? 'flex' : 'inline-flex'} items-center rounded-lg bg-muted ${className}`}
className={`relative ${fullWidth ? 'flex' : 'inline-flex'} items-center rounded-lg bg-surface-tertiary ${className}`}
role="radiogroup"
aria-labelledby={ariaLabelledBy}
>
{selectedIndex >= 0 && isMounted && (
<div
className="pointer-events-none absolute inset-y-0 rounded-md border border-border/50 bg-background shadow-sm transition-all duration-300 ease-out"
className="pointer-events-none absolute inset-y-0 rounded-md border border-border-light bg-surface-primary shadow-sm transition-all duration-300 ease-out"
style={backgroundStyle}
/>
)}
@ -117,8 +117,8 @@ const Radio: React.NamedExoticComponent<RadioProps> = memo(function Radio({
aria-checked={currentValue === option.value}
onClick={() => handleChange(option.value)}
disabled={disabled}
className={`relative z-10 flex h-[34px] items-center justify-center gap-2 rounded-md px-4 text-sm font-medium transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${
currentValue === option.value ? 'text-foreground' : 'text-foreground'
className={`relative z-10 flex h-[34px] items-center justify-center gap-2 rounded-md px-4 text-sm font-medium transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary ${
currentValue === option.value ? 'text-text-primary' : 'text-text-primary'
} ${disabled ? 'cursor-not-allowed opacity-50' : ''} ${fullWidth ? 'flex-1' : ''} ${buttonClassName}`}
>
{option.icon && (

View file

@ -22,13 +22,13 @@ const ResizableHandle = ({
}): JSX.Element => (
<Separator
className={cn(
'relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1',
'relative flex w-px items-center justify-center bg-border-medium after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-text-primary focus-visible:ring-offset-1',
className,
)}
{...props}
>
{withHandle && (
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border-medium">
<GripVertical className="h-2.5 w-2.5" />
</div>
)}
@ -44,13 +44,13 @@ const ResizableHandleAlt = ({
}): JSX.Element => (
<Separator
className={cn(
'group relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1',
'group relative flex w-px items-center justify-center bg-border-medium after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-text-primary focus-visible:ring-offset-1',
className,
)}
{...props}
>
{withHandle && (
<div className="invisible z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border group-hover:visible group-active:visible group-data-[separator=active]:visible">
<div className="invisible z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border-medium group-hover:visible group-active:visible group-data-[separator=active]:visible">
<GripVertical className="h-2.5 w-2.5" />
</div>
)}

View file

@ -80,7 +80,7 @@ const SecretInput: React.ForwardRefExoticComponent<
id={id}
type={isVisible ? 'text' : 'password'}
className={cn(
'flex h-10 w-full rounded-lg border border-border-light bg-transparent py-2 pl-3 text-sm transition-colors placeholder:text-muted-foreground hover:border-border-medium focus-visible:border-border-heavy focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
'flex h-10 w-full rounded-lg border border-border-light bg-transparent py-2 pl-3 text-sm transition-colors placeholder:text-text-secondary hover:border-border-medium focus-visible:border-border-heavy focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
className ?? '',
copyButton != null || showCopy ? 'pr-20' : 'pr-11',
)}

View file

@ -26,8 +26,8 @@ const SelectTrigger: React.ForwardRefExoticComponent<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-gray-200 border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 [&>span]:line-clamp-1',
'rounded-lg hover:bg-gray-100/50 dark:hover:bg-gray-700',
'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-border-medium bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-surface-primary placeholder:text-text-secondary focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
'rounded-lg hover:bg-surface-hover',
className,
)}
{...props}
@ -49,10 +49,7 @@ const SelectScrollUpButton: React.ForwardRefExoticComponent<
>(({ className = '', ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn(
'flex cursor-default items-center justify-center py-1 dark:text-white',
className,
)}
className={cn('flex cursor-default items-center justify-center py-1', className)}
{...props}
>
<ChevronUpIcon />
@ -69,10 +66,7 @@ const SelectScrollDownButton: React.ForwardRefExoticComponent<
>(({ className = '', ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn(
'flex cursor-default items-center justify-center py-1 dark:text-white',
className,
)}
className={cn('flex cursor-default items-center justify-center py-1', className)}
{...props}
>
<ChevronDownIcon />
@ -91,7 +85,7 @@ const SelectContent: React.ForwardRefExoticComponent<
<SelectPrimitive.Content
ref={ref}
className={cn(
'bg-popover text-popover-foreground relative z-40 max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-gray-200 shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-gray-600',
'relative z-40 max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-border-light bg-surface-secondary text-text-primary shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
position === 'popper'
? 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1'
: '',
@ -142,8 +136,8 @@ const SelectItem: React.ForwardRefExoticComponent<
<SelectPrimitive.Item
ref={ref}
className={cn(
'relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'rounded-lg hover:bg-gray-100/50 dark:hover:bg-gray-700',
'relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-surface-hover focus:text-text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'rounded-lg hover:bg-surface-hover',
className,
)}
{...props}
@ -167,7 +161,7 @@ const SelectSeparator: React.ForwardRefExoticComponent<
>(({ className = '', ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn('-mx-1 my-1 h-px bg-muted', className)}
className={cn('-mx-1 my-1 h-px bg-surface-tertiary', className)}
{...props}
/>
));

View file

@ -119,13 +119,13 @@ function SelectDropDown({
}
}}
className={cn(
'relative flex w-full cursor-default flex-col rounded-md border border-black/10 bg-white py-2 pl-3 pr-10 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:bg-white dark:border-gray-600 dark:bg-gray-700 sm:text-sm',
'relative flex w-full cursor-default flex-col rounded-md border border-border-light bg-surface-secondary py-2 pl-3 pr-10 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:ring-offset-2 disabled:bg-surface-secondary sm:text-sm',
className ?? '',
)}
>
{showLabel && (
<Label
className="block text-xs text-gray-700 dark:text-gray-500"
className="block text-xs text-text-secondary"
id="headlessui-listbox-label-:r1:"
data-headlessui-state=""
>
@ -135,13 +135,13 @@ function SelectDropDown({
<span className="inline-flex w-full truncate">
<span
className={cn(
'flex h-6 items-center gap-1 truncate text-sm text-gray-800 dark:text-white',
'flex h-6 items-center gap-1 truncate text-sm text-text-primary',
!showLabel ? 'text-xs' : '',
currentValueClass ?? '',
)}
>
{!showLabel && !emptyTitle && (
<span className="text-xs text-gray-700 dark:text-gray-500">{title}:</span>
<span className="text-xs text-text-secondary">{title}:</span>
)}
{renderIcon && optionIconSide !== 'right' && (
<span className="icon-md flex items-center">
@ -172,7 +172,7 @@ function SelectDropDown({
viewBox="0 0 24 24"
strokeLinecap="round"
strokeLinejoin="round"
className="h-4 w-4 text-gray-400"
className="h-4 w-4 text-text-tertiary"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
@ -192,7 +192,7 @@ function SelectDropDown({
>
<ListboxOptions
className={cn(
'absolute z-10 mt-2 max-h-60 w-full overflow-auto rounded border bg-white text-xs ring-black/10 dark:border-gray-600 dark:bg-gray-700 dark:ring-white/20 md:w-[100%]',
'absolute z-10 mt-2 max-h-60 w-full overflow-auto rounded border border-border-light bg-surface-secondary text-xs md:w-[100%]',
optionsListClass ?? '',
)}
>
@ -201,7 +201,7 @@ function SelectDropDown({
key={'listbox-render-option'}
value={null}
className={cn(
'group relative flex h-[42px] cursor-pointer select-none items-center overflow-hidden pl-3 pr-9 text-gray-800 hover:bg-gray-20 dark:text-white dark:hover:bg-gray-700',
'group relative flex h-[42px] cursor-pointer select-none items-center overflow-hidden pl-3 pr-9 text-text-primary hover:bg-surface-hover',
optionsClass ?? '',
)}
>
@ -230,7 +230,7 @@ function SelectDropDown({
value={option}
className={({ active }) =>
cn(
'group relative flex h-[42px] cursor-pointer select-none items-center overflow-hidden pl-3 pr-9 text-gray-800 hover:bg-gray-20 dark:text-white dark:hover:bg-gray-600',
'group relative flex h-[42px] cursor-pointer select-none items-center overflow-hidden pl-3 pr-9 text-text-primary hover:bg-surface-hover',
active ? 'bg-surface-active text-text-primary' : '',
optionsClass ?? '',
)
@ -239,7 +239,7 @@ function SelectDropDown({
<span className="flex items-center gap-1.5 truncate">
<span
className={cn(
'flex h-6 items-center gap-1 text-gray-800 dark:text-gray-200',
'flex h-6 items-center gap-1 text-text-primary',
option === value ? 'font-semibold' : '',
iconSide === 'left' ? 'ml-4' : '',
)}
@ -259,7 +259,7 @@ function SelectDropDown({
{currentValue === activeValue && (
<span
className={cn(
'absolute inset-y-0 flex items-center text-gray-800 dark:text-gray-200',
'absolute inset-y-0 flex items-center text-text-primary',
iconSide === 'left' ? 'left-0 pl-2' : 'right-0 pr-3',
)}
>

View file

@ -37,14 +37,16 @@ const Slider: React.ForwardRefExoticComponent<SliderProps & React.RefAttributes<
}}
>
<SliderPrimitive.Track
{...{ className: 'relative h-2 w-full grow overflow-hidden rounded-full bg-secondary' }}
{...{
className: 'relative h-2 w-full grow overflow-hidden rounded-full bg-surface-tertiary',
}}
>
<SliderPrimitive.Range {...{ className: 'absolute h-full bg-primary' }} />
<SliderPrimitive.Range {...{ className: 'absolute h-full bg-surface-inverted' }} />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb
{...{
className:
'block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
'block h-5 w-5 rounded-full border-2 border-border-xheavy bg-surface-primary ring-offset-surface-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
'aria-labelledby': ariaLabelledBy,
'aria-label': ariaLabel,
'aria-describedby': ariaDescribedBy,

View file

@ -23,7 +23,7 @@ const Switch: React.ForwardRefExoticComponent<
({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-switch-unchecked',
'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:ring-offset-2 focus-visible:ring-offset-surface-primary disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-surface-inverted data-[state=unchecked]:bg-switch-unchecked',
className,
)}
{...props}
@ -31,7 +31,7 @@ const Switch: React.ForwardRefExoticComponent<
>
<SwitchPrimitives.Thumb
className={cn(
'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0',
'pointer-events-none block h-5 w-5 rounded-full bg-surface-primary shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0',
)}
/>
</SwitchPrimitives.Root>

View file

@ -45,7 +45,7 @@ const TableFooter: React.ForwardRefExoticComponent<
({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', className)}
className={cn('border-t bg-surface-tertiary font-medium [&>tr]:last:border-b-0', className)}
{...props}
/>
),
@ -59,7 +59,7 @@ const TableRow: React.ForwardRefExoticComponent<
<tr
ref={ref}
className={cn(
'border-b border-border-light transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
'border-b border-border-light transition-colors hover:bg-surface-tertiary data-[state=selected]:bg-surface-tertiary',
className,
)}
{...props}
@ -75,7 +75,7 @@ const TableHead: React.ForwardRefExoticComponent<
<th
ref={ref}
className={cn(
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
'h-12 px-4 text-left align-middle font-medium text-text-secondary [&:has([role=checkbox])]:pr-0',
className,
)}
{...props}
@ -118,7 +118,7 @@ const TableCaption: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLTableCaptionElement> & React.RefAttributes<HTMLTableCaptionElement>
> = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(
({ className, ...props }, ref) => (
<caption ref={ref} className={cn('mt-4 text-sm text-muted-foreground', className)} {...props} />
<caption ref={ref} className={cn('mt-4 text-sm text-text-secondary', className)} {...props} />
),
);
TableCaption.displayName = 'TableCaption';

View file

@ -33,7 +33,7 @@ const TabsTrigger: React.ForwardRefExoticComponent<
>(({ className = '', ...props }, ref) => (
<TabsPrimitive.Trigger
className={cn(
'inline-flex min-w-[100px] items-center justify-center rounded-[0.185rem] px-3 py-1.5 text-sm font-medium text-gray-700 transition-all disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-gray-800 data-[state=active]:shadow-sm dark:data-[state=active]:bg-gray-700 dark:data-[state=active]:text-gray-200',
'inline-flex min-w-[100px] items-center justify-center rounded-[0.185rem] px-3 py-1.5 text-sm font-medium text-text-secondary transition-all disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-surface-primary data-[state=active]:text-text-primary data-[state=active]:shadow-sm',
className,
)}
{...props}

View file

@ -11,7 +11,7 @@ const Textarea: React.ForwardRefExoticComponent<
return (
<textarea
className={cn(
'flex h-20 w-full resize-none rounded-md border border-gray-300 bg-transparent px-3 py-2 text-sm placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:text-gray-50 dark:focus:ring-gray-400 dark:focus:ring-offset-gray-900',
'flex h-20 w-full resize-none rounded-md border border-border-medium bg-transparent px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:outline-none focus:ring-2 focus:ring-text-primary focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
ref={ref}

View file

@ -36,7 +36,7 @@ const Theme = ({ theme, onChange }: { theme: string; onChange: (value: string) =
return (
<button
className="flex items-center gap-2 rounded-lg p-2 text-text-primary transition-colors hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 dark:focus-visible:ring-0"
className="flex items-center gap-2 rounded-lg p-2 text-text-primary transition-colors hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:ring-offset-2"
aria-label={localize('com_ui_toggle_theme')}
aria-keyshortcuts="Ctrl+Shift+T"
onClick={(e) => {
@ -90,7 +90,7 @@ const ThemeSelector = ({ returnThemeOnly }: { returnThemeOnly?: boolean }): JSX.
}
return (
<div className="flex flex-col items-center justify-center bg-white pt-6 dark:bg-gray-900 sm:pt-0">
<div className="flex flex-col items-center justify-center bg-surface-primary pt-6 sm:pt-0">
<div className="absolute bottom-0 left-0 m-4">
<Theme theme={theme} onChange={changeTheme} />
</div>

View file

@ -2,7 +2,7 @@ import React from 'react';
import { JSX } from 'react/jsx-runtime';
export default function DotsIcon({
className = 'h-4 w-4 flex-shrink-0 text-gray-500',
className = 'h-4 w-4 flex-shrink-0 text-text-secondary',
}: {
className?: string;
}): JSX.Element {

View file

@ -8,7 +8,7 @@ export default function NewChatIcon({ className = '' }: { className?: string }):
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={cn('text-black dark:text-white', className)}
className={cn('text-text-primary', className)}
aria-hidden="true"
>
<path

View file

@ -14,7 +14,7 @@ export default function SendIcon({
height={size}
viewBox={'0 0 24 24'}
fill="none"
className={cn('text-white dark:text-black', className)}
className={cn('text-text-inverted', className)}
aria-hidden="true"
>
<path

View file

@ -14,7 +14,7 @@ export default function StopGeneratingIcon({
viewBox="0 0 24 24"
strokeLinecap="round"
strokeLinejoin="round"
className={cn('h-3 w-3 text-gray-600 dark:text-gray-400', className)}
className={cn('h-3 w-3 text-text-secondary', className)}
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"

View file

@ -38,6 +38,12 @@ export const darkTheme: IThemeRGB = {
'rgb-surface-destructive': '153 27 27', // #991b1b (red-800)
'rgb-surface-destructive-hover': '127 29 29', // #7f1d1d (red-900)
'rgb-surface-chat': '47 47 47', // #2f2f2f (gray-700)
'rgb-surface-inverted': '255 255 255', // #fff (white)
'rgb-surface-inverted-hover': '236 236 236', // #ececec (gray-100)
'rgb-text-inverted': '23 23 23', // #171717 (gray-850)
'rgb-surface-fixed': '255 255 255', // #fff (white) — same in light + dark
'rgb-surface-fixed-hover': '236 236 236', // #ececec (gray-100) — same in light + dark
'rgb-text-fixed': '33 33 33', // #212121 (gray-800) — same in light + dark
// Border colors
'rgb-border-light': '47 47 47', // #2f2f2f (gray-700)
@ -52,21 +58,9 @@ export const darkTheme: IThemeRGB = {
// Presentation
'rgb-presentation': '33 33 33', // #212121 (gray-800)
// Utility colors (mapped to existing colors for backwards compatibility)
'rgb-background': '33 33 33', // Same as surface-primary
'rgb-foreground': '255 255 255', // Same as text-primary
'rgb-primary': '66 66 66', // Same as surface-active
'rgb-primary-foreground': '255 255 255', // Same as surface-primary-contrast
'rgb-secondary': '42 42 42', // Same as surface-secondary
'rgb-secondary-foreground': '193 193 193', // Same as text-secondary
'rgb-muted': '56 56 56', // Same as surface-tertiary
'rgb-muted-foreground': '140 140 140', // Same as text-tertiary
'rgb-accent': '82 82 82', // Same as surface-active-alt
'rgb-accent-foreground': '255 255 255', // Same as text-primary
'rgb-destructive-foreground': '255 255 255', // Same as text-primary
'rgb-border': '82 82 82', // Same as border-medium
'rgb-input': '66 66 66', // Same as border-light
'rgb-ring': '255 255 255', // Same as ring-primary
'rgb-card': '42 42 42', // Same as surface-secondary
'rgb-card-foreground': '255 255 255', // Same as text-primary
// Retained for excluded SidePanel/Agents + SidePanel/Builder (pending migration)
'rgb-background': '18 18 18', // 0 0% 7%
'rgb-primary': '250 250 250', // 0 0% 98%
'rgb-primary-foreground': '23 23 23', // 0 0% 9%
'rgb-ring': '212 212 212', // 0 0% 83.1%
};

View file

@ -38,6 +38,12 @@ export const defaultTheme: IThemeRGB = {
'rgb-surface-destructive': '185 28 28', // #b91c1c (red-700)
'rgb-surface-destructive-hover': '153 27 27', // #991b1b (red-800)
'rgb-surface-chat': '255 255 255', // #fff (white)
'rgb-surface-inverted': '23 23 23', // #171717 (gray-850)
'rgb-surface-inverted-hover': '47 47 47', // #2f2f2f (gray-700)
'rgb-text-inverted': '255 255 255', // #fff (white)
'rgb-surface-fixed': '255 255 255', // #fff (white) — same in light + dark
'rgb-surface-fixed-hover': '236 236 236', // #ececec (gray-100) — same in light + dark
'rgb-text-fixed': '33 33 33', // #212121 (gray-800) — same in light + dark
// Border colors
'rgb-border-light': '227 227 227', // #e3e3e3 (gray-200)
@ -52,21 +58,9 @@ export const defaultTheme: IThemeRGB = {
// Presentation
'rgb-presentation': '255 255 255', // #fff (white)
// Utility colors (mapped to existing colors for backwards compatibility)
'rgb-background': '255 255 255', // Same as surface-primary
'rgb-foreground': '17 17 17', // Same as text-primary
'rgb-primary': '235 235 235', // Same as surface-active
'rgb-primary-foreground': '0 0 0', // Same as surface-primary-contrast
'rgb-secondary': '247 247 248', // Same as surface-secondary
'rgb-secondary-foreground': '66 66 66', // Same as text-secondary
'rgb-muted': '250 250 250', // Same as surface-tertiary
'rgb-muted-foreground': '120 120 120', // Same as text-tertiary
'rgb-accent': '245 245 245', // Same as surface-active-alt
'rgb-accent-foreground': '17 17 17', // Same as text-primary
'rgb-destructive-foreground': '17 17 17', // Same as text-primary
'rgb-border': '215 215 215', // Same as border-medium
'rgb-input': '230 230 230', // Same as border-light
'rgb-ring': '180 180 180', // Same as ring-primary
'rgb-card': '247 247 248', // Same as surface-secondary
'rgb-card-foreground': '17 17 17', // Same as text-primary
// Retained for excluded SidePanel/Agents + SidePanel/Builder (pending migration)
'rgb-background': '255 255 255', // 0 0% 100%
'rgb-primary': '23 23 23', // 0 0% 9%
'rgb-primary-foreground': '250 250 250', // 0 0% 98%
'rgb-ring': '10 10 10', // 0 0% 3.9%
};

View file

@ -36,6 +36,12 @@ export interface IThemeRGB {
'rgb-surface-destructive'?: string;
'rgb-surface-destructive-hover'?: string;
'rgb-surface-chat'?: string;
'rgb-surface-inverted'?: string;
'rgb-surface-inverted-hover'?: string;
'rgb-text-inverted'?: string;
'rgb-surface-fixed'?: string;
'rgb-surface-fixed-hover'?: string;
'rgb-text-fixed'?: string;
// Border colors
'rgb-border-light'?: string;
@ -50,23 +56,11 @@ export interface IThemeRGB {
// Presentation
'rgb-presentation'?: string;
// Utility colors
// Retained for excluded SidePanel/Agents + SidePanel/Builder (pending migration)
'rgb-background'?: string;
'rgb-foreground'?: string;
'rgb-primary'?: string;
'rgb-primary-foreground'?: string;
'rgb-secondary'?: string;
'rgb-secondary-foreground'?: string;
'rgb-muted'?: string;
'rgb-muted-foreground'?: string;
'rgb-accent'?: string;
'rgb-accent-foreground'?: string;
'rgb-destructive-foreground'?: string;
'rgb-border'?: string;
'rgb-input'?: string;
'rgb-ring'?: string;
'rgb-card'?: string;
'rgb-card-foreground'?: string;
}
/**
@ -99,6 +93,12 @@ export interface IThemeVariables {
'--surface-destructive': string;
'--surface-destructive-hover': string;
'--surface-chat': string;
'--surface-inverted': string;
'--surface-inverted-hover': string;
'--text-inverted': string;
'--surface-fixed': string;
'--surface-fixed-hover': string;
'--text-fixed': string;
'--border-light': string;
'--border-medium': string;
'--border-medium-alt': string;
@ -107,23 +107,11 @@ export interface IThemeVariables {
'--brand-purple': string;
'--presentation': string;
// Utility variables
// Retained for excluded SidePanel/Agents + SidePanel/Builder (pending migration)
'--background': string;
'--foreground': string;
'--primary': string;
'--primary-foreground': string;
'--secondary': string;
'--secondary-foreground': string;
'--muted': string;
'--muted-foreground': string;
'--accent': string;
'--accent-foreground': string;
'--destructive-foreground': string;
'--border': string;
'--input': string;
'--ring': string;
'--card': string;
'--card-foreground': string;
}
/**
@ -156,6 +144,12 @@ export interface IThemeColors {
'surface-destructive'?: string;
'surface-destructive-hover'?: string;
'surface-chat'?: string;
'surface-inverted'?: string;
'surface-inverted-hover'?: string;
'text-inverted'?: string;
'surface-fixed'?: string;
'surface-fixed-hover'?: string;
'text-fixed'?: string;
'border-light'?: string;
'border-medium'?: string;
'border-medium-alt'?: string;
@ -164,23 +158,11 @@ export interface IThemeColors {
'brand-purple'?: string;
presentation?: string;
// Utility colors
// Retained for excluded SidePanel/Agents + SidePanel/Builder (pending migration)
background?: string;
foreground?: string;
primary?: string;
'primary-foreground'?: string;
secondary?: string;
'secondary-foreground'?: string;
muted?: string;
'muted-foreground'?: string;
accent?: string;
'accent-foreground'?: string;
'destructive-foreground'?: string;
border?: string;
input?: string;
ring?: string;
card?: string;
'card-foreground'?: string;
}
export interface Theme {

View file

@ -52,6 +52,12 @@ function mapTheme(rgb: IThemeRGB): Partial<IThemeVariables> {
'rgb-surface-destructive': '--surface-destructive',
'rgb-surface-destructive-hover': '--surface-destructive-hover',
'rgb-surface-chat': '--surface-chat',
'rgb-surface-inverted': '--surface-inverted',
'rgb-surface-inverted-hover': '--surface-inverted-hover',
'rgb-text-inverted': '--text-inverted',
'rgb-surface-fixed': '--surface-fixed',
'rgb-surface-fixed-hover': '--surface-fixed-hover',
'rgb-text-fixed': '--text-fixed',
'rgb-border-light': '--border-light',
'rgb-border-medium': '--border-medium',
'rgb-border-medium-alt': '--border-medium-alt',
@ -60,23 +66,11 @@ function mapTheme(rgb: IThemeRGB): Partial<IThemeVariables> {
'rgb-brand-purple': '--brand-purple',
'rgb-presentation': '--presentation',
// Utility colors
// Retained for excluded SidePanel/Agents + SidePanel/Builder (pending migration)
'rgb-background': '--background',
'rgb-foreground': '--foreground',
'rgb-primary': '--primary',
'rgb-primary-foreground': '--primary-foreground',
'rgb-secondary': '--secondary',
'rgb-secondary-foreground': '--secondary-foreground',
'rgb-muted': '--muted',
'rgb-muted-foreground': '--muted-foreground',
'rgb-accent': '--accent',
'rgb-accent-foreground': '--accent-foreground',
'rgb-destructive-foreground': '--destructive-foreground',
'rgb-border': '--border',
'rgb-input': '--input',
'rgb-ring': '--ring',
'rgb-card': '--card',
'rgb-card-foreground': '--card-foreground',
};
Object.entries(mappings).forEach(([rgbKey, cssVar]) => {

View file

@ -99,6 +99,12 @@ function createTailwindColors() {
'surface-destructive': cssVar('--surface-destructive'),
'surface-destructive-hover': cssVar('--surface-destructive-hover'),
'surface-chat': cssVar('--surface-chat'),
'surface-inverted': cssVar('--surface-inverted'),
'surface-inverted-hover': cssVar('--surface-inverted-hover'),
'text-inverted': cssVar('--text-inverted'),
'surface-fixed': cssVar('--surface-fixed'),
'surface-fixed-hover': cssVar('--surface-fixed-hover'),
'text-fixed': cssVar('--text-fixed'),
'border-light': cssVar('--border-light'),
'border-medium': cssVar('--border-medium'),
@ -123,36 +129,15 @@ function createTailwindColors() {
'status-neutral-subtle': cssVar('--status-neutral-subtle'),
'status-neutral-border': cssVar('--status-neutral-border'),
border: hslVar('--border'),
input: hslVar('--input'),
'switch-unchecked': hslVar('--switch-unchecked'),
ring: hslVar('--ring'),
// Retained for excluded SidePanel/Agents + SidePanel/Builder (pending migration)
background: hslVar('--background'),
foreground: hslVar('--foreground'),
ring: hslVar('--ring'),
primary: {
DEFAULT: hslVar('--primary'),
foreground: hslVar('--primary-foreground'),
},
secondary: {
DEFAULT: hslVar('--secondary'),
foreground: hslVar('--secondary-foreground'),
},
destructive: {
DEFAULT: hslVar('--destructive'),
foreground: hslVar('--destructive-foreground'),
},
muted: {
DEFAULT: hslVar('--muted'),
foreground: hslVar('--muted-foreground'),
},
accent: {
DEFAULT: hslVar('--accent'),
foreground: hslVar('--accent-foreground'),
},
card: {
DEFAULT: hslVar('--card'),
foreground: hslVar('--card-foreground'),
},
};
}