"use client"; import { useEffect, useState } from "react"; import type { EdgeKind, NodeKind } from "@/lib/graph/types"; /** Design tokens resolved from CSS variables so the canvas follows light/dark mode (oklch strings are valid canvas colours). */ export interface ThemeColors { bg: string; bgElev: string; fg: string; fgMuted: string; fgFaint: string; line: string; lineStrong: string; accent: string; ai: string; success: string; warning: string; danger: string; font: string } const DEFAULTS: ThemeColors = { bg: "#fcfcfb", bgElev: "#ffffff", fg: "#1f2330", fgMuted: "#6b7080", fgFaint: "#a0a4b0", line: "#e6e7ea", lineStrong: "#cfd1d6", accent: "#4a63d6", ai: "#8a5bd6", success: "#3f9a65", warning: "#d9a63f", danger: "#d14b3a", font: "Inter, system-ui, sans-serif" }; export function readThemeColors(): ThemeColors { if (typeof window === "undefined") return DEFAULTS; const s = getComputedStyle(document.documentElement); const v = (n: string, fb: string) => s.getPropertyValue(n).trim() || fb; return { bg: v("--bg", DEFAULTS.bg), bgElev: v("--bg-elev", DEFAULTS.bgElev), fg: v("--fg", DEFAULTS.fg), fgMuted: v("--fg-muted", DEFAULTS.fgMuted), fgFaint: v("--fg-faint", DEFAULTS.fgFaint), line: v("--line", DEFAULTS.line), lineStrong: v("--line-strong", DEFAULTS.lineStrong), accent: v("--accent", DEFAULTS.accent), ai: v("--ai", DEFAULTS.ai), success: v("--success", DEFAULTS.success), warning: v("--warning", DEFAULTS.warning), danger: v("--danger", DEFAULTS.danger), font: v("--font-sans", DEFAULTS.font) }; } export function useThemeColors(): ThemeColors { const [c, setC] = useState(DEFAULTS); useEffect(() => { setC(readThemeColors()); const mo = new MutationObserver(() => setC(readThemeColors())); mo.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] }); return () => mo.disconnect(); }, []); return c; } export const kindColor = (c: ThemeColors, kind: NodeKind) => ({ page: c.accent, database: c.success, research: c.ai, row: c.warning, attachment: c.fgMuted, tag: c.fgFaint })[kind] ?? c.accent; export const edgeColor = (c: ThemeColors, kind: EdgeKind, suggested: boolean) => (suggested ? c.ai : kind === "relation" ? c.success : kind === "link" ? c.lineStrong : c.line); /** Tailwind classes matching kindColor, for legends/badges. */ export const KIND_CLASS: Record = { page: "bg-accent", database: "bg-success", research: "bg-ai", row: "bg-warning", attachment: "bg-fg-muted", tag: "bg-fg-faint" };