mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-03-12 13:29:15 +01:00
121 lines
3.9 KiB
TypeScript
121 lines
3.9 KiB
TypeScript
// 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 { clsx } from "clsx";
|
|
import { GlobalModel } from "@/models";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
|
import "./markdown.less";
|
|
import { boundMethod } from "autobind-decorator";
|
|
|
|
function LinkRenderer(props: any): any {
|
|
let newUrl = "https://extern?" + encodeURIComponent(props.href);
|
|
return (
|
|
<a href={newUrl} target="_blank" rel={"noopener"}>
|
|
{props.children}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
function HeaderRenderer(props: any, hnum: number): any {
|
|
return <div className={clsx("title", "is-" + hnum)}>{props.children}</div>;
|
|
}
|
|
|
|
function CodeRenderer(props: any): any {
|
|
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>;
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
this.blockRef = React.createRef();
|
|
this.blockIndex = GlobalModel.inputModel.addCodeBlockToCodeSelect(this.blockRef, this.props.uuid);
|
|
}
|
|
|
|
@boundMethod
|
|
handleClick(e: React.MouseEvent<HTMLPreElement>) {
|
|
console.log("this.blockIndex", this.blockIndex);
|
|
GlobalModel.inputModel.setCodeSelectSelectedCodeBlock(this.blockIndex);
|
|
}
|
|
|
|
render() {
|
|
console.log("this.blockIndex", this.blockIndex);
|
|
let selected = this.blockIndex == this.props.codeSelectSelectedIndex;
|
|
return (
|
|
<pre ref={this.blockRef} className={clsx({ selected: selected })} onClick={this.handleClick}>
|
|
{this.props.children}
|
|
</pre>
|
|
);
|
|
}
|
|
}
|
|
|
|
@mobxReact.observer
|
|
class Markdown extends React.Component<
|
|
{ text: string; style?: any; extraClassName?: string; codeSelect?: boolean },
|
|
{}
|
|
> {
|
|
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;
|
|
let codeSelect = this.props.codeSelect;
|
|
let curCodeSelectIndex = GlobalModel.inputModel.getCodeSelectSelectedIndex();
|
|
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),
|
|
};
|
|
return (
|
|
<div className={clsx("markdown content", this.props.extraClassName)} style={this.props.style}>
|
|
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
|
|
{text}
|
|
</ReactMarkdown>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
export { Markdown };
|