refactor markdown (for alerts), remote cmddone delay

This commit is contained in:
sawka 2023-04-04 14:04:44 -07:00
parent f470b8e66f
commit e6aa2bae86
7 changed files with 59 additions and 75 deletions

View File

@ -9,26 +9,7 @@ import {If, For, When, Otherwise, Choose} from "tsx-control-statements/component
import cn from "classnames"; import cn from "classnames";
import type {BookmarkType} from "./types"; import type {BookmarkType} from "./types";
import {GlobalModel, GlobalCommandRunner} from "./model"; import {GlobalModel, GlobalCommandRunner} from "./model";
import ReactMarkdown from 'react-markdown' import {CmdStrCode, Markdown} from "./elements";
import remarkGfm from 'remark-gfm'
import {CmdStrCode} from "./elements";
function LinkRenderer(props : any) : any {
let newUrl = "https://extern?" + encodeURIComponent(props.href);
return <a href={newUrl} target="_blank">{props.children}</a>
}
function HeaderRenderer(props : any, hnum : number) : any {
return (
<div className={cn("title", "is-" + hnum)}>{props.children}</div>
);
}
function CodeRenderer(props : any) : any {
return (
<code className={cn({"inline": props.inline})}>{props.children}</code>
);
}
@mobxReact.observer @mobxReact.observer
class Bookmark extends React.Component<{bookmark : BookmarkType}, {}> { class Bookmark extends React.Component<{bookmark : BookmarkType}, {}> {
@ -102,16 +83,6 @@ class Bookmark extends React.Component<{bookmark : BookmarkType}, {}> {
let model = GlobalModel.bookmarksModel; let model = GlobalModel.bookmarksModel;
let isSelected = (model.activeBookmark.get() == bm.bookmarkid); let isSelected = (model.activeBookmark.get() == bm.bookmarkid);
let markdown = bm.description ?? ""; let markdown = bm.description ?? "";
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: CodeRenderer,
};
let hasDesc = markdown != ""; let hasDesc = markdown != "";
let isEditing = (model.editingBookmark.get() == bm.bookmarkid); let isEditing = (model.editingBookmark.get() == bm.bookmarkid);
let isCopied = mobx.computed(() => (model.copiedIndicator.get() == bm.bookmarkid)).get(); let isCopied = mobx.computed(() => (model.copiedIndicator.get() == bm.bookmarkid)).get();
@ -150,9 +121,7 @@ class Bookmark extends React.Component<{bookmark : BookmarkType}, {}> {
<div className="bookmark-id-div">{bm.bookmarkid.substr(0, 8)}</div> <div className="bookmark-id-div">{bm.bookmarkid.substr(0, 8)}</div>
<div className="bookmark-content"> <div className="bookmark-content">
<If condition={hasDesc}> <If condition={hasDesc}>
<div className="markdown"> <Markdown text={markdown}/>
<ReactMarkdown children={markdown} remarkPlugins={[remarkGfm]} components={markdownComponents}/>
</div>
</If> </If>
<CmdStrCode cmdstr={bm.cmdstr} onUse={this.handleUse} onCopy={this.clickCopy} isCopied={isCopied} fontSize="large" limitHeight={false}/> <CmdStrCode cmdstr={bm.cmdstr} onUse={this.handleUse} onCopy={this.clickCopy} isCopied={isCopied} fontSize="large" limitHeight={false}/>
</div> </div>

View File

@ -3,6 +3,8 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx"; import * as mobx from "mobx";
import {sprintf} from "sprintf-js"; import {sprintf} from "sprintf-js";
import {boundMethod} from "autobind-decorator"; import {boundMethod} from "autobind-decorator";
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import cn from "classnames"; import cn from "classnames";
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components"; import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
import type {RemoteType} from "./types"; import type {RemoteType} from "./types";
@ -194,4 +196,43 @@ class InfoMessage extends React.Component<{width : number, children : React.Reac
} }
} }
export {CmdStrCode, Toggle, renderCmdText, RemoteStatusLight, InlineSettingsTextEdit, InfoMessage}; function LinkRenderer(props : any) : any {
let newUrl = "https://extern?" + encodeURIComponent(props.href);
return <a href={newUrl} target="_blank">{props.children}</a>
}
function HeaderRenderer(props : any, hnum : number) : any {
return (
<div className={cn("title", "is-" + hnum)}>{props.children}</div>
);
}
function CodeRenderer(props : any) : any {
return (
<code className={cn({"inline": props.inline})}>{props.children}</code>
);
}
@mobxReact.observer
class Markdown extends React.Component<{text : string, style? : any, extraClassName? : string}, {}> {
render() {
let text = this.props.text;
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: CodeRenderer,
};
return (
<div className={cn("markdown content", this.props.extraClassName)} style={this.props.style}>
<ReactMarkdown children={text} remarkPlugins={[remarkGfm]} components={markdownComponents}/>
</div>
);
}
}
export {CmdStrCode, Toggle, renderCmdText, RemoteStatusLight, InlineSettingsTextEdit, InfoMessage, Markdown};

View File

@ -14,14 +14,12 @@ import localizedFormat from 'dayjs/plugin/localizedFormat';
import {GlobalModel, GlobalCommandRunner, Session, Cmd, ScreenLines, Screen, riToRPtr, TabColors, RemoteColors} from "./model"; import {GlobalModel, GlobalCommandRunner, Session, Cmd, ScreenLines, Screen, riToRPtr, TabColors, RemoteColors} from "./model";
import {windowWidthToCols, windowHeightToRows, termHeightFromRows, termWidthFromCols, getMonoFontSize} from "./textmeasure"; import {windowWidthToCols, windowHeightToRows, termHeightFromRows, termWidthFromCols, getMonoFontSize} from "./textmeasure";
import {isModKeyPress, boundInt, sortAndFilterRemotes} from "./util"; import {isModKeyPress, boundInt, sortAndFilterRemotes} from "./util";
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import {BookmarksView} from "./bookmarks"; import {BookmarksView} from "./bookmarks";
import {HistoryView} from "./history"; import {HistoryView} from "./history";
import {Line, Prompt} from "./linecomps"; import {Line, Prompt} from "./linecomps";
import {ScreenSettingsModal, SessionSettingsModal, LineSettingsModal, ClientSettingsModal} from "./settings"; import {ScreenSettingsModal, SessionSettingsModal, LineSettingsModal, ClientSettingsModal} from "./settings";
import {RemotesModal} from "./remotes"; import {RemotesModal} from "./remotes";
import {renderCmdText, RemoteStatusLight} from "./elements"; import {renderCmdText, RemoteStatusLight, Markdown} from "./elements";
import {LinesView} from "./linesview"; import {LinesView} from "./linesview";
dayjs.extend(localizedFormat) dayjs.extend(localizedFormat)
@ -1774,9 +1772,14 @@ class AlertModal extends React.Component<{}, {}> {
<i onClick={this.closeModal} className="fa-sharp fa-solid fa-times"/> <i onClick={this.closeModal} className="fa-sharp fa-solid fa-times"/>
</div> </div>
</header> </header>
<div className="inner-content content"> <If condition={message.markdown}>
<p>{message.message}</p> <Markdown text={message.message} extraClassName="inner-content"/>
</div> </If>
<If condition={!message.markdown}>
<div className="inner-content content">
<p>{message.message}</p>
</div>
</If>
<footer> <footer>
<If condition={isConfirm}> <If condition={isConfirm}>
<div onClick={this.closeModal} className="button is-prompt-cancel is-outlined is-small">Cancel</div> <div onClick={this.closeModal} className="button is-prompt-cancel is-outlined is-small">Cancel</div>

View File

@ -4,30 +4,12 @@ import * as mobxReact from "mobx-react";
import cn from "classnames"; import cn from "classnames";
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components"; import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
import {WindowSize, RendererContext, TermOptsType, LineType, RendererOpts} from "./types"; import {WindowSize, RendererContext, TermOptsType, LineType, RendererOpts} from "./types";
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import {boundInt} from "./util"; import {boundInt} from "./util";
import {sprintf} from "sprintf-js"; import {sprintf} from "sprintf-js";
import {Markdown} from "./elements";
type OV<V> = mobx.IObservableValue<V>; type OV<V> = mobx.IObservableValue<V>;
function LinkRenderer(props : any) : any {
let newUrl = "https://extern?" + encodeURIComponent(props.href);
return <a href={newUrl} target="_blank">{props.children}</a>
}
function HeaderRenderer(props : any, hnum : number) : any {
return (
<div className={cn("title", "is-" + hnum)}>{props.children}</div>
);
}
function CodeRenderer(props : any) : any {
return (
<code className={cn({"inline": props.inline})}>{props.children}</code>
);
}
const MaxMarkdownSize = 50000; const MaxMarkdownSize = 50000;
@mobxReact.observer @mobxReact.observer
@ -60,16 +42,6 @@ class SimpleMarkdownRenderer extends React.Component<{data : Blob, context : Ren
if (this.markdownText.get() == null) { if (this.markdownText.get() == null) {
return <div className="markdown-renderer" style={{height: this.props.savedHeight}}/> return <div className="markdown-renderer" style={{height: this.props.savedHeight}}/>
} }
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: CodeRenderer,
};
let opts = this.props.opts; let opts = this.props.opts;
let markdownText = this.markdownText.get(); let markdownText = this.markdownText.get();
let maxWidth = opts.maxSize.width; let maxWidth = opts.maxSize.width;
@ -80,9 +52,7 @@ class SimpleMarkdownRenderer extends React.Component<{data : Blob, context : Ren
return ( return (
<div className="markdown-renderer"> <div className="markdown-renderer">
<div className="markdown-scroller" style={{maxHeight: opts.maxSize.height}}> <div className="markdown-scroller" style={{maxHeight: opts.maxSize.height}}>
<div className="markdown content" style={{maxWidth: maxWidth, minWidth: minWidth}}> <Markdown text={this.markdownText.get()} style={{maxHeight: opts.maxSize.height}}/>
<ReactMarkdown children={this.markdownText.get()} remarkPlugins={[remarkGfm]} components={markdownComponents}/>
</div>
</div> </div>
</div> </div>
); );

View File

@ -2741,7 +2741,7 @@ class Model {
} }
let term = screen.getTermWrap(cmdId); let term = screen.getTermWrap(cmdId);
if (term != null) { if (term != null) {
setTimeout(() => term.cmdDone(), 300); term.cmdDone();
} }
} }
} }

View File

@ -960,7 +960,7 @@ class RemotesModal extends React.Component<{model : RemotesModalModel}, {}> {
return ( return (
<div className="remote-detail flex-centered-row"> <div className="remote-detail flex-centered-row">
<div> <div>
No Remote Selected No Connection Selected
</div> </div>
</div> </div>
); );
@ -981,7 +981,7 @@ class RemotesModal extends React.Component<{model : RemotesModalModel}, {}> {
<header> <header>
<div className="modal-title">Connections</div> <div className="modal-title">Connections</div>
<div className="close-icon"> <div className="close-icon">
<i onClick={this.closeModal} className="fa-sharp fa-solid fa-times"/> <i title="Close (Escape)" onClick={this.closeModal} className="fa-sharp fa-solid fa-times"/>
</div> </div>
</header> </header>
<div className="inner-content"> <div className="inner-content">

View File

@ -481,6 +481,7 @@ type AlertMessageType = {
title? : string, title? : string,
message : string, message : string,
confirm? : boolean, confirm? : boolean,
markdown? : boolean,
}; };
type HistorySearchParams = { type HistorySearchParams = {