feat: add file upload section for cover image and article content in create article form

This commit is contained in:
2026-04-09 23:07:47 -03:00
parent ff8df41d4b
commit 534d206f0e
4 changed files with 278 additions and 70 deletions

View File

@@ -0,0 +1,113 @@
'use client';
import { Button } from '@/ui/components/shadcn/button';
import {
Field,
FieldDescription,
FieldError,
} from '@/ui/components/shadcn/field';
import {
FileUpload,
FileUploadDropzone,
FileUploadItem,
FileUploadItemDelete,
FileUploadItemMetadata,
FileUploadItemPreview,
FileUploadList,
FileUploadTrigger,
} from '@/ui/components/shadcn/file-upload';
import { X } from 'lucide-react';
import React, { useCallback } from 'react';
export interface FileUploadFieldProps {
file: File | null;
onFileChange: (file: File | null) => void;
accept?: string;
validate?: (file: File) => string | null;
onFileReject?: (file: File, message: string) => void;
label?: string;
description?: string;
error?: string;
icon?: React.ReactNode;
}
export const FileUploadField: React.FC<FileUploadFieldProps> = ({
file,
onFileChange,
accept,
validate,
onFileReject,
label = 'File',
description,
error,
icon,
}) => {
const handleAccept = useCallback(
(files: File[]) => {
const accepted = files[0];
if (accepted) onFileChange(accepted);
},
[onFileChange]
);
const handleValueChange = useCallback(
(files: File[]) => {
if (files.length === 0) onFileChange(null);
},
[onFileChange]
);
return (
<Field data-invalid={!!error}>
<FileUpload
value={file ? [file] : []}
onValueChange={handleValueChange}
onAccept={handleAccept}
onFileReject={onFileReject}
onFileValidate={validate}
accept={accept}
maxFiles={1}
multiple={false}
label={label}
className='min-w-0'
>
<FileUploadDropzone className='p-3'>
{icon}
<div className='flex flex-col gap-0.5 text-center'>
<p className='text-xs font-medium text-foreground'>
{label}
</p>
<p className='text-xs text-muted-foreground'>
Drag & drop or{' '}
<FileUploadTrigger className='cursor-pointer font-medium text-primary underline-offset-4 hover:underline'>
browse
</FileUploadTrigger>
</p>
</div>
</FileUploadDropzone>
<FileUploadList>
{file && (
<FileUploadItem value={file}>
<FileUploadItemPreview />
<FileUploadItemMetadata size='sm' />
<FileUploadItemDelete asChild>
<Button
type='button'
variant='ghost'
size='icon'
className='ml-auto size-7 shrink-0'
>
<X className='size-3.5' />
</Button>
</FileUploadItemDelete>
</FileUploadItem>
)}
</FileUploadList>
</FileUpload>
{description && <FieldDescription>{description}</FieldDescription>}
{error && <FieldError errors={[new Error(error)]} />}
</Field>
);
};