fix pre tag bg color in markdown (#678)

This commit is contained in:
Red J Adaya
2024-06-14 10:00:53 -07:00
committed by GitHub
parent 2361154551
commit 66310e8bfb
6 changed files with 65 additions and 192 deletions
-1
View File
@@ -7,7 +7,6 @@ export { InlineSettingsTextEdit } from "./inlinesettingstextedit";
export { InputDecoration } from "./inputdecoration";
export { LinkButton } from "./linkbutton";
export { Markdown } from "./markdown";
export { Markdown2 } from "./markdown2";
export { Modal } from "./modal";
export { PasswordField } from "./passwordfield";
export { ResizableSidebar } from "./resizablesidebar";
+1 -1
View File
@@ -46,7 +46,7 @@
padding: 2px 4px 2px 6px;
}
pre.codeblock {
pre {
background-color: var(--markdown-bg-color);
margin: 4px 10px;
padding: 0.4em 0.7em;
+61 -74
View File
@@ -5,14 +5,14 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { CopyButton } from "@/elements";
import { clsx } from "clsx";
import { GlobalModel } from "@/models";
import { v4 as uuidv4 } from "uuid";
import * as mobx from "mobx";
import { If } from "tsx-control-statements/components";
import "./markdown.less";
import { boundMethod } from "autobind-decorator";
function LinkRenderer(props: any): any {
function Link(props: any): JSX.Element {
let newUrl = "https://extern?" + encodeURIComponent(props.href);
return (
<a href={newUrl} target="_blank" rel={"noopener"}>
@@ -21,99 +21,86 @@ function LinkRenderer(props: any): any {
);
}
function HeaderRenderer(props: any, hnum: number): any {
function Header(props: any, hnum: number): JSX.Element {
return <div className={clsx("title", "is-" + hnum)}>{props.children}</div>;
}
function CodeRenderer(props: any): any {
function Code(props: any): JSX.Element {
return <code>{props.children}</code>;
}
@mobxReact.observer
class CodeBlockMarkdown extends React.Component<
{ children: React.ReactNode; codeSelectSelectedIndex?: number; uuid: string },
{}
> {
blockIndex: number;
blockRef: React.RefObject<HTMLPreElement>;
const CodeBlock = mobxReact.observer(
(props: { children: React.ReactNode; onClickExecute?: (cmd: string) => void }): JSX.Element => {
const copied: OV<boolean> = mobx.observable.box(false, { name: "copied" });
constructor(props) {
super(props);
this.blockRef = React.createRef();
this.blockIndex = GlobalModel.inputModel.addCodeBlockToCodeSelect(this.blockRef, this.props.uuid);
}
const getTextContent = (children: any) => {
if (typeof children === "string") {
return children;
} else if (Array.isArray(children)) {
return children.map(getTextContent).join("");
} else if (children.props && children.props.children) {
return getTextContent(children.props.children);
}
return "";
};
render() {
let clickHandler: (e: React.MouseEvent<HTMLElement>, blockIndex: number) => void;
let inputModel = GlobalModel.inputModel;
clickHandler = (e: React.MouseEvent<HTMLElement>, blockIndex: number) => {
const sel = window.getSelection();
if (sel?.toString().length == 0) {
inputModel.setCodeSelectSelectedCodeBlock(blockIndex);
const handleCopy = async (e: React.MouseEvent) => {
let textToCopy = getTextContent(props.children);
textToCopy = textToCopy.replace(/\n$/, ""); // remove trailing newline
await navigator.clipboard.writeText(textToCopy);
copied.set(true);
setTimeout(() => copied.set(false), 2000); // Reset copied state after 2 seconds
};
const handleExecute = (e: React.MouseEvent) => {
let textToCopy = getTextContent(props.children);
textToCopy = textToCopy.replace(/\n$/, ""); // remove trailing newline
if (props.onClickExecute) {
props.onClickExecute(textToCopy);
return;
}
};
let selected = this.blockIndex == this.props.codeSelectSelectedIndex;
return (
<pre
ref={this.blockRef}
className={clsx({ selected: selected })}
onClick={(event) => clickHandler(event, this.blockIndex)}
>
{this.props.children}
<pre className="codeblock">
{props.children}
<div className="codeblock-actions">
<CopyButton className="copy-button" onClick={handleCopy} title="Copy" />
<If condition={props.onClickExecute}>
<i className="fa-regular fa-square-terminal" onClick={handleExecute}></i>
</If>
</div>
</pre>
);
}
}
);
@mobxReact.observer
class Markdown extends React.Component<
{ text: string; style?: any; extraClassName?: string; codeSelect?: boolean },
{
text: string;
style?: any;
className?: string;
onClickExecute?: (cmd: string) => void;
},
{}
> {
curUuid: string;
constructor(props) {
super(props);
this.curUuid = uuidv4();
}
@boundMethod
CodeBlockRenderer(props: any, codeSelect: boolean, codeSelectIndex: number, curUuid: string): any {
if (codeSelect) {
return (
<CodeBlockMarkdown codeSelectSelectedIndex={codeSelectIndex} uuid={curUuid}>
{props.children}
</CodeBlockMarkdown>
);
} else {
const clickHandler = (e: React.MouseEvent<HTMLElement>) => {
let blockText = (e.target as HTMLElement).innerText;
if (blockText) {
blockText = blockText.replace(/\n$/, ""); // remove trailing newline
navigator.clipboard.writeText(blockText);
}
};
return <pre onClick={(event) => clickHandler(event)}>{props.children}</pre>;
}
}
render() {
let text = this.props.text;
let codeSelect = this.props.codeSelect;
let curCodeSelectIndex = GlobalModel.inputModel.getCodeSelectSelectedIndex();
let { text, className, onClickExecute } = this.props;
let markdownComponents = {
a: LinkRenderer,
h1: (props) => HeaderRenderer(props, 1),
h2: (props) => HeaderRenderer(props, 2),
h3: (props) => HeaderRenderer(props, 3),
h4: (props) => HeaderRenderer(props, 4),
h5: (props) => HeaderRenderer(props, 5),
h6: (props) => HeaderRenderer(props, 6),
code: (props) => CodeRenderer(props),
pre: (props) => this.CodeBlockRenderer(props, codeSelect, curCodeSelectIndex, this.curUuid),
a: Link,
h1: (props) => <Header {...props} hnum={1} />,
h2: (props) => <Header {...props} hnum={2} />,
h3: (props) => <Header {...props} hnum={3} />,
h4: (props) => <Header {...props} hnum={4} />,
h5: (props) => <Header {...props} hnum={5} />,
h6: (props) => <Header {...props} hnum={6} />,
code: Code,
pre: (props) => <CodeBlock {...props} onClickExecute={onClickExecute} />,
};
return (
<div className={clsx("markdown content", this.props.extraClassName)} style={this.props.style}>
<div className={clsx("markdown content", className)} style={this.props.style}>
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
{text}
</ReactMarkdown>
-112
View File
@@ -1,112 +0,0 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import * as mobxReact from "mobx-react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { CopyButton } from "@/elements";
import { clsx } from "clsx";
import * as mobx from "mobx";
import { If } from "tsx-control-statements/components";
import "./markdown.less";
function Link(props: any): JSX.Element {
let newUrl = "https://extern?" + encodeURIComponent(props.href);
return (
<a href={newUrl} target="_blank" rel={"noopener"}>
{props.children}
</a>
);
}
function Header(props: any, hnum: number): JSX.Element {
return <div className={clsx("title", "is-" + hnum)}>{props.children}</div>;
}
function Code(props: any): JSX.Element {
return <code>{props.children}</code>;
}
const CodeBlock = mobxReact.observer(
(props: { children: React.ReactNode; onClickExecute?: (cmd: string) => void }): JSX.Element => {
const copied: OV<boolean> = mobx.observable.box(false, { name: "copied" });
const getTextContent = (children: any) => {
if (typeof children === "string") {
return children;
} else if (Array.isArray(children)) {
return children.map(getTextContent).join("");
} else if (children.props && children.props.children) {
return getTextContent(children.props.children);
}
return "";
};
const handleCopy = async (e: React.MouseEvent) => {
let textToCopy = getTextContent(props.children);
textToCopy = textToCopy.replace(/\n$/, ""); // remove trailing newline
await navigator.clipboard.writeText(textToCopy);
copied.set(true);
setTimeout(() => copied.set(false), 2000); // Reset copied state after 2 seconds
};
const handleExecute = (e: React.MouseEvent) => {
let textToCopy = getTextContent(props.children);
textToCopy = textToCopy.replace(/\n$/, ""); // remove trailing newline
if (props.onClickExecute) {
props.onClickExecute(textToCopy);
return;
}
};
return (
<pre className="codeblock">
{props.children}
<div className="codeblock-actions">
<CopyButton className="copy-button" onClick={handleCopy} title="Copy" />
<If condition={props.onClickExecute}>
<i className="fa-regular fa-square-terminal" onClick={handleExecute}></i>
</If>
</div>
</pre>
);
}
);
@mobxReact.observer
class Markdown2 extends React.Component<
{
text: string;
style?: any;
className?: string;
onClickExecute?: (cmd: string) => void;
},
{}
> {
render() {
let { text, className, onClickExecute } = this.props;
let markdownComponents = {
a: Link,
h1: (props) => <Header {...props} hnum={1} />,
h2: (props) => <Header {...props} hnum={2} />,
h3: (props) => <Header {...props} hnum={3} />,
h4: (props) => <Header {...props} hnum={4} />,
h5: (props) => <Header {...props} hnum={5} />,
h6: (props) => <Header {...props} hnum={6} />,
code: Code,
pre: (props) => <CodeBlock {...props} onClickExecute={onClickExecute} />,
};
return (
<div className={clsx("markdown content", className)} style={this.props.style}>
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
{text}
</ReactMarkdown>
</div>
);
}
}
export { Markdown2 };
+3 -3
View File
@@ -7,7 +7,7 @@ import * as mobx from "mobx";
import { GlobalModel } from "@/models";
import { boundMethod } from "autobind-decorator";
import { For, If } from "tsx-control-statements/components";
import { Markdown2, TypingIndicator } from "@/elements";
import { Markdown, TypingIndicator } from "@/elements";
import type { OverlayScrollbars } from "overlayscrollbars";
import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react";
import tinycolor from "tinycolor2";
@@ -72,7 +72,7 @@ class ChatItem extends React.Component<
<div className="chat-msg-header">
<i className="fa-sharp fa-solid fa-user"></i>
</div>
<Markdown2 className="msg-text" text={chatItem.userquery} />
<Markdown className="msg-text" text={chatItem.userquery} />
</>
);
if (isassistantresponse) {
@@ -94,7 +94,7 @@ class ChatItem extends React.Component<
<div className="chat-msg-header">
<i className="fa-sharp fa-solid fa-sparkles"></i>
</div>
<Markdown2 text={assistantresponse.message} onClickExecute={onSetCmdInputValue} />
<Markdown text={assistantresponse.message} onClickExecute={onSetCmdInputValue} />
</>
);
}
-1
View File
@@ -6,7 +6,6 @@ import * as mobx from "mobx";
import * as mobxReact from "mobx-react";
import { sprintf } from "sprintf-js";
import { Markdown } from "@/elements";
import { GlobalModel } from "@/models/global";
import "./markdown.less";