"use client"; import { useState, useRef, useEffect, useMemo } from "react"; import { SectionEditor } from "../_components/SectionEditor"; import { InputField, TextareaField } from "../_components/FormField"; import { ArrayEditor } from "../_components/ArrayEditor"; import { icons, type LucideIcon } from "lucide-react"; // PascalCase "HeartPulse" → kebab "heart-pulse" function toKebab(name: string) { return name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); } // All icons as { key: kebab-name, Icon: component, label: PascalCase } const ALL_ICONS = Object.entries(icons).map(([name, Icon]) => ({ key: toKebab(name), Icon: Icon as LucideIcon, label: name, })); const ICON_BY_KEY = Object.fromEntries(ALL_ICONS.map((i) => [i.key, i])); function IconPicker({ value, onChange, }: { value: string; onChange: (v: string) => void; }) { const [open, setOpen] = useState(false); const [search, setSearch] = useState(""); const ref = useRef(null); const inputRef = useRef(null); const selected = ICON_BY_KEY[value]; useEffect(() => { if (!open) return; function handle(e: MouseEvent) { if (ref.current && !ref.current.contains(e.target as Node)) { setOpen(false); setSearch(""); } } document.addEventListener("mousedown", handle); return () => document.removeEventListener("mousedown", handle); }, [open]); const filtered = useMemo(() => { if (!search) return ALL_ICONS.slice(0, 60); const q = search.toLowerCase(); return ALL_ICONS.filter((i) => i.label.toLowerCase().includes(q)).slice(0, 60); }, [search]); const SelectedIcon = selected?.Icon; return (
{open && (
setSearch(e.target.value)} placeholder="Поиск иконки... (flame, heart, star...)" className="w-full rounded-md border border-white/10 bg-neutral-900 px-3 py-1.5 text-sm text-white outline-none focus:border-gold/50 placeholder:text-neutral-600" />
{filtered.length === 0 ? (
Ничего не найдено
) : (
{filtered.map(({ key, Icon, label }) => ( ))}
)}
)}
); } const COLOR_SWATCHES: { value: string; bg: string }[] = [ { value: "rose", bg: "bg-rose-500" }, { value: "orange", bg: "bg-orange-500" }, { value: "amber", bg: "bg-amber-500" }, { value: "yellow", bg: "bg-yellow-400" }, { value: "lime", bg: "bg-lime-500" }, { value: "emerald", bg: "bg-emerald-500" }, { value: "teal", bg: "bg-teal-500" }, { value: "cyan", bg: "bg-cyan-500" }, { value: "sky", bg: "bg-sky-500" }, { value: "blue", bg: "bg-blue-500" }, { value: "indigo", bg: "bg-indigo-500" }, { value: "violet", bg: "bg-violet-500" }, { value: "purple", bg: "bg-purple-500" }, { value: "fuchsia", bg: "bg-fuchsia-500" }, { value: "pink", bg: "bg-pink-500" }, { value: "red", bg: "bg-red-500" }, ]; interface ClassesData { title: string; items: { name: string; description: string; icon: string; detailedDescription?: string; images?: string[]; color?: string; }[]; } export default function ClassesEditorPage() { return ( sectionKey="classes" title="Направления"> {(data, update) => ( <> update({ ...data, title: v })} /> update({ ...data, items })} renderItem={(item, _i, updateItem) => (
updateItem({ ...item, name: v })} /> updateItem({ ...item, icon: v })} />
{COLOR_SWATCHES.map((c) => { const isUsed = data.items.some( (other) => other !== item && other.color === c.value ); if (isUsed) return null; return (
updateItem({ ...item, description: v })} rows={2} /> updateItem({ ...item, detailedDescription: v }) } rows={4} />
)} createItem={() => ({ name: "", description: "", icon: "sparkles", detailedDescription: "", images: [], })} addLabel="Добавить направление" /> )} ); }