import { Image as ImageIcon, Trash2, Upload } from 'lucide-react'; import TextInputArea from '@/components/TextInputArea'; import { useTranslation } from 'react-i18next'; import CopyButton from '@/components/CopyButton'; import DecodeResultPaper from '@/components/DecodeResultPaper'; import { Button } from '@/components/ui/button'; import { downloadBlob, formatFileSize } from '@/utils/base64Converter'; import { useStorageState } from '@/utils/useStorageState'; import type { Base64ConvertDirection } from '@/types/storage'; import SwitchButtonGroup from '@/components/SwitchButtonGroup'; import { useBase64Converter } from './useBase64Converter'; import { cn } from '@/lib/utils'; const isValidDirection = (val: unknown): val is Base64ConvertDirection => val === 'encode' || val === 'decode'; interface Base64ConverterSectionProps { mode: 'file' | 'image'; } export default function Base64ConverterSection({ mode }: Base64ConverterSectionProps) { const { t } = useTranslation('base64Converter'); const [direction, setDirection] = useStorageState( `base64Converter/${mode}Mode/direction`, 'encode', isValidDirection, ); const { result, info, isLoading, isDragging, setIsDragging, fileInputRef, encodeError, decodeInput, setDecodeInput, decoded, decodeError, decodedFileName, setCustomFileName, resetAll, safeFileSelect, maxFileSizeStr, } = useBase64Converter({ mode }); const handleDirectionChange = (next: Base64ConvertDirection) => { if (!next || next === direction) return; resetAll(); setDirection(next); }; const handleDownload = () => { if (decoded) downloadBlob(decoded.blob, decodedFileName); }; return (
{direction === 'encode' ? (
{ e.preventDefault(); setIsDragging(true); }} onDragLeave={() => setIsDragging(false)} onDrop={(e) => { e.preventDefault(); setIsDragging(false); const file = e.dataTransfer.files[0]; if (file) safeFileSelect(file); }} onClick={() => fileInputRef.current?.click()} className={cn( 'flex flex-col items-center justify-center min-h-[190px] border-2 border-dashed rounded-2xl p-8 cursor-pointer transition-all duration-300', isDragging ? 'border-primary bg-primary/10' : info ? 'border-primary/60 bg-primary/5' : 'border-border bg-muted/40 hover:border-primary/80 hover:bg-muted/70', )} > { const file = e.target.files?.[0]; if (file) safeFileSelect(file); }} /> {isLoading ? (
) : info ? (
{mode === 'image' && result && (
preview
)} {info.name} {formatFileSize(info.size)} ยท {info.type} {t('clickOrDropToReplace')}
) : (
{mode === 'image' ? ( ) : ( )} {mode === 'image' ? t('clickOrDropToImage') : t('clickOrDropToFile')} {t('maxFileSize', { max: maxFileSizeStr })} {mode === 'image' && ( {t('supportedFormats')} )}
)}
{encodeError && (
{encodeError}
)} {result && (
{t('base64Output')}
2000 ? `${result.output.substring(0, 2000)}...` : result.output } showClear={false} minRows={4} />
{t('originalSize')}:{' '} {formatFileSize(result.originalBytes)} | {t('encodedSize')}:{' '} {formatFileSize(result.outputBytes)}
)}
) : (
{decoded && ( {mode === 'image' && (
decoded preview
)}
)}
)}
); }