"use client"; import { useEffect, useMemo, useRef, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { Palette, Check, Loader2, Save, Undo2, RotateCcw, ChevronRight, Pipette, } from "lucide-react"; import { apiUpdateSiteSettings } from "@/lib/api"; import { toast } from "@/lib/toast"; import { ACCENT_PRESETS, DEFAULT_ACCENT, applyAccentTheme, deriveAccentPair, findPreset, normalizeHex, } from "@/lib/theme"; // 后台「外观设置」:站点主题色预设 + 自定义取色 + 实时预览。 // 修改时立即对整页实时预览(仅本地),保存后才写库并对所有用户生效。 export default function AppearanceAdmin({ initialAccent }: { initialAccent: string }) { const router = useRouter(); // 已保存值:空串=内置默认(靛蓝) const [savedHex, setSavedHex] = useState(initialAccent || ""); const [draft, setDraft] = useState(initialAccent || DEFAULT_ACCENT); const [saving, setSaving] = useState(false); const savedRef = useRef(savedHex); savedRef.current = savedHex; const normalized = useMemo(() => normalizeHex(draft), [draft]); const pair = useMemo( () => (normalized ? deriveAccentPair(normalized) : null), [normalized] ); const preset = useMemo(() => (normalized ? findPreset(normalized) : null), [normalized]); // 保存提交值:默认靛蓝落库为空串(前端不注入覆盖,保持内置令牌单一来源) const submitHex = normalized && normalized !== DEFAULT_ACCENT ? normalized : ""; const dirty = (savedHex || DEFAULT_ACCENT) !== (normalized || ""); const invalid = draft.trim() !== "" && !normalized; // 实时预览:合法颜色即应用;离开页面时还原为已保存值,避免未保存预览残留 useEffect(() => { if (normalized) applyAccentTheme(normalized); return () => { applyAccentTheme(savedRef.current || null); }; }, [normalized]); const handleSave = async () => { if (!normalized || saving) return; setSaving(true); try { const res = await apiUpdateSiteSettings({ accent: submitHex }); const next = (res.accent || "").toLowerCase(); setSavedHex(next); applyAccentTheme(next || null); router.refresh(); toast(next ? "主题色已保存并对全站生效" : "已恢复默认主题色"); } catch (e) { toast(e instanceof Error ? e.message : "保存失败", "error"); applyAccentTheme(savedRef.current || null); } finally { setSaving(false); } }; const discard = () => { setDraft(savedHex || DEFAULT_ACCENT); applyAccentTheme(savedHex || null); }; return (
配置站点主题色,全站按钮、链接、选中态会统一联动
浅/暗两套色板均已调校,保证文字对比度达标
取色器选色或输入 HEX 值;浅色下对比度过低时会自动校正,保证按钮与文字可读
颜色格式无效,请输入 6 位 HEX 值(如 3B5BDB)
)} {pair?.adjusted && (该颜色与白底对比度不足,浅色模式已自动校正为 {pair.light}(暗色模式同步派生 {pair.dark})
)} {preset && preset.light === DEFAULT_ACCENT && (当前为内置默认色,保存时会清除自定义配置
)}{dirty ? "有未保存的改动,整页正处于实时预览状态" : "设置已是保存状态"}