mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-03-11 13:23:06 +01:00
PE-44 md viewer (#21)
* md does render. need cleanups * simul scrolling works * preview button works * md previewer works * use Markdown component from elements, fix null ptr with unset ref * add scroller div back in * scrollers should overscroll contain --------- Co-authored-by: sawka
This commit is contained in:
parent
ca13c28a3f
commit
9a578c04d3
151
package.json
151
package.json
@ -1,77 +1,78 @@
|
||||
{
|
||||
"name": "Prompt",
|
||||
"version": "0.3.0",
|
||||
"main": "dist/emain.js",
|
||||
"license": "Proprietary",
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "^4.5.1",
|
||||
"autobind-decorator": "^2.4.0",
|
||||
"classnames": "^2.3.1",
|
||||
"dayjs": "^1.11.3",
|
||||
"dompurify": "^3.0.2",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"mobx": "^6.6.0",
|
||||
"mobx-react": "^7.5.0",
|
||||
"monaco-editor": "^0.41.0",
|
||||
"node-fetch": "^3.2.10",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-markdown": "^8.0.5",
|
||||
"remark": "^14.0.2",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"sprintf-js": "^1.1.2",
|
||||
"throttle-debounce": "^5.0.0",
|
||||
"tsx-control-statements": "^4.1.1",
|
||||
"uuid": "^9.0.0",
|
||||
"winston": "^3.8.2",
|
||||
"xterm": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.17.10",
|
||||
"@babel/core": "^7.18.2",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.2",
|
||||
"@babel/plugin-proposal-private-methods": "^7.18.6",
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@babel/plugin-transform-react-jsx": "^7.17.12",
|
||||
"@babel/plugin-transform-runtime": "^7.18.2",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-react": "^7.17.12",
|
||||
"@babel/preset-typescript": "^7.17.12",
|
||||
"@electron-forge/cli": "^6.0.0-beta.70",
|
||||
"@electron-forge/maker-deb": "^6.0.0-beta.70",
|
||||
"@electron-forge/maker-rpm": "^6.0.0-beta.70",
|
||||
"@electron-forge/maker-squirrel": "^6.0.0-beta.70",
|
||||
"@electron-forge/maker-zip": "^6.0.0-beta.70",
|
||||
"@types/classnames": "^2.3.1",
|
||||
"@types/electron": "^1.6.10",
|
||||
"@types/node": "^18.0.3",
|
||||
"@types/react": "^18.0.12",
|
||||
"@types/uuid": "9.0.0",
|
||||
"babel-loader": "^9.1.3",
|
||||
"babel-plugin-jsx-control-statements": "^4.1.2",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^6.7.1",
|
||||
"electron": "25.4.0",
|
||||
"electron-rebuild": "^3.2.8",
|
||||
"http-server": "^14.1.1",
|
||||
"less": "^4.1.2",
|
||||
"less-loader": "^11.0.0",
|
||||
"lodash-webpack-plugin": "^0.11.6",
|
||||
"mini-css-extract-plugin": "^2.6.0",
|
||||
"prettier": "^2.8.8",
|
||||
"style-loader": "^3.3.1",
|
||||
"typescript": "^4.7.3",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.9.1",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make"
|
||||
}
|
||||
"name": "Prompt",
|
||||
"version": "0.3.0",
|
||||
"main": "dist/emain.js",
|
||||
"license": "Proprietary",
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "^4.5.1",
|
||||
"autobind-decorator": "^2.4.0",
|
||||
"classnames": "^2.3.1",
|
||||
"dayjs": "^1.11.3",
|
||||
"dompurify": "^3.0.2",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"mobx": "^6.6.0",
|
||||
"mobx-react": "^7.5.0",
|
||||
"monaco-editor": "^0.41.0",
|
||||
"node-fetch": "^3.2.10",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-markdown": "^8.0.5",
|
||||
"remark": "^14.0.2",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"sprintf-js": "^1.1.2",
|
||||
"throttle-debounce": "^5.0.0",
|
||||
"tsx-control-statements": "^4.1.1",
|
||||
"uuid": "^9.0.0",
|
||||
"winston": "^3.8.2",
|
||||
"xterm": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.17.10",
|
||||
"@babel/core": "^7.18.2",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.2",
|
||||
"@babel/plugin-proposal-private-methods": "^7.18.6",
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@babel/plugin-transform-react-jsx": "^7.17.12",
|
||||
"@babel/plugin-transform-runtime": "^7.18.2",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-react": "^7.17.12",
|
||||
"@babel/preset-typescript": "^7.17.12",
|
||||
"@electron-forge/cli": "^6.0.0-beta.70",
|
||||
"@electron-forge/maker-deb": "^6.0.0-beta.70",
|
||||
"@electron-forge/maker-rpm": "^6.0.0-beta.70",
|
||||
"@electron-forge/maker-squirrel": "^6.0.0-beta.70",
|
||||
"@electron-forge/maker-zip": "^6.0.0-beta.70",
|
||||
"@types/classnames": "^2.3.1",
|
||||
"@types/electron": "^1.6.10",
|
||||
"@types/node": "^18.0.3",
|
||||
"@types/react": "^18.0.12",
|
||||
"@types/uuid": "9.0.0",
|
||||
"babel-loader": "^9.1.3",
|
||||
"babel-plugin-jsx-control-statements": "^4.1.2",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^6.7.1",
|
||||
"electron": "25.4.0",
|
||||
"electron-rebuild": "^3.2.8",
|
||||
"http-server": "^14.1.1",
|
||||
"less": "^4.1.2",
|
||||
"less-loader": "^11.0.0",
|
||||
"lodash-webpack-plugin": "^0.11.6",
|
||||
"mini-css-extract-plugin": "^2.6.0",
|
||||
"prettier": "^2.8.8",
|
||||
"style-loader": "^3.3.1",
|
||||
"typescript": "^4.7.3",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.9.1",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"react-split-it": "^2.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make"
|
||||
}
|
||||
}
|
||||
|
@ -236,6 +236,7 @@ input[type="checkbox"] {
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
@ -253,24 +254,42 @@ input[type="checkbox"] {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
|
||||
.monaco-editor .monaco-editor-background {
|
||||
background-color: rgba(255, 255, 255, 0.075) !important;
|
||||
}
|
||||
.cmd-hints {
|
||||
.monaco-editor .scrollbar {
|
||||
height: 4px !important;
|
||||
width: 4px !important;
|
||||
}
|
||||
.monaco-editor .scrollbar .slider {
|
||||
background-color: rgba(255, 255, 255) !important;
|
||||
}
|
||||
|
||||
.cmd-hints,
|
||||
.dropdown {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin-right: 26px;
|
||||
min-width: 6rem;
|
||||
max-width: 6rem;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.hint-item {
|
||||
border-radius: 4px 4px 0 0;
|
||||
padding: 3px 9px 2px 8px;
|
||||
line-height: 15px;
|
||||
line-height: 19px;
|
||||
text-align: center;
|
||||
}
|
||||
section {
|
||||
transition: height 0.3s ease-in-out;
|
||||
}
|
||||
.preview {
|
||||
color: #000;
|
||||
background-color: rgb(200, 200, 200);
|
||||
}
|
||||
.preview:hover {
|
||||
background-color: white !important;
|
||||
}
|
||||
.save-enabled {
|
||||
color: white;
|
||||
background-color: #4e9a06;
|
||||
@ -309,7 +328,7 @@ input[type="checkbox"] {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown-renderer .markdown {
|
||||
.renderer-container .markdown {
|
||||
padding: 5px;
|
||||
line-height: 1.5;
|
||||
width: fit-content;
|
||||
|
@ -1,8 +1,13 @@
|
||||
import * as React from "react";
|
||||
import { RendererContext, RendererOpts, LineStateType, RendererModelContainerApi } from "../types";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import cn from "classnames";
|
||||
import { Markdown } from "../elements";
|
||||
import { GlobalModel, GlobalCommandRunner } from "../model";
|
||||
import Split from "react-split-it";
|
||||
import "./split.css";
|
||||
import loader from "@monaco-editor/loader";
|
||||
import { editor } from "monaco-editor";
|
||||
loader.config({ paths: { vs: "./node_modules/monaco-editor/min/vs" } });
|
||||
|
||||
function renderCmdText(text: string): any {
|
||||
@ -37,6 +42,9 @@ class SourceCodeRenderer extends React.Component<
|
||||
isClosed: boolean;
|
||||
editorHeight: number;
|
||||
message: { status: string; text: string };
|
||||
isPreviewerAvailable: boolean;
|
||||
showPreview: boolean;
|
||||
editorFraction: number;
|
||||
}
|
||||
> {
|
||||
/**
|
||||
@ -45,23 +53,32 @@ class SourceCodeRenderer extends React.Component<
|
||||
*/
|
||||
static codeCache = new Map();
|
||||
|
||||
// which languages have preview options
|
||||
languagesWithPreviewer = ["markdown"];
|
||||
filePath;
|
||||
cacheKey;
|
||||
originalData;
|
||||
monacoEditor: any; // reference to mounted monaco editor. TODO need the correct type
|
||||
markdownRef;
|
||||
syncing;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.monacoEditor = null;
|
||||
const editorHeight = Math.max(props.savedHeight - 25, 0); // must subtract the padding/margin to get the real editorHeight
|
||||
this.markdownRef = React.createRef();
|
||||
this.syncing = false; // to avoid recursive calls between the two scroll listeners
|
||||
this.state = {
|
||||
code: null,
|
||||
languages: [],
|
||||
selectedLanguage: "",
|
||||
isSave: false,
|
||||
isClosed: false,
|
||||
editorHeight: editorHeight,
|
||||
editorHeight,
|
||||
message: null,
|
||||
isPreviewerAvailable: false,
|
||||
showPreview: this.props.lineState["showPreview"],
|
||||
editorFraction: this.props.lineState["editorFraction"] || 0.5,
|
||||
};
|
||||
}
|
||||
|
||||
@ -89,8 +106,12 @@ class SourceCodeRenderer extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
setInitialLanguage = (editor) => {
|
||||
saveLineState = (kvp) => {
|
||||
const { screenId, lineId } = this.props.context;
|
||||
GlobalCommandRunner.setLineState(screenId, lineId, { ...this.props.lineState, ...kvp }, false);
|
||||
};
|
||||
|
||||
setInitialLanguage = (editor) => {
|
||||
// set all languages
|
||||
const languages = monaco.languages.getLanguages().map((lang) => lang.id);
|
||||
this.setState({ languages });
|
||||
@ -105,19 +126,17 @@ class SourceCodeRenderer extends React.Component<
|
||||
.find((lang) => lang.extensions?.includes("." + extension));
|
||||
if (detectedLanguageObj) {
|
||||
detectedLanguage = detectedLanguageObj.id;
|
||||
GlobalCommandRunner.setLineState(
|
||||
screenId,
|
||||
lineId,
|
||||
{ ...this.props.lineState, lang: detectedLanguage },
|
||||
false
|
||||
);
|
||||
this.saveLineState({ lang: detectedLanguage });
|
||||
}
|
||||
}
|
||||
if (detectedLanguage) {
|
||||
const model = editor.getModel();
|
||||
if (model) {
|
||||
monaco.editor.setModelLanguage(model, detectedLanguage);
|
||||
this.setState({ selectedLanguage: detectedLanguage });
|
||||
this.setState({
|
||||
selectedLanguage: detectedLanguage,
|
||||
isPreviewerAvailable: this.languagesWithPreviewer.includes(detectedLanguage),
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -135,6 +154,17 @@ class SourceCodeRenderer extends React.Component<
|
||||
e.preventDefault();
|
||||
this.doClose();
|
||||
}
|
||||
if (e.code === "KeyP" && (e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
this.togglePreview();
|
||||
}
|
||||
});
|
||||
editor.onDidScrollChange((e) => {
|
||||
if (!this.syncing && e.scrollTopChanged) {
|
||||
this.syncing = true;
|
||||
this.handleEditorScrollChange(e);
|
||||
this.syncing = false;
|
||||
}
|
||||
});
|
||||
if (this.props.shouldFocus) {
|
||||
this.monacoEditor.focus();
|
||||
@ -150,23 +180,49 @@ class SourceCodeRenderer extends React.Component<
|
||||
}
|
||||
};
|
||||
|
||||
handleEditorScrollChange(e) {
|
||||
// Get the maximum scrollable height for the editor
|
||||
const scrollableHeightEditor = this.monacoEditor.getScrollHeight() - this.monacoEditor.getLayoutInfo().height;
|
||||
|
||||
// Calculate the scroll percentage
|
||||
const verticalScrollPercentage = e.scrollTop / scrollableHeightEditor;
|
||||
|
||||
// Apply the same percentage to the markdown div
|
||||
const markdownDiv = this.markdownRef.current;
|
||||
if (markdownDiv) {
|
||||
const scrollableHeightMarkdown = markdownDiv.scrollHeight - markdownDiv.clientHeight;
|
||||
markdownDiv.scrollTop = verticalScrollPercentage * scrollableHeightMarkdown;
|
||||
}
|
||||
}
|
||||
|
||||
handleDivScroll() {
|
||||
if (!this.syncing) {
|
||||
this.syncing = true;
|
||||
// Calculate the scroll percentage for the markdown div
|
||||
const markdownDiv = this.markdownRef.current;
|
||||
const scrollableHeightMarkdown = markdownDiv.scrollHeight - markdownDiv.clientHeight;
|
||||
const verticalScrollPercentage = markdownDiv.scrollTop / scrollableHeightMarkdown;
|
||||
|
||||
// Apply the same percentage to the editor
|
||||
const scrollableHeightEditor =
|
||||
this.monacoEditor.getScrollHeight() - this.monacoEditor.getLayoutInfo().height;
|
||||
this.monacoEditor.setScrollTop(verticalScrollPercentage * scrollableHeightEditor);
|
||||
|
||||
this.syncing = false;
|
||||
}
|
||||
}
|
||||
|
||||
handleLanguageChange = (event) => {
|
||||
const { screenId, lineId } = this.props.context;
|
||||
const selectedLanguage = event.target.value;
|
||||
this.setState({ selectedLanguage });
|
||||
this.setState({
|
||||
selectedLanguage,
|
||||
isPreviewerAvailable: this.languagesWithPreviewer.includes(selectedLanguage),
|
||||
});
|
||||
if (this.monacoEditor) {
|
||||
const model = this.monacoEditor.getModel();
|
||||
if (model) {
|
||||
monaco.editor.setModelLanguage(model, selectedLanguage);
|
||||
GlobalCommandRunner.setLineState(
|
||||
screenId,
|
||||
lineId,
|
||||
{
|
||||
...this.props.lineState,
|
||||
lang: selectedLanguage,
|
||||
},
|
||||
false
|
||||
);
|
||||
this.saveLineState({ lang: selectedLanguage });
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -251,9 +307,112 @@ class SourceCodeRenderer extends React.Component<
|
||||
return !(this.props.readOnly || this.state.isClosed);
|
||||
}
|
||||
|
||||
getCodeEditor = () => (
|
||||
<div style={{ maxHeight: this.props.opts.maxSize.height }}>
|
||||
<Editor
|
||||
theme="hc-black"
|
||||
height={this.state.editorHeight}
|
||||
defaultLanguage={this.state.selectedLanguage}
|
||||
defaultValue={this.state.code}
|
||||
onMount={this.handleEditorDidMount}
|
||||
options={{
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: GlobalModel.termFontSize.get(),
|
||||
fontFamily: "JetBrains Mono",
|
||||
readOnly: !this.getAllowEditing(),
|
||||
}}
|
||||
onChange={this.handleEditorChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
getPreviewer = () => {
|
||||
return (
|
||||
<div
|
||||
className="scroller"
|
||||
style={{ maxHeight: this.props.opts.maxSize.height }}
|
||||
ref={this.markdownRef}
|
||||
onScroll={() => this.handleDivScroll()}
|
||||
>
|
||||
<Markdown text={this.state.code} style={{width: "100%", padding: "1rem"}}/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
togglePreview = () => {
|
||||
this.saveLineState({ showPreview: !this.state.showPreview });
|
||||
this.setState({ showPreview: !this.state.showPreview });
|
||||
};
|
||||
|
||||
getEditorControls = () => {
|
||||
const { selectedLanguage, isSave, languages, isPreviewerAvailable, showPreview } = this.state;
|
||||
let allowEditing = this.getAllowEditing();
|
||||
return (
|
||||
<div style={{ position: "absolute", bottom: "-3px", right: "8px" }}>
|
||||
{isPreviewerAvailable && (
|
||||
<div className="cmd-hints" style={{ minWidth: "8rem", maxWidth: "8rem" }}>
|
||||
<div onClick={this.togglePreview} className={`hint-item preview`}>
|
||||
{`${showPreview ? "hide" : "show"} preview (`}
|
||||
{renderCmdText("P")}
|
||||
{`)`}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<select className="dropdown" value={selectedLanguage} onChange={this.handleLanguageChange}>
|
||||
{languages.map((lang, index) => (
|
||||
<option key={index} value={lang}>
|
||||
{lang}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{allowEditing && (
|
||||
<div className="cmd-hints">
|
||||
<div onClick={this.doSave} className={`hint-item ${isSave ? "save-enabled" : "save-disabled"}`}>
|
||||
{`save (`}
|
||||
{renderCmdText("S")}
|
||||
{`)`}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{allowEditing && (
|
||||
<div className="cmd-hints">
|
||||
<div
|
||||
onClick={this.doClose}
|
||||
className={`hint-item ${!isSave ? "close-enabled" : "close-disabled"}`}
|
||||
>
|
||||
{`close (`}
|
||||
{renderCmdText("D")}
|
||||
{`)`}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
getMessage = () => (
|
||||
<div style={{ position: "absolute", bottom: "-3px", left: "14px" }}>
|
||||
<div
|
||||
className="message"
|
||||
style={{
|
||||
fontSize: GlobalModel.termFontSize.get(),
|
||||
fontFamily: "JetBrains Mono",
|
||||
background: `${this.state.message.status === "error" ? "red" : "#4e9a06"}`,
|
||||
}}
|
||||
>
|
||||
{this.state.message.text}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
setSizes = (sizes) => {
|
||||
this.setState({ editorFraction: sizes[0] });
|
||||
this.saveLineState({ editorFraction: sizes[0] });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { opts, exitcode } = this.props;
|
||||
const { selectedLanguage, code, isSave } = this.state;
|
||||
const { exitcode } = this.props;
|
||||
const { code, message, isPreviewerAvailable, showPreview, editorFraction } = this.state;
|
||||
|
||||
if (code == null)
|
||||
return <div className="renderer-container code-renderer" style={{ height: this.props.savedHeight }} />;
|
||||
@ -272,77 +431,14 @@ class SourceCodeRenderer extends React.Component<
|
||||
</div>
|
||||
);
|
||||
|
||||
let allowEditing = this.getAllowEditing();
|
||||
return (
|
||||
<div className="renderer-container code-renderer">
|
||||
<div className="scroller" style={{ maxHeight: opts.maxSize.height }}>
|
||||
<Editor
|
||||
theme="hc-black"
|
||||
height={this.state.editorHeight}
|
||||
defaultLanguage={selectedLanguage}
|
||||
defaultValue={code}
|
||||
onMount={this.handleEditorDidMount}
|
||||
options={{
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: GlobalModel.termFontSize.get(),
|
||||
fontFamily: "JetBrains Mono",
|
||||
readOnly: !allowEditing,
|
||||
}}
|
||||
onChange={this.handleEditorChange}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ position: "absolute", bottom: "-3px", right: 0 }}>
|
||||
<select
|
||||
className="dropdown"
|
||||
value={this.state.selectedLanguage}
|
||||
onChange={this.handleLanguageChange}
|
||||
style={{ minWidth: "6rem", maxWidth: "6rem", marginRight: "26px" }}
|
||||
>
|
||||
{this.state.languages.map((lang, index) => (
|
||||
<option key={index} value={lang}>
|
||||
{lang}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{allowEditing && (
|
||||
<div className="cmd-hints" style={{ minWidth: "6rem", maxWidth: "6rem", marginLeft: "-18px" }}>
|
||||
<div
|
||||
onClick={this.doSave}
|
||||
className={`hint-item ${isSave ? "save-enabled" : "save-disabled"}`}
|
||||
>
|
||||
{`save (`}
|
||||
{renderCmdText("S")}
|
||||
{`)`}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{allowEditing && (
|
||||
<div className="cmd-hints" style={{ minWidth: "6rem", maxWidth: "6rem", marginLeft: "-18px" }}>
|
||||
<div
|
||||
onClick={this.doClose}
|
||||
className={`hint-item ${!isSave ? "close-enabled" : "close-disabled"}`}
|
||||
>
|
||||
{`close (`}
|
||||
{renderCmdText("D")}
|
||||
{`)`}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{this.state.message && (
|
||||
<div style={{ position: "absolute", bottom: "-3px", left: "14px" }}>
|
||||
<div
|
||||
className="message"
|
||||
style={{
|
||||
fontSize: GlobalModel.termFontSize.get(),
|
||||
fontFamily: "JetBrains Mono",
|
||||
background: `${this.state.message.status === "error" ? "red" : "#4e9a06"}`,
|
||||
}}
|
||||
>
|
||||
{this.state.message.text}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Split sizes={[editorFraction, 1 - editorFraction]} onSetSizes={this.setSizes}>
|
||||
{this.getCodeEditor()}
|
||||
{isPreviewerAvailable && showPreview && this.getPreviewer()}
|
||||
</Split>
|
||||
{this.getEditorControls()}
|
||||
{message && this.getMessage()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
50
src/view/split.css
Normal file
50
src/view/split.css
Normal file
@ -0,0 +1,50 @@
|
||||
/* example-split.css */
|
||||
.jsoneditor {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.split-horizontal {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.split-vertical {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
background: rgb(100, 100, 100);
|
||||
max-width: 4px;
|
||||
}
|
||||
.gutter-horizontal {
|
||||
cursor: col-resize;
|
||||
}
|
||||
.gutter-vertical {
|
||||
cursor: row-resize;
|
||||
}
|
||||
.gutter:hover {
|
||||
background: rgb(155, 155, 155);
|
||||
}
|
||||
.gutter-dragging:hover {
|
||||
background: rgb(155, 155, 155);
|
||||
}
|
||||
|
||||
.pane {
|
||||
flex-shrink: 1;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
min-width: 20rem;
|
||||
}
|
||||
.pane-dragging {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scrollable {
|
||||
height: 100vh;
|
||||
max-height: 100vh;
|
||||
overflow: scroll;
|
||||
}
|
@ -6217,7 +6217,7 @@ promise@^7.1.1:
|
||||
dependencies:
|
||||
asap "~2.0.3"
|
||||
|
||||
prop-types@^15.0.0:
|
||||
prop-types@^15.0.0, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@ -6377,6 +6377,13 @@ react-markdown@^8.0.5:
|
||||
unist-util-visit "^4.0.0"
|
||||
vfile "^5.0.0"
|
||||
|
||||
react-split-it@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-split-it/-/react-split-it-2.0.0.tgz#827a79becec8eea63df0866fb6db2071c3e37307"
|
||||
integrity sha512-MRb8Aez8c7243Nc2y/LoxPea2aW+GCCeSa7GgapChvAB52rFksOB7uiGmFJPfj5DfIt73e1+DGZZCx6zVkm0rA==
|
||||
dependencies:
|
||||
prop-types "^15.8.1"
|
||||
|
||||
react-textarea-autosize@^8.3.2:
|
||||
version "8.5.2"
|
||||
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.5.2.tgz#6421df2b5b50b9ca8c5e96fd31be688ea7fa2f9d"
|
||||
|
Loading…
Reference in New Issue
Block a user