style: add md styles (#9)

This commit is contained in:
BiggerRain
2024-11-14 09:39:22 +08:00
committed by GitHub
parent c6ca2988a7
commit 7618291f6f
8 changed files with 1362 additions and 26 deletions

View File

@@ -15,12 +15,15 @@
"@tauri-apps/plugin-http": "~2.0.1",
"@tauri-apps/plugin-shell": ">=2.0.0",
"@tauri-apps/plugin-websocket": "~2",
"@traptitech/markdown-it-katex": "^3.6.0",
"axios": "^1.7.7",
"clsx": "^2.1.1",
"framer-motion": "^11.11.11",
"highlight.js": "^11.10.0",
"i18next": "^23.16.2",
"lodash": "^4.17.21",
"lucide-react": "^0.453.0",
"markdown-it": "^14.1.0",
"mermaid": "^11.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -39,6 +42,7 @@
"devDependencies": {
"@tauri-apps/cli": ">=2.0.0",
"@types/lodash": "^4.17.12",
"@types/markdown-it": "^14.1.2",
"@types/node": "^22.8.4",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",

84
pnpm-lock.yaml generated
View File

@@ -23,6 +23,9 @@ importers:
'@tauri-apps/plugin-websocket':
specifier: ~2
version: 2.0.0
'@traptitech/markdown-it-katex':
specifier: ^3.6.0
version: 3.6.0
axios:
specifier: ^1.7.7
version: 1.7.7
@@ -32,6 +35,9 @@ importers:
framer-motion:
specifier: ^11.11.11
version: 11.11.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
highlight.js:
specifier: ^11.10.0
version: 11.10.0
i18next:
specifier: ^23.16.2
version: 23.16.2
@@ -41,6 +47,9 @@ importers:
lucide-react:
specifier: ^0.453.0
version: 0.453.0(react@18.3.1)
markdown-it:
specifier: ^14.1.0
version: 14.1.0
mermaid:
specifier: ^11.4.0
version: 11.4.0
@@ -90,6 +99,9 @@ importers:
'@types/lodash':
specifier: ^4.17.12
version: 4.17.12
'@types/markdown-it':
specifier: ^14.1.2
version: 14.1.2
'@types/node':
specifier: ^22.8.4
version: 22.8.4
@@ -679,6 +691,9 @@ packages:
'@tauri-apps/plugin-websocket@2.0.0':
resolution: {integrity: sha512-O2qRxZCljd4g+ceJhW7LfgQr+fg0fBBiAaLiMopoKL6TXKMnhBHOenp4nZ5/MoVTr77OQIDNO6Jp/c1YwiRVtQ==}
'@traptitech/markdown-it-katex@3.6.0':
resolution: {integrity: sha512-CnJzTWxsgLGXFdSrWRaGz7GZ1kUUi8g3E9HzJmeveX1YwVJavrKYqysktfHZQsujdnRqV5O7g8FPKEA/aeTkOQ==}
'@types/babel__core@7.20.5':
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
@@ -805,12 +820,21 @@ packages:
'@types/katex@0.16.7':
resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
'@types/linkify-it@5.0.0':
resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
'@types/lodash@4.17.12':
resolution: {integrity: sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==}
'@types/markdown-it@14.1.2':
resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==}
'@types/mdast@4.0.4':
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
'@types/mdurl@2.0.0':
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
'@types/ms@0.7.34':
resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
@@ -886,6 +910,9 @@ packages:
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
@@ -1366,6 +1393,10 @@ packages:
hastscript@8.0.0:
resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==}
highlight.js@11.10.0:
resolution: {integrity: sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==}
engines: {node: '>=12.0.0'}
highlight.js@11.9.0:
resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==}
engines: {node: '>=12.0.0'}
@@ -1487,6 +1518,9 @@ packages:
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
linkify-it@5.0.0:
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
local-pkg@0.5.0:
resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
engines: {node: '>=14'}
@@ -1518,6 +1552,10 @@ packages:
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
markdown-it@14.1.0:
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
hasBin: true
markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
@@ -1577,6 +1615,9 @@ packages:
mdast-util-to-string@4.0.0:
resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
mdurl@2.0.0:
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -1824,6 +1865,10 @@ packages:
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -2051,6 +2096,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
uc.micro@2.1.0:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
ufo@1.5.4:
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
@@ -2693,6 +2741,10 @@ snapshots:
dependencies:
'@tauri-apps/api': 2.0.2
'@traptitech/markdown-it-katex@3.6.0':
dependencies:
katex: 0.16.11
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.25.8
@@ -2853,12 +2905,21 @@ snapshots:
'@types/katex@0.16.7': {}
'@types/linkify-it@5.0.0': {}
'@types/lodash@4.17.12': {}
'@types/markdown-it@14.1.2':
dependencies:
'@types/linkify-it': 5.0.0
'@types/mdurl': 2.0.0
'@types/mdast@4.0.4':
dependencies:
'@types/unist': 3.0.3
'@types/mdurl@2.0.0': {}
'@types/ms@0.7.34': {}
'@types/node@22.8.4':
@@ -2933,6 +2994,8 @@ snapshots:
arg@5.0.2: {}
argparse@2.0.1: {}
asynckit@0.4.0: {}
autoprefixer@10.4.20(postcss@8.4.47):
@@ -3478,6 +3541,8 @@ snapshots:
property-information: 6.5.0
space-separated-tokens: 2.0.2
highlight.js@11.10.0: {}
highlight.js@11.9.0: {}
html-parse-stringify@3.0.1:
@@ -3573,6 +3638,10 @@ snapshots:
lines-and-columns@1.2.4: {}
linkify-it@5.0.0:
dependencies:
uc.micro: 2.1.0
local-pkg@0.5.0:
dependencies:
mlly: 1.7.2
@@ -3604,6 +3673,15 @@ snapshots:
dependencies:
react: 18.3.1
markdown-it@14.1.0:
dependencies:
argparse: 2.0.1
entities: 4.5.0
linkify-it: 5.0.0
mdurl: 2.0.0
punycode.js: 2.3.1
uc.micro: 2.1.0
markdown-table@3.0.4: {}
marked@13.0.3: {}
@@ -3778,6 +3856,8 @@ snapshots:
dependencies:
'@types/mdast': 4.0.4
mdurl@2.0.0: {}
merge2@1.4.1: {}
mermaid@11.4.0:
@@ -4145,6 +4225,8 @@ snapshots:
proxy-from-env@1.1.0: {}
punycode.js@2.3.1: {}
queue-microtask@1.2.3: {}
react-dom@18.3.1(react@18.3.1):
@@ -4448,6 +4530,8 @@ snapshots:
typescript@5.6.3: {}
uc.micro@2.1.0: {}
ufo@1.5.4: {}
undici-types@6.19.8: {}

View File

@@ -2,8 +2,8 @@ import { Bot, User } from "lucide-react";
import { useState } from "react";
import type { Message } from "./types";
import { TypingAnimation } from "./TypingAnimation";
// import { Markdown } from "./Markdown";
// import { TypingAnimation } from "./TypingAnimation";
import { Markdown } from "./Markdown";
interface ChatMessageProps {
message: Message;
@@ -49,19 +49,19 @@ export function ChatMessage({ message, isTyping }: ChatMessageProps) {
</p>
<div className="prose dark:prose-invert prose-sm max-w-none">
<p className="text-gray-600 dark:text-gray-300 leading-relaxed">
{isTyping && isAssistant ? (
{isAssistant ? (
<>
<TypingAnimation
{/* <TypingAnimation
text={message._source?.message || ""}
onComplete={() => setIsAnimationComplete(true)}
/>
{/* <Markdown
/> */}
<Markdown
key={isTyping ? "loading" : "done"}
content={(message._source?.message || "")}
loading={isTyping}
onDoubleClickCapture={() => {}}
/> */}
{!isAnimationComplete && (
/>
{isTyping && (
<span className="inline-block w-1.5 h-4 ml-0.5 -mb-0.5 bg-current animate-pulse" />
)}
</>

View File

@@ -1,7 +1,6 @@
import React, { useRef, useState, RefObject, useEffect, useMemo } from "react";
import clsx from "clsx";
import ReactMarkdown from "react-markdown";
// import "katex/dist/katex.min.css";
import RemarkMath from "remark-math";
import RemarkBreaks from "remark-breaks";
import RehypeKatex from "rehype-katex";
@@ -12,6 +11,10 @@ import { useDebouncedCallback } from "use-debounce";
import { copyToClipboard, useWindowSize } from "../../utils";
import "./markdown.css";
import "./highlight.css";
// 8
export function Mermaid(props: { code: string }) {
const ref = useRef<HTMLDivElement>(null);
const [hasError, setHasError] = useState(false);
@@ -228,6 +231,7 @@ function _MarkDownContent(props: { content: string }) {
return tryWrapHtmlCode(escapeBrackets(props.content));
}, [props.content]);
console.log(11212, props.content);
return (
<ReactMarkdown
remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
@@ -300,15 +304,7 @@ export function Markdown(
onDoubleClickCapture={props.onDoubleClickCapture}
dir="auto"
>
{props.loading ? (
<div className="flex gap-2 items-center text-gray-500 dark:text-gray-400">
<div className="w-2 h-2 rounded-full bg-current animate-bounce" />
<div className="w-2 h-2 rounded-full bg-current animate-bounce [animation-delay:0.2s]" />
<div className="w-2 h-2 rounded-full bg-current animate-bounce [animation-delay:0.4s]" />
</div>
) : (
<MarkdownContent content={props.content} />
)}
<MarkdownContent content={props.content} />
</div>
);
}

View File

@@ -1,8 +1,8 @@
import { useEffect, useState } from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import "./index.css";
interface TypingAnimationProps {
text: string;
onComplete?: () => void;
@@ -36,7 +36,7 @@ export function TypingAnimation({
return (
<ReactMarkdown
className="prose" // 使用 Tailwind 的 `prose` 类来美化 Markdown
className="prose"
children={text}
remarkPlugins={[remarkGfm]}
/>

View File

@@ -0,0 +1,115 @@
.markdown-body {
pre {
padding: 0;
}
pre,
code {
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
}
pre code {
display: block;
overflow-x: auto;
padding: 1em;
}
code {
padding: 3px 5px;
}
.hljs,
pre {
background: #1a1b26;
color: #cbd2ea;
}
/*!
Theme: Tokyo-night-Dark
origin: https://github.com/enkia/tokyo-night-vscode-theme
Description: Original highlight.js style
Author: (c) Henri Vandersleyen <hvandersleyen@gmail.com>
License: see project LICENSE
Touched: 2022
*/
.hljs-comment,
.hljs-meta {
color: #565f89;
}
.hljs-deletion,
.hljs-doctag,
.hljs-regexp,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-selector-pseudo,
.hljs-tag,
.hljs-template-tag,
.hljs-variable.language_ {
color: #f7768e;
}
.hljs-link,
.hljs-literal,
.hljs-number,
.hljs-params,
.hljs-template-variable,
.hljs-type,
.hljs-variable {
color: #ff9e64;
}
.hljs-attribute,
.hljs-built_in {
color: #e0af68;
}
.hljs-keyword,
.hljs-property,
.hljs-subst,
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
color: #7dcfff;
}
.hljs-selector-tag {
color: #73daca;
}
.hljs-addition,
.hljs-bullet,
.hljs-quote,
.hljs-string,
.hljs-symbol {
color: #9ece6a;
}
.hljs-code,
.hljs-formula,
.hljs-section {
color: #7aa2f7;
}
.hljs-attr,
.hljs-char.escape_,
.hljs-keyword,
.hljs-name,
.hljs-operator {
color: #bb9af7;
}
.hljs-punctuation {
color: #c0caf5;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: 700;
}
}

View File

@@ -12,7 +12,7 @@ import { ChatInput } from "./ChatInput";
import { Sidebar } from "./Sidebar";
import type { Chat, Message } from "./types";
import { useTheme } from "../ThemeProvider";
import { Footer } from "../SearchChat/Footer";
// import { Footer } from "../SearchChat/Footer";
import { tauriFetch } from "../../api/tauriFetchClient";
import { useWebSocket } from "../../hooks/useWebSocket";
@@ -286,7 +286,11 @@ export default function ChatAI({ changeMode }: ChatAIProps) {
</button>
{/* <ThemeToggle /> */}
<MessageSquarePlus className="cursor-pointer" onClick={createNewChat} />
<MessageSquarePlus
className="cursor-pointer"
onClick={createNewChat}
/>
</header>
</motion.div>
@@ -319,10 +323,9 @@ export default function ChatAI({ changeMode }: ChatAIProps) {
message: curMessage,
},
}}
isTyping={isTyping}
isTyping={!curChatEnd}
/>
) : null}
{/* Loading */}
{isTyping && (
<div className="flex pt-0 pb-4 pl-20 gap-2 items-center text-gray-500 dark:text-gray-400">
<div className="w-2 h-2 rounded-full bg-current animate-bounce" />
@@ -346,14 +349,16 @@ export default function ChatAI({ changeMode }: ChatAIProps) {
<ChatInput
onSend={handleSendMessage}
disabled={isTyping}
disabledChange={setIsTyping}
disabledChange={(value) => {
setIsTyping(value)
}}
changeMode={changeMode}
/>
</motion.div>
</div>
</div>
<Footer isChat={true} />
{/* <Footer isChat={true} /> */}
</motion.div>
);
}

File diff suppressed because it is too large Load Diff