refactor(ui): update ui for user settings, etc. (#13532)

### What problem does this PR solve?

Update UI styles:
- **User settings**
- Component styles: 
   - `ui/button.tsx`
   - `ui/checkbox.tsx`
   - `avatar-upload.tsx`
   - `file-uploader.tsx`
   - `icon-font.tsx`

### Type of change

- [x] Refactoring
This commit is contained in:
Jimmy Ben Klieve
2026-03-12 13:33:36 +08:00
committed by GitHub
parent 0da9c4618d
commit 31a8184f63
25 changed files with 687 additions and 621 deletions

View File

@ -318,7 +318,7 @@ export const AvatarUpload = forwardRef<HTMLInputElement, AvatarUploadProps>(
data-testid={uploadInputTestId}
/>
</div>
<div className="margin-1 text-sm text-text-secondary">
<div className="ms-1 text-xs text-text-secondary">
{tips ?? t('knowledgeConfiguration.photoTip')}
</div>

View File

@ -76,7 +76,7 @@ function UploadForm({ submit, showParseOnCreation }: UploadFormProps) {
data-testid="parse-on-creation-toggle"
onCheckedChange={field.onChange}
checked={field.value}
></Switch>
/>
)}
</RAGFlowFormItem>
)}
@ -85,7 +85,7 @@ function UploadForm({ submit, showParseOnCreation }: UploadFormProps) {
<FileUploader
value={field.value}
onValueChange={field.onChange}
accept={{ '*': [] }}
accept={{}}
data-testid="dataset-upload-dropzone"
/>
)}
@ -124,10 +124,7 @@ export function FileUploadDialog({
</TabsContent>
<TabsContent value="password">{t('common.comingSoon')}</TabsContent>
</Tabs> */}
<UploadForm
submit={onOk!}
showParseOnCreation={showParseOnCreation}
></UploadForm>
<UploadForm submit={onOk!} showParseOnCreation={showParseOnCreation} />
<DialogFooter>
<ButtonLoading type="submit" loading={loading} form={UploadFormId}>
{t('common.save')}

View File

@ -2,7 +2,7 @@
'use client';
import { FileText, FolderUp, Upload, X } from 'lucide-react';
import { FileText, FolderUp, LucideTrash2, Upload } from 'lucide-react';
import * as React from 'react';
import Dropzone, {
type DropzoneProps,
@ -80,12 +80,12 @@ function FileCard({ file, progress, onRemove }: FileCardProps) {
<div className="flex items-center gap-2">
<Button
type="button"
variant="outline"
variant="delete"
size="icon"
className="size-7"
onClick={onRemove}
>
<X className="size-4" aria-hidden="true" />
<LucideTrash2 className="size-4" aria-hidden="true" />
<span className="sr-only">Remove file</span>
</Button>
</div>
@ -300,71 +300,67 @@ export function FileUploader(props: FileUploaderProps) {
const isDisabled = disabled || (files?.length ?? 0) >= maxFileCount;
const renderDropzone = (isFolderMode: boolean = false) => (
<Dropzone
onDrop={onDrop}
accept={isFolderMode ? undefined : accept}
maxSize={maxSize}
maxFiles={maxFileCount}
multiple={maxFileCount > 1 || multiple}
disabled={isDisabled}
noClick={isFolderMode}
noDrag={isFolderMode}
>
{({ getRootProps, getInputProps, isDragActive }) => (
<div
{...getRootProps()}
className={cn(
'group relative grid h-72 w-full cursor-pointer place-items-center rounded-lg border border-dashed border-border-default px-5 py-2.5 text-center transition hover:bg-border-button bg-bg-card',
'ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
isDragActive && 'border-border-button',
isDisabled && 'pointer-events-none opacity-60',
className,
)}
{...dropzoneProps}
>
{!isFolderMode && <input {...getInputProps()} />}
{isDragActive && !isFolderMode ? (
<div className="flex flex-col items-center justify-center gap-4 sm:px-5">
<div className="rounded-full border border-dashed p-3">
<Upload
className="size-7 text-text-secondary transition-colors group-hover:text-text-primary"
aria-hidden="true"
/>
</div>
<p className="font-medium text-text-secondary">
{t('fileManager.dropFilesHere', 'Drop the files here')}
</p>
</div>
) : (
<div
className="flex flex-col items-center justify-center gap-4 sm:px-5"
onClick={() => {
if (isFolderMode && !isDisabled) {
folderInputRef.current?.click();
}
}}
>
<div className="rounded-full border border-dashed p-3">
{isFolderMode ? (
<FolderUp
className="size-7 text-text-secondary transition-colors group-hover:text-text-primary"
aria-hidden="true"
/>
) : (
const renderDropzone = (isFolderMode: boolean = false) => {
const IconComponent = isFolderMode ? FolderUp : Upload;
return (
<Dropzone
onDrop={onDrop}
accept={isFolderMode ? undefined : accept}
maxSize={maxSize}
maxFiles={maxFileCount}
multiple={maxFileCount > 1 || multiple}
disabled={isDisabled}
noClick={isFolderMode}
noDrag={isFolderMode}
>
{({ getRootProps, getInputProps, isDragActive }) => (
<div
{...getRootProps()}
className={cn(
'group relative grid h-72 w-full cursor-pointer place-items-center rounded-lg border border-dashed border-border-default',
'px-5 py-2.5 text-center transition hover:bg-bg-card outline-none',
'focus-visible:border-accent-primary focus-visible:bg-bg-card',
isDragActive && 'border-border-button',
isDisabled && 'pointer-events-none opacity-60',
className,
)}
{...dropzoneProps}
>
{!isFolderMode && <input {...getInputProps()} />}
{isDragActive && !isFolderMode ? (
<div className="flex flex-col items-center justify-center gap-4 sm:px-5">
<div>
<Upload
className="size-7 text-text-secondary transition-colors group-hover:text-text-primary"
aria-hidden="true"
/>
)}
</div>
<p className="font-medium text-text-secondary">
{t('fileManager.dropFilesHere', 'Drop the files here')}
</p>
</div>
<div className="flex flex-col gap-px">
<p className="font-medium text-text-secondary ">
) : (
<div
className="flex flex-col items-center justify-center gap-4 sm:px-5"
onClick={() => {
if (isFolderMode && !isDisabled) {
folderInputRef.current?.click();
}
}}
>
<IconComponent
className="size-12 stroke-1 text-text-secondary transition-colors group-hover:text-text-primary"
aria-hidden="true"
/>
<p className="font-medium text-text-secondary">
{title ||
(isFolderMode
? t('fileManager.uploadFolderTitle', 'Upload Folder')
: t('knowledgeDetails.uploadTitle'))}
</p>
<p className="text-sm text-text-disabled">
{description ||
(isFolderMode
@ -375,12 +371,12 @@ export function FileUploader(props: FileUploaderProps) {
: t('knowledgeDetails.uploadDescription'))}
</p>
</div>
</div>
)}
</div>
)}
</Dropzone>
);
)}
</div>
)}
</Dropzone>
);
};
return (
<div className="relative flex flex-col gap-4 overflow-hidden">
@ -417,7 +413,7 @@ export function FileUploader(props: FileUploaderProps) {
)}
{files?.length ? (
<div className="h-fit w-full px-3">
<div className="h-fit w-full">
<div className="flex max-h-48 flex-col gap-4 overflow-auto scrollbar-auto">
{files?.map((file, index) => (
<FileCard

View File

@ -21,14 +21,12 @@ export function IconFontFill({
isFill = true,
}: IconFontType & { isFill?: boolean }) {
return (
<span className={cn('size-4', className)}>
<svg
className={cn('size-4', className)}
style={{ fill: isFill ? 'currentColor' : '' }}
>
<use xlinkHref={`#icon-${name}`} />
</svg>
</span>
<svg
className={cn('size-4', className)}
style={{ fill: isFill ? 'currentColor' : '' }}
>
<use xlinkHref={`#icon-${name}`} />
</svg>
);
}

View File

@ -68,6 +68,13 @@ const buttonVariants = cva(
hover:bg-state-error/10 focus-visible:bg-state-error/10
`,
'danger-hover': `
bg-bg-input border-border-button
hover:bg-state-error/10 focus-visible:bg-state-error/10
hover:text-state-error focus-visible:text-state-error
hover:border-state-error focus-visible:border-state-error
`,
// Ghost variant series
// Button has transparent background, without borders
ghost: `
@ -91,11 +98,11 @@ const buttonVariants = cva(
size: {
auto: '',
xl: 'h-12 rounded-xl px-5',
xl: 'h-12 rounded-xl px-5 gap-3',
lg: 'h-10 rounded-lg px-4',
default: 'h-8 rounded px-3',
sm: 'h-7 rounded-sm px-2',
xs: 'h-6 rounded-xs px-1',
sm: 'h-7 rounded-sm px-2 gap-1',
xs: 'h-6 rounded-xs px-1 gap-0.5',
'icon-xl': 'size-12 rounded-xl',
'icon-lg': 'size-10 rounded-lg',

View File

@ -1,7 +1,7 @@
'use client';
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import { LucideCheck } from 'lucide-react';
import { LucideCheck, LucideMinus } from 'lucide-react';
import * as React from 'react';
import { cn } from '@/lib/utils';
@ -23,7 +23,12 @@ const Checkbox = React.forwardRef<
{...props}
>
<CheckboxPrimitive.Indicator className="flex items-center justify-center text-current">
<LucideCheck className="size-2.5 stroke-[3]" />
{props.checked === 'indeterminate' && (
<LucideMinus className="size-2.5 stroke-[3]" />
)}
{props.checked === true && (
<LucideCheck className="size-2.5 stroke-[3]" />
)}
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
));