import { useId, useRef, useState } from 'react' import { ImageIcon, ImagePlusIcon, Loader2Icon } from 'lucide-react' import { DEFAULT_IMAGE_TITLE } from '../../data/constants' import { adminApi } from '../../admin/adminClient' import { useAdmin } from '../../admin/AdminContext' import { useSmartTextField } from './useSmartTextField' type ImageFieldProps = { label: string value: string onSave: (url: string) => Promise /** متن جایگزین (Alt) */ alt?: string onSaveAlt?: (alt: string) => Promise /** عنوان تصویر (Title) */ title?: string onSaveTitle?: (title: string) => Promise /** * پیشنهاد Alt وقتی کاربر چیزی ننوشته — مثل «{عنوان مقاله} - تصویر شاخص». * هرگز از URL یا نام فایل ساخته نمی‌شود. */ altFallback?: string /** پیشنهاد عنوان تصویر — پیش‌فرض «Photo 1» */ titleFallback?: string } const META_FIELD_CLASS = 'mt-1.5 w-full border border-ivory/15 bg-char px-3 py-2 text-xs font-light text-ivory placeholder:text-ivory/30 focus:border-copper focus:outline-none' /** * انتخاب و آپلود تصویر به MinIO با پیش‌نمایش بزرگ. * ترتیب فیلدها: ۱) عنوان تصویر (پیش‌فرض «Photo 1») ۲) متن جایگزین (پیش‌فرض «{عنوان} - تصویر شاخص»). * هر دو «دستی یا پیش‌فرض» هستند و Alt هرگز از URL ساخته نمی‌شود. * پیش‌فرض خودکار با فوکوس پاک می‌شود تا کاربر بلافاصله تایپ کند و با بلورِ خالی برمی‌گردد. */ export function ImageField({ label, value, onSave, alt, onSaveAlt, title, onSaveTitle, altFallback = '', titleFallback = '', }: ImageFieldProps) { const { runSave, isAuthenticated, isEditMode } = useAdmin() const inputRef = useRef(null) const titleId = useId() const altId = useId() const [uploading, setUploading] = useState(false) const showTitle = title !== undefined || !!onSaveTitle const showAlt = alt !== undefined || !!onSaveAlt const titleField = useSmartTextField({ value: title ?? '', fallback: titleFallback, hardFallback: DEFAULT_IMAGE_TITLE, onCommit: onSaveTitle, }) const altField = useSmartTextField({ value: alt ?? '', fallback: altFallback, hardFallback: label, onCommit: onSaveAlt, }) if (!isAuthenticated || !isEditMode) return null const pick = async (file: File | undefined) => { if (!file) return setUploading(true) try { await runSave(async () => { const { url } = await adminApi.upload(file) const ok = await onSave(url) if (!ok) throw new Error('ذخیره نشد') // پیش‌فرض‌های Alt/Title همان لحظه ثبت می‌شوند تا تصویر بدون متادیتا نماند if (showTitle) await titleField.commit() if (showAlt) await altField.commit() }) } finally { setUploading(false) } } return (

{label}

{/* پیش‌نمایش بزرگ تصویر */}
{value ? ( {altField.display ) : (
)}
{(showTitle || showAlt) && (
{showTitle && (
titleField.onChange(event.target.value)} onFocus={titleField.onFocus} onBlur={titleField.onBlur} placeholder={titleFallback.trim() || DEFAULT_IMAGE_TITLE} className={META_FIELD_CLASS} />
)} {showAlt && (
altField.onChange(event.target.value)} onFocus={altField.onFocus} onBlur={altField.onBlur} placeholder={ altFallback.trim() || 'توضیح کوتاه تصویر برای سئو و صفحه‌خوان‌ها' } className={META_FIELD_CLASS} />
)}
)} { void pick(event.target.files?.[0]) event.target.value = '' }} />
) }