mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
terminal font-size updates (margins, paddings, etc.) (#315)
* reorganize line styles, split lines.less into lines.less and line.less * switch everyone to use termFontSize getter (easier to find usages) * better font-family font-size update logic * update line styles, clean up more * replace icons, fix line heights * make paddings/margins more consistent * fix more margins, make command completions use termfontfamily * updates for cmdinput margins, font sizes, etc. * fix more font sizes and margins (mostly command input) * add comment
This commit is contained in:
parent
b7539a26c7
commit
61de455b90
@ -2,6 +2,12 @@
|
||||
|
||||
:root {
|
||||
--fa-style-family: "Font Awesome 6 Sharp";
|
||||
|
||||
// these variables are overridden by user settings
|
||||
--termfontfamily: "JetBrains Mono", monospace;
|
||||
--termfontsize: 12px;
|
||||
--termlineheight: 15px;
|
||||
--termpad: 7px; // padding value (scaled to termfontsize)
|
||||
}
|
||||
|
||||
html,
|
||||
|
@ -160,7 +160,7 @@ class Bookmark extends React.Component<BookmarkProps, {}> {
|
||||
<div className="bookmark-id-div">{bm.bookmarkid.substr(0, 8)}</div>
|
||||
<div className="bookmark-content">
|
||||
<If condition={hasDesc}>
|
||||
<Markdown text={markdown} />
|
||||
<Markdown text={markdown} extraClassName="bottom-margin" />
|
||||
</If>
|
||||
<CmdStrCode
|
||||
cmdstr={bm.cmdstr}
|
||||
|
@ -27,7 +27,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
@boundMethod
|
||||
handleChangeFontSize(fontSize: string): void {
|
||||
const newFontSize = Number(fontSize);
|
||||
if (GlobalModel.termFontSize.get() == newFontSize) {
|
||||
if (GlobalModel.getTermFontSize() == newFontSize) {
|
||||
return;
|
||||
}
|
||||
const prtn = GlobalCommandRunner.setTermFontSize(newFontSize, false);
|
||||
@ -144,7 +144,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
const maxTokensStr = String(
|
||||
openAIOpts.maxtokens == null || openAIOpts.maxtokens == 0 ? 1000 : openAIOpts.maxtokens
|
||||
);
|
||||
const curFontSize = GlobalModel.termFontSize.get();
|
||||
const curFontSize = GlobalModel.getTermFontSize();
|
||||
const curFontFamily = GlobalModel.getTermFontFamily();
|
||||
|
||||
return (
|
||||
|
@ -2,11 +2,14 @@
|
||||
|
||||
.markdown {
|
||||
color: @term-white;
|
||||
margin-bottom: 10px;
|
||||
font-family: @markdown-font;
|
||||
font-size: 14px;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
&.bottom-margin {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: @markdown-highlight;
|
||||
color: @term-white;
|
||||
|
@ -41,7 +41,7 @@ class AlertModal extends React.Component<{}, {}> {
|
||||
<Modal.Header onClose={this.closeModal} title={title} />
|
||||
<div className="wave-modal-body">
|
||||
<If condition={message?.markdown}>
|
||||
<Markdown text={message?.message ?? ""} />
|
||||
<Markdown text={message?.message ?? ""} extraClassName="bottom-margin" />
|
||||
</If>
|
||||
<If condition={!message?.markdown}>{message?.message}</If>
|
||||
<If condition={message.confirmflag}>
|
||||
|
@ -59,7 +59,7 @@ export const UserInputModal = (userInputRequest: UserInputRequest) => {
|
||||
<div className="wave-modal-body">
|
||||
<div className="userinput-query">
|
||||
<If condition={userInputRequest.markdown}>
|
||||
<Markdown text={userInputRequest.querytext} />
|
||||
<Markdown text={userInputRequest.querytext} extraClassName="bottom-margin" />
|
||||
</If>
|
||||
<If condition={!userInputRequest.markdown}>{userInputRequest.querytext}</If>
|
||||
</div>
|
||||
|
@ -291,7 +291,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
||||
|
||||
let model = this.model;
|
||||
let isTermFocused = this.model.remoteTermWrapFocus.get();
|
||||
let termFontSize = GlobalModel.termFontSize.get();
|
||||
let termFontSize = GlobalModel.getTermFontSize();
|
||||
let termWidth = textmeasure.termWidthFromCols(appconst.RemotePtyCols, termFontSize);
|
||||
let remoteAliasText = util.isBlank(remote.remotealias) ? "(none)" : remote.remotealias;
|
||||
let selectedRemoteStatus = this.getSelectedRemote().status;
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
.term-prompt {
|
||||
font-weight: normal;
|
||||
font-size: var(--termfontsize);
|
||||
line-height: var(--termlineheight);
|
||||
font-family: var(--termfontfamily);
|
||||
|
||||
.icon {
|
||||
@ -12,6 +14,10 @@
|
||||
fill: @wave-green;
|
||||
}
|
||||
|
||||
i {
|
||||
margin-right: 0.25em; // em for relative sizing
|
||||
}
|
||||
|
||||
.term-prompt-branch {
|
||||
color: @term-white;
|
||||
}
|
||||
@ -21,9 +27,6 @@
|
||||
}
|
||||
|
||||
.term-prompt-remote {
|
||||
i {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.term-prompt-remote {
|
||||
|
@ -8,7 +8,6 @@ import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import { GlobalModel } from "@/models";
|
||||
import cn from "classnames";
|
||||
import { isBlank } from "@/util/util";
|
||||
import { ReactComponent as FolderIcon } from "@/assets/icons/folder.svg";
|
||||
|
||||
import "./prompt.less";
|
||||
|
||||
@ -76,6 +75,7 @@ class Prompt extends React.Component<{ rptr: RemotePtrType; festate: Record<stri
|
||||
if (rptr == null || isBlank(rptr.remoteid)) {
|
||||
return <span className={cn("term-prompt", "color-green")}> </span>;
|
||||
}
|
||||
let termFontSize = GlobalModel.getTermFontSize();
|
||||
let remote = GlobalModel.getRemote(this.props.rptr.remoteid);
|
||||
let remoteStr = getRemoteStr(rptr);
|
||||
let festate = this.props.festate ?? {};
|
||||
@ -96,7 +96,7 @@ class Prompt extends React.Component<{ rptr: RemotePtrType; festate: Record<stri
|
||||
}
|
||||
let cwdElem = (
|
||||
<span title="current directory" className="term-prompt-cwd">
|
||||
<FolderIcon className="icon" />
|
||||
<i className="fa-sharp fa-solid fa-folder" style={{ marginRight: Math.ceil(termFontSize / 4) }} />
|
||||
{cwd}
|
||||
</span>
|
||||
);
|
||||
|
366
src/app/line/line.less
Normal file
366
src/app/line/line.less
Normal file
@ -0,0 +1,366 @@
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.line {
|
||||
margin: 1rem 1rem 0 1rem;
|
||||
padding: var(--termpad) var(--termpad) var(--termpad) var(--termpad);
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
background: @base-background;
|
||||
border: 1px solid transparent;
|
||||
|
||||
&.line-cmd {
|
||||
flex-direction: column;
|
||||
scroll-margin-bottom: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&.line-text {
|
||||
// old formatting for text lines (requires override)
|
||||
flex-direction: row;
|
||||
padding-top: 5px;
|
||||
|
||||
.line-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&.line-invalid {
|
||||
color: @term-white;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border: 1px solid rgba(@base-color, 0.8) !important;
|
||||
box-shadow: 0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border: 1px solid rgba(@wave-green, 0.8) !important;
|
||||
box-shadow: 0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
}
|
||||
|
||||
.load-error-text {
|
||||
color: @term-red;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.renderer-loading {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.sidebar-message {
|
||||
color: @term-yellow;
|
||||
}
|
||||
|
||||
.focus-indicator {
|
||||
height: calc(100% - 7px);
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
&.line-simple {
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
color: rgba(@base-color, 0.6);
|
||||
|
||||
.simple-line-header {
|
||||
display: flex;
|
||||
margin-top: 5px;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.ts {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.simple-line-status {
|
||||
.linenum {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0.5em;
|
||||
vertical-align: text-top;
|
||||
fill: @base-color;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: @wave-green;
|
||||
fill: @wave-green;
|
||||
}
|
||||
|
||||
.fail {
|
||||
color: @error-red;
|
||||
fill: @error-red;
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: @warning-yellow;
|
||||
fill: @warning-yellow;
|
||||
}
|
||||
}
|
||||
|
||||
&.top-border {
|
||||
border-top: 1px solid #777;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
margin: 0px 5px 5px 5px;
|
||||
padding: 0px 5px 5px 12px;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&:hover .meta .termopts {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:hover .meta .settings {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.line-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
font-weight: normal;
|
||||
font-family: var(--termfontfamily);
|
||||
font-size: var(--termfontsize);
|
||||
line-height: var(--termlineheight);
|
||||
|
||||
&.is-expanded {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.line-icon {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
cursor: pointer;
|
||||
padding: 3px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.line-icon-show {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.line-icon + .line-icon {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.line-icon.active {
|
||||
visibility: visible;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:hover .line-icon {
|
||||
visibility: visible;
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.meta.meta-line1 {
|
||||
color: rgba(@base-color, 0.6) !important;
|
||||
}
|
||||
|
||||
.meta.meta-line2 {
|
||||
margin-left: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
.line-header + div:not(.zero-height) {
|
||||
margin-top: var(--termpad);
|
||||
}
|
||||
|
||||
.meta-wrap {
|
||||
flex: 1 1 0px;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.meta {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.user {
|
||||
color: lighten(@soft-blue, 10%);
|
||||
font-weight: bold;
|
||||
margin-top: 1px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.ts,
|
||||
.termopts,
|
||||
.renderer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.renderer {
|
||||
margin-left: 3px;
|
||||
svg {
|
||||
width: 1em;
|
||||
margin-right: 0.5em;
|
||||
fill: rgba(@base-color, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.settings {
|
||||
display: none;
|
||||
margin-left: 0.5em;
|
||||
cursor: pointer;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
border-radius: 50%;
|
||||
line-height: 1em;
|
||||
svg {
|
||||
fill: rgba(@base-color, 0.6);
|
||||
&:hover {
|
||||
fill: @base-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.termopts {
|
||||
display: none;
|
||||
.resize-button {
|
||||
cursor: pointer;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.metapart-mono {
|
||||
margin-left: 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.cmdtext {
|
||||
overflow: hidden;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.cmdtext-overflow {
|
||||
flex-shrink: 0;
|
||||
padding-right: 2px;
|
||||
color: @term-white;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.cmdtext-expanded-wrapper {
|
||||
padding-left: 6px;
|
||||
overflow-y: auto;
|
||||
max-height: 60px;
|
||||
border-left: 2px solid #333;
|
||||
margin-left: 3px;
|
||||
|
||||
.cmdtext-expanded {
|
||||
white-space: pre;
|
||||
|
||||
color: @term-white;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd-hints {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
display: none;
|
||||
|
||||
.hint-item {
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
.loading-div {
|
||||
height: 20px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
&.has-rtnstate .terminal-wrapper {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.terminal-wrapper {
|
||||
line-height: normal;
|
||||
|
||||
&.zero-height {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.terminal-connectelem {
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
&.cmd-done .terminal .xterm-cursor {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.terminal-loading-message {
|
||||
position: absolute;
|
||||
top: calc(40% - 8px);
|
||||
left: 50px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd-rtnstate {
|
||||
position: relative;
|
||||
|
||||
.cmd-rtnstate-label {
|
||||
font-family: var(--termfontfamily);
|
||||
position: relative;
|
||||
font-size: 10px;
|
||||
z-index: 2;
|
||||
margin: 6px 0 2px 10px;
|
||||
padding: 2px 5px 0px 5px;
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
color: @term-white;
|
||||
background-color: #151715;
|
||||
}
|
||||
|
||||
.cmd-rtnstate-diff {
|
||||
font-family: var(--termfontfamily);
|
||||
color: @term-white;
|
||||
white-space: pre;
|
||||
margin-left: 10px;
|
||||
padding-left: 10px;
|
||||
padding-bottom: 1px;
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
max-height: 50px;
|
||||
overflow-y: auto;
|
||||
direction: rtl;
|
||||
|
||||
.cmd-rtnstate-diff-inner {
|
||||
direction: ltr;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd-rtnstate-sep {
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #333;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
width: min(300px, 50%);
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
}
|
||||
}
|
@ -25,17 +25,9 @@ import * as lineutil from "./lineutil";
|
||||
import { ErrorBoundary } from "@/common/error/errorboundary";
|
||||
import * as appconst from "@/app/appconst";
|
||||
|
||||
import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
|
||||
import { ReactComponent as CommentIcon } from "@/assets/icons/line/comment.svg";
|
||||
import { ReactComponent as QuestionIcon } from "@/assets/icons/line/question.svg";
|
||||
import { ReactComponent as WarningIcon } from "@/assets/icons/line/triangle-exclamation.svg";
|
||||
import { ReactComponent as XmarkIcon } from "@/assets/icons/line/xmark.svg";
|
||||
import { ReactComponent as FillIcon } from "@/assets/icons/line/fill.svg";
|
||||
import { ReactComponent as GearIcon } from "@/assets/icons/line/gear.svg";
|
||||
|
||||
import { RotateIcon } from "@/common/icons/icons";
|
||||
|
||||
import "./lines.less";
|
||||
import "./line.less";
|
||||
|
||||
dayjs.extend(localizedFormat);
|
||||
|
||||
@ -44,41 +36,40 @@ class SmallLineAvatar extends React.Component<{ line: LineType; cmd: Cmd; onRigh
|
||||
render() {
|
||||
const { line, cmd } = this.props;
|
||||
const lineNumStr = (line.linenumtemp ? "~" : "#") + String(line.linenum);
|
||||
const status = cmd != null ? cmd.getStatus() : "done";
|
||||
const rtnstate = cmd != null ? cmd.getRtnState() : false;
|
||||
let status = cmd != null ? cmd.getStatus() : "done";
|
||||
const exitcode = cmd != null ? cmd.getExitCode() : 0;
|
||||
const isComment = line.linetype == "text";
|
||||
let icon = null;
|
||||
let iconTitle = null;
|
||||
if (isComment) {
|
||||
icon = <CommentIcon />;
|
||||
icon = <i className="fa-sharp fa-solid fa-comment" />;
|
||||
iconTitle = "comment";
|
||||
} else if (status == "done") {
|
||||
if (exitcode === 0) {
|
||||
icon = <CheckIcon className="success" />;
|
||||
icon = <i className="success fa-sharp fa-solid fa-check" />;
|
||||
iconTitle = "success";
|
||||
} else {
|
||||
icon = <XmarkIcon className="fail" />;
|
||||
icon = <i className="fail fa-sharp fa-solid fa-xmark" />;
|
||||
iconTitle = "exitcode " + exitcode;
|
||||
}
|
||||
} else if (status == "hangup") {
|
||||
icon = <WarningIcon className="warning" />;
|
||||
icon = <i className="warning fa-sharp fa-solid fa-triangle-exclamation" />;
|
||||
iconTitle = status;
|
||||
} else if (status == "error") {
|
||||
icon = <XmarkIcon className="fail" />;
|
||||
icon = <i className="fail fa-sharp fa-solid fa-xmark" />;
|
||||
iconTitle = "error";
|
||||
} else if (status == "running" || "detached") {
|
||||
icon = <RotateIcon className="warning spin" />;
|
||||
} else if (status == "running" || status == "detached") {
|
||||
icon = <i className="warning fa-sharp fa-solid fa-rotate fa-spin" />;
|
||||
iconTitle = "running";
|
||||
} else {
|
||||
icon = <QuestionIcon />;
|
||||
icon = <i className="fail fa-sharp fa-solid fa-question" />;
|
||||
iconTitle = "unknown";
|
||||
}
|
||||
return (
|
||||
<div
|
||||
onContextMenu={this.props.onRightClick}
|
||||
title={iconTitle}
|
||||
className={cn("simple-line-status", "status-" + status, rtnstate ? "has-rtnstate" : null)}
|
||||
className={cn("simple-line-status", "status-" + status)}
|
||||
>
|
||||
<span className="linenum">{lineNumStr}</span>
|
||||
<div className="avatar">{icon}</div>
|
||||
@ -88,52 +79,22 @@ class SmallLineAvatar extends React.Component<{ line: LineType; cmd: Cmd; onRigh
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class LineCmd extends React.Component<
|
||||
{
|
||||
screen: LineContainerType;
|
||||
line: LineType;
|
||||
width: number;
|
||||
staticRender: boolean;
|
||||
visible: OV<boolean>;
|
||||
onHeightChange: LineHeightChangeCallbackType;
|
||||
renderMode: RenderModeType;
|
||||
overrideCollapsed: OV<boolean>;
|
||||
noSelect?: boolean;
|
||||
showHints?: boolean;
|
||||
},
|
||||
{}
|
||||
> {
|
||||
lineRef: React.RefObject<any> = React.createRef();
|
||||
cmdTextRef: React.RefObject<any> = React.createRef();
|
||||
class RtnState extends React.Component<{ cmd: Cmd; line: LineType }> {
|
||||
rtnStateDiff: mobx.IObservableValue<string> = mobx.observable.box(null, {
|
||||
name: "linecmd-rtn-state-diff",
|
||||
});
|
||||
rtnStateDiffFetched: boolean = false;
|
||||
lastHeight: number;
|
||||
isOverflow: OV<boolean> = mobx.observable.box(false, {
|
||||
name: "line-overflow",
|
||||
});
|
||||
isCmdExpanded: OV<boolean> = mobx.observable.box(false, {
|
||||
name: "cmd-expanded",
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
componentDidMount() {
|
||||
this.componentDidUpdate();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.checkStateDiffLoad();
|
||||
}
|
||||
|
||||
checkStateDiffLoad(): void {
|
||||
const { screen, line, staticRender, visible } = this.props;
|
||||
if (staticRender) {
|
||||
return;
|
||||
}
|
||||
if (!visible.get()) {
|
||||
if (this.rtnStateDiffFetched) {
|
||||
this.rtnStateDiffFetched = false;
|
||||
this.setRtnStateDiff(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const cmd = screen.getCmd(line);
|
||||
let cmd = this.props.cmd;
|
||||
if (cmd == null || !cmd.getRtnState() || this.rtnStateDiffFetched) {
|
||||
return;
|
||||
}
|
||||
@ -179,6 +140,68 @@ class LineCmd extends React.Component<
|
||||
})();
|
||||
}
|
||||
|
||||
render() {
|
||||
let { cmd } = this.props;
|
||||
const rsdiff = this.rtnStateDiff.get();
|
||||
const termFontSize = GlobalModel.getTermFontSize();
|
||||
let rtnStateDiffSize = termFontSize - 2;
|
||||
if (rtnStateDiffSize < 10) {
|
||||
rtnStateDiffSize = Math.max(termFontSize, 10);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
key="rtnstate"
|
||||
className="cmd-rtnstate"
|
||||
style={{
|
||||
visibility: cmd.getStatus() == "done" ? "visible" : "hidden",
|
||||
}}
|
||||
>
|
||||
<If condition={rsdiff == null || rsdiff == ""}>
|
||||
<div className="cmd-rtnstate-label">state unchanged</div>
|
||||
<div className="cmd-rtnstate-sep"></div>
|
||||
</If>
|
||||
<If condition={rsdiff != null && rsdiff != ""}>
|
||||
<div className="cmd-rtnstate-label">new state</div>
|
||||
<div className="cmd-rtnstate-sep"></div>
|
||||
<div className="cmd-rtnstate-diff" style={{ fontSize: rtnStateDiffSize }}>
|
||||
<div className="cmd-rtnstate-diff-inner">{this.rtnStateDiff.get()}</div>
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class LineCmd extends React.Component<
|
||||
{
|
||||
screen: LineContainerType;
|
||||
line: LineType;
|
||||
width: number;
|
||||
staticRender: boolean;
|
||||
visible: OV<boolean>;
|
||||
onHeightChange: LineHeightChangeCallbackType;
|
||||
renderMode: RenderModeType;
|
||||
overrideCollapsed: OV<boolean>;
|
||||
noSelect?: boolean;
|
||||
showHints?: boolean;
|
||||
},
|
||||
{}
|
||||
> {
|
||||
lineRef: React.RefObject<any> = React.createRef();
|
||||
cmdTextRef: React.RefObject<any> = React.createRef();
|
||||
lastHeight: number;
|
||||
isOverflow: OV<boolean> = mobx.observable.box(false, {
|
||||
name: "line-overflow",
|
||||
});
|
||||
isCmdExpanded: OV<boolean> = mobx.observable.box(false, {
|
||||
name: "cmd-expanded",
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.componentDidUpdate(null, null, null);
|
||||
this.checkCmdText();
|
||||
@ -241,7 +264,6 @@ class LineCmd extends React.Component<
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot: { height: number }): void {
|
||||
this.handleHeightChange();
|
||||
this.checkStateDiffLoad();
|
||||
this.checkCmdText();
|
||||
}
|
||||
|
||||
@ -385,7 +407,7 @@ class LineCmd extends React.Component<
|
||||
let height = 45 + 24; // height of zero height terminal
|
||||
const usedRows = screen.getUsedRows(lineutil.getRendererContext(line), line, cmd, width);
|
||||
if (usedRows > 0) {
|
||||
height = 48 + 24 + termHeightFromRows(usedRows, GlobalModel.termFontSize.get(), cmd.getTermMaxRows());
|
||||
height = 48 + 24 + termHeightFromRows(usedRows, GlobalModel.getTermFontSize(), cmd.getTermMaxRows());
|
||||
}
|
||||
return height;
|
||||
}
|
||||
@ -452,7 +474,6 @@ class LineCmd extends React.Component<
|
||||
|
||||
renderMeta1(cmd: Cmd) {
|
||||
let { line } = this.props;
|
||||
let termOpts = cmd.getTermOpts();
|
||||
let formattedTime: string = "";
|
||||
let restartTs = cmd.getRestartTs();
|
||||
let timeTitle: string = null;
|
||||
@ -472,16 +493,10 @@ class LineCmd extends React.Component<
|
||||
<div> </div>
|
||||
<If condition={!isBlank(renderer) && renderer != "terminal"}>
|
||||
<div className="renderer">
|
||||
<FillIcon />
|
||||
<i className="fa-sharp fa-solid fa-fill" />
|
||||
{renderer}
|
||||
</div>
|
||||
</If>
|
||||
<div className="termopts">
|
||||
({termOpts.rows}x{termOpts.cols})
|
||||
</div>
|
||||
<div className="settings hoverEffect" onClick={this.handleLineSettings}>
|
||||
<GearIcon />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -583,6 +598,7 @@ class LineCmd extends React.Component<
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const isRtnState = cmd.getRtnState() && false; // turning off rtnstate for now
|
||||
const isSelected = mobx
|
||||
.computed(() => screen.getSelectedLine() == line.linenum, {
|
||||
name: "computed-isSelected",
|
||||
@ -621,14 +637,13 @@ class LineCmd extends React.Component<
|
||||
.get();
|
||||
const isRunning = cmd.isRunning();
|
||||
const isExpanded = this.isCmdExpanded.get();
|
||||
const rsdiff = this.rtnStateDiff.get();
|
||||
const mainDivCn = cn(
|
||||
"line",
|
||||
"line-cmd",
|
||||
{ selected: isSelected },
|
||||
{ active: isSelected && isFocused },
|
||||
{ "cmd-done": !isRunning },
|
||||
{ "has-rtnstate": cmd.getRtnState() }
|
||||
{ "has-rtnstate": isRtnState }
|
||||
);
|
||||
let rendererPlugin: RendererPluginType = null;
|
||||
const isNoneRenderer = line.renderer == "none";
|
||||
@ -637,11 +652,7 @@ class LineCmd extends React.Component<
|
||||
}
|
||||
const rendererType = lineutil.getRendererType(line);
|
||||
const hidePrompt = rendererPlugin?.hidePrompt;
|
||||
const termFontSize = GlobalModel.termFontSize.get();
|
||||
let rtnStateDiffSize = termFontSize - 2;
|
||||
if (rtnStateDiffSize < 10) {
|
||||
rtnStateDiffSize = Math.max(termFontSize, 10);
|
||||
}
|
||||
const termFontSize = GlobalModel.getTermFontSize();
|
||||
const containerType = screen.getContainerType();
|
||||
return (
|
||||
<div
|
||||
@ -700,6 +711,14 @@ class LineCmd extends React.Component<
|
||||
>
|
||||
<i className="fa-sharp fa-solid fa-right-to-line" />
|
||||
</div>
|
||||
<div
|
||||
key="settings"
|
||||
title="Line Settings"
|
||||
className="line-icon"
|
||||
onClick={this.handleLineSettings}
|
||||
>
|
||||
<i className="fa-sharp fa-regular fa-ellipsis-vertical" />
|
||||
</div>
|
||||
</If>
|
||||
<If condition={containerType == appconst.LineContainer_Sidebar}>
|
||||
<div
|
||||
@ -711,7 +730,7 @@ class LineCmd extends React.Component<
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
<If condition={isInSidebar}>
|
||||
<If condition={!isMinimized && isInSidebar}>
|
||||
<div className="sidebar-message" style={{ fontSize: termFontSize }}>
|
||||
showing in sidebar =>
|
||||
</div>
|
||||
@ -752,26 +771,8 @@ class LineCmd extends React.Component<
|
||||
/>
|
||||
</If>
|
||||
</ErrorBoundary>
|
||||
<If condition={cmd.getRtnState()}>
|
||||
<div
|
||||
key="rtnstate"
|
||||
className="cmd-rtnstate"
|
||||
style={{
|
||||
visibility: cmd.getStatus() == "done" ? "visible" : "hidden",
|
||||
}}
|
||||
>
|
||||
<If condition={rsdiff == null || rsdiff == ""}>
|
||||
<div className="cmd-rtnstate-label">state unchanged</div>
|
||||
<div className="cmd-rtnstate-sep"></div>
|
||||
</If>
|
||||
<If condition={rsdiff != null && rsdiff != ""}>
|
||||
<div className="cmd-rtnstate-label">new state</div>
|
||||
<div className="cmd-rtnstate-sep"></div>
|
||||
<div className="cmd-rtnstate-diff" style={{ fontSize: rtnStateDiffSize }}>
|
||||
<div className="cmd-rtnstate-diff-inner">{this.rtnStateDiff.get()}</div>
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
<If condition={isRtnState}>
|
||||
<RtnState cmd={cmd} line={line} />
|
||||
</If>
|
||||
<If condition={isSelected && !isFocused && rendererType == "terminal"}>
|
||||
<div className="cmd-hints">
|
||||
|
@ -1,462 +1,5 @@
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.line.line-text {
|
||||
flex-direction: row;
|
||||
padding-top: 5px;
|
||||
|
||||
.line-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.line .load-error-text {
|
||||
color: @term-red;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.line .renderer-loading {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.line.line-cmd {
|
||||
flex-direction: column;
|
||||
scroll-margin-bottom: 20px;
|
||||
position: relative;
|
||||
|
||||
.plus {
|
||||
opacity: 0.5;
|
||||
}
|
||||
&:hover {
|
||||
.plus {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-message {
|
||||
color: @term-yellow;
|
||||
}
|
||||
|
||||
.line-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-bottom: 0.7rem;
|
||||
width: 100%;
|
||||
line-height: 1.2;
|
||||
|
||||
&.is-expanded {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&.hide-prompt {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.line-icon {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
cursor: pointer;
|
||||
padding: 3px;
|
||||
border-radius: 50%;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.line-icon-show {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.line-icon + .line-icon {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.line-icon.active {
|
||||
visibility: visible;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:hover .line-icon {
|
||||
visibility: visible;
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.meta.meta-line1 {
|
||||
color: rgba(@base-color, 0.6) !important;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.meta.meta-line2 {
|
||||
margin-left: -2px;
|
||||
}
|
||||
|
||||
&.has-rtnstate .terminal-wrapper {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
.loading-div {
|
||||
height: 20px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.terminal-wrapper {
|
||||
line-height: normal;
|
||||
|
||||
&.zero-height {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.terminal-connectelem {
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
&.cmd-done .terminal .xterm-cursor {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.terminal-loading-message {
|
||||
position: absolute;
|
||||
top: calc(40% - 8px);
|
||||
left: 50px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd-rtnstate {
|
||||
position: relative;
|
||||
|
||||
.cmd-rtnstate-label {
|
||||
font-family: var(--termfontfamily);
|
||||
position: relative;
|
||||
font-size: 10px;
|
||||
z-index: 2;
|
||||
margin: 6px 0 2px 10px;
|
||||
padding: 2px 5px 0px 5px;
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
color: @term-white;
|
||||
background-color: #151715;
|
||||
}
|
||||
|
||||
.cmd-rtnstate-diff {
|
||||
font-family: var(--termfontfamily);
|
||||
color: @term-white;
|
||||
white-space: pre;
|
||||
margin-left: 10px;
|
||||
padding-left: 10px;
|
||||
padding-bottom: 1px;
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
max-height: 50px;
|
||||
overflow-y: auto;
|
||||
direction: rtl;
|
||||
|
||||
.cmd-rtnstate-diff-inner {
|
||||
direction: ltr;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd-rtnstate-sep {
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #333;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
width: min(300px, 50%);
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 1rem 1rem 0 1rem;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
background: @base-background;
|
||||
border: 1px solid transparent;
|
||||
|
||||
&.selected {
|
||||
border: 1px solid rgba(@base-color, 0.8) !important;
|
||||
box-shadow: 0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border: 1px solid rgba(@wave-green, 0.8) !important;
|
||||
box-shadow: 0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
}
|
||||
|
||||
.focus-indicator {
|
||||
height: calc(100% - 7px);
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
&.line-simple {
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
color: rgba(@base-color, 0.6);
|
||||
|
||||
.simple-line-header {
|
||||
display: flex;
|
||||
margin-top: 5px;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.ts {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.simple-line-status {
|
||||
.linenum {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.has-rtnstate {
|
||||
.linenum {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin: 0 0.5em;
|
||||
vertical-align: text-top;
|
||||
fill: @base-color;
|
||||
}
|
||||
|
||||
.success {
|
||||
fill: @wave-green;
|
||||
}
|
||||
|
||||
.fail {
|
||||
fill: @error-red;
|
||||
}
|
||||
|
||||
.warning {
|
||||
fill: @warning-yellow;
|
||||
}
|
||||
}
|
||||
|
||||
&.top-border {
|
||||
border-top: 1px solid #777;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
margin: 0px 5px 5px 5px;
|
||||
padding: 0px 5px 5px 12px;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&:hover .meta .termopts {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:hover .meta .settings {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
max-height: 38px;
|
||||
width: 38px;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
color: @term-white;
|
||||
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
|
||||
&.rtnstate {
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.comment-icon {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: -4px;
|
||||
}
|
||||
|
||||
&.status-done {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
&.ephemeral {
|
||||
opacity: 0.5;
|
||||
outline: 1px solid white;
|
||||
}
|
||||
|
||||
&.status-error {
|
||||
.status-icon {
|
||||
color: @error-red;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-hangup {
|
||||
.status-icon {
|
||||
color: @term-yellow;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-running {
|
||||
background-color: @soft-blue;
|
||||
}
|
||||
|
||||
&.status-waiting {
|
||||
background-color: @term-yellow;
|
||||
}
|
||||
|
||||
&.status-detached {
|
||||
background-color: @soft-blue;
|
||||
.status-icon {
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
color: @term-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.meta-wrap {
|
||||
flex: 1 1 0px;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.meta {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.simple-line-status {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.user {
|
||||
color: lighten(@soft-blue, 10%);
|
||||
font-weight: bold;
|
||||
margin-top: 1px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.ts,
|
||||
.termopts,
|
||||
.renderer {
|
||||
display: flex;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.renderer {
|
||||
margin-left: 3px;
|
||||
margin-top: 5px;
|
||||
svg {
|
||||
width: 1em;
|
||||
margin-right: 0.5em;
|
||||
fill: rgba(@base-color, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.settings {
|
||||
display: none;
|
||||
margin-left: 0.5em;
|
||||
margin-top: 0.65em;
|
||||
cursor: pointer;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
border-radius: 50%;
|
||||
line-height: 1em;
|
||||
svg {
|
||||
fill: rgba(@base-color, 0.6);
|
||||
&:hover {
|
||||
fill: @base-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.termopts {
|
||||
margin-top: 5px;
|
||||
display: none;
|
||||
.resize-button {
|
||||
cursor: pointer;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.metapart-mono {
|
||||
margin-left: 8px;
|
||||
margin-top: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.cmdtext {
|
||||
overflow: hidden;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.cmdtext-overflow {
|
||||
flex-shrink: 0;
|
||||
padding-right: 2px;
|
||||
color: @term-white;
|
||||
cursor: pointer;
|
||||
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.cmdtext-expanded-wrapper {
|
||||
margin-top: 2px;
|
||||
padding-left: 6px;
|
||||
overflow-y: auto;
|
||||
max-height: 60px;
|
||||
border-left: 2px solid #333;
|
||||
margin-left: 3px;
|
||||
|
||||
.cmdtext-expanded {
|
||||
white-space: pre;
|
||||
|
||||
color: @term-white;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd-hints {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
display: none;
|
||||
|
||||
.hint-item {
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line.line-invalid {
|
||||
color: @term-white;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.lines {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -6,11 +6,10 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 12px;
|
||||
width: calc(100% - 24px);
|
||||
padding: 12px;
|
||||
padding-bottom: 6px;
|
||||
bottom: var(--termfontsize);
|
||||
right: var(--termfontsize);
|
||||
width: calc(100% - 2 * var(--termfontsize));
|
||||
padding: var(--termfontsize);
|
||||
z-index: 100;
|
||||
background: @background-session-components;
|
||||
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.5), 0px 3px 8px 0px rgba(0, 0, 0, 0.35),
|
||||
@ -24,7 +23,7 @@
|
||||
}
|
||||
|
||||
&.has-info {
|
||||
padding-top: 10px;
|
||||
padding-top: var(--termpad);
|
||||
}
|
||||
|
||||
.focus-indicator {
|
||||
@ -34,7 +33,7 @@
|
||||
}
|
||||
|
||||
&.has-history {
|
||||
padding-top: 5px;
|
||||
padding-top: var(--termpad);
|
||||
height: max(300px, 40%);
|
||||
}
|
||||
|
||||
@ -101,7 +100,11 @@
|
||||
|
||||
.cmd-input-field {
|
||||
position: relative;
|
||||
padding-right: 17em;
|
||||
padding-right: var(--termpad);
|
||||
font-family: var(--termfontfamily);
|
||||
font-weight: normal;
|
||||
line-height: var(--termlineheight);
|
||||
font-size: var(--termfontsize);
|
||||
|
||||
.cmd-hints {
|
||||
position: absolute;
|
||||
@ -115,10 +118,15 @@
|
||||
.textareainput-div {
|
||||
position: relative;
|
||||
|
||||
&.control {
|
||||
padding: var(--termpad) 0;
|
||||
}
|
||||
|
||||
.shelltag {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
right: 3px;
|
||||
// 13px = 10px height + 3px padding. subtract termpad to account for textareainput-div padding
|
||||
bottom: calc(-13px + var(--termpad));
|
||||
right: 0px;
|
||||
font-size: 10px;
|
||||
color: @text-secondary;
|
||||
line-height: 1;
|
||||
@ -131,14 +139,15 @@
|
||||
textarea {
|
||||
color: @term-bright-white;
|
||||
background-color: @textarea-background;
|
||||
padding: 0.5em;
|
||||
padding: var(--termpad);
|
||||
resize: none;
|
||||
overflow: auto;
|
||||
overflow-wrap: anywhere;
|
||||
border-color: transparent;
|
||||
border: none;
|
||||
font-family: var(--termfontfamily);
|
||||
font-weight: normal;
|
||||
line-height: var(--termlineheight);
|
||||
font-size: var(--termfontsize);
|
||||
|
||||
&.display-disabled {
|
||||
background-color: #444;
|
||||
}
|
||||
@ -350,7 +359,7 @@
|
||||
.cmd-input-info {
|
||||
flex-shrink: 1;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: var(--termpad);
|
||||
|
||||
.info-msg {
|
||||
color: @soft-blue;
|
||||
@ -377,6 +386,9 @@
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
padding-bottom: 5px;
|
||||
font-weight: normal;
|
||||
font-family: var(--termfontfamily);
|
||||
font-size: var(--termfontsize);
|
||||
|
||||
.info-comp {
|
||||
min-width: 200px;
|
||||
|
@ -214,37 +214,6 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
screen={screen}
|
||||
onHeightChange={this.handleInnerHeightUpdate}
|
||||
/>
|
||||
<div className="control cmd-exec">
|
||||
{/**<div onClick={inputModel.toggleExpandInput} className="hint-item color-white">
|
||||
{inputModel.inputExpanded.get() ? "shrink" : "expand"} input ({renderCmdText("E")})
|
||||
</div>**/}
|
||||
{!focusVal && (
|
||||
<div onClick={this.clickFocusInputHint} className="cmd-btn hoverEffect">
|
||||
<div className="hint-elem">focus input ({renderCmdText("I")})</div>
|
||||
</div>
|
||||
)}
|
||||
{focusVal && (
|
||||
<div className="cmd-btn hoverEffect">
|
||||
<If condition={historyShow}>
|
||||
<div className="hint-elem" onMouseDown={this.clickHistoryHint}>
|
||||
close (esc)
|
||||
</div>
|
||||
</If>
|
||||
<If condition={!historyShow}>
|
||||
<div className="hint-elem" onMouseDown={this.clickHistoryHint}>
|
||||
history (ctrl-r)
|
||||
</div>
|
||||
<div className="hint-elem" onMouseDown={this.clickAIHint}>
|
||||
AI (ctrl-space)
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
)}
|
||||
<ExecIcon
|
||||
onClick={inputModel.uiSubmitCommand}
|
||||
className={`icon ${inputModel.getCurLine().trim() === "" ? "disabled" : "hoverEffect"}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -579,11 +579,11 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
|
||||
if (activeScreen != null) {
|
||||
activeScreen.focusType.get(); // for reaction
|
||||
}
|
||||
let termFontSize = 14;
|
||||
// fontSize*1.5 (line-height) + 2 * 0.5em padding
|
||||
let computedInnerHeight = displayLines * (termFontSize * 1.5) + 2 * 0.5 * termFontSize;
|
||||
// inner height + 2*1em padding
|
||||
let computedOuterHeight = computedInnerHeight + 2 * 1.0 * termFontSize;
|
||||
let termFontSize = GlobalModel.getTermFontSize();
|
||||
let fontSize = getMonoFontSize(termFontSize);
|
||||
let termPad = Math.floor(fontSize.height / 2);
|
||||
let computedInnerHeight = displayLines * fontSize.height + 2 * termPad;
|
||||
let computedOuterHeight = computedInnerHeight + 2 * termPad;
|
||||
let shellType: string = "";
|
||||
let screen = GlobalModel.getActiveScreen();
|
||||
if (screen != null) {
|
||||
|
@ -108,7 +108,7 @@ class ScreenView extends React.Component<{ session: Session; screen: Screen }, {
|
||||
if (screenWidth == null) {
|
||||
return <div className="screen-view" ref={this.screenViewRef}></div>;
|
||||
}
|
||||
let fontSize = GlobalModel.termFontSize.get();
|
||||
let fontSize = GlobalModel.getTermFontSize();
|
||||
let dprStr = sprintf("%0.3f", GlobalModel.devicePixelRatio.get());
|
||||
let viewOpts = screen.viewOpts.get();
|
||||
let hasSidebar = viewOpts?.sidebar?.open;
|
||||
|
@ -28,7 +28,7 @@ class ForwardLineContainer {
|
||||
this.winSize = winSize;
|
||||
let termWrap = this.getTermWrap(this.lineId);
|
||||
if (termWrap != null) {
|
||||
let fontSize = this.globalModel.termFontSize.get();
|
||||
let fontSize = this.globalModel.getTermFontSize();
|
||||
let cols = windowWidthToCols(winSize.width, fontSize);
|
||||
let rows = windowHeightToRows(winSize.height, fontSize);
|
||||
termWrap.resizeCols(cols);
|
||||
|
@ -114,8 +114,8 @@ class HistoryViewModel {
|
||||
this.specialLineContainer = null;
|
||||
} else {
|
||||
this.activeItem.set(hitem.historyid);
|
||||
let width = termWidthFromCols(80, this.globalModel.termFontSize.get());
|
||||
let height = termHeightFromRows(25, this.globalModel.termFontSize.get(), 25);
|
||||
let width = termWidthFromCols(80, this.globalModel.getTermFontSize());
|
||||
let height = termHeightFromRows(25, this.globalModel.getTermFontSize(), 25);
|
||||
this.specialLineContainer = new SpecialLineContainer(
|
||||
this,
|
||||
{ width, height },
|
||||
|
@ -33,7 +33,7 @@ import { MainSidebarModel } from "./mainsidebar";
|
||||
import { Screen } from "./screen";
|
||||
import { Cmd } from "./cmd";
|
||||
import { GlobalCommandRunner } from "./global";
|
||||
import { clearMonoFontCache } from "@/util/textmeasure";
|
||||
import { clearMonoFontCache, getMonoFontSize } from "@/util/textmeasure";
|
||||
import type { TermWrap } from "@/plugins/terminal/term";
|
||||
|
||||
type SWLinePtr = {
|
||||
@ -338,19 +338,29 @@ class Model {
|
||||
return this.termFontSize.get();
|
||||
}
|
||||
|
||||
setTermFontSize(fontSize: number) {
|
||||
updateTermFontSizeVars(fontSize: number, force: boolean) {
|
||||
if (!force && fontSize == this.termFontSize.get()) {
|
||||
return;
|
||||
}
|
||||
if (fontSize < appconst.MinFontSize) {
|
||||
fontSize = appconst.MinFontSize;
|
||||
}
|
||||
if (fontSize > appconst.MaxFontSize) {
|
||||
fontSize = appconst.MaxFontSize;
|
||||
}
|
||||
const monoFontSize = getMonoFontSize(fontSize);
|
||||
mobx.action(() => {
|
||||
this.termFontSize.set(fontSize);
|
||||
this.bumpRenderVersion();
|
||||
this.setStyleVar("--termfontsize", fontSize + "px");
|
||||
this.setStyleVar("--termlineheight", monoFontSize.height + "px");
|
||||
this.setStyleVar("--termpad", Math.floor(monoFontSize.height / 2) + "px");
|
||||
})();
|
||||
}
|
||||
|
||||
setStyleVar(name: string, value: string) {
|
||||
document.documentElement.style.setProperty(name, value);
|
||||
}
|
||||
|
||||
getBaseWsHostPort(): string {
|
||||
if (this.isDev) {
|
||||
return appconst.DevServerWsEndpoint;
|
||||
@ -1131,6 +1141,16 @@ class Model {
|
||||
}
|
||||
|
||||
setClientData(clientData: ClientDataType) {
|
||||
let newFontFamily = clientData?.feopts?.termfontfamily;
|
||||
if (newFontFamily == null) {
|
||||
newFontFamily = "JetBrains Mono";
|
||||
}
|
||||
let newFontSize = clientData?.feopts?.termfontsize;
|
||||
if (newFontSize == null) {
|
||||
newFontSize = appconst.DefaultTermFontSize;
|
||||
}
|
||||
const ffUpdated = newFontFamily != this.getTermFontFamily();
|
||||
const fsUpdated = newFontSize != this.getTermFontSize();
|
||||
mobx.action(() => {
|
||||
this.clientData.set(clientData);
|
||||
})();
|
||||
@ -1139,15 +1159,17 @@ class Model {
|
||||
shortcut = clientData?.clientopts?.globalshortcut;
|
||||
}
|
||||
getApi().reregisterGlobalShortcut(shortcut);
|
||||
let fontFamily = clientData?.feopts?.termfontfamily;
|
||||
if (fontFamily == null) {
|
||||
fontFamily = "JetBrains Mono";
|
||||
if (ffUpdated) {
|
||||
// this also updates fontSize vars
|
||||
loadFonts(newFontFamily);
|
||||
document.fonts.ready.then(() => {
|
||||
clearMonoFontCache();
|
||||
this.updateTermFontSizeVars(this.termFontSize.get(), true); // forces an update of css vars
|
||||
this.bumpRenderVersion();
|
||||
});
|
||||
} else if (fsUpdated) {
|
||||
this.updateTermFontSizeVars(newFontSize, true);
|
||||
}
|
||||
loadFonts(fontFamily);
|
||||
document.fonts.ready.then(() => {
|
||||
clearMonoFontCache();
|
||||
this.bumpRenderVersion();
|
||||
});
|
||||
}
|
||||
|
||||
submitCommandPacket(cmdPk: FeCmdPacketType, interactive: boolean): Promise<CommandRtnType> {
|
||||
|
@ -402,15 +402,15 @@ class Screen {
|
||||
return;
|
||||
}
|
||||
this.lastScreenSize = winSize;
|
||||
let cols = windowWidthToCols(winSize.width, this.globalModel.termFontSize.get());
|
||||
let rows = windowHeightToRows(winSize.height, this.globalModel.termFontSize.get());
|
||||
let cols = windowWidthToCols(winSize.width, this.globalModel.getTermFontSize());
|
||||
let rows = windowHeightToRows(winSize.height, this.globalModel.getTermFontSize());
|
||||
this._termSizeCallback(rows, cols);
|
||||
}
|
||||
|
||||
getMaxContentSize(): WindowSize {
|
||||
if (this.lastScreenSize == null) {
|
||||
let width = termWidthFromCols(80, this.globalModel.termFontSize.get());
|
||||
let height = termHeightFromRows(25, this.globalModel.termFontSize.get(), 25);
|
||||
let width = termWidthFromCols(80, this.globalModel.getTermFontSize());
|
||||
let height = termHeightFromRows(25, this.globalModel.getTermFontSize(), 25);
|
||||
return { width, height };
|
||||
}
|
||||
let winSize = this.lastScreenSize;
|
||||
@ -423,8 +423,8 @@ class Screen {
|
||||
|
||||
getIdealContentSize(): WindowSize {
|
||||
if (this.lastScreenSize == null) {
|
||||
let width = termWidthFromCols(80, this.globalModel.termFontSize.get());
|
||||
let height = termHeightFromRows(25, this.globalModel.termFontSize.get(), 25);
|
||||
let width = termWidthFromCols(80, this.globalModel.getTermFontSize());
|
||||
let height = termHeightFromRows(25, this.globalModel.getTermFontSize(), 25);
|
||||
return { width, height };
|
||||
}
|
||||
let winSize = this.lastScreenSize;
|
||||
|
@ -127,7 +127,7 @@ class SpecialLineContainer {
|
||||
}
|
||||
let termWrap = this.getTermWrap(cmd.lineId);
|
||||
if (termWrap == null) {
|
||||
let cols = windowWidthToCols(width, this.globalModel.termFontSize.get());
|
||||
let cols = windowWidthToCols(width, this.globalModel.getTermFontSize());
|
||||
let usedRows = this.globalModel.getContentHeight(context);
|
||||
if (usedRows != null) {
|
||||
return usedRows;
|
||||
|
@ -307,7 +307,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.termFontSize.get() * 1.5);
|
||||
const lineHeight = Math.ceil(GlobalModel.getTermFontSize() * 1.5);
|
||||
_editorHeight = Math.min(noOfLines * lineHeight + 10, fullWindowHeight);
|
||||
}
|
||||
this.setState({ editorHeight: _editorHeight }, () => {
|
||||
@ -434,7 +434,7 @@ class SourceCodeRenderer extends React.Component<
|
||||
<div
|
||||
className="code-renderer"
|
||||
style={{
|
||||
fontSize: GlobalModel.termFontSize.get(),
|
||||
fontSize: GlobalModel.getTermFontSize(),
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
|
@ -7,6 +7,7 @@ import * as mobx from "mobx";
|
||||
import { debounce } from "throttle-debounce";
|
||||
import * as util from "@/util/util";
|
||||
import { GlobalModel } from "@/models";
|
||||
import cn from "classnames";
|
||||
|
||||
class SimpleBlobRendererModel {
|
||||
context: RendererContext;
|
||||
@ -246,7 +247,7 @@ class SimpleBlobRenderer extends React.Component<
|
||||
return (
|
||||
<div
|
||||
ref={this.wrapperDivRef}
|
||||
className="renderer-loading"
|
||||
className={cn("renderer-loading", { "zero-height": height == 0 })}
|
||||
style={{ minHeight: height, fontSize: model.opts.termFontSize }}
|
||||
>
|
||||
loading content <i className="fa fa-ellipsis fa-fade" />
|
||||
@ -259,7 +260,7 @@ class SimpleBlobRenderer extends React.Component<
|
||||
}
|
||||
let { festate, cmdstr, exitcode } = this.props.initParams.rawCmd;
|
||||
return (
|
||||
<div ref={this.wrapperDivRef} className="sr-wrapper">
|
||||
<div ref={this.wrapperDivRef} className={cn("sr-wrapper", { "zero-height": model.savedHeight == 0 })}>
|
||||
<Comp
|
||||
cwd={festate.cwd}
|
||||
cmdstr={cmdstr}
|
||||
|
@ -182,7 +182,7 @@ const CSVRenderer: FC<Props> = (props: Props) => {
|
||||
|
||||
if (isFileTooLarge) {
|
||||
return (
|
||||
<div className="csv-renderer" style={{ fontSize: GlobalModel.termFontSize.get() }}>
|
||||
<div className="csv-renderer" style={{ fontSize: GlobalModel.getTermFontSize() }}>
|
||||
<div className="load-error-text">The file size exceeds 10MB and cannot be displayed.</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,7 +1,6 @@
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.image-renderer {
|
||||
padding: 10px;
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
.markdown-renderer {
|
||||
color: @term-white;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.scroller {
|
||||
overflow-y: auto;
|
||||
|
@ -148,7 +148,7 @@ class TerminalRenderer extends React.Component<
|
||||
.get();
|
||||
let cmd = screen.getCmd(line); // will not be null
|
||||
let usedRows = screen.getUsedRows(lineutil.getRendererContext(line), line, cmd, width);
|
||||
let termHeight = termHeightFromRows(usedRows, GlobalModel.termFontSize.get(), cmd.getTermMaxRows());
|
||||
let termHeight = termHeightFromRows(usedRows, GlobalModel.getTermFontSize(), cmd.getTermMaxRows());
|
||||
if (usedRows === 0) {
|
||||
termHeight = 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user