import { useEffect, useRef, useState } from 'react' import { createPortal } from 'react-dom' import { X } from 'lucide-react' import { useT } from '../i18n/useT' import type { WebsiteStaticImageSlotKind } from '../types/websiteStaticImage' import { staticImagePageLabel, staticImagePageOptions, } from '../utils/staticImagePages' import styles from './CategoryModal.module.css' export interface WebsiteStaticImageSlotFormValues { key: string label: string kind: WebsiteStaticImageSlotKind aspectRatio: string recommendedWidth: string itemCount: string pageKey: string } interface WebsiteStaticImageSlotModalProps { open: boolean onClose: () => void onSubmit: (values: WebsiteStaticImageSlotFormValues) => void initial?: Partial title: string submitLabel: string isSubmitting?: boolean lockKey?: boolean } const ANIMATION_MS = 220 const KEY_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]*$/ const ASPECT_OPTIONS = ['16:9', '16:5', '12:19', '9:4', '4:3', '3:2', '1:1', '21:9'] function slugifyKey(raw: string): string { const slug = raw .trim() .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, '') if (!slug || !/^[a-z]/.test(slug)) return '' return KEY_PATTERN.test(slug) ? slug : '' } export function WebsiteStaticImageSlotModal({ open, onClose, onSubmit, initial, title, submitLabel, isSubmitting = false, lockKey = false, }: WebsiteStaticImageSlotModalProps) { const t = useT() const formRef = useRef(null) const [mounted, setMounted] = useState(open) const [closing, setClosing] = useState(false) const [key, setKey] = useState(initial?.key ?? '') const [label, setLabel] = useState(initial?.label ?? '') const [kind, setKind] = useState(initial?.kind ?? 'single') const [aspectRatio, setAspectRatio] = useState(initial?.aspectRatio ?? '16:9') const [recommendedWidth, setRecommendedWidth] = useState(initial?.recommendedWidth ?? '1440') const [itemCount, setItemCount] = useState(initial?.itemCount ?? '') const [pageKey, setPageKey] = useState(initial?.pageKey ?? 'home') const [keyTouched, setKeyTouched] = useState(Boolean(initial?.key)) useEffect(() => { if (open) { setMounted(true) setClosing(false) setKey(initial?.key ?? '') setLabel(initial?.label ?? '') setKind(initial?.kind ?? 'single') setAspectRatio(initial?.aspectRatio ?? '16:9') setRecommendedWidth(initial?.recommendedWidth ?? '1440') setItemCount(initial?.itemCount ?? '') setPageKey(initial?.pageKey ?? 'home') setKeyTouched(Boolean(initial?.key) || lockKey) } else if (mounted) { setClosing(true) const timer = setTimeout(() => { setMounted(false) setClosing(false) }, ANIMATION_MS) return () => clearTimeout(timer) } }, [open, mounted, initial, lockKey]) useEffect(() => { if (!mounted || closing) return const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } document.addEventListener('keydown', onKey) return () => document.removeEventListener('keydown', onKey) }, [mounted, closing, onClose]) if (!mounted) return null function handleSubmit(e: React.FormEvent) { e.preventDefault() const nextLabel = label.trim() const nextKey = slugifyKey(key) || slugifyKey(nextLabel) if (!nextKey || !nextLabel) return onSubmit({ key: nextKey, label: nextLabel, kind, aspectRatio, recommendedWidth: recommendedWidth.trim(), itemCount: kind === 'single' ? '1' : itemCount.trim(), pageKey, }) } return createPortal(
e.target === e.currentTarget && onClose()} role="presentation" >

{title}

{ const next = e.target.value setLabel(next) if (!keyTouched && !lockKey) setKey(slugifyKey(next)) }} placeholder={t('website.staticImages.slotLabelPlaceholder')} disabled={isSubmitting} required />
{ setKeyTouched(true) setKey(e.target.value) }} placeholder="home-hero" disabled={isSubmitting || lockKey} required />
{kind === 'list' ? (
setItemCount(e.target.value.replace(/[^\d]/g, ''))} placeholder={t('website.staticImages.itemCountPlaceholder')} disabled={isSubmitting} />

{t('website.staticImages.itemCountHint')}

) : null}
setRecommendedWidth(e.target.value.replace(/[^\d]/g, ''))} placeholder="1440" disabled={isSubmitting} />
, document.body, ) }