mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-24 18:42:35 +00:00
fix(webui): sync code block theme with dark mode toggle instantly
- Replace one-time DOM read with MutationObserver on <html> class - Remove hardcoded #0a0a0a background, let oneDark/oneLight own it - Add light-mode header/copy-button colors (bg-zinc-100 for light) - Bump font size from 13px to 14px, line-height from 1.55 to 1.6 - Add subtle border to distinguish code block edges
This commit is contained in:
parent
a7caee1186
commit
375b1f0328
@ -1,4 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { Check, Copy } from "lucide-react";
|
import { Check, Copy } from "lucide-react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||||
@ -15,33 +15,67 @@ interface CodeBlockProps {
|
|||||||
className?: string;
|
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) {
|
export function CodeBlock({ language, code, className }: CodeBlockProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
|
const isDark = useIsDark();
|
||||||
|
|
||||||
const onCopy = () => {
|
const onCopy = useCallback(() => {
|
||||||
if (!navigator.clipboard) return;
|
if (!navigator.clipboard) return;
|
||||||
navigator.clipboard.writeText(code).then(() => {
|
navigator.clipboard.writeText(code).then(() => {
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
setTimeout(() => setCopied(false), 1_500);
|
setTimeout(() => setCopied(false), 1_500);
|
||||||
});
|
});
|
||||||
};
|
}, [code]);
|
||||||
|
|
||||||
const isDark =
|
|
||||||
typeof window !== "undefined"
|
|
||||||
? document.documentElement.classList.contains("dark")
|
|
||||||
: true;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("overflow-hidden rounded-lg", className)}>
|
<div
|
||||||
<div className="flex items-center justify-between bg-zinc-900 px-4 py-1.5 text-xs font-medium text-zinc-200">
|
className={cn(
|
||||||
<span className="lowercase">
|
"overflow-hidden rounded-lg border",
|
||||||
|
isDark ? "border-white/10" : "border-black/10",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex items-center justify-between px-4 py-1.5 text-xs font-medium",
|
||||||
|
isDark
|
||||||
|
? "bg-zinc-800 text-zinc-300"
|
||||||
|
: "bg-zinc-100 text-zinc-600",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className="lowercase font-mono">
|
||||||
{language || t("code.fallbackLanguage")}
|
{language || t("code.fallbackLanguage")}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onCopy}
|
onClick={onCopy}
|
||||||
className="inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-zinc-300 transition-colors hover:bg-zinc-800 hover:text-zinc-100"
|
className={cn(
|
||||||
|
"inline-flex items-center gap-1 rounded px-1.5 py-0.5 font-mono transition-colors",
|
||||||
|
isDark
|
||||||
|
? "text-zinc-400 hover:bg-zinc-700 hover:text-zinc-200"
|
||||||
|
: "text-zinc-500 hover:bg-zinc-200 hover:text-zinc-700",
|
||||||
|
)}
|
||||||
aria-label={t("code.copyAria")}
|
aria-label={t("code.copyAria")}
|
||||||
>
|
>
|
||||||
{copied ? (
|
{copied ? (
|
||||||
@ -58,9 +92,8 @@ export function CodeBlock({ language, code, className }: CodeBlockProps) {
|
|||||||
customStyle={{
|
customStyle={{
|
||||||
margin: 0,
|
margin: 0,
|
||||||
padding: "1rem",
|
padding: "1rem",
|
||||||
background: "var(--tw-prose-pre-bg, #0a0a0a)",
|
fontSize: "0.875rem",
|
||||||
fontSize: "0.8125rem",
|
lineHeight: 1.6,
|
||||||
lineHeight: 1.55,
|
|
||||||
}}
|
}}
|
||||||
PreTag="pre"
|
PreTag="pre"
|
||||||
wrapLongLines
|
wrapLongLines
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user