Adjust styles to match the design system (#11118)

### What problem does this PR solve?

- Modify and adjust styles (CSS vars, components) to match the design
system
- Adjust file and directory structure of admin UI

### Type of change

- [x] Refactoring
This commit is contained in:
Jimmy Ben Klieve
2025-11-10 10:05:19 +08:00
committed by GitHub
parent 660386d3b5
commit 1cd54832b5
42 changed files with 685 additions and 539 deletions

View File

@ -39,7 +39,7 @@ const AvatarFallback = React.forwardRef<
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
'flex h-full w-full items-center justify-center rounded-full bg-muted',
'flex h-full w-full items-center justify-center rounded-full bg-bg-member',
className,
)}
{...props}

View File

@ -4,16 +4,18 @@ import * as React from 'react';
import { cn } from '@/lib/utils';
const badgeVariants = cva(
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors outline-none focus:outline-none',
{
variants: {
variant: {
default:
'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
'border-transparent bg-bg-primary text-text-primary hover:bg-primary/80',
secondary:
'border-transparent bg-bg-card text-text-sub-title-invert hover:bg-secondary/80 rounded-md',
'border-transparent bg-bg-card text-text-secondary rounded-md',
success:
'border-transparent bg-state-success/5 text-state-success rounded-md',
destructive:
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
'border-transparent bg-state-error/5 text-state-error rounded-md',
outline: 'text-foreground',
},
},

View File

@ -3,28 +3,56 @@ import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';
import { cn } from '@/lib/utils';
import { Loader2, Plus } from 'lucide-react';
import { LucideLoader2, Plus } from 'lucide-react';
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
cn(
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors outline-0',
'disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*="size-"])]:size-4 shrink-0 [&_svg]:shrink-0',
),
{
variants: {
variant: {
default:
'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
destructive:
'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
outline:
'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
'bg-text-primary text-bg-base shadow-xs hover:bg-text-primary/90 focus-visible:bg-text-primary/90',
destructive: `
bg-state-error text-white shadow-xs
hover:bg-state-error/90 focus-visible:ring-state-error/20 dark:focus-visible:ring-state-error/40
`,
outline: `
text-text-secondary bg-bg-input border-0.5 border-border-button
hover:text-text-primary hover:bg-border-button hover:border-border-default
focus-visible:text-text-primary focus-visible:bg-border-button focus-visible:border-border-button
`,
secondary:
'bg-bg-input text-text-primary shadow-xs hover:bg-bg-input/80 border border-border-button',
ghost:
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
ghost: `
text-text-secondary
hover:bg-border-button hover:text-text-primary
focus-visible:text-text-primary focus-visible:bg-border-button
`,
link: 'text-primary underline-offset-4 hover:underline',
icon: 'bg-colors-background-inverse-standard text-foreground hover:bg-colors-background-inverse-standard/80',
dashed: 'border border-dashed border-input hover:bg-accent',
transparent: 'bg-transparent hover:bg-accent border',
danger: 'bg-transparent border border-state-error text-state-error',
transparent: `
text-text-secondary bg-transparent border-0.5 border-border-button
hover:text-text-primary hover:bg-border-button
focus-visible:text-text-primary focus-visible:bg-border-button focus-visible:border-border-button
`,
danger: `
bg-transparent border border-state-error text-state-error
hover:bg-state-error/10 focus-visible:bg-state-error/10
`,
highlighted: `
bg-text-primary text-bg-base border-b-4 border-b-accent-primary
hover:bg-text-primary/90 focus-visible:bg-text-primary/90
`,
},
size: {
default: 'h-8 px-2.5 py-1.5 ',
@ -45,46 +73,48 @@ export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
loading?: boolean;
block?: boolean;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
(
{
children,
className,
variant,
size,
asChild = false,
loading = false,
disabled = false,
block = false,
...props
},
ref,
) => {
const Comp = asChild ? Slot : 'button';
return (
<Comp
className={cn(
'bg-bg-card',
{ 'block w-full': block },
buttonVariants({ variant, size, className }),
)}
ref={ref}
disabled={loading || disabled}
{...props}
/>
>
{loading && <LucideLoader2 className="animate-spin" />}
{children}
</Comp>
);
},
);
Button.displayName = 'Button';
export const ButtonLoading = React.forwardRef<
HTMLButtonElement,
Omit<ButtonProps, 'asChild'> & { loading?: boolean }
>(
(
{ className, variant, size, children, loading = false, disabled, ...props },
ref,
) => {
return (
<Button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
disabled={loading || disabled}
>
{loading && <Loader2 className="animate-spin" />}
{children}
</Button>
);
},
);
export const ButtonLoading = Button;
ButtonLoading.displayName = 'ButtonLoading';

View File

@ -9,7 +9,7 @@ const Card = React.forwardRef<
<div
ref={ref}
className={cn(
'rounded-lg border-border-default border shadow-sm bg-bg-input',
'rounded-lg border-border-button border-0.5 shadow-sm bg-bg-input transition-shadow',
className,
)}
{...props}
@ -60,7 +60,11 @@ const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
<div
ref={ref}
className={cn('p-6 pt-0 transition-shadow', className)}
{...props}
/>
));
CardContent.displayName = 'CardContent';

View File

@ -13,7 +13,11 @@ const Checkbox = React.forwardRef<
<CheckboxPrimitive.Root
ref={ref}
className={cn(
'peer h-3.5 w-3.5 shrink-0 rounded-sm border border-text-secondary 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 size-4 shrink-0 rounded-sm border border-border-button outline-0 transition-colors bg-bg-component',
'hover:border-border-default hover:bg-border-button',
'focus-visible:border-border-default focus-visible:bg-border-default',
'disabled:cursor-not-allowed disabled:opacity-50',
'data-[state=checked]:text-text-primary data-[state=checked]:border-border-default',
className,
)}
{...props}
@ -21,7 +25,7 @@ const Checkbox = React.forwardRef<
<CheckboxPrimitive.Indicator
className={cn('flex items-center justify-center text-current')}
>
<Check className="h-3.5 w-3.5" />
<Check className="size-3" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
));

View File

@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<
<DialogPrimitive.Overlay
ref={ref}
className={cn(
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
'fixed inset-0 z-50 bg-black/50 backdrop-blur-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
className,
)}
{...props}
@ -38,13 +38,20 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-xl translate-x-[-50%] translate-y-[-50%] gap-4 border bg-bg-base p-6 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%] sm:rounded-lg',
'outline-0 fixed left-[50%] top-[50%] z-50 grid w-full max-w-xl translate-x-[-50%] translate-y-[-50%] gap-4 border bg-bg-base p-6 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%] sm:rounded-lg',
className,
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 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 p-2 rounded-sm opacity-70 outline-none text-text-secondary transition-colors
hover:bg-border-button hover:text-text-primary
focus-visible:bg-border-button focus-visible:text-text-primary
disabled:pointer-events-none data-[state=open]:bg-bg-accent data-[state=open]:text-muted-foreground
"
>
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
@ -102,7 +109,7 @@ const DialogDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn('text-sm text-muted-foreground', className)}
className={cn('text-sm text-text-primary', className)}
{...props}
/>
));

View File

@ -65,7 +65,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground 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',
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-bg-base p-1 text-popover-foreground 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',
className,
)}
{...props}

View File

@ -97,19 +97,18 @@ const FormLabel = React.forwardRef<
required?: boolean;
}
>(({ className, tooltip, required = false, ...props }, ref) => {
const { error, formItemId } = useFormField();
const { formItemId } = useFormField();
return (
<Label
ref={ref}
className={cn(error && 'text-destructive', className, 'flex pb-0.5')}
className={cn(className, 'flex pb-0.5')}
htmlFor={formItemId}
{...props}
>
<section>
{required && <span className="text-destructive">*</span>}
{props.children}
</section>
{required && <span className="text-state-error">*</span>}
{props.children}
{tooltip && <FormTooltip tooltip={tooltip}></FormTooltip>}
</Label>
);
@ -171,7 +170,7 @@ const FormMessage = React.forwardRef<
<p
ref={ref}
id={formMessageId}
className={cn('text-sm font-medium text-destructive', className)}
className={cn('text-sm font-medium text-state-error', className)}
{...props}
>
{body}

View File

@ -3,14 +3,17 @@ import * as React from 'react';
import { cn } from '@/lib/utils';
import { Eye, EyeOff, Search } from 'lucide-react';
import { useState } from 'react';
import { Button } from './button';
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'prefix'> {
value?: string | number | readonly string[] | undefined;
prefix?: React.ReactNode;
suffix?: React.ReactNode;
}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, value, onChange, ...props }, ref) => {
({ className, type, value, onChange, prefix, suffix, ...props }, ref) => {
const isControlled = value !== undefined;
const { defaultValue, ...restProps } = props;
const inputValue = isControlled ? value : defaultValue;
@ -29,99 +32,80 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
onChange?.(e);
}
};
return (
<>
{type !== 'password' && (
<input
type={type === 'password' && showPassword ? 'text' : type}
className={cn(
'flex h-8 w-full rounded-md border border-input bg-bg-input px-2 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-text-disabled focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 text-text-primary',
className,
)}
ref={ref}
value={inputValue ?? ''}
onChange={handleChange}
{...restProps}
/>
const isPasswordInput = type === 'password';
const inputEl = (
<input
ref={ref}
type={isPasswordInput && showPassword ? 'text' : type}
className={cn(
'flex h-8 w-full rounded-md border-0.5 border-input bg-bg-input px-3 py-2 outline-none text-sm text-text-primary',
'file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-text-disabled',
'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent-primary',
'disabled:cursor-not-allowed disabled:opacity-50 transition-colors',
{
'pl-12': !!prefix,
'pr-12': !!suffix || isPasswordInput,
'pr-24': !!suffix && isPasswordInput,
},
className,
)}
{type === 'password' && (
<div className="relative w-full">
<input
type={type === 'password' && showPassword ? 'text' : type}
className={cn(
'flex h-8 w-full rounded-md border border-input bg-bg-input px-2 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-text-disabled focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 text-text-primary',
className,
)}
ref={ref}
value={inputValue ?? ''}
onChange={handleChange}
{...restProps}
/>
<button
value={inputValue ?? ''}
onChange={handleChange}
{...restProps}
/>
);
if (prefix || suffix || isPasswordInput) {
return (
<div className="relative">
{prefix && (
<span className="absolute left-0 top-[50%] translate-y-[-50%]">
{prefix}
</span>
)}
{inputEl}
{suffix && (
<span
className={cn('absolute right-0 top-[50%] translate-y-[-50%]', {
'right-14': isPasswordInput,
})}
>
{suffix}
</span>
)}
{isPasswordInput && (
<Button
variant="transparent"
type="button"
className="absolute inset-y-0 right-0 pr-3 flex items-center"
className="border-0 absolute right-1 top-[50%] translate-y-[-50%]"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? (
<EyeOff className="h-4 w-4 text-text-secondary" />
<EyeOff className="size-[1em]" />
) : (
<Eye className="h-4 w-4 text-text-secondary" />
<Eye className="size-[1em]" />
)}
</button>
</div>
)}
</>
);
</Button>
)}
</div>
);
}
return inputEl;
},
);
Input.displayName = 'Input';
export interface ExpandedInputProps extends Omit<InputProps, 'prefix'> {
prefix?: React.ReactNode;
suffix?: React.ReactNode;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface ExpandedInputProps extends InputProps {}
const ExpandedInput = ({
suffix,
prefix,
className,
...props
}: ExpandedInputProps) => {
return (
<div className="relative">
<span
className={cn({
['absolute left-3 top-[50%] translate-y-[-50%]']: prefix,
})}
>
{prefix}
</span>
<Input
className={cn(
{ 'pr-8': !!suffix, 'pl-8': !!prefix },
'bg-bg-base',
className,
)}
{...props}
></Input>
<span
className={cn({
['absolute right-3 top-[50%] translate-y-[-50%]']: suffix,
})}
>
{suffix}
</span>
</div>
);
};
const ExpandedInput = Input;
const SearchInput = (props: InputProps) => {
return (
<ExpandedInput
prefix={<Search className="size-3.5" />}
{...props}
></ExpandedInput>
);
return <Input {...props} prefix={<Search className="ml-3 size-[1em]" />} />;
};
type Value = string | readonly string[] | number | undefined;

View File

@ -46,6 +46,7 @@ const PaginationLink = ({
...props
}: PaginationLinkProps) => (
<a
href="#"
aria-current={isActive ? 'page' : undefined}
className={cn(
'size-8',
@ -70,7 +71,7 @@ const PaginationPrevious = ({
className={cn('gap-1 pl-2.5', className)}
{...props}
>
<ChevronLeft className="h-4 w-4" />
<ChevronLeft className="size-4" />
</PaginationLink>
);
PaginationPrevious.displayName = 'PaginationPrevious';
@ -85,7 +86,7 @@ const PaginationNext = ({
className={cn('gap-1 pr-2.5', className)}
{...props}
>
<ChevronRight className="h-4 w-4" />
<ChevronRight className="size-4" />
</PaginationLink>
);
PaginationNext.displayName = 'PaginationNext';
@ -96,7 +97,7 @@ const PaginationEllipsis = ({
}: React.ComponentProps<'span'>) => (
<span
aria-hidden
className={cn('flex h-9 w-9 items-center justify-center', className)}
className={cn('flex items-center justify-center', className)}
{...props}
>
<MoreHorizontal className="h-4 w-4" />

View File

@ -39,7 +39,11 @@ const PopoverContent = React.forwardRef<
align={align}
sideOffset={sideOffset}
className={cn(
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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',
'z-50 w-72 rounded-md border-0.5 border-border-button bg-bg-base p-4 text-text-primary shadow-lg outline-none',
'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-9',
'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',
className,
)}
{...props}

View File

@ -27,7 +27,12 @@ function RadioGroupItem({
<RadioGroupPrimitive.Item
data-slot="radio-group-item"
className={cn(
'border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
'text-primary aspect-square size-4 shrink-0 rounded-full',
'transition-all outline-none border border-border-button bg-bg-component',
'hover:border-border-default hover:bg-border-default',
'focus-visible:border-border-default focus-visible:bg-border-default',
'aria-[invalid]:border-state-error aria-[invalid]:bg-state-error/5 aria-[invalid]:text-state-error',
'disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
@ -36,7 +41,7 @@ function RadioGroupItem({
data-slot="radio-group-indicator"
className="relative flex items-center justify-center"
>
<CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
<CircleIcon className="fill-current absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
);

View File

@ -49,7 +49,7 @@ function Radio({ value, checked, disabled, onChange, children }: RadioProps) {
<span
className={cn(
'flex h-4 w-4 items-center justify-center rounded-full border border-border transition-colors',
'peer ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
'peer outline-none focus-visible:border-border-button',
isChecked && 'border-primary bg-primary/10',
mergedDisabled && 'border-muted',
)}

View File

@ -23,7 +23,7 @@ export type RAGFlowPaginationType = {
export function RAGFlowPagination({
current = 1,
pageSize = 10,
pageSize = 5,
total = 0,
onChange,
showSizeChanger = true,
@ -172,13 +172,14 @@ export function RAGFlowPagination({
</PaginationItem>
</PaginationContent>
</Pagination>
{showSizeChanger && (
<RAGFlowSelect
options={sizeChangerOptions}
value={currentPageSize}
onChange={handlePageSizeChange}
triggerClassName="bg-bg-card"
></RAGFlowSelect>
triggerClassName="bg-bg-card border-transparent"
/>
)}
</section>
);

View File

@ -26,7 +26,11 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
'flex h-8 w-full items-center bg-bg-input justify-between rounded-md border border-input px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
'flex h-8 w-full items-center bg-bg-input justify-between rounded-md border-0.5 border-border-button',
'px-3 py-2 text-sm outline-none transition-colors text-text-secondary placeholder:text-muted-foreground',
'hover:text-text-primary hover:bg-border-button',
'focus-visible:text-text-primary focus-visible:bg-border-button',
'disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
className,
)}
{...props}
@ -91,7 +95,11 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Content
ref={ref}
className={cn(
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground 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',
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border-0.5 border-border-card bg-bg-base text-popover-foreground 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',
className,
@ -134,7 +142,8 @@ const SelectItem = React.forwardRef<
<SelectPrimitive.Item
ref={ref}
className={cn(
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-2 text-sm outline-none text-text-secondary',
'focus:bg-border-button focus:text-text-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className,
)}
{...props}

View File

@ -11,16 +11,23 @@ const Switch = React.forwardRef<
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
'peer inline-flex h-3.5 w-6 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-accent-primary data-[state=unchecked]:bg-text-sub-title',
'group/switch inline-flex h-4 w-7 shrink-0 cursor-pointer items-center rounded-full',
'border-2 border-transparent overflow-hidden transition-colors',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary',
'disabled:cursor-not-allowed disabled:opacity-50',
'data-[state=checked]:bg-accent-primary data-[state=unchecked]:bg-text-sub-title',
className,
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
'pointer-events-none block size-3 rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-2 data-[state=unchecked]:translate-x-0',
)}
className="
pointer-events-none block w-3 h-3 rounded-full bg-white shadow-lg ring-0 transition-all ease-out
group-hover/switch:w-4 group-focus-visible/switch:w-4
data-[state=checked]:translate-x-3 data-[state=unchecked]:translate-x-0
group-hover/switch:data-[state=checked]:translate-x-2 group-focus-visible/switch:data-[state=checked]:translate-x-2
"
/>
</SwitchPrimitives.Root>
));

View File

@ -27,7 +27,10 @@ const TableHeader = React.forwardRef<
>(({ className, ...props }, ref) => (
<thead
ref={ref}
className={cn('[&_tr]:border-b top-0 sticky bg-bg-title z-10', className)}
className={cn(
'[&_tr]:border-b-0.5 top-0 sticky bg-bg-title z-10',
className,
)}
{...props}
/>
));
@ -52,7 +55,7 @@ const TableFooter = React.forwardRef<
<tfoot
ref={ref}
className={cn(
'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0',
'border-t-0.5 border-border-button bg-muted/50 font-medium [&>tr]:last:border-b-0',
className,
)}
{...props}
@ -67,7 +70,7 @@ const TableRow = React.forwardRef<
<tr
ref={ref}
className={cn(
'border-b border-border-button transition-colors hover:bg-bg-card data-[state=selected]:bg-bg-card',
'border-b-0.5 border-border-button transition-colors hover:bg-bg-card data-[state=selected]:bg-bg-card',
className,
)}
{...props}
@ -82,7 +85,7 @@ const TableHead = React.forwardRef<
<th
ref={ref}
className={cn(
'h-12 px-4 text-left align-middle font-normal text-text-secondary [&:has([role=checkbox])]:pr-0 ',
'first-of-type:pl-6 last-of-type:pr-6 h-14 px-4 text-left align-middle font-normal text-text-secondary [&:has([role=checkbox])]:pr-0 ',
className,
)}
{...props}
@ -97,7 +100,7 @@ const TableCell = React.forwardRef<
<td
ref={ref}
className={cn(
'p-4 align-middle [&:has([role=checkbox])]:pr-0 text-text-primary font-normal',
'first-of-type:pl-6 last-of-type:pr-6 px-4 py-3 align-middle [&:has([role=checkbox])]:pr-0 text-text-primary font-normal',
className,
)}
{...props}

View File

@ -29,7 +29,11 @@ const TabsTrigger = React.forwardRef<
<TabsPrimitive.Trigger
ref={ref}
className={cn(
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-bg-base data-[state=active]:text-text-primary data-[state=active]:shadow-sm',
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5',
'text-sm font-medium ring-offset-background transition-all',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
'disabled:pointer-events-none disabled:opacity-50',
'data-[state=active]:bg-bg-base data-[state=active]:text-text-primary data-[state=active]:shadow-sm',
className,
)}
{...props}