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

@ -117,7 +117,7 @@ const AgentDetail: React.FC<AgentDetailProps> = ({ agent, isOpen, onClose }) =>
if (name && email) {
return (
<a href={`mailto:${email}`} className="text-primary hover:underline">
<a href={`mailto:${email}`} className="text-text-primary hover:underline">
{name}
</a>
);
@ -125,7 +125,7 @@ const AgentDetail: React.FC<AgentDetailProps> = ({ agent, isOpen, onClose }) =>
if (email) {
return (
<a href={`mailto:${email}`} className="text-primary hover:underline">
<a href={`mailto:${email}`} className="text-text-primary hover:underline">
{email}
</a>
);

View file

@ -116,7 +116,7 @@ const AgentDetailContent: React.FC<AgentDetailContentProps> = ({ agent }) => {
if (name && email) {
return (
<a href={`mailto:${email}`} className="text-primary hover:underline">
<a href={`mailto:${email}`} className="text-text-primary hover:underline">
{name}
</a>
);
@ -124,7 +124,7 @@ const AgentDetailContent: React.FC<AgentDetailContentProps> = ({ agent }) => {
if (email) {
return (
<a href={`mailto:${email}`} className="text-primary hover:underline">
<a href={`mailto:${email}`} className="text-text-primary hover:underline">
{email}
</a>
);

View file

@ -129,7 +129,7 @@ const AgentGrid: React.FC<AgentGridProps> = ({
// Simple loading spinner
const loadingSpinner = (
<div className="flex justify-center py-12">
<Spinner className="h-8 w-8 text-primary" />
<Spinner className="h-8 w-8 text-text-primary" />
</div>
);
@ -207,7 +207,7 @@ const AgentGrid: React.FC<AgentGridProps> = ({
aria-live="polite"
aria-label={localize('com_agents_loading')}
>
<Spinner className="h-6 w-6 text-primary" />
<Spinner className="h-6 w-6 text-text-primary" />
<span className="sr-only">{localize('com_agents_loading')}</span>
</div>
)}

View file

@ -92,7 +92,7 @@ const SearchBar: React.FC<SearchBarProps> = ({ value, onSearch, className = '' }
<button
type="button"
onClick={handleClear}
className="group absolute right-4 top-1/2 flex size-5 -translate-y-1/2 items-center justify-center rounded-full transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
className="group absolute right-4 top-1/2 flex size-5 -translate-y-1/2 items-center justify-center rounded-full transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-text-primary focus:ring-offset-2"
aria-label={localize('com_agents_clear_search')}
title={localize('com_agents_clear_search')}
>

View file

@ -188,7 +188,7 @@ const VirtualizedAgentGrid: React.FC<VirtualizedAgentGridProps> = ({
aria-live="polite"
aria-label={localize('com_agents_loading')}
>
<Spinner className="h-6 w-6 text-primary" />
<Spinner className="h-6 w-6 text-text-primary" />
<span className="sr-only">{localize('com_agents_loading')}</span>
</div>
)}
@ -209,7 +209,7 @@ const VirtualizedAgentGrid: React.FC<VirtualizedAgentGridProps> = ({
// Simple loading spinner
const loadingSpinner = (
<div className="flex justify-center py-12">
<Spinner className="h-8 w-8 text-primary" />
<Spinner className="h-8 w-8 text-text-primary" />
</div>
);

View file

@ -359,7 +359,7 @@ describe('AgentGrid Integration with useGetMarketplaceAgentsQuery', () => {
);
// Should show loading spinner
const spinner = document.querySelector('.text-primary');
const spinner = document.querySelector('.text-text-primary');
expect(spinner).toBeInTheDocument();
});

View file

@ -263,7 +263,7 @@ describe('VirtualizedAgentGrid', () => {
// Should show loading spinner
const spinner = document.querySelector('.spinner');
expect(spinner).toBeInTheDocument();
expect(spinner).toHaveClass('h-8 w-8 text-primary');
expect(spinner).toHaveClass('h-8 w-8 text-text-primary');
});
it('has proper accessibility attributes', () => {

View file

@ -236,7 +236,7 @@ const ChatForm = memo(function ChatForm({
const baseClasses = useMemo(
() =>
cn(
'md:py-3.5 m-0 w-full resize-none py-[13px] placeholder-black/60 bg-transparent dark:placeholder-white/60 [&:has(textarea:focus)]:shadow-[0_2px_6px_rgba(0,0,0,.05)]',
'md:py-3.5 m-0 w-full resize-none py-[13px] placeholder:text-text-tertiary bg-transparent [&:has(textarea:focus)]:shadow-[0_2px_6px_rgba(0,0,0,.05)]',
isCollapsed ? 'max-h-[52px]' : 'max-h-[45vh] md:max-h-[55vh]',
isMoreThanThreeRows ? 'pl-5' : 'px-5',
),

View file

@ -75,7 +75,7 @@ const FileUpload: React.FC<FileUploadProps> = ({
type="button"
onClick={handleClick}
className={cn(
'mr-1 flex h-auto cursor-pointer items-center rounded bg-transparent px-2 py-1 text-xs font-normal text-text-secondary transition-colors hover:bg-surface-hover hover:text-status-success focus:ring-ring',
'mr-1 flex h-auto cursor-pointer items-center rounded bg-transparent px-2 py-1 text-xs font-normal text-text-secondary transition-colors hover:bg-surface-hover hover:text-status-success focus:ring-text-primary',
statusColor,
containerClassName,
)}

View file

@ -115,7 +115,7 @@ const ImagePreview = ({
type="button"
className={cn(
'relative size-14 overflow-hidden rounded-xl transition-shadow',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-primary',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:ring-offset-2 focus-visible:ring-offset-surface-primary',
className,
)}
style={style}

View file

@ -29,7 +29,7 @@ export function MyFilesModal({
<OGDialog open={open} onOpenChange={onOpenChange} triggerRef={triggerRef}>
<OGDialogContent
title={localize('com_nav_my_files')}
className="w-11/12 bg-background text-text-primary shadow-2xl"
className="w-11/12 bg-surface-primary text-text-primary shadow-2xl"
>
<OGDialogHeader>
<OGDialogTitle>{localize('com_nav_my_files')}</OGDialogTitle>

View file

@ -11,7 +11,7 @@ export default function ProgressCircle({
<div className="absolute inset-0 flex items-center justify-center bg-black/5 text-white">
<svg width="120" height="120" viewBox="0 0 120 120" className="h-6 w-6">
<circle
className="origin-[50%_50%] -rotate-90 stroke-gray-400"
className="origin-[50%_50%] -rotate-90 stroke-border-heavy"
strokeWidth="10"
fill="transparent"
r="55"

View file

@ -44,7 +44,7 @@ export function ColumnVisibilityDropdown<TData>({
<Menu.MenuButton
aria-label={localize('com_files_filter_by')}
className={cn(
'inline-flex h-9 items-center justify-center gap-2 rounded-md border border-input bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground 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 h-9 items-center justify-center gap-2 rounded-md border border-border-medium bg-transparent px-3 text-sm font-medium ring-offset-surface-primary transition-colors hover:bg-surface-hover hover:text-text-primary 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',
isSmallScreen && 'px-2 py-1',
)}
>

View file

@ -129,7 +129,7 @@ export default function DataTable<TData, TValue>({ columns, data }: DataTablePro
/>
</div>
</div>
<div className="relative grid h-full max-h-[calc(100vh-20rem)] min-h-[calc(100vh-20rem)] w-full flex-1 overflow-hidden overflow-x-auto overflow-y-auto rounded-md border border-black/10 dark:border-white/10">
<div className="relative grid h-full max-h-[calc(100vh-20rem)] min-h-[calc(100vh-20rem)] w-full flex-1 overflow-hidden overflow-x-auto overflow-y-auto rounded-md border border-border-light">
<Table className="w-full min-w-[300px] border-separate border-spacing-0">
<TableHeader className="sticky top-0 z-50">
{table.getHeaderGroups().map((headerGroup) => (
@ -196,7 +196,7 @@ export default function DataTable<TData, TValue>({ columns, data }: DataTablePro
</div>
<div className="flex items-center justify-end gap-2 py-4">
<div className="ml-2 flex-1 truncate text-xs text-muted-foreground sm:ml-4 sm:text-sm">
<div className="ml-2 flex-1 truncate text-xs text-text-secondary sm:ml-4 sm:text-sm">
<span className="hidden sm:inline">
{localize('com_files_number_selected', {
0: `${table.getFilteredSelectedRowModel().rows.length}`,

View file

@ -105,7 +105,7 @@ export function SortFilterHeader<TData, TValue>({
aria-pressed={column.getIsFiltered() ? 'true' : 'false'}
aria-current={sortState ? 'true' : 'false'}
className={cn(
'inline-flex items-center gap-2 rounded-lg px-2 py-0 text-xs transition-colors hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring data-[open]:bg-surface-hover sm:px-2 sm:py-2 sm:text-sm',
'inline-flex items-center gap-2 rounded-lg px-2 py-0 text-xs transition-colors hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary data-[open]:bg-surface-hover sm:px-2 sm:py-2 sm:text-sm',
column.getIsFiltered() && 'border-b-2 border-b-border-xheavy',
)}
>

View file

@ -87,7 +87,7 @@ export default function MCPConfigDialog({
render={({ field }) => {
const placeholder = localize('com_ui_mcp_enter_var', { 0: details.title });
const className =
'w-full rounded-md border-border-medium shadow-sm focus:border-border-heavy focus:ring-ring-primary dark:bg-surface-tertiary dark:text-text-primary sm:text-sm';
'w-full rounded-md border-border-medium shadow-sm focus:border-border-heavy focus:ring-ring-primary sm:text-sm';
if (details.sensitive === false) {
return (
<Input

View file

@ -73,7 +73,7 @@ function TokenUsageIndicator({
aria-haspopup="dialog"
className={cn(
'flex size-9 items-center justify-center rounded-full p-1 transition-colors',
'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary',
'duration-300 animate-in fade-in zoom-in-95',
)}
>

View file

@ -16,7 +16,7 @@ import ConvoIcon from '~/components/Endpoints/ConvoIcon';
import { useLocalize, useAuthContext } from '~/hooks';
const containerClassName =
'shadow-stroke relative flex h-full items-center justify-center rounded-full bg-surface-primary dark:bg-presentation text-text-primary dark:after:shadow-none ';
'shadow-stroke relative flex h-full items-center justify-center rounded-full bg-presentation text-text-primary dark:after:shadow-none ';
function getTextSizeClass(text: string | undefined | null) {
if (!text) {

View file

@ -126,10 +126,7 @@ export const CustomMenuSeparator = React.forwardRef<HTMLHRElement, Ariakit.MenuS
<Ariakit.MenuSeparator
ref={ref}
{...props}
className={cn(
'my-0.5 h-0 w-full border-t border-border-light',
props.className,
)}
className={cn('my-0.5 h-0 w-full border-t border-border-light', props.className)}
/>
);
},
@ -170,7 +167,7 @@ export const CustomMenuItem = React.forwardRef<HTMLDivElement, CustomMenuItemPro
blurOnHoverEnd: false,
...props,
className: cn(
'relative flex cursor-default items-center gap-2 rounded-lg px-2 py-1 outline-none! scroll-m-1 scroll-mt-[calc(var(--combobox-height,0px)+var(--label-height,4px))] aria-disabled:opacity-25 data-[active-item]:bg-black/[0.075] data-[active-item]:text-text-primary dark:data-[active-item]:bg-white/10 sm:text-sm min-w-0 w-full before:absolute before:left-0 before:top-1 before:bottom-1 before:w-0.5 before:bg-transparent before:rounded-full data-[active-item]:before:bg-text-primary',
'relative flex cursor-default items-center gap-2 rounded-lg px-2 py-1 outline-none! scroll-m-1 scroll-mt-[calc(var(--combobox-height,0px)+var(--label-height,4px))] aria-disabled:opacity-25 data-[active-item]:bg-surface-active data-[active-item]:text-text-primary sm:text-sm min-w-0 w-full before:absolute before:left-0 before:top-1 before:bottom-1 before:w-0.5 before:bg-transparent before:rounded-full data-[active-item]:before:bg-text-primary',
props.className,
),
};

View file

@ -132,7 +132,7 @@ const EditPresetDialog = ({
return (
<OGDialog open={presetModalVisible} onOpenChange={handleOpenChange} triggerRef={triggerRef}>
<OGDialogContent className="h-[100dvh] max-h-[100dvh] w-full max-w-full overflow-y-auto bg-surface-dialog dark:border-border-light dark:text-text-secondary md:h-auto md:max-h-[90vh] md:max-w-[75vw] md:rounded-lg lg:max-w-[950px]">
<OGDialogContent className="h-[100dvh] max-h-[100dvh] w-full max-w-full overflow-y-auto bg-surface-dialog md:h-auto md:max-h-[90vh] md:max-w-[75vw] md:rounded-lg lg:max-w-[950px]">
<OGDialogTitle>
{localize('com_ui_edit_preset_title', { title: preset?.title })}
</OGDialogTitle>

View file

@ -63,7 +63,7 @@ const PresetItems: FC<{
<DialogTrigger asChild>
<button
type="button"
className="mr-1 flex h-[32px] cursor-pointer items-center rounded bg-transparent px-2 py-1 text-xs font-medium text-text-secondary transition-colors hover:bg-surface-hover hover:text-text-destructive focus:ring-ring"
className="mr-1 flex h-[32px] cursor-pointer items-center rounded bg-transparent px-2 py-1 text-xs font-medium text-text-secondary transition-colors hover:bg-surface-hover hover:text-text-destructive focus:ring-text-primary"
aria-label={localize('com_ui_clear_all')}
>
<svg
@ -152,7 +152,7 @@ const PresetItems: FC<{
<Icon
context="menu-item"
iconURL={getEndpointField(endpointsConfig, preset.endpoint, 'iconURL')}
className="icon-md mr-1 dark:text-text-primary"
className="icon-md mr-1"
endpoint={preset.endpoint}
/>
)

View file

@ -114,7 +114,7 @@ const Image = ({
onClick={() => setIsOpen(true)}
className={cn(
'relative mt-1 w-full max-w-lg cursor-pointer overflow-hidden rounded-lg border border-border-light text-text-secondary-alt shadow-md transition-shadow',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-primary',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:ring-offset-2 focus-visible:ring-offset-surface-primary',
className,
)}
style={heightStyle}

View file

@ -28,7 +28,7 @@ const parseThinkingContent = (text: string) => {
const LoadingFallback = () => (
<div className="text-message mb-[0.625rem] flex min-h-[20px] flex-col items-start gap-3 overflow-visible">
<div className="markdown prose dark:prose-invert light w-full break-words dark:text-text-primary">
<div className="markdown prose dark:prose-invert light w-full break-words">
<div className="absolute">
<p className="submitting relative">
<span className="result-thinking" />

View file

@ -4,7 +4,7 @@ import { memo } from 'react';
const EmptyTextPart = memo(() => {
return (
<div className="text-message flex min-h-[20px] flex-col items-start gap-3 overflow-visible">
<div className="markdown prose dark:prose-invert light w-full break-words dark:text-text-primary">
<div className="markdown prose dark:prose-invert light w-full break-words">
<div className="absolute">
<p className="submitting relative">
<span className="result-thinking" />

View file

@ -466,7 +466,7 @@ export default function SubagentCall({
<div
className={cn(
'flex h-5 w-5 shrink-0 items-center justify-center overflow-hidden rounded-full',
running && !subagentAgent && 'animate-pulse text-primary',
running && !subagentAgent && 'animate-pulse text-text-primary',
)}
aria-hidden="true"
>
@ -641,7 +641,7 @@ function SubagentPrompt({
aria-expanded={expanded}
aria-label={toggleLabel}
title={toggleLabel}
className="inline-flex h-8 items-center gap-1.5 rounded-md px-2 text-xs font-medium text-text-secondary transition hover:bg-surface-tertiary hover:text-text-primary focus:outline-none focus:ring-2 focus:ring-ring"
className="inline-flex h-8 items-center gap-1.5 rounded-md px-2 text-xs font-medium text-text-secondary transition hover:bg-surface-tertiary hover:text-text-primary focus:outline-none focus:ring-2 focus:ring-text-primary"
>
{expanded ? (
<Minimize2 size={14} aria-hidden="true" />

View file

@ -113,7 +113,7 @@ const SummaryButton = memo(
? 'opacity-0 group-focus-within/summary-container:opacity-100 group-hover/summary-container:opacity-100'
: 'opacity-0',
'hover:bg-surface-hover hover:text-text-primary',
'focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white',
'focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary',
)}
>
<span className="sr-only">

View file

@ -104,7 +104,7 @@ export const ThinkingButton = memo(
? 'opacity-0 group-focus-within/thinking-container:opacity-100 group-hover/thinking-container:opacity-100'
: 'opacity-0',
'hover:bg-surface-hover hover:text-text-primary',
'focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white',
'focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary',
)}
>
<span className="sr-only">

View file

@ -70,7 +70,7 @@ const SearchContent = ({
className={cn(
'markdown prose dark:prose-invert light w-full break-words',
message.isCreatedByUser && !enableUserMsgMarkdown && 'whitespace-pre-wrap',
message.isCreatedByUser ? 'dark:text-gray-20' : 'dark:text-gray-70',
message.isCreatedByUser ? 'dark:text-gray-20' : 'dark:text-gray-100',
)}
dir="auto"
>

View file

@ -254,7 +254,7 @@ export default function ToolCallGroup({
<div
className={cn(
'flex h-5 w-5 shrink-0 items-center justify-center text-text-secondary',
!allCompleted && isSubmitting && 'animate-pulse text-primary',
!allCompleted && isSubmitting && 'animate-pulse text-text-primary',
)}
aria-hidden="true"
>

View file

@ -73,7 +73,7 @@ const UIResourceCarousel: React.FC<UIResourceCarouselProps> = React.memo(({ uiRe
<button
type="button"
onClick={() => scroll('left')}
className={`absolute left-2 top-1/2 z-20 -translate-y-1/2 rounded-xl bg-white p-2 text-gray-800 shadow-lg transition-all duration-200 hover:scale-110 hover:bg-gray-100 hover:shadow-xl active:scale-95 dark:bg-gray-200 dark:text-gray-800 dark:hover:bg-gray-300 ${
className={`absolute left-2 top-1/2 z-20 -translate-y-1/2 rounded-xl bg-surface-fixed p-2 text-text-fixed shadow-lg transition-all duration-200 hover:scale-110 hover:bg-surface-fixed-hover hover:shadow-xl active:scale-95 ${
isContainerHovered ? 'opacity-100' : 'pointer-events-none opacity-0'
}`}
aria-label="Scroll left"
@ -125,7 +125,7 @@ const UIResourceCarousel: React.FC<UIResourceCarouselProps> = React.memo(({ uiRe
<button
type="button"
onClick={() => scroll('right')}
className={`absolute right-2 top-1/2 z-20 -translate-y-1/2 rounded-xl bg-white p-2 text-gray-800 shadow-lg transition-all duration-200 hover:scale-110 hover:bg-gray-100 hover:shadow-xl active:scale-95 dark:bg-gray-200 dark:text-gray-800 dark:hover:bg-gray-300 ${
className={`absolute right-2 top-1/2 z-20 -translate-y-1/2 rounded-xl bg-surface-fixed p-2 text-text-fixed shadow-lg transition-all duration-200 hover:scale-110 hover:bg-surface-fixed-hover hover:shadow-xl active:scale-95 ${
isContainerHovered ? 'opacity-100' : 'pointer-events-none opacity-0'
}`}
aria-label="Scroll right"

View file

@ -221,7 +221,7 @@ function buttonClasses(isActive: boolean, isLast: boolean) {
'group-hover:visible group-focus-within:visible group-[.final-completion]:visible',
!isLast &&
'group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:hover)]:opacity-0',
'focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:outline-none',
'focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:outline-none',
isActive && 'active text-text-primary bg-surface-hover',
);
}

View file

@ -98,7 +98,7 @@ const PopoverButton: React.FC<PopoverButtonProps> = ({
</Ariakit.Button>
}
/>
<Ariakit.HovercardDisclosure className="rounded-full text-text-secondary focus:outline-none focus:ring-2 focus:ring-ring">
<Ariakit.HovercardDisclosure className="rounded-full text-text-secondary focus:outline-none focus:ring-2 focus:ring-text-primary">
<VisuallyHidden>
{localize('com_ui_fork_more_details_about', { 0: label })}
</VisuallyHidden>
@ -166,7 +166,7 @@ const CheckboxOption: React.FC<CheckboxOptionProps> = ({
}
onToggle(value);
}}
className="h-4 w-4 rounded-sm border border-primary ring-offset-background transition duration-300 ease-in-out 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"
className="h-4 w-4 rounded-sm border border-border-xheavy ring-offset-surface-primary transition duration-300 ease-in-out 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"
aria-label={localize(labelKey)}
/>
<label
@ -178,7 +178,7 @@ const CheckboxOption: React.FC<CheckboxOptionProps> = ({
</div>
}
/>
<Ariakit.HovercardDisclosure className="ml-1 rounded-full text-text-secondary focus:outline-none focus:ring-2 focus:ring-ring">
<Ariakit.HovercardDisclosure className="ml-1 rounded-full text-text-secondary focus:outline-none focus:ring-2 focus:ring-text-primary">
<VisuallyHidden>{localize(infoKey)}</VisuallyHidden>
{chevronDown}
</Ariakit.HovercardDisclosure>
@ -232,7 +232,7 @@ export default function Fork({
'group-hover:visible group-focus-within:visible group-[.final-completion]:visible',
!isLast &&
'group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:hover)]:opacity-0',
'focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:outline-none',
'focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:outline-none',
isActive && 'active text-text-primary bg-surface-hover',
);
@ -381,7 +381,7 @@ export default function Fork({
</button>
}
/>
<Ariakit.HovercardDisclosure className="rounded-full text-text-secondary focus:outline-none focus:ring-2 focus:ring-ring">
<Ariakit.HovercardDisclosure className="rounded-full text-text-secondary focus:outline-none focus:ring-2 focus:ring-text-primary">
<VisuallyHidden>{localize('com_ui_fork_more_info_options')}</VisuallyHidden>
{chevronDown}
</Ariakit.HovercardDisclosure>

View file

@ -90,7 +90,7 @@ const HoverButton = memo(
!isLast &&
'group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:hover)]:opacity-0',
!isVisible && 'opacity-0',
'focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:outline-none',
'focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:outline-none',
isActive && isVisible && 'active text-text-primary bg-surface-hover',
className,
);

View file

@ -13,7 +13,7 @@ const MessageContainer = React.memo(function MessageContainer({
}) {
return (
<div
className="text-token-text-primary w-full border-0 bg-transparent dark:border-0 dark:bg-transparent"
className="text-token-text-primary w-full border-0 bg-transparent"
onWheel={handleScroll}
onTouchMove={handleScroll}
>

View file

@ -836,8 +836,8 @@ function MessageNav({ scrollableRef }: { scrollableRef: React.RefObject<HTMLDivE
'group/nav absolute right-2 top-1/2 z-40 hidden max-h-[min(24rem,calc(100%-2rem))]',
'-translate-y-1/2 flex-col items-center gap-1.5 rounded-full px-1 py-2 md:flex',
'opacity-30 transition-opacity duration-300',
'hover:bg-black/5 hover:opacity-100 dark:hover:bg-white/5',
'focus-within:bg-black/5 focus-within:opacity-100 dark:focus-within:bg-white/5',
'hover:bg-surface-hover hover:opacity-100',
'focus-within:bg-surface-hover focus-within:opacity-100',
)}
>
<button

View file

@ -100,7 +100,7 @@ export default function Message(props: TMessageProps) {
return (
<>
<div
className="w-full border-0 bg-transparent dark:border-0 dark:bg-transparent"
className="w-full border-0 bg-transparent"
onWheel={handleScroll}
onTouchMove={handleScroll}
>

View file

@ -50,7 +50,7 @@ function MessagesViewContent({
width: '100%',
}}
>
<div ref={contentRef} className="flex flex-col pb-9 pt-14 dark:bg-transparent">
<div ref={contentRef} className="flex flex-col pb-9 pt-14">
{(_messagesTree && _messagesTree.length == 0) || _messagesTree === null ? (
<div
className={cn(

View file

@ -20,7 +20,7 @@ export default function MinimalHoverButtons({ message, searchResults }: THoverBu
return (
<div className="visible mt-1 flex justify-center gap-1 self-end text-text-tertiary lg:justify-start">
<button
className="ml-0 flex items-center gap-1.5 rounded-lg p-1.5 text-xs text-text-secondary-alt transition-colors duration-200 hover:bg-surface-hover hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black group-focus-within:opacity-100 group-hover:opacity-100 dark:focus-visible:ring-white [@media(hover:hover)]:opacity-0"
className="ml-0 flex items-center gap-1.5 rounded-lg p-1.5 text-xs text-text-secondary-alt transition-colors duration-200 hover:bg-surface-hover hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary group-focus-within:opacity-100 group-hover:opacity-100 [@media(hover:hover)]:opacity-0"
onClick={() => copyToClipboard(setIsCopied)}
type="button"
title={

View file

@ -25,7 +25,7 @@ const MinimalMessages = React.forwardRef(
width: '100%',
}}
>
<div className="flex flex-col pb-9 text-sm dark:bg-transparent">
<div className="flex flex-col pb-9 text-sm">
{props.children}
<div className="dark:gpt-dark-gray group h-0 w-full flex-shrink-0 dark:border-gray-800/50" />
</div>

View file

@ -27,7 +27,7 @@ export default function SiblingSwitch({
'hover-button rounded-lg p-1.5 text-text-secondary-alt',
'hover:text-text-primary hover:bg-surface-hover',
'group-hover:visible group-focus-within:visible group-[.final-completion]:visible',
'focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:outline-none',
'focus-visible:ring-2 focus-visible:ring-text-primary focus-visible:outline-none',
);
return siblingCount > 1 ? (

View file

@ -58,7 +58,7 @@ const RenameForm: React.FC<RenameFormProps> = ({
<div className="flex gap-1" role="toolbar">
<button
onClick={() => onCancel()}
className="rounded-md p-1 hover:opacity-70 focus:outline-none focus:ring-2 focus:ring-ring"
className="rounded-md p-1 hover:opacity-70 focus:outline-none focus:ring-2 focus:ring-text-primary"
aria-label={localize('com_ui_cancel')}
type="button"
>
@ -66,7 +66,7 @@ const RenameForm: React.FC<RenameFormProps> = ({
</button>
<button
onClick={() => onSubmit(titleInput)}
className="rounded-md p-1 hover:opacity-70 focus:outline-none focus:ring-2 focus:ring-ring"
className="rounded-md p-1 hover:opacity-70 focus:outline-none focus:ring-2 focus:ring-text-primary"
aria-label={localize('com_ui_save')}
type="button"
>

View file

@ -78,14 +78,14 @@ function Examples({ readonly, examples, setExample, addExample, removeExample }:
<div className="flex justify-center">
<Button
type="button"
className="mr-2 mt-1 h-auto items-center justify-center bg-transparent px-3 py-2 text-xs font-medium font-normal text-text-primary hover:bg-surface-hover hover:text-text-primary focus:ring-0 focus:ring-offset-0 dark:bg-transparent dark:focus:outline-none dark:focus:ring-offset-0"
className="mr-2 mt-1 h-auto items-center justify-center bg-transparent px-3 py-2 text-xs font-medium font-normal text-text-primary hover:bg-surface-hover hover:text-text-primary focus:ring-0 focus:ring-offset-0 dark:focus:outline-none dark:focus:ring-offset-0"
onClick={removeExample}
>
<Minus className="w-[16px]" aria-hidden="true" />
</Button>
<Button
type="button"
className="mt-1 h-auto items-center justify-center bg-transparent px-3 py-2 text-xs font-medium font-normal text-text-primary hover:bg-surface-hover hover:text-text-primary focus:ring-0 focus:ring-offset-0 dark:bg-transparent dark:focus:outline-none dark:focus:ring-offset-0"
className="mt-1 h-auto items-center justify-center bg-transparent px-3 py-2 text-xs font-medium font-normal text-text-primary hover:bg-surface-hover hover:text-text-primary focus:ring-0 focus:ring-offset-0 dark:focus:outline-none dark:focus:ring-offset-0"
onClick={addExample}
>
<Plus className="w-[16px]" aria-hidden="true" />

View file

@ -11,7 +11,7 @@ export default function ActionButton({ onClick }: ActionButtonProps) {
return (
<div className="w-32">
<Button
className="w-full rounded-md border border-text-primary bg-surface-primary p-0 text-text-primary hover:bg-primary hover:text-primary-foreground"
className="w-full rounded-md border border-text-primary bg-surface-primary p-0 text-text-primary hover:bg-surface-inverted hover:text-text-inverted"
onClick={onClick}
>
{/* Action Button */}

View file

@ -111,7 +111,7 @@ export default function DataTableFile<TData, TValue>({
deleteFiles({ files: filesToDelete as TFile[], setFiles });
setRowSelection({});
}}
className="ml-1 gap-2 dark:hover:bg-gray-850/25 sm:ml-0"
className="ml-1 gap-2 hover:bg-surface-hover sm:ml-0"
disabled={!table.getFilteredSelectedRowModel().rows.length || isDeleting}
>
{isDeleting ? (
@ -161,7 +161,7 @@ export default function DataTableFile<TData, TValue>({
</div>
</div>
</div>
<div className="relative mt-3 max-h-[25rem] min-h-0 overflow-y-auto rounded-md border border-black/10 pb-4 dark:border-white/10 sm:min-h-[28rem]">
<div className="relative mt-3 max-h-[25rem] min-h-0 overflow-y-auto rounded-md border border-border-light pb-4 sm:min-h-[28rem]">
<Table className="w-full min-w-[600px] border-separate border-spacing-0">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
@ -192,7 +192,7 @@ export default function DataTableFile<TData, TValue>({
return (
<TableHead
key={header.id}
className="align-start sticky top-0 rounded-t border-b border-black/10 bg-surface-secondary px-2 py-1 text-left font-medium text-text-secondary dark:border-white/10 sm:px-4 sm:py-2"
className="align-start sticky top-0 rounded-t border-b border-border-light bg-surface-secondary px-2 py-1 text-left font-medium text-text-secondary sm:px-4 sm:py-2"
style={style}
>
{header.isPlaceholder
@ -210,7 +210,7 @@ export default function DataTableFile<TData, TValue>({
<TableRow
key={row.id}
data-state={row.getIsSelected() && 'selected'}
className="border-b border-black/10 text-left text-text-secondary dark:border-white/10 [tr:last-child_&]:border-b-0"
className="border-b border-border-light text-left text-text-secondary [tr:last-child_&]:border-b-0"
>
{row.getVisibleCells().map((cell, index) => {
const maxWidth =
@ -247,7 +247,7 @@ export default function DataTableFile<TData, TValue>({
</Table>
</div>
<div className="ml-4 mr-4 mt-4 flex h-auto items-center justify-end space-x-2 py-4 sm:ml-0 sm:mr-0 sm:h-0">
<div className="ml-2 flex-1 text-sm text-muted-foreground">
<div className="ml-2 flex-1 text-sm text-text-secondary">
{localize('com_files_number_selected', {
0: `${table.getFilteredSelectedRowModel().rows.length}`,
1: `${table.getFilteredRowModel().rows.length}`,

View file

@ -9,7 +9,7 @@ type UploadFileProps = {
export default function UploadFileButton({ onClick }: UploadFileProps) {
return (
<div className="w-full">
<Button className="w-full bg-primary px-3 text-primary-foreground" onClick={onClick}>
<Button className="w-full bg-surface-inverted px-3 text-text-inverted" onClick={onClick}>
<PlusIcon className="h-4 w-4 font-bold" />
&nbsp; <span className="text-nowrap">Upload New File</span>
</Button>

View file

@ -63,7 +63,7 @@ const UploadFileModal = ({ open, onOpenChange }) => {
</div>
<div className="flex w-full flex-row justify-evenly sm:w-1/3">
<Button
className="mr-3 w-full rounded-md border border-black bg-white p-0 text-black hover:bg-white"
className="mr-3 w-full rounded-md border border-border-medium bg-surface-secondary p-0 text-text-primary hover:bg-surface-hover"
onClick={() => {
onOpenChange(false);
}}
@ -71,7 +71,7 @@ const UploadFileModal = ({ open, onOpenChange }) => {
Cancel
</Button>
<Button
className="w-full rounded-md border border-black bg-black p-0 text-white"
className="w-full rounded-md border border-border-xheavy bg-surface-inverted p-0 text-text-inverted"
onClick={() => {
console.log('upload file');
}}

View file

@ -9,7 +9,7 @@ type VectorStoreButtonProps = {
export default function VectorStoreButton({ onClick }: VectorStoreButtonProps) {
return (
<div className="w-full">
<Button className="w-full bg-primary p-0 text-primary-foreground" onClick={onClick}>
<Button className="w-full bg-surface-inverted p-0 text-text-inverted" onClick={onClick}>
<PlusIcon className="h-4 w-4 font-bold" />
&nbsp; <span className="text-nowrap">Add Store</span>
</Button>

View file

@ -8,7 +8,7 @@ export default function Regenerate({ onClick }: TGenButtonProps) {
return (
<Button onClick={onClick} shortcutId="regenerateResponse">
<RegenerateIcon className="h-3 w-3 flex-shrink-0 text-gray-600/90 dark:text-gray-400" />
<RegenerateIcon className="h-3 w-3 flex-shrink-0 text-text-secondary" />
{localize('com_ui_regenerate')}
</Button>
);

View file

@ -8,7 +8,7 @@ export default function Stop({ onClick }: TGenButtonProps) {
return (
<Button type="stop" onClick={onClick} shortcutId="stopGenerating">
<StopGeneratingIcon className="text-gray-600/90 dark:text-gray-400" />
<StopGeneratingIcon className="text-text-secondary" />
{localize('com_ui_stop')}
</Button>
);

View file

@ -81,7 +81,7 @@ function MultiSelectDropDown({
<>
<ListboxButton
className={cn(
'relative flex w-full cursor-default flex-col rounded-md border border-black/10 bg-surface-secondary py-2 pl-3 pr-10 text-left focus:outline-none focus:ring-0 focus:ring-offset-0 dark:border-gray-600 dark:border-white/20 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:outline-none focus:ring-0 focus:ring-offset-0 sm:text-sm',
className ?? '',
)}
id={excludeIds[0]}
@ -120,12 +120,12 @@ function MultiSelectDropDown({
<img
src={v.icon}
alt={`${v} logo`}
className="h-full w-full rounded-sm bg-white"
className="h-full w-full rounded-sm bg-surface-fixed"
/>
) : (
<Wrench className="h-full w-full rounded-sm bg-white" />
<Wrench className="h-full w-full rounded-sm bg-surface-fixed" />
)}
<div className="absolute inset-0 rounded-sm ring-1 ring-inset ring-black/10" />
<div className="absolute inset-0 rounded-sm ring-1 ring-inset ring-border-light" />
</div>
))}
</div>
@ -161,7 +161,7 @@ function MultiSelectDropDown({
<ListboxOptions
ref={menuRef}
className={cn(
'absolute z-50 mt-2 max-h-60 w-full overflow-auto rounded bg-surface-secondary text-base text-xs ring-1 ring-black/10 focus:outline-none dark:ring-white/20 dark:last:border-0 md:w-[100%]',
'absolute z-50 mt-2 max-h-60 w-full overflow-auto rounded bg-surface-secondary text-base text-xs ring-1 ring-border-light focus:outline-none dark:last:border-0 md:w-[100%]',
optionsClassName,
)}
>
@ -175,7 +175,7 @@ function MultiSelectDropDown({
<ListboxOption
key={i}
value={option[optionValueKey]}
className="group relative flex h-[42px] cursor-pointer select-none items-center overflow-hidden border-b border-black/10 pl-3 pr-9 text-text-primary last:border-0 hover:bg-surface-hover dark:border-white/20"
className="group relative flex h-[42px] cursor-pointer select-none items-center overflow-hidden border-b border-border-light pl-3 pr-9 text-text-primary last:border-0 hover:bg-surface-hover"
>
<span className="flex items-center gap-1.5 truncate">
{!option.isButton && (
@ -185,12 +185,12 @@ function MultiSelectDropDown({
<img
src={option.icon}
alt={`${option.name} logo`}
className="h-full w-full rounded-sm bg-white"
className="h-full w-full rounded-sm bg-surface-fixed"
/>
) : (
<Wrench className="h-full w-full rounded-sm bg-white" />
<Wrench className="h-full w-full rounded-sm bg-surface-fixed" />
)}
<div className="absolute inset-0 rounded-sm ring-1 ring-inset ring-black/10"></div>
<div className="absolute inset-0 rounded-sm ring-1 ring-inset ring-border-light"></div>
</div>
</span>
)}

View file

@ -52,15 +52,13 @@ function MultiSelectPop({
<button
data-testid="select-dropdown-button"
className={cn(
'relative flex flex-col rounded-md border border-black/10 bg-surface-secondary py-2 pl-3 pr-10 text-left focus:outline-none focus:ring-0 focus:ring-offset-0 dark:border-gray-700 sm:text-sm',
'relative flex flex-col rounded-md border border-border-light bg-surface-secondary py-2 pl-3 pr-10 text-left focus:outline-none focus:ring-0 focus:ring-offset-0 sm:text-sm',
'pointer-cursor font-normal',
'hover:bg-surface-hover radix-state-open:bg-surface-hover',
)}
>
{' '}
{showLabel && (
<label className="block text-xs text-text-secondary">{title}</label>
)}
{showLabel && <label className="block text-xs text-text-secondary">{title}</label>}
<span className="inline-flex" id={excludeIds[2]}>
<span
className={cn(
@ -69,7 +67,7 @@ function MultiSelectPop({
)}
>
{/* {!showLabel && title.length > 0 && (
<span className="text-xs text-gray-700 dark:text-gray-500">{title}:</span>
<span className="text-xs text-text-secondary">{title}:</span>
)} */}
<span className="flex items-center gap-1">
<div className="flex gap-1">
@ -79,9 +77,9 @@ function MultiSelectPop({
{v.icon ? (
<img src={v.icon} alt={`${v} logo`} className="icon-lg rounded-sm" />
) : (
<Wrench className="icon-lg rounded-sm bg-white" />
<Wrench className="icon-lg rounded-sm bg-surface-fixed" />
)}
<div className="absolute inset-0 rounded-sm ring-1 ring-inset ring-black/10" />
<div className="absolute inset-0 rounded-sm ring-1 ring-inset ring-border-light" />
</div>
))}
</div>
@ -137,7 +135,7 @@ function MultiSelectPop({
className="icon-sm mr-1 rounded-sm bg-cover"
/>
) : (
<Wrench className="icon-sm mr-1 rounded-sm bg-white bg-cover dark:bg-gray-800" />
<Wrench className="icon-sm mr-1 rounded-sm bg-surface-secondary bg-cover" />
)
}
/>

View file

@ -68,7 +68,7 @@ function SelectDropDownPop({
<button
data-testid="select-dropdown-button"
className={cn(
'pointer-cursor relative flex flex-col rounded-lg border border-black/10 bg-surface-secondary py-2 pl-3 pr-10 text-left focus:ring-0 focus:ring-offset-0 dark:border-gray-700 sm:text-sm',
'pointer-cursor relative flex flex-col rounded-lg border border-border-light bg-surface-secondary py-2 pl-3 pr-10 text-left focus:ring-0 focus:ring-offset-0 sm:text-sm',
'hover:bg-surface-hover radix-state-open:bg-surface-hover',
'min-w-[200px] max-w-[215px] sm:min-w-full sm:max-w-full',
)}
@ -76,9 +76,7 @@ function SelectDropDownPop({
aria-haspopup="false"
>
{' '}
{showLabel && (
<label className="block text-xs text-text-secondary">{title}</label>
)}
{showLabel && <label className="block text-xs text-text-secondary">{title}</label>}
<span className="inline-flex w-full">
<span
className={cn(

View file

@ -36,7 +36,7 @@ const GoogleConfig = ({ userKey, setUserKey }: Pick<TConfigProps, 'userKey' | 's
<FileUpload
id={AuthKeys.GOOGLE_SERVICE_KEY}
className="w-full"
containerClassName="dark:bg-gray-700 h-10 max-h-10 w-full resize-none py-2 dark:ring-1 dark:ring-gray-600"
containerClassName="bg-surface-secondary h-10 max-h-10 w-full resize-none py-2"
text={localize('com_endpoint_config_key_import_json_key')}
successText={localize('com_endpoint_config_key_import_json_key_success')}
invalidText={localize('com_endpoint_config_key_import_json_key_invalid')}

View file

@ -136,7 +136,7 @@ const RevokeKeysButton = ({
variant="destructive"
onClick={onClick}
disabled={isLoading}
className="bg-destructive text-white transition-all duration-200 hover:bg-destructive/80"
className="bg-surface-destructive text-white transition-all duration-200 hover:bg-surface-destructive-hover"
>
{isLoading ? <Spinner /> : localize('com_ui_revoke')}
</Button>

View file

@ -101,7 +101,7 @@ export default function MCPServerMenuItem({
className={cn(
'flex h-4 w-4 flex-shrink-0 items-center justify-center rounded-sm border',
isSelected
? 'border-primary bg-primary text-primary-foreground'
? 'border-border-xheavy bg-surface-inverted text-text-inverted'
: 'border-border-xheavy bg-transparent',
)}
>

View file

@ -118,7 +118,9 @@ function CompactStatusDot({ serverStatus, isInitializing }: CompactStatusDotProp
}
if (!serverStatus) {
return <div className="size-3 rounded-full border-2 border-surface-secondary bg-status-neutral" />;
return (
<div className="size-3 rounded-full border-2 border-surface-secondary bg-status-neutral" />
);
}
const { connectionState, requiresOAuth } = serverStatus;
@ -145,7 +147,7 @@ function LoadingStatusIcon({ serverName, onCancel, canCancel }: InitializingStat
<button
type="button"
onClick={onCancel}
className="group flex size-6 items-center justify-center rounded p-1 hover:bg-red-100 dark:hover:bg-red-900/20"
className="group flex size-6 items-center justify-center rounded p-1 hover:bg-status-error-subtle"
aria-label={localize('com_ui_cancel')}
title={localize('com_ui_cancel')}
>

View file

@ -14,7 +14,7 @@ const MessageContainer = React.memo(function MessageContainer({
}) {
return (
<div
className="text-token-text-primary w-full border-0 bg-transparent dark:border-0 dark:bg-transparent"
className="text-token-text-primary w-full border-0 bg-transparent"
onWheel={handleScroll}
onTouchMove={handleScroll}
>

View file

@ -108,7 +108,7 @@ const BookmarkNav: FC<BookmarkNavProps> = ({ tags, setTags }: BookmarkNavProps)
aria-pressed={tags.length > 0}
className={cn(
'flex items-center justify-center',
'size-9 border-none text-text-primary hover:bg-accent hover:text-accent-foreground',
'size-9 border-none text-text-primary hover:bg-surface-hover hover:text-text-primary',
'rounded-lg border-none p-2 hover:bg-surface-active-alt',
'outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring-primary',
isMenuOpen ? 'bg-surface-hover' : '',

View file

@ -82,7 +82,7 @@ export default function NavToggle({
<div className="flex h-6 w-6 flex-col items-center">
{/* Top bar */}
<div
className="h-3 w-1 rounded-full bg-black dark:bg-white"
className="h-3 w-1 rounded-full bg-surface-inverted"
style={{
...transition,
transform: `translateY(0.15rem) rotate(${topBarRotation}) translateZ(0px)`,
@ -90,7 +90,7 @@ export default function NavToggle({
/>
{/* Bottom bar */}
<div
className="h-3 w-1 rounded-full bg-black dark:bg-white"
className="h-3 w-1 rounded-full bg-surface-inverted"
style={{
...transition,
transform: `translateY(-0.15rem) rotate(${bottomBarRotation}) translateZ(0px)`,

View file

@ -63,7 +63,7 @@ export default function SettingsDialog({ open, onOpenChange }: TDialogProps) {
<div className="fixed inset-0 flex w-screen items-center justify-center p-4">
<DialogPanel
className={cn(
'flex max-h-[85vh] w-full flex-col overflow-hidden rounded-2xl bg-background shadow-2xl',
'flex max-h-[85vh] w-full flex-col overflow-hidden rounded-2xl bg-surface-primary shadow-2xl',
'md:h-[85vh] md:w-[900px]',
)}
>

View file

@ -110,7 +110,7 @@ const BackupCodesItem: React.FC = () => {
>
{Array.isArray(user?.backupCodes) && user?.backupCodes.length > 0 ? (
<>
<div className="border-warning-300 bg-warning-50 dark:border-warning-700 dark:bg-warning-900/20 mb-6 rounded-lg border p-4">
<div className="mb-6 rounded-lg border border-status-warning-border bg-status-warning-subtle p-4">
<p className="text-sm text-text-secondary">
{localize('com_ui_backup_codes_security_info')}
</p>
@ -146,8 +146,8 @@ const BackupCodesItem: React.FC = () => {
}}
className={`flex flex-col rounded-xl border p-4 backdrop-blur-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${
isUsed
? 'border-red-200 bg-red-50/80 dark:border-red-800 dark:bg-red-900/20'
: 'border-green-200 bg-green-50/80 dark:border-green-800 dark:bg-green-900/20'
? 'border-status-error-border bg-status-error-subtle'
: 'border-status-success-border bg-status-success-subtle'
} `}
>
<div className="flex items-center justify-between" aria-hidden="true">
@ -256,7 +256,7 @@ const BackupCodesItem: React.FC = () => {
setUseBackup(!useBackup);
setOtpToken('');
}}
className="text-sm text-primary hover:underline"
className="text-sm text-text-primary hover:underline"
>
{useBackup ? localize('com_ui_use_2fa_code') : localize('com_ui_use_backup_code')}
</button>

View file

@ -145,7 +145,7 @@ const DeleteAccount = ({ disabled = false }: { title?: string; disabled?: boolea
setUseBackup(!useBackup);
setOtpToken('');
}}
className="text-sm text-primary hover:underline"
className="text-sm text-text-primary hover:underline"
>
{useBackup ? localize('com_ui_use_2fa_code') : localize('com_ui_use_backup_code')}
</button>
@ -182,7 +182,7 @@ const renderDeleteButton = (
<button
className={cn(
'mt-4 flex w-full items-center justify-center rounded-lg bg-surface-tertiary px-4 py-2 transition-all duration-200',
isLocked ? 'cursor-not-allowed opacity-30' : 'bg-surface-destructive text-destructive-foreground',
isLocked ? 'cursor-not-allowed opacity-30' : 'bg-surface-destructive text-white',
)}
onClick={handleDeleteUser}
disabled={isDeleting || isLocked}

View file

@ -221,7 +221,7 @@ const TwoFactorAuthentication: React.FC = () => {
>
<OGDialogHeader>
<OGDialogTitle className="mb-2 flex items-center gap-3 text-2xl font-bold">
<SmartphoneIcon className="h-6 w-6 text-primary" aria-hidden="true" />
<SmartphoneIcon className="h-6 w-6 text-text-primary" aria-hidden="true" />
{user?.twoFactorEnabled
? localize('com_ui_2fa_disable')
: localize('com_ui_2fa_setup')}

View file

@ -79,7 +79,7 @@ export const DisablePhase: React.FC<DisablePhaseProps> = ({ onDisable, isDisabli
</Button>
<button
onClick={() => setUseBackup(!useBackup)}
className="text-sm text-primary hover:underline"
className="text-sm text-text-primary hover:underline"
>
{useBackup ? localize('com_ui_use_2fa_code') : localize('com_ui_use_backup_code')}
</button>

View file

@ -28,7 +28,7 @@ export const QRPhase: React.FC<QRPhaseProps> = ({ secret, otpauthUrl, onNext })
<motion.div
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
className="rounded-2xl bg-white p-4 shadow-lg"
className="rounded-2xl bg-surface-fixed p-4 shadow-lg"
>
<QRCodeSVG value={otpauthUrl} size={240} />
</motion.div>

View file

@ -30,7 +30,7 @@ export default function ApiKeys() {
</Button>
</OGDialogTrigger>
<OGDialogContent
className="w-11/12 max-w-2xl bg-background text-text-primary shadow-2xl"
className="w-11/12 max-w-2xl bg-surface-primary text-text-primary shadow-2xl"
aria-describedby={undefined}
>
<OGDialogHeader className="space-y-0 pr-8 text-left">

View file

@ -199,7 +199,7 @@ export default function SharedLinks() {
to={`/share/${shareId}`}
target="_blank"
rel="noopener noreferrer"
className="group flex items-center gap-1 truncate rounded-sm text-link underline decoration-1 underline-offset-2 hover:decoration-2 focus:outline-none focus:ring-2 focus:ring-ring"
className="group flex items-center gap-1 truncate rounded-sm text-link underline decoration-1 underline-offset-2 hover:decoration-2 focus:outline-none focus:ring-2 focus:ring-text-primary"
title={title}
>
<span className="truncate">{title}</span>
@ -275,7 +275,7 @@ export default function SharedLinks() {
href={`/c/${row.original.conversationId}`}
target="_blank"
rel="noopener noreferrer"
className="flex h-8 w-8 items-center justify-center rounded-md p-0 transition-colors hover:bg-surface-hover focus:outline-none focus:ring-2 focus:ring-ring"
className="flex h-8 w-8 items-center justify-center rounded-md p-0 transition-colors hover:bg-surface-hover focus:outline-none focus:ring-2 focus:ring-text-primary"
aria-label={localize('com_ui_open_source_chat_new_tab_title', {
title: row.original.title || localize('com_ui_untitled'),
})}
@ -324,7 +324,7 @@ export default function SharedLinks() {
<OGDialogContent
title={localize('com_nav_shared_links')}
className="w-11/12 max-w-5xl bg-background text-text-primary shadow-2xl"
className="w-11/12 max-w-5xl bg-surface-primary text-text-primary shadow-2xl"
>
<OGDialogHeader>
<OGDialogTitle>{localize('com_nav_shared_links')}</OGDialogTitle>

View file

@ -31,7 +31,7 @@ export function ArchivedChatsModal({
tabIndex={-1}
onOpenAutoFocus={handleOpenAutoFocus}
title={localize('com_nav_archived_chats')}
className="w-11/12 max-w-[1000px] bg-background text-text-primary shadow-2xl focus:outline-none"
className="w-11/12 max-w-[1000px] bg-surface-primary text-text-primary shadow-2xl focus:outline-none"
>
<OGDialogHeader>
<OGDialogTitle>{localize('com_nav_archived_chats')}</OGDialogTitle>

View file

@ -178,7 +178,7 @@ export default function ArchivedChatsTable({
to={`/c/${conversationId}`}
target="_blank"
rel="noopener noreferrer"
className="group flex items-center gap-1 truncate rounded-sm text-link underline decoration-1 underline-offset-2 hover:decoration-2 focus:outline-none focus:ring-2 focus:ring-ring"
className="group flex items-center gap-1 truncate rounded-sm text-link underline decoration-1 underline-offset-2 hover:decoration-2 focus:outline-none focus:ring-2 focus:ring-text-primary"
title={title}
aria-label={localize('com_ui_open_archived_chat_new_tab_title', { title })}
>

View file

@ -61,7 +61,7 @@ export default function OAuthError() {
<p className="mb-6 text-sm text-text-secondary">{getErrorMessage(error)}</p>
<button
onClick={() => window.close()}
className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-ring-primary focus:ring-offset-2"
className="rounded-md bg-surface-inverted px-4 py-2 text-sm font-medium text-text-inverted hover:bg-surface-inverted-hover focus:outline-none focus:ring-2 focus:ring-ring-primary focus:ring-offset-2"
aria-label={localize('com_ui_close_window') || 'Close Window'}
>
{localize('com_ui_close_window') || 'Close Window'}

View file

@ -41,7 +41,7 @@ function PluginAuthForm({ plugin, onSubmit, isEntityTool }: TPluginAuthFormProps
const authField = config.authField.split('||')[0];
const isOptional = config.optional === true;
const inputClassName =
'flex h-10 max-h-10 w-full resize-none rounded-md border border-border-light bg-transparent px-3 py-2 text-sm text-text-secondary shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-text-tertiary focus:border-border-medium focus:bg-surface-secondary focus:outline-none focus:ring-0 focus:ring-gray-400 focus:ring-opacity-0 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-700 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
'flex h-10 max-h-10 w-full resize-none rounded-md border border-border-light bg-transparent px-3 py-2 text-sm text-text-secondary shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-text-tertiary focus:border-border-medium focus:bg-surface-secondary focus:outline-none focus:ring-0 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50';
const sharedProps = {
id: authField,
'aria-invalid': !!errors[authField],
@ -69,7 +69,7 @@ function PluginAuthForm({ plugin, onSubmit, isEntityTool }: TPluginAuthFormProps
<div key={`${authField}-${i}`} className="flex w-full flex-col gap-1">
<label
htmlFor={authField}
className="mb-1 text-left text-sm font-medium text-gray-700/70 dark:text-gray-50/70"
className="mb-1 text-left text-sm font-medium text-text-primary"
>
{config.label}
</label>

View file

@ -23,7 +23,7 @@ const PluginPagination: React.FC<TPluginPaginationProps> = ({
};
return (
<div className="flex gap-2 text-sm text-black/60 dark:text-white/70">
<div className="flex gap-2 text-sm text-text-secondary">
<div
role="button"
tabIndex={0}
@ -36,8 +36,8 @@ const PluginPagination: React.FC<TPluginPaginationProps> = ({
}}
className={`flex cursor-default items-center text-sm ${
currentPage === 1
? 'text-black/70 opacity-50 dark:text-white/70'
: 'text-black/70 hover:text-black/50 dark:text-white/70 dark:hover:text-white/50'
? 'text-text-secondary opacity-50'
: 'text-text-secondary hover:text-text-primary'
}`}
style={{ userSelect: 'none' }}
>
@ -90,8 +90,8 @@ const PluginPagination: React.FC<TPluginPaginationProps> = ({
}}
className={`flex cursor-default items-center text-sm ${
currentPage === maxPage
? 'text-black/70 opacity-50 dark:text-white/70'
: 'text-black/70 hover:text-black/50 dark:text-white/70 dark:hover:text-white/50'
? 'text-text-secondary opacity-50'
: 'text-text-secondary hover:text-text-primary'
}`}
style={{ userSelect: 'none' }}
>

View file

@ -26,8 +26,8 @@ const VersionBadge = ({
className={cn(
'inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium',
isProduction
? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-400'
: 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-400',
? 'bg-status-success-subtle text-status-success'
: 'bg-status-info-subtle text-status-info',
)}
>
{isProduction ? (
@ -106,7 +106,7 @@ const VersionCard = ({
className={cn(
'group mb-2 ml-2 flex flex-1 flex-col rounded-lg border p-3 text-left',
isSelected
? 'border-green-500/50 bg-green-50/50 dark:bg-green-950/20'
? 'border-status-success-border bg-status-success-subtle'
: 'border-border-medium bg-transparent hover:border-border-heavy hover:bg-surface-hover',
)}
onClick={onClick}
@ -116,7 +116,7 @@ const VersionCard = ({
<span
className={cn(
'text-sm font-semibold',
isSelected ? 'text-green-700 dark:text-green-400' : 'text-text-primary',
isSelected ? 'text-status-success' : 'text-text-primary',
)}
>
{localize('com_ui_version_var', { 0: versionNumber })}

View file

@ -74,7 +74,7 @@ const CategorySelector: React.FC<CategorySelectorProps> = ({
const trigger = (
<Ariakit.MenuButton
className={cn(
'focus:ring-offset-ring-offset relative inline-flex h-9 items-center justify-between rounded-xl border border-border-medium bg-transparent px-3 text-sm text-text-primary transition-all duration-200 ease-in-out hover:bg-accent hover:text-accent-foreground focus:ring-ring-primary',
'focus:ring-offset-ring-offset relative inline-flex h-9 items-center justify-between rounded-xl border border-border-medium bg-transparent px-3 text-sm text-text-primary transition-all duration-200 ease-in-out hover:bg-surface-hover hover:text-text-primary focus:ring-ring-primary',
'gap-2 sm:w-fit',
className,
)}

View file

@ -76,7 +76,7 @@ const VersionsPanel = React.memo(
className={cn(
'w-full gap-1.5 transition-all duration-200',
isProductionVersion &&
'border border-green-500/30 bg-green-50 text-green-700 hover:bg-green-100 dark:bg-green-950/30 dark:text-green-400 dark:hover:bg-green-950/50',
'border border-status-success-border bg-status-success-subtle text-status-success hover:bg-status-success-subtle',
)}
onClick={() => {
if (!selectedPrompt) {

View file

@ -145,7 +145,7 @@ export default function VariableForm({
return (
<div className="mx-auto p-1 md:container">
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div className="mb-6 max-h-screen max-w-[80vw] overflow-auto rounded-md bg-surface-tertiary p-4 text-text-secondary dark:bg-surface-primary sm:max-w-full md:max-h-96">
<div className="mb-6 max-h-screen max-w-[80vw] overflow-auto rounded-md bg-surface-tertiary p-4 text-text-secondary sm:max-w-full md:max-h-96">
<ReactMarkdown
/** @ts-ignore */
remarkPlugins={[supersub, remarkGfm, [remarkMath, { singleDollarTextMath: false }]]}
@ -157,7 +157,7 @@ export default function VariableForm({
]}
/** @ts-ignore */
components={{ code: codeNoExecution, p: PromptVariableGfm }}
className="markdown prose dark:prose-invert light my-1 max-h-[50vh] max-w-full break-words dark:text-text-secondary"
className="markdown prose dark:prose-invert light my-1 max-h-[50vh] max-w-full break-words"
>
{generateHighlightedMarkdown()}
</ReactMarkdown>

View file

@ -51,7 +51,7 @@ export default function Message(props: TMessageProps) {
return (
<>
<div className="text-token-text-primary w-full border-0 bg-transparent dark:border-0 dark:bg-transparent">
<div className="text-token-text-primary w-full border-0 bg-transparent">
<div className="m-auto justify-center p-4 py-2 md:gap-6">
<div className="final-completion group mx-auto flex flex-1 gap-3 md:max-w-[47rem] md:px-5 lg:px-1 xl:max-w-[55rem] xl:px-5">
<div className="relative flex flex-shrink-0 flex-col items-end">

View file

@ -22,9 +22,9 @@ export default function MessagesView({
width: '100%',
}}
>
<div className="flex flex-col pb-16 text-sm dark:bg-transparent">
<div className="flex flex-col pb-16 text-sm">
{(_messagesTree && _messagesTree.length === 0) || _messagesTree === null ? (
<div className="flex w-full items-center justify-center gap-1 bg-surface-secondary p-3 text-sm text-text-tertiary dark:border-gray-800/50">
<div className="flex w-full items-center justify-center gap-1 bg-surface-secondary p-3 text-sm text-text-tertiary">
{localize('com_ui_nothing_found')}
</div>
) : (

View file

@ -128,7 +128,7 @@ function SharedView() {
);
const mainContent = (
<div className="transition-width relative flex h-full w-full flex-1 flex-col items-stretch overflow-hidden pt-0 dark:bg-surface-secondary">
<div className="transition-width relative flex h-full w-full flex-1 flex-col items-stretch overflow-hidden bg-surface-secondary pt-0">
<div className="relative flex h-full min-h-0 flex-col text-text-primary" role="presentation">
{content}
{footer}

View file

@ -284,7 +284,7 @@ export default function GenericGrantAccessDialog({
disabled={disabled}
className={cn('h-9', buttonClassName)}
>
<div className="flex min-w-[32px] items-center justify-center gap-2 text-blue-500">
<div className="flex min-w-[32px] items-center justify-center gap-2 text-status-info">
<span className="flex h-6 w-6 items-center justify-center">
<Share2Icon className="icon-md h-4 w-4" />
</span>
@ -356,7 +356,7 @@ export default function GenericGrantAccessDialog({
return (
<div className="space-y-2">
{!hasAtLeastOneOwner && hasChanges && (
<div className="rounded-lg border border-destructive/30 bg-destructive/10 p-3 text-center">
<div className="rounded-lg border border-status-error-border bg-status-error-subtle p-3 text-center">
<div className="flex items-center justify-center gap-2 text-sm text-text-destructive">
<UserX className="h-4 w-4" aria-hidden="true" />
{localize('com_ui_at_least_one_owner_required')}

View file

@ -38,7 +38,7 @@ export default function SelectedPrincipalsList({
if (principles.length === 0) {
return (
<div className={`space-y-3 ${className}`}>
<div className="rounded-lg border border-dashed border-border-medium py-8 text-center text-muted-foreground">
<div className="rounded-lg border border-dashed border-border-medium py-8 text-center text-text-secondary">
<Users className="mx-auto mb-2 h-8 w-8 opacity-50" aria-hidden="true" />
<p className="mt-1 text-xs">{localize('com_ui_search_above_to_add_all')}</p>
</div>
@ -58,14 +58,14 @@ export default function SelectedPrincipalsList({
return (
<div
key={share.idOnTheSource + '-principalList'}
className="bg-surface flex items-center justify-between rounded-2xl border border-border p-3"
className="bg-surface flex items-center justify-between rounded-2xl border border-border-light p-3"
>
<div className="flex min-w-0 flex-1 items-center gap-3">
<PrincipalAvatar principal={share} size="md" />
<div className="min-w-0 flex-1">
<div className="truncate text-sm font-medium">{displayName}</div>
<div className="flex items-center gap-1 text-xs text-muted-foreground">
<div className="flex items-center gap-1 text-xs text-text-secondary">
<span>{subtitle}</span>
{share.source === 'entra' && (
<>
@ -99,7 +99,7 @@ export default function SelectedPrincipalsList({
<Button
variant="outline"
onClick={() => onRemoveHandler(share.idOnTheSource!)}
className="h-9 w-9 p-0 hover:border-destructive/10 hover:bg-destructive/10 hover:text-destructive"
className="h-9 w-9 p-0 hover:border-status-error-border hover:bg-status-error-subtle hover:text-text-destructive"
aria-label={localize('com_ui_remove_user', { 0: displayName })}
>
<X className="h-4 w-4" aria-hidden="true" />

View file

@ -54,7 +54,7 @@ export default function PublicSharingToggle({
<div
className={cn(
'transition-colors duration-200',
isPublic ? 'text-blue-600 dark:text-blue-500' : 'text-text-secondary',
isPublic ? 'text-status-info' : 'text-text-secondary',
)}
>
<Globe className="size-5" />
@ -114,9 +114,7 @@ export default function PublicSharingToggle({
<div
className={cn(
'transition-all duration-300',
isPublic
? 'scale-100 text-blue-600 dark:text-blue-500'
: 'scale-95 text-text-secondary',
isPublic ? 'scale-100 text-status-info' : 'scale-95 text-text-secondary',
)}
>
<Shield className="size-5" />

View file

@ -28,7 +28,7 @@ function SkillToggle({ enabled, onChange, ariaLabel }: SkillToggleProps) {
>
<span
className={cn(
'pointer-events-none mt-0.5 inline-block size-4 rounded-full bg-white shadow-sm transition-transform duration-200',
'pointer-events-none mt-0.5 inline-block size-4 rounded-full bg-surface-fixed shadow-sm transition-transform duration-200',
enabled ? 'translate-x-[1.125rem]' : 'translate-x-0.5',
)}
/>

View file

@ -42,7 +42,7 @@ const CategorySelector: React.FC<CategorySelectorProps> = ({ className = '' }) =
const trigger = (
<Ariakit.MenuButton
className={cn(
'focus:ring-offset-ring-offset relative inline-flex h-9 items-center justify-between rounded-xl border border-border-medium bg-transparent px-3 text-sm text-text-primary transition-all duration-200 ease-in-out hover:bg-accent hover:text-accent-foreground focus:ring-ring-primary',
'focus:ring-offset-ring-offset relative inline-flex h-9 items-center justify-between rounded-xl border border-border-medium bg-transparent px-3 text-sm text-text-primary transition-all duration-200 ease-in-out hover:bg-surface-hover hover:text-text-primary focus:ring-ring-primary',
'gap-2 sm:w-fit',
className,
)}

View file

@ -80,14 +80,14 @@ function MCPToolItem({
<img
src={icon}
alt={localize('com_ui_logo', { 0: name })}
className="h-full w-full rounded-[5px] bg-white"
className="h-full w-full rounded-[5px] bg-surface-fixed"
/>
) : (
<div className="flex h-full w-full items-center justify-center rounded-[5px] border border-border-medium bg-transparent">
<Wrench className="h-8 w-8 text-text-secondary" />
</div>
)}
<div className="absolute inset-0 rounded-[5px] ring-1 ring-inset ring-black/10"></div>
<div className="absolute inset-0 rounded-[5px] ring-1 ring-inset ring-border-light"></div>
</div>
</div>
<div className="flex min-w-0 flex-col items-start justify-between">

View file

@ -36,14 +36,14 @@ function ToolItem({ tool, onAddTool, onRemoveTool, isInstalled = false }: ToolIt
<img
src={icon}
alt={localize('com_ui_logo', { 0: name })}
className="h-full w-full rounded-[5px] bg-white"
className="h-full w-full rounded-[5px] bg-surface-fixed"
/>
) : (
<div className="flex h-full w-full items-center justify-center rounded-[5px] border border-border-medium bg-transparent">
<Wrench className="h-8 w-8 text-text-secondary" />
</div>
)}
<div className="absolute inset-0 rounded-[5px] ring-1 ring-inset ring-black/10"></div>
<div className="absolute inset-0 rounded-[5px] ring-1 ring-inset ring-border-light"></div>
</div>
</div>
<div className="flex min-w-0 flex-col items-start justify-between">
@ -63,7 +63,7 @@ function ToolItem({ tool, onAddTool, onRemoveTool, isInstalled = false }: ToolIt
</button>
) : (
<button
className="btn relative bg-gray-300 hover:bg-gray-400 dark:bg-gray-50 dark:hover:bg-gray-200"
className="btn relative bg-surface-tertiary hover:bg-surface-hover"
onClick={handleClick}
aria-label={`${localize('com_nav_tool_remove')} ${name}`}
>

View file

@ -133,7 +133,7 @@ export function SourceHovercard({
isFile ? (
<button
onClick={handleFileClick}
className="ml-1 inline-flex h-5 max-w-36 items-center gap-1 overflow-hidden text-ellipsis whitespace-nowrap rounded-xl border border-border-heavy bg-surface-secondary px-2 text-xs font-medium text-text-primary no-underline transition-colors hover:bg-surface-hover dark:border-border-medium dark:hover:bg-surface-tertiary"
className="ml-1 inline-flex h-5 max-w-36 items-center gap-1 overflow-hidden text-ellipsis whitespace-nowrap rounded-xl border border-border-heavy bg-surface-secondary px-2 text-xs font-medium text-text-primary no-underline transition-colors hover:bg-surface-hover"
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
title={
@ -148,7 +148,7 @@ export function SourceHovercard({
href={source.link}
target="_blank"
rel="noopener noreferrer"
className="ml-1 inline-block h-5 max-w-36 cursor-pointer items-center overflow-hidden text-ellipsis whitespace-nowrap rounded-xl border border-border-heavy bg-surface-secondary px-2 text-xs font-medium no-underline transition-colors hover:bg-surface-hover dark:border-border-medium dark:hover:bg-surface-tertiary"
className="ml-1 inline-block h-5 max-w-36 cursor-pointer items-center overflow-hidden text-ellipsis whitespace-nowrap rounded-xl border border-border-heavy bg-surface-secondary px-2 text-xs font-medium no-underline transition-colors hover:bg-surface-hover"
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
@ -157,7 +157,7 @@ export function SourceHovercard({
)
}
/>
<Ariakit.HovercardDisclosure className="ml-0.5 rounded-full text-text-primary focus:outline-none focus:ring-2 focus:ring-ring">
<Ariakit.HovercardDisclosure className="ml-0.5 rounded-full text-text-primary focus:outline-none focus:ring-2 focus:ring-text-primary">
<VisuallyHidden>{localize('com_citation_more_details', { label })}</VisuallyHidden>
<ChevronDown className="icon-sm" aria-hidden="true" />
</Ariakit.HovercardDisclosure>

View file

@ -81,7 +81,7 @@ function SourceItem({ source, expanded = false }: SourceItemProps) {
</a>
}
/>
<Ariakit.HovercardDisclosure className="absolute right-2 rounded-full text-text-primary focus:outline-none focus:ring-2 focus:ring-ring">
<Ariakit.HovercardDisclosure className="absolute right-2 rounded-full text-text-primary focus:outline-none focus:ring-2 focus:ring-text-primary">
<VisuallyHidden>
{localize('com_citation_more_details', { label: domain })}
</VisuallyHidden>
@ -319,7 +319,9 @@ const FileItem = React.memo(function FileItem({
</span>
)}
</div>
{error && <div className="mt-1 text-xs text-text-destructive">{getErrorMessage(error)}</div>}
{error && (
<div className="mt-1 text-xs text-text-destructive">{getErrorMessage(error)}</div>
)}
</button>
);
}
@ -723,7 +725,7 @@ function SourcesComponent({ messageId, conversationId }: SourcesProps = {}) {
containerClassName="flex min-w-full mb-4"
tabListClassName="flex items-center mb-2 border-b border-border-light overflow-x-auto"
tabPanelClassName="w-full overflow-x-auto scrollbar-none md:mx-0 md:px-0"
tabClassName="flex items-center whitespace-nowrap text-xs font-medium text-token-text-secondary px-1 pt-2 pb-1 border-b-2 border-transparent data-[state=active]:text-text-primary outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
tabClassName="flex items-center whitespace-nowrap text-xs font-medium text-token-text-secondary px-1 pt-2 pb-1 border-b-2 border-transparent data-[state=active]:text-text-primary outline-none focus:ring-2 focus:ring-text-primary focus:ring-offset-2"
/>
</div>
);
@ -752,7 +754,7 @@ export default function Sources(props: SourcesProps) {
</div>
<button
onClick={() => window.location.reload()}
className="hover:bg-surface-primary-hover rounded-md bg-surface-primary px-3 py-1 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-ring"
className="hover:bg-surface-primary-hover rounded-md bg-surface-primary px-3 py-1 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-text-primary"
aria-label={localize('com_sources_reload_page')}
>
{localize('com_ui_refresh')}

View file

@ -41,7 +41,7 @@ class SourcesErrorBoundary extends Component<Props, State> {
<div className="mb-2 text-sm text-text-secondary">Sources temporarily unavailable</div>
<button
onClick={() => window.location.reload()}
className="hover:bg-surface-primary-hover rounded-md bg-surface-primary px-3 py-1 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-ring"
className="hover:bg-surface-primary-hover rounded-md bg-surface-primary px-3 py-1 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-text-primary"
aria-label="Reload the page"
>
Refresh

View file

@ -91,11 +91,11 @@ function UnknownIcon({
const currentEndpoint = endpoint.toLowerCase();
if (currentEndpoint === KnownEndpoints.xai) {
return <XAIcon className={cn(className, 'text-black dark:text-white')} />;
return <XAIcon className={cn(className, 'text-text-primary')} />;
}
if (currentEndpoint === KnownEndpoints.moonshot) {
return <MoonshotIcon className={cn(className, 'text-black dark:text-white')} />;
return <MoonshotIcon className={cn(className, 'text-text-primary')} />;
}
if (iconURL) {

View file

@ -135,7 +135,7 @@ export default function RouteErrorBoundary() {
</h2>
{/* Error Message */}
<div className="mb-4 rounded-xl border border-red-500/20 bg-red-500/5 p-4 text-sm text-gray-600 dark:text-gray-200">
<div className="mb-4 rounded-xl border border-status-error-border bg-status-error-subtle p-4 text-sm text-text-secondary">
<h3 className="mb-2 font-medium">{localize('com_ui_error_message_prefix')}</h3>
<pre className="whitespace-pre-wrap text-sm font-light leading-relaxed text-text-primary">
{errorDetails.message}
@ -145,7 +145,7 @@ export default function RouteErrorBoundary() {
{/* Status Information */}
{(typeof errorDetails.status === 'number' ||
typeof errorDetails.statusText === 'string') && (
<div className="mb-4 rounded-xl border border-yellow-500/20 bg-yellow-500/5 p-4 text-sm text-text-primary">
<div className="mb-4 rounded-xl border border-status-warning-border bg-status-warning-subtle p-4 text-sm text-text-primary">
<h3 className="mb-2 font-medium">{localize('com_ui_status_prefix')}:</h3>
<p className="text-text-primary">
{typeof errorDetails.status === 'number' && `${errorDetails.status} `}
@ -171,7 +171,7 @@ export default function RouteErrorBoundary() {
</Button>
</div>
</summary>
<div className="overflow-x-auto rounded-lg bg-black/5 p-4 dark:bg-white/5">
<div className="overflow-x-auto rounded-lg bg-surface-tertiary p-4">
{formatStackTrace(errorDetails.stack).map(({ number, content }) => (
<div key={number} className="flex">
<span className="select-none pr-4 font-mono text-xs text-text-secondary">

View file

@ -96,7 +96,7 @@ export default function Search() {
</div>
{(messages && messages.length === 0) || messages == null ? (
<div className="absolute inset-0 flex items-center justify-center">
<div className="rounded-lg bg-white p-6 text-lg text-gray-500 dark:border-gray-800/50 dark:bg-gray-800 dark:text-gray-300">
<div className="rounded-lg bg-surface-secondary p-6 text-lg text-text-secondary">
{localize('com_ui_nothing_found')}
</div>
</div>

View file

@ -133,24 +133,17 @@ html {
--status-neutral: var(--gray-600);
--status-neutral-subtle: var(--gray-100);
--status-neutral-border: var(--gray-300);
/* These are test styles */
--surface-inverted: var(--gray-850);
--surface-inverted-hover: var(--gray-700);
--text-inverted: var(--white);
--surface-fixed: var(--white);
--surface-fixed-hover: var(--gray-100);
--text-fixed: var(--gray-800);
/* Retained for excluded SidePanel/Agents + SidePanel/Builder (pending migration) */
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--radius: 0.5rem;
--chart-1: 12 76% 61%;
@ -215,24 +208,17 @@ html {
--status-neutral: var(--gray-300);
--status-neutral-subtle: var(--gray-800);
--status-neutral-border: var(--gray-700);
/* These are test styles */
--surface-inverted: var(--white);
--surface-inverted-hover: var(--gray-100);
--text-inverted: var(--gray-850);
--surface-fixed: var(--white);
--surface-fixed-hover: var(--gray-100);
--text-fixed: var(--gray-800);
/* Retained for excluded SidePanel/Agents + SidePanel/Builder (pending migration) */
--background: 0 0% 7%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 40.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;

View file

@ -1,9 +1,9 @@
import type { TMessage } from 'librechat-data-provider';
const even =
'w-full border-b border-black/10 dark:border-gray-800/50 text-gray-800 bg-white dark:text-gray-200 group dark:bg-gray-800 hover:bg-gray-200/25 hover:text-gray-700 dark:hover:bg-gray-800 dark:hover:text-gray-200';
'w-full border-b border-border-light text-text-primary bg-surface-secondary group hover:bg-surface-hover hover:text-text-primary';
const odd =
'w-full border-b border-black/10 bg-gray-50 dark:border-gray-800/50 text-gray-800 dark:text-gray-200 group bg-gray-200 dark:bg-gray-700 hover:bg-gray-200/40 hover:text-gray-700 dark:hover:bg-gray-800 dark:hover:text-gray-200';
'w-full border-b border-border-light text-text-primary group bg-surface-active-alt hover:bg-surface-hover hover:text-text-primary';
export function groupIntoList({
messages,

View file

@ -82,16 +82,16 @@ export const removeFocusRings =
'focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0';
export const cardStyle =
'transition-colors rounded-md min-w-[75px] border font-normal bg-white hover:bg-gray-50 dark:border-gray-700 dark:hover:bg-gray-700 dark:bg-gray-800 text-black dark:text-gray-600 focus:outline-none data-[state=open]:bg-gray-50 dark:data-[state=open]:bg-gray-700';
'transition-colors rounded-md min-w-[75px] border border-border-medium font-normal bg-surface-secondary hover:bg-surface-hover text-text-primary focus:outline-none data-[state=open]:bg-surface-hover';
export const defaultTextProps =
'rounded-md border border-gray-200 focus:border-gray-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none focus-within:placeholder:text-text-primary focus:placeholder:text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-700 dark:border-gray-600 dark:focus:bg-gray-600 dark:focus:border-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:outline-none';
'rounded-md border border-border-light focus:border-border-heavy focus:bg-surface-secondary bg-transparent text-sm text-text-primary shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none focus-within:placeholder:text-text-primary focus:placeholder:text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-text-primary focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50';
export const optionText =
'p-0 shadow-none text-right pr-1 h-8 border-transparent hover:bg-gray-800/10 dark:hover:bg-white/10 dark:focus:bg-white/10 transition-colors';
'p-0 shadow-none text-right pr-1 h-8 border-transparent hover:bg-surface-hover transition-colors';
export const defaultTextPropsLabel =
'rounded-md border border-gray-300 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.10)] outline-none focus-within:placeholder:text-text-primary focus:placeholder:text-text-primary placeholder:text-text-secondary focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:bg-gray-700 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-600 dark:focus:outline-none';
'rounded-md border border-border-medium bg-transparent text-sm text-text-primary shadow-[0_0_10px_rgba(0,0,0,0.10)] outline-none focus-within:placeholder:text-text-primary focus:placeholder:text-text-primary placeholder:text-text-secondary focus:outline-none disabled:cursor-not-allowed disabled:opacity-50';
export function capitalizeFirstLetter(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1);

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',
},

Some files were not shown because too many files have changed in this diff Show more