50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
import { useTheme, resolveTheme, DARK_SURFACES } from "./theme-provider";
|
|
|
|
// 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).
|
|
*
|
|
* Reactive to UI theme switches: the value is derived from the provider's
|
|
* theme state (the single source of truth), so the moment `setTheme` fires,
|
|
* 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 { theme } = useTheme();
|
|
if (!mounted) return false;
|
|
return DARK_SURFACES.includes(resolveTheme(theme));
|
|
}
|
|
|
|
/**
|
|
* 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";
|
|
}
|