"use client"; import { useEffect, useState } from "react"; import { useTheme, DARK_SURFACES } from "./theme-provider"; import { getGroupColor, getThemedGroupColor, type GroupColor } from "@/lib/colors"; // The themes whose *surfaces* are dark (see app/globals.css) come from the // provider's single source of truth -- currently Dark, Ocean, Pine, Plum, // Midnight, Ember, Rosewood. Anything that used to compare // `resolvedTheme === "dark"` to pick a color variant (group card // fills/strokes, markdown widget color modes, ...) uses this instead. function useMounted(): boolean { const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); return mounted; } /** * True when the active theme has dark surfaces (Dark, Ocean, Pine, Plum, * Midnight, Ember, Rosewood, Cyberpunk). * * Reactive to UI theme switches: the value is derived from the provider's * `resolvedTheme` -- the single source of truth for what's actually * applied, including a project's scoped theme (see theme-provider) -- so * the moment `setTheme` fires (or a scope lifts), every consumer * re-renders with the new variant in the same commit: no stale card * colors, no manual refresh needed. * * Hydration-safe: until mounted we always report "light", matching the * server render (the no-FOUC script in app/layout.tsx covers the CSS side * of that first frame). */ export function isDarkTheme(): boolean { const mounted = useMounted(); const { resolvedTheme } = useTheme(); if (!mounted) return false; return DARK_SURFACES.includes(resolvedTheme); } /** True when the "cyberpunk" theme is active. Used to swap the neon * color palette onto group cards only for that theme. */ export function isCyberpunkTheme(): boolean { const mounted = useMounted(); const { resolvedTheme } = useTheme(); if (!mounted) return false; return resolvedTheme === "cyberpunk"; } /** * The group color for the active theme. Themes with their own palette * (cyberpunk, blueprint, vaporwave, notebook, starfield -- see * lib/colors.ts) get theirs; everything else gets the base color. Same * contract as isDarkTheme: reactive to theme switches (derived from the * provider's state, so a setTheme re-renders every consumer in the same * commit) and hydration-safe (until mounted we report the base color, * matching the server render). */ export function useGroupColor(key: string): GroupColor { const mounted = useMounted(); const { resolvedTheme } = useTheme(); if (!mounted) return getGroupColor(key); return getThemedGroupColor(resolvedTheme, key); } /** * The `data-color-mode` value the markdown editor/preview widgets expect. * They only understand light/dark, so the light looks (default, sunset, * meadow, honey, rose, lavender, slate) report as light and the dark looks * report as dark. */ export function colorModeFromTheme(): "light" | "dark" { return isDarkTheme() ? "dark" : "light"; }