"use client"; import { useTranslations } from "next-intl"; import { useRef, useState } from "react"; import { applyPresetManager, applyTheme, clearBackground, deleteTheme, importTheme, renameTheme, saveBackground, saveCurrentTheme, uploadBackground, } from "@/actions/theme-manager"; import { Button } from "@/components/ui/button"; import { BACKGROUND_POSITIONS, BACKGROUND_REPEATS, BACKGROUND_SIZES, } from "@/lib/theme-bg"; import type { CustomTheme } from "@/lib/theme-custom-store"; import { serializeThemeExport, swatchColors } from "@/lib/theme-manager-format"; import { PRESETS } from "@/lib/theme-presets"; export type ThemeManagerBackground = { image: string; position: string; size: string; repeat: string; }; interface ThemeManagerPanelProps { themes: CustomTheme[]; current: Record; background: ThemeManagerBackground; activeName: string; notice?: string; } const PRESET_SWATCH_KEYS = [ "color_primary", "color_accent", "color_surface", "color_text", ] as const; function safeFileStem(name: string): string { return (name.trim().replace(/[^a-zA-Z0-9-_]+/g, "-") || "theme").slice(0, 60); } function downloadJson(name: string, settings: Record) { const blob = new Blob([serializeThemeExport(name, settings)], { type: "application/json", }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `${safeFileStem(name)}.atom-theme.json`; a.click(); URL.revokeObjectURL(url); } function Swatches({ settings, size = 16, }: { settings: Record; size?: number; }) { return (
{swatchColors(settings).map((color) => ( ))}
); } function RenameInline({ theme }: { theme: CustomTheme }) { const t = useTranslations( "pages.housekeeping.domains.hotel.routes.themeManager", ); const [editing, setEditing] = useState(false); const [val, setVal] = useState(theme.name); if (!editing) { return ( ); } return (
setVal(e.target.value)} className="w-28 px-1.5 py-0.5 rounded-md border bg-[var(--admin-canvas)] text-[var(--admin-text)] text-xs" style={{ borderColor: "var(--admin-border)" }} />
); } export function ThemeManagerPanel({ themes, current, background, activeName, notice, }: ThemeManagerPanelProps) { const t = useTranslations( "pages.housekeeping.domains.hotel.routes.themeManager", ); const [saveName, setSaveName] = useState(""); const [importName, setImportName] = useState(""); const [importError, setImportError] = useState(false); const uploadFormRef = useRef(null); const noticeKey = notice as | "saved" | "applied" | "renamed" | "deleted" | "imported" | "preset" | "background" | "importError" | "backgroundError" | undefined; return (
{noticeKey ? (
{t(`notice.${noticeKey}`)}
) : null}

{t("currentThemeTitle")}

{t("currentThemeHint")}

{activeName}
setSaveName(e.target.value)} placeholder={t("savePlaceholder")} className="px-3 py-2 rounded-lg border bg-[var(--admin-canvas)] text-sm text-[var(--admin-text)] w-56" style={{ borderColor: "var(--admin-border)" }} />

{t("savedThemesTitle")}

{t("savedThemesHint")}

{themes.length === 0 ? (

{t("noThemes")}

) : (
{themes.map((theme) => { const active = theme.name === activeName; return (
{active ? ( {t("active")} ) : null}
{theme.name}
{ if ( !window.confirm( t("deleteConfirm", { name: theme.name }), ) ) e.preventDefault(); }} >
); })}
)}

{t("importTitle")}

{t("importHint")}

{importError ? (

{t("invalidFile")}

) : null}

{t("presetsTitle")}

{Object.entries(PRESETS).map(([name, palette]) => (
))}

{t("backgroundTitle")}

{t("backgroundHint")}

{t("backgroundPreviewLabel")}

{background.image ? (
) : null}
); }