codeedit ui updates (#366)

* codeedit UI updates

* deal with long messages, cleanup
This commit is contained in:
Mike Sawka 2024-03-01 18:11:28 -08:00 committed by GitHub
parent 089862d990
commit adf83c73b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 127 additions and 53 deletions

View File

@ -67,6 +67,11 @@
}
}
&.term-inline {
padding: 2px 8px;
border-radius: 3px;
}
&.disabled {
opacity: 0.5;
}

View File

@ -22,6 +22,7 @@ interface ButtonProps {
style?: React.CSSProperties;
autoFocus?: boolean;
className?: string;
termInline?: boolean;
}
class Button extends React.Component<ButtonProps> {
@ -40,12 +41,31 @@ class Button extends React.Component<ButtonProps> {
}
render() {
const { leftIcon, rightIcon, theme, children, disabled, variant, color, style, autoFocus, className } =
this.props;
const {
leftIcon,
rightIcon,
theme,
children,
disabled,
variant,
color,
style,
autoFocus,
termInline,
className,
} = this.props;
return (
<button
className={cn("wave-button", theme, variant, color, { disabled: disabled }, className)}
className={cn(
"wave-button",
theme,
variant,
color,
{ disabled: disabled },
{ "term-inline": termInline },
className
)}
onClick={this.handleClick}
disabled={disabled}
style={style}

View File

@ -61,6 +61,7 @@
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 5px;
padding-left: 5px;
}
div.icon {

View File

@ -45,24 +45,17 @@
overflow: auto;
}
}
section {
// transition: height 0.3s ease-in-out;
}
.messageContainer {
position: absolute;
bottom: -3px;
left: 14px;
.message {
background: var(--app-success-color);
border-radius: 6px;
margin-bottom: 1rem;
padding: 4px 1rem;
max-width: 80vw;
&.error {
background: var(--app-error-color);
}
.code-message {
text-wrap: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color: var(--term-bright-green);
&.error {
color: var(--term-bright-red);
}
}
.readonly {
position: absolute;
top: 0.2em;
@ -83,14 +76,38 @@
.split-horizontal {
display: flex;
width: 100%;
height: 100%;
height: calc(100% - var(--termlineheight) - 7px);
border-bottom: 1px solid var(--app-border-color);
}
.split-vertical {
display: flex;
flex-direction: column;
height: 100%;
}
.code-statusbar {
display: flex;
gap: var(--termpad);
flex-direction: row;
align-items: center;
font-size: var(--termfontsize);
line-height: var(--termlineheight);
background-color: var(--app-panel-bg-color);
border-top: 1px solid var(--app-border-color);
padding: 3px var(--termpad) 3px var(--termpad);
height: calc(var(--termlineheight) + 11px);
.wave-button {
line-height: var(--termlineheight) !important;
text-wrap: nowrap;
}
select.dropdown {
max-width: 200px;
}
}
.gutter {
flex-shrink: 0;
flex-grow: 0;

View File

@ -4,11 +4,14 @@
import * as React from "react";
import Editor, { Monaco } from "@monaco-editor/react";
import type * as MonacoTypes from "monaco-editor/esm/vs/editor/editor.api";
import cn from "classnames";
import { If } from "tsx-control-statements/components";
import { Markdown } from "@/elements";
import { GlobalModel, GlobalCommandRunner } from "@/models";
import Split from "react-split-it";
import loader from "@monaco-editor/loader";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
import { Button, Dropdown } from "@/elements";
import "./code.less";
@ -57,7 +60,7 @@ class SourceCodeRenderer extends React.Component<
isSave: boolean;
isClosed: boolean;
editorHeight: number;
message: { status: string; text: string };
message: { status: "success" | "error"; text: string };
isPreviewerAvailable: boolean;
showPreview: boolean;
editorFraction: number;
@ -71,13 +74,14 @@ class SourceCodeRenderer extends React.Component<
static codeCache = new Map();
// which languages have preview options
languagesWithPreviewer = ["markdown"];
filePath;
cacheKey;
originalCode;
monacoEditor: any; // reference to mounted monaco editor. TODO need the correct type
markdownRef;
syncing;
languagesWithPreviewer: string[] = ["markdown", "mdx"];
filePath: string;
cacheKey: string;
originalCode: string;
monacoEditor: MonacoTypes.editor.IStandaloneCodeEditor; // reference to mounted monaco editor. TODO need the correct type
markdownRef: React.RefObject<HTMLDivElement>;
syncing: boolean;
monacoOptions: MonacoTypes.editor.IEditorOptions & MonacoTypes.editor.IGlobalEditorOptions;
constructor(props) {
super(props);
@ -164,6 +168,10 @@ class SourceCodeRenderer extends React.Component<
this.monacoEditor = editor;
this.setInitialLanguage(editor);
this.setEditorHeight();
setTimeout(() => {
let opts = this.getEditorOptions();
editor.updateOptions(opts);
}, 2000);
editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => {
let waveEvent = adaptFromReactOrNativeKeyEvent(e.browserEvent);
if (checkKeyPressed(waveEvent, "Cmd:s") && this.state.isSave) {
@ -232,8 +240,8 @@ class SourceCodeRenderer extends React.Component<
}
}
handleLanguageChange = (event) => {
const selectedLanguage = event.target.value;
handleLanguageChange = (e: any) => {
const selectedLanguage = e.target.value;
this.setState({
selectedLanguage,
isPreviewerAvailable: this.languagesWithPreviewer.includes(selectedLanguage),
@ -320,7 +328,7 @@ class SourceCodeRenderer extends React.Component<
let allowEditing = this.getAllowEditing();
if (!allowEditing) {
const noOfLines = Math.max(this.state.code.split("\n").length, 5);
const lineHeight = Math.ceil(GlobalModel.getTermFontSize() * 1.5);
const lineHeight = Math.ceil(GlobalModel.lineHeightEnv.lineHeight);
_editorHeight = Math.min(noOfLines * lineHeight + 10, fullWindowHeight);
}
this.setState({ editorHeight: _editorHeight }, () => {
@ -339,6 +347,27 @@ class SourceCodeRenderer extends React.Component<
return !(this.props.readOnly || this.state.isClosed);
}
updateEditorOpts(): void {
if (!this.monacoEditor) {
return;
}
let opts = this.getEditorOptions();
this.monacoEditor.updateOptions(opts);
}
getEditorOptions(): MonacoTypes.editor.IEditorOptions {
let opts: MonacoTypes.editor.IEditorOptions = {
scrollBeyondLastLine: false,
fontSize: GlobalModel.getTermFontSize(),
fontFamily: GlobalModel.getTermFontFamily(),
readOnly: !this.getAllowEditing(),
};
if (this.state.showPreview) {
opts.minimap = { enabled: false };
}
return opts;
}
getCodeEditor = () => (
<div style={{ maxHeight: this.props.opts.maxSize.height }}>
{this.state.showReadonly && <div className="readonly">{"read-only"}</div>}
@ -348,12 +377,7 @@ class SourceCodeRenderer extends React.Component<
defaultLanguage={this.state.selectedLanguage}
value={this.state.code}
onMount={this.handleEditorDidMount}
options={{
scrollBeyondLastLine: false,
fontSize: GlobalModel.getTermFontSize(),
fontFamily: GlobalModel.getTermFontFamily(),
readOnly: !this.getAllowEditing(),
}}
options={this.getEditorOptions()}
onChange={this.handleEditorChange}
/>
</div>
@ -375,22 +399,23 @@ class SourceCodeRenderer extends React.Component<
togglePreview = () => {
this.saveLineState({ showPreview: !this.state.showPreview });
this.setState({ showPreview: !this.state.showPreview });
setTimeout(() => this.updateEditorOpts(), 0);
};
getEditorControls = () => {
const { selectedLanguage, isSave, languages, isPreviewerAvailable, showPreview } = this.state;
let allowEditing = this.getAllowEditing();
return (
<div className="buttonContainer">
{isPreviewerAvailable && (
<div className="button">
<>
<If condition={isPreviewerAvailable}>
<Button theme="primary" termInline={true}>
<div onClick={this.togglePreview} className={`preview`}>
{`${showPreview ? "hide" : "show"} preview (`}
{renderCmdText("P")}
{`)`}
</div>
</div>
)}
</Button>
</If>
<select className="dropdown" value={selectedLanguage} onChange={this.handleLanguageChange}>
{languages.map((lang, index) => (
<option key={index} value={lang}>
@ -398,25 +423,23 @@ class SourceCodeRenderer extends React.Component<
</option>
))}
</select>
{allowEditing && (
<div className={`button ${isSave ? "" : "disabled"}`}>
<If condition={allowEditing}>
<Button theme="primary" termInline={true}>
<div onClick={() => this.doSave()}>
{`save (`}
{renderCmdText("S")}
{`)`}
</div>
</div>
)}
{allowEditing && (
<div className="button">
</Button>
<Button className="primary" termInline={true}>
<div onClick={this.doClose} className={`close`}>
{`close (`}
{renderCmdText("D")}
{`)`}
</div>
</div>
)}
</div>
</Button>
</If>
</>
);
};
@ -461,8 +484,16 @@ class SourceCodeRenderer extends React.Component<
{this.getCodeEditor()}
{isPreviewerAvailable && showPreview && this.getPreviewer()}
</Split>
{this.getEditorControls()}
{message && this.getMessage()}
<div className="flex-spacer" />
<div className="code-statusbar">
<If condition={message != null}>
<div className={cn("code-message", { error: message.status == "error" })}>
{this.state.message.text}
</div>
</If>
<div className="flex-spacer" />
{this.getEditorControls()}
</div>
</div>
);
}