Skip to content

Commit 66310e8

Browse files
authored
fix pre tag bg color in markdown (wavetermdev#678)
1 parent 2361154 commit 66310e8

File tree

6 files changed

+65
-192
lines changed

6 files changed

+65
-192
lines changed

src/app/common/elements/index.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ export { InlineSettingsTextEdit } from "./inlinesettingstextedit";
77
export { InputDecoration } from "./inputdecoration";
88
export { LinkButton } from "./linkbutton";
99
export { Markdown } from "./markdown";
10-
export { Markdown2 } from "./markdown2";
1110
export { Modal } from "./modal";
1211
export { PasswordField } from "./passwordfield";
1312
export { ResizableSidebar } from "./resizablesidebar";

src/app/common/elements/markdown.less

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
padding: 2px 4px 2px 6px;
4747
}
4848

49-
pre.codeblock {
49+
pre {
5050
background-color: var(--markdown-bg-color);
5151
margin: 4px 10px;
5252
padding: 0.4em 0.7em;

src/app/common/elements/markdown.tsx

+61-74
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import * as React from "react";
55
import * as mobxReact from "mobx-react";
66
import ReactMarkdown from "react-markdown";
77
import remarkGfm from "remark-gfm";
8+
import { CopyButton } from "@/elements";
89
import { clsx } from "clsx";
9-
import { GlobalModel } from "@/models";
10-
import { v4 as uuidv4 } from "uuid";
10+
import * as mobx from "mobx";
11+
import { If } from "tsx-control-statements/components";
1112

1213
import "./markdown.less";
13-
import { boundMethod } from "autobind-decorator";
1414

15-
function LinkRenderer(props: any): any {
15+
function Link(props: any): JSX.Element {
1616
let newUrl = "https://extern?" + encodeURIComponent(props.href);
1717
return (
1818
<a href={newUrl} target="_blank" rel={"noopener"}>
@@ -21,99 +21,86 @@ function LinkRenderer(props: any): any {
2121
);
2222
}
2323

24-
function HeaderRenderer(props: any, hnum: number): any {
24+
function Header(props: any, hnum: number): JSX.Element {
2525
return <div className={clsx("title", "is-" + hnum)}>{props.children}</div>;
2626
}
2727

28-
function CodeRenderer(props: any): any {
28+
function Code(props: any): JSX.Element {
2929
return <code>{props.children}</code>;
3030
}
3131

32-
@mobxReact.observer
33-
class CodeBlockMarkdown extends React.Component<
34-
{ children: React.ReactNode; codeSelectSelectedIndex?: number; uuid: string },
35-
{}
36-
> {
37-
blockIndex: number;
38-
blockRef: React.RefObject<HTMLPreElement>;
32+
const CodeBlock = mobxReact.observer(
33+
(props: { children: React.ReactNode; onClickExecute?: (cmd: string) => void }): JSX.Element => {
34+
const copied: OV<boolean> = mobx.observable.box(false, { name: "copied" });
3935

40-
constructor(props) {
41-
super(props);
42-
this.blockRef = React.createRef();
43-
this.blockIndex = GlobalModel.inputModel.addCodeBlockToCodeSelect(this.blockRef, this.props.uuid);
44-
}
36+
const getTextContent = (children: any) => {
37+
if (typeof children === "string") {
38+
return children;
39+
} else if (Array.isArray(children)) {
40+
return children.map(getTextContent).join("");
41+
} else if (children.props && children.props.children) {
42+
return getTextContent(children.props.children);
43+
}
44+
return "";
45+
};
4546

46-
render() {
47-
let clickHandler: (e: React.MouseEvent<HTMLElement>, blockIndex: number) => void;
48-
let inputModel = GlobalModel.inputModel;
49-
clickHandler = (e: React.MouseEvent<HTMLElement>, blockIndex: number) => {
50-
const sel = window.getSelection();
51-
if (sel?.toString().length == 0) {
52-
inputModel.setCodeSelectSelectedCodeBlock(blockIndex);
47+
const handleCopy = async (e: React.MouseEvent) => {
48+
let textToCopy = getTextContent(props.children);
49+
textToCopy = textToCopy.replace(/\n$/, ""); // remove trailing newline
50+
await navigator.clipboard.writeText(textToCopy);
51+
copied.set(true);
52+
setTimeout(() => copied.set(false), 2000); // Reset copied state after 2 seconds
53+
};
54+
55+
const handleExecute = (e: React.MouseEvent) => {
56+
let textToCopy = getTextContent(props.children);
57+
textToCopy = textToCopy.replace(/\n$/, ""); // remove trailing newline
58+
if (props.onClickExecute) {
59+
props.onClickExecute(textToCopy);
60+
return;
5361
}
5462
};
55-
let selected = this.blockIndex == this.props.codeSelectSelectedIndex;
63+
5664
return (
57-
<pre
58-
ref={this.blockRef}
59-
className={clsx({ selected: selected })}
60-
onClick={(event) => clickHandler(event, this.blockIndex)}
61-
>
62-
{this.props.children}
65+
<pre className="codeblock">
66+
{props.children}
67+
<div className="codeblock-actions">
68+
<CopyButton className="copy-button" onClick={handleCopy} title="Copy" />
69+
<If condition={props.onClickExecute}>
70+
<i className="fa-regular fa-square-terminal" onClick={handleExecute}></i>
71+
</If>
72+
</div>
6373
</pre>
6474
);
6575
}
66-
}
76+
);
6777

6878
@mobxReact.observer
6979
class Markdown extends React.Component<
70-
{ text: string; style?: any; extraClassName?: string; codeSelect?: boolean },
80+
{
81+
text: string;
82+
style?: any;
83+
className?: string;
84+
onClickExecute?: (cmd: string) => void;
85+
},
7186
{}
7287
> {
73-
curUuid: string;
74-
75-
constructor(props) {
76-
super(props);
77-
this.curUuid = uuidv4();
78-
}
79-
80-
@boundMethod
81-
CodeBlockRenderer(props: any, codeSelect: boolean, codeSelectIndex: number, curUuid: string): any {
82-
if (codeSelect) {
83-
return (
84-
<CodeBlockMarkdown codeSelectSelectedIndex={codeSelectIndex} uuid={curUuid}>
85-
{props.children}
86-
</CodeBlockMarkdown>
87-
);
88-
} else {
89-
const clickHandler = (e: React.MouseEvent<HTMLElement>) => {
90-
let blockText = (e.target as HTMLElement).innerText;
91-
if (blockText) {
92-
blockText = blockText.replace(/\n$/, ""); // remove trailing newline
93-
navigator.clipboard.writeText(blockText);
94-
}
95-
};
96-
return <pre onClick={(event) => clickHandler(event)}>{props.children}</pre>;
97-
}
98-
}
99-
10088
render() {
101-
let text = this.props.text;
102-
let codeSelect = this.props.codeSelect;
103-
let curCodeSelectIndex = GlobalModel.inputModel.getCodeSelectSelectedIndex();
89+
let { text, className, onClickExecute } = this.props;
10490
let markdownComponents = {
105-
a: LinkRenderer,
106-
h1: (props) => HeaderRenderer(props, 1),
107-
h2: (props) => HeaderRenderer(props, 2),
108-
h3: (props) => HeaderRenderer(props, 3),
109-
h4: (props) => HeaderRenderer(props, 4),
110-
h5: (props) => HeaderRenderer(props, 5),
111-
h6: (props) => HeaderRenderer(props, 6),
112-
code: (props) => CodeRenderer(props),
113-
pre: (props) => this.CodeBlockRenderer(props, codeSelect, curCodeSelectIndex, this.curUuid),
91+
a: Link,
92+
h1: (props) => <Header {...props} hnum={1} />,
93+
h2: (props) => <Header {...props} hnum={2} />,
94+
h3: (props) => <Header {...props} hnum={3} />,
95+
h4: (props) => <Header {...props} hnum={4} />,
96+
h5: (props) => <Header {...props} hnum={5} />,
97+
h6: (props) => <Header {...props} hnum={6} />,
98+
code: Code,
99+
pre: (props) => <CodeBlock {...props} onClickExecute={onClickExecute} />,
114100
};
101+
115102
return (
116-
<div className={clsx("markdown content", this.props.extraClassName)} style={this.props.style}>
103+
<div className={clsx("markdown content", className)} style={this.props.style}>
117104
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
118105
{text}
119106
</ReactMarkdown>

src/app/common/elements/markdown2.tsx

-112
This file was deleted.

src/app/sidebar/aichat.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as mobx from "mobx";
77
import { GlobalModel } from "@/models";
88
import { boundMethod } from "autobind-decorator";
99
import { For, If } from "tsx-control-statements/components";
10-
import { Markdown2, TypingIndicator } from "@/elements";
10+
import { Markdown, TypingIndicator } from "@/elements";
1111
import type { OverlayScrollbars } from "overlayscrollbars";
1212
import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react";
1313
import tinycolor from "tinycolor2";
@@ -72,7 +72,7 @@ class ChatItem extends React.Component<
7272
<div className="chat-msg-header">
7373
<i className="fa-sharp fa-solid fa-user"></i>
7474
</div>
75-
<Markdown2 className="msg-text" text={chatItem.userquery} />
75+
<Markdown className="msg-text" text={chatItem.userquery} />
7676
</>
7777
);
7878
if (isassistantresponse) {
@@ -94,7 +94,7 @@ class ChatItem extends React.Component<
9494
<div className="chat-msg-header">
9595
<i className="fa-sharp fa-solid fa-sparkles"></i>
9696
</div>
97-
<Markdown2 text={assistantresponse.message} onClickExecute={onSetCmdInputValue} />
97+
<Markdown text={assistantresponse.message} onClickExecute={onSetCmdInputValue} />
9898
</>
9999
);
100100
}

src/plugins/markdown/markdown.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import * as mobx from "mobx";
66
import * as mobxReact from "mobx-react";
77
import { sprintf } from "sprintf-js";
88
import { Markdown } from "@/elements";
9-
import { GlobalModel } from "@/models/global";
109

1110
import "./markdown.less";
1211

0 commit comments

Comments
 (0)