diff --git a/webui/src/components/CodeBlock.tsx b/webui/src/components/CodeBlock.tsx index 68032d29b..c19a78645 100644 --- a/webui/src/components/CodeBlock.tsx +++ b/webui/src/components/CodeBlock.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { Check, Copy } from "lucide-react"; import { useTranslation } from "react-i18next"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; @@ -15,33 +15,67 @@ interface CodeBlockProps { className?: string; } +/** Read dark mode straight from the DOM — stays in sync with Tailwind's `dark:`. */ +function useIsDark() { + const [isDark, setIsDark] = useState(() => + typeof document !== "undefined" + ? document.documentElement.classList.contains("dark") + : true, + ); + + useEffect(() => { + const el = document.documentElement; + const observer = new MutationObserver(() => { + setIsDark(el.classList.contains("dark")); + }); + observer.observe(el, { attributeFilter: ["class"] }); + return () => observer.disconnect(); + }, []); + + return isDark; +} + export function CodeBlock({ language, code, className }: CodeBlockProps) { const { t } = useTranslation(); const [copied, setCopied] = useState(false); + const isDark = useIsDark(); - const onCopy = () => { + const onCopy = useCallback(() => { if (!navigator.clipboard) return; navigator.clipboard.writeText(code).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1_500); }); - }; - - const isDark = - typeof window !== "undefined" - ? document.documentElement.classList.contains("dark") - : true; + }, [code]); return ( -
-
- +
+
+ {language || t("code.fallbackLanguage")}