diff --git a/src/components/FieldSetWithStatus.tsx b/src/components/FieldSetWithStatus.tsx index 97aababc..d3ea17d7 100644 --- a/src/components/FieldSetWithStatus.tsx +++ b/src/components/FieldSetWithStatus.tsx @@ -2,6 +2,7 @@ import { LegacyRef } from 'react'; import { experimental_useFormStatus as useFormStatus } from 'react-dom'; +import Spinner from './Spinner'; export default function FieldSetWithStatus({ id, @@ -9,6 +10,8 @@ export default function FieldSetWithStatus({ note, value, onChange, + placeholder, + loading, required, readOnly, type = 'text', @@ -19,6 +22,8 @@ export default function FieldSetWithStatus({ note?: string value: string onChange?: (value: string) => void + placeholder?: string + loading?: boolean required?: boolean readOnly?: boolean type?: 'text' | 'password' @@ -29,7 +34,7 @@ export default function FieldSetWithStatus({ return (
onChange?.(e.target.value)} type={type} autoComplete="off" diff --git a/src/photo/PhotoForm.tsx b/src/photo/PhotoForm.tsx index e8b78e86..2c68281f 100644 --- a/src/photo/PhotoForm.tsx +++ b/src/photo/PhotoForm.tsx @@ -37,11 +37,13 @@ export default function PhotoForm({ const url = formData.url ?? ''; useEffect(() => { + let timeout: NodeJS.Timeout; + const image = new Image(); image.crossOrigin = 'anonymous'; image.src = url; image.onload = () => { - const timeout = setTimeout(() => { + timeout = setTimeout(() => { const canvas = canvasRef.current; if (canvas) { canvas.width = THUMBNAIL_WIDTH * BLUR_SCALE; @@ -72,9 +74,10 @@ export default function PhotoForm({ } else { console.error('Cannot generate blur data: canvas not found'); } - }, 1000); - return () => clearTimeout(timeout); + }, 2000); }; + + return () => clearTimeout(timeout); }, [url, type]); const isFormValid = FORM_METADATA_ENTRIES.every(([key, { required }]) => @@ -110,7 +113,7 @@ export default function PhotoForm({ > {FORM_METADATA_ENTRIES.map(([ key, - { label, note, required, readOnly, hideIfEmpty }, + { label, note, required, readOnly, hideIfEmpty, loadingMessage }, ]) => (!hideIfEmpty || formData[key]) && setFormData({ ...formData, [key]: value })} required={required} readOnly={readOnly} + placeholder={loadingMessage && !formData[key] + ? loadingMessage + : undefined} + loading={loadingMessage && !formData[key] ? true : false} />)}
{type === 'edit' && diff --git a/src/photo/form.ts b/src/photo/form.ts index 39ca6c7b..f58a2968 100644 --- a/src/photo/form.ts +++ b/src/photo/form.ts @@ -18,16 +18,18 @@ type FormMeta = { readOnly?: boolean hideIfEmpty?: boolean hideTemporarily?: boolean + loadingMessage?: string }; const FORM_METADATA: Record = { title: { label: 'title' }, tags: { label: 'tags', note: 'comma-separated values' }, id: { label: 'id', readOnly: true, hideIfEmpty: true }, + // eslint-disable-next-line max-len + blurData: { label: 'blur data', readOnly: true, required: true, loadingMessage: 'Generating blur data ...' }, url: { label: 'url', readOnly: true }, extension: { label: 'extension', readOnly: true }, aspectRatio: { label: 'aspect ratio', readOnly: true }, - blurData: { label: 'blur data', readOnly: true, required: true }, make: { label: 'camera make' }, model: { label: 'camera model' }, focalLength: { label: 'focal length' },