From 1f05f259d0bade092307f3ee9825f0126d880529 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Tue, 2 Jun 2026 22:44:46 +0800 Subject: [PATCH] =?UTF-8?q?fix(chat):=20=E4=BF=AE=E5=A4=8D=E6=9A=97?= =?UTF-8?q?=E9=BB=91=E6=A8=A1=E5=BC=8F=E4=B8=8B=20Markdown=20=E5=92=8C?= =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E6=9D=A1=E6=A0=B7=E5=BC=8F=20=E2=80=94=20?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E5=BC=8F=20useIsDark=20hook=20+=20=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E4=B8=BB=E9=A2=98=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- skills-lock.json | 6 ++-- .../components/chat/ChatScrollArea.tsx | 7 ++++- .../chat/parts/CodeBlockWithCopy.tsx | 31 +++++++++++++++++-- .../components/chat/parts/TextPart.tsx | 5 ++- src/web/css.d.ts | 3 ++ src/web/hooks/use-is-dark.ts | 6 ++++ src/web/styles.css | 27 +++++++++++++--- 7 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 src/web/hooks/use-is-dark.ts diff --git a/skills-lock.json b/skills-lock.json index e221d31..89040ed 100644 --- a/skills-lock.json +++ b/skills-lock.json @@ -5,19 +5,19 @@ "source": "vercel/ai", "sourceType": "github", "skillPath": "skills/use-ai-sdk/SKILL.md", - "computedHash": "c99d2a95b3a5f8fad218f288503f9e724ba0f12bf4e8aaf2c792a9f2bc318ab6" + "computedHash": "2249889eb47ef0f61c4dba4cf2afe01c1c8dd793bb4c24230347c1ab909bb7dd" }, "ant-design": { "source": "ant-design/antd-skill", "sourceType": "github", "skillPath": "skills/ant-design/SKILL.md", - "computedHash": "096d4ac9513e43030f960aab49b50168a3d5eb35be86926ac6e96e5998ea9466" + "computedHash": "4d0447d48fced080b2825ecc0fb4d7ca836c8015882899c643acca0b864d5179" }, "antd": { "source": "ant-design/antd-skill", "sourceType": "github", "skillPath": "skills/antd/SKILL.md", - "computedHash": "5e26c8042060bb811118927b5daf637af7929a00fa973dd8f5f804f3ba6e2bf2" + "computedHash": "4295010f09f85855cab9e9de9ec7f96c14541474b4f3f9d6ef89006430931b94" }, "x-components": { "source": "ant-design/x", diff --git a/src/web/consoles/workbench/components/chat/ChatScrollArea.tsx b/src/web/consoles/workbench/components/chat/ChatScrollArea.tsx index ce1c357..7ce3122 100644 --- a/src/web/consoles/workbench/components/chat/ChatScrollArea.tsx +++ b/src/web/consoles/workbench/components/chat/ChatScrollArea.tsx @@ -6,6 +6,7 @@ import "overlayscrollbars/styles/overlayscrollbars.css"; import { OverlayScrollbarsComponent, type OverlayScrollbarsComponentRef } from "overlayscrollbars-react"; import { useCallback, useRef, useState } from "react"; +import { useIsDark } from "../../../../hooks/use-is-dark"; import { useChatScroll } from "./use-chat-scroll"; interface ChatScrollAreaProps { @@ -18,6 +19,7 @@ export function ChatScrollArea({ children, messages, status }: ChatScrollAreaPro const scrollRef = useRef(null); const osRef = useRef(null); const [viewportElement, setViewportElement] = useState(null); + const isDark = useIsDark(); const handleOsInitialized = useCallback(() => { const os = osRef.current; @@ -38,7 +40,10 @@ export function ChatScrollArea({ children, messages, status }: ChatScrollAreaPro events={{ initialized: handleOsInitialized }} options={{ overflow: { x: "hidden", y: "scroll" }, - scrollbars: { autoHide: "move", theme: "os-theme-custom" }, + scrollbars: { + autoHide: "move", + theme: isDark ? "os-theme-custom-dark" : "os-theme-custom", + }, }} ref={osRef} > diff --git a/src/web/consoles/workbench/components/chat/parts/CodeBlockWithCopy.tsx b/src/web/consoles/workbench/components/chat/parts/CodeBlockWithCopy.tsx index 8875950..8cbff14 100644 --- a/src/web/consoles/workbench/components/chat/parts/CodeBlockWithCopy.tsx +++ b/src/web/consoles/workbench/components/chat/parts/CodeBlockWithCopy.tsx @@ -2,6 +2,27 @@ import { CopyOutlined } from "@ant-design/icons"; import { CodeHighlighter } from "@ant-design/x"; import { App, Button, Flex, Typography } from "antd"; import React from "react"; +import { oneDark, oneLight } from "react-syntax-highlighter/dist/esm/styles/prism"; + +import { useIsDark } from "../../../../../hooks/use-is-dark"; + +type SyntaxTheme = Record>; + +const customOneDark: SyntaxTheme = { + ...(oneDark as SyntaxTheme), + 'pre[class*="language-"]': { + ...(oneDark as SyntaxTheme)['pre[class*="language-"]'], + margin: 0, + }, +}; + +const customOneLight: SyntaxTheme = { + ...(oneLight as SyntaxTheme), + 'pre[class*="language-"]': { + ...(oneLight as SyntaxTheme)['pre[class*="language-"]'], + margin: 0, + }, +}; interface CodeBlockWithCopyProps { block?: boolean; @@ -13,14 +34,14 @@ interface CodeBlockWithCopyProps { export function CodeBlockWithCopy({ block, children, className, lang }: CodeBlockWithCopyProps) { const { message } = App.useApp(); + const isDark = useIsDark(); if (!block) { return {children}; } const codeText = extractText(children); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const displayLang = lang || "plaintext"; + const displayLang = lang ?? "plaintext"; const handleCopy = () => { void navigator.clipboard.writeText(codeText).then(() => { @@ -44,7 +65,11 @@ export function CodeBlockWithCopy({ block, children, className, lang }: CodeBloc ); return ( - + {codeText} ); diff --git a/src/web/consoles/workbench/components/chat/parts/TextPart.tsx b/src/web/consoles/workbench/components/chat/parts/TextPart.tsx index 32541db..2c9b4cd 100644 --- a/src/web/consoles/workbench/components/chat/parts/TextPart.tsx +++ b/src/web/consoles/workbench/components/chat/parts/TextPart.tsx @@ -1,9 +1,11 @@ import { XMarkdown } from "@ant-design/x-markdown"; +import "@ant-design/x-markdown/themes/dark.css"; import "@ant-design/x-markdown/themes/light.css"; import { Typography } from "antd"; import type { PartProps } from "./types"; +import { useIsDark } from "../../../../../hooks/use-is-dark"; import { CodeBlockWithCopy } from "./CodeBlockWithCopy"; interface TextPartProps extends PartProps { @@ -18,6 +20,7 @@ const xmarkdownComponents = { export function TextPart({ isStreaming, part, role }: TextPartProps) { const text = typeof part["text"] === "string" ? part["text"] : ""; + const isDark = useIsDark(); return (
@@ -25,7 +28,7 @@ export function TextPart({ isStreaming, part, role }: TextPartProps) { {text} ) : (