UI updates for command prompt / cmdinput (#354)

* remove [local] from prompt, remove prompt icons, restore --term vars (remove --prompt vars)

* working on prompt colors, cmdtext

* more generous padding around commands (and cmdinput)

* fix cmdinput background color

* fixes for cmdinput info box
This commit is contained in:
Mike Sawka 2024-02-27 22:46:07 -08:00 committed by GitHub
parent 17990afd5d
commit 0464cccf0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 146 additions and 223 deletions

View File

@ -1,73 +1,72 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
.term-prompt { .term-prompt {
font-weight: normal; font-weight: normal;
font-size: var(--termfontsize); font-size: var(--termfontsize);
line-height: var(--termlineheight); line-height: var(--termlineheight);
font-family: var(--termfontfamily); font-family: var(--termfontfamily);
color: var(--term-gray);
.icon {
margin: 0 4px 0 2px;
vertical-align: middle;
width: 1.2em;
height: 1.2em;
fill: var(--app-accent-color);
}
i { i {
margin-right: 0.25em; // em for relative sizing margin-right: 0.25em; // em for relative sizing
} }
}
.term-prompt.term-prompt-color {
.term-prompt-branch { .term-prompt-branch {
color: var(--prompt-white); color: var(--term-white);
} }
.term-prompt-python { .term-prompt-python {
color: var(--prompt-bright-magenta); color: var(--term-bright-magenta);
} }
.term-prompt-remote { .term-prompt-remote {
} color: var(--term-bright-green);
.term-prompt-remote {
color: var(--prompt-bright-green);
&.color-green { &.color-green {
color: var(--prompt-bright-green); color: var(--term-bright-green);
} }
&.color-red { &.color-red {
color: var(--prompt-bright-red); color: var(--term-bright-red);
} }
&.color-blue { &.color-blue {
color: var(--prompt-bright-blue); color: var(--term-bright-blue);
} }
&.color-yellow { &.color-yellow {
color: var(--prompt-bright-yellow); color: var(--term-bright-yellow);
} }
&.color-magenta { &.color-magenta {
color: var(--prompt-bright-magenta); color: var(--term-bright-magenta);
} }
&.color-cyan { &.color-cyan {
color: var(--prompt-bright-cyan); color: var(--termt-bright-cyan);
} }
&.color-white { &.color-white {
color: var(--prompt-bright-white); color: var(--term-bright-white);
} }
&.color-orange { &.color-orange {
color: var(--prompt-orange); color: var(--term-orange);
} }
} }
.term-prompt-cwd { .term-prompt-cwd {
color: var(--prompt-bright-green); color: var(--term-bright-green);
} }
.term-prompt-end { .term-prompt-end-user {
color: var(--prompt-bright-green); color: var(--term-bright-green);
}
.term-prompt-end-root {
color: var(--term-bright-red);
} }
} }

View File

@ -69,7 +69,7 @@ function getCwdStr(remote: RemoteType, state: Record<string, string>): string {
} }
@mobxReact.observer @mobxReact.observer
class Prompt extends React.Component<{ rptr: RemotePtrType; festate: Record<string, string> }, {}> { class Prompt extends React.Component<{ rptr: RemotePtrType; festate: Record<string, string>; color: boolean }, {}> {
render() { render() {
let rptr = this.props.rptr; let rptr = this.props.rptr;
if (rptr == null || isBlank(rptr.remoteid)) { if (rptr == null || isBlank(rptr.remoteid)) {
@ -96,24 +96,30 @@ class Prompt extends React.Component<{ rptr: RemotePtrType; festate: Record<stri
} }
let cwdElem = ( let cwdElem = (
<span title="current directory" className="term-prompt-cwd"> <span title="current directory" className="term-prompt-cwd">
<i className="fa-sharp fa-solid fa-folder" style={{ marginRight: Math.ceil(termFontSize / 4) }} />
{cwd} {cwd}
</span> </span>
); );
let remoteElem = ( let remoteElem = null;
<span title={remoteTitle} className={cn("term-prompt-remote", remoteColorClass)}> if (remoteStr != "local") {
[{remoteStr}]{" "} remoteElem = (
</span> <span title={remoteTitle} className={cn("term-prompt-remote", remoteColorClass)}>
); [{remoteStr}]{" "}
let rootIndicatorElem = <span className="term-prompt-end">{isRoot ? "#" : "$"}</span>; </span>
);
}
let rootIndicatorElem = null;
if (isRoot) {
rootIndicatorElem = <span className="term-prompt-end-root">#</span>;
} else {
rootIndicatorElem = <span className="term-prompt-end-user">$</span>;
}
let branchElem = null; let branchElem = null;
let pythonElem = null; let pythonElem = null;
if (!isBlank(festate["PROMPTVAR_GITBRANCH"])) { if (!isBlank(festate["PROMPTVAR_GITBRANCH"])) {
let branchName = festate["PROMPTVAR_GITBRANCH"]; let branchName = festate["PROMPTVAR_GITBRANCH"];
branchElem = ( branchElem = (
<span title="current git branch" className="term-prompt-branch"> <span title="current git branch" className="term-prompt-branch">
<i className="fa-sharp fa-solid fa-code-branch" /> git:({branchName}){" "}
{branchName}{" "}
</span> </span>
); );
} }
@ -122,16 +128,14 @@ class Prompt extends React.Component<{ rptr: RemotePtrType; festate: Record<stri
let venv = getShortVEnv(venvDir); let venv = getShortVEnv(venvDir);
pythonElem = ( pythonElem = (
<span title="python venv" className="term-prompt-python"> <span title="python venv" className="term-prompt-python">
<i className="fa-brands fa-python" /> venv:({venv}){" "}
{venv}{" "}
</span> </span>
); );
} }
return ( return (
<span className="term-prompt"> <span className={cn("term-prompt", { "term-prompt-color": this.props.color })}>
{remoteElem} {pythonElem} {remoteElem} {pythonElem}
{branchElem} {cwdElem} {branchElem} {rootIndicatorElem}
{cwdElem} {rootIndicatorElem}
</span> </span>
); );
} }

View File

@ -253,7 +253,7 @@
.line-container { .line-container {
padding: 0px 10px 10px 10px; padding: 0px 10px 10px 10px;
overflow-x: auto; overflow-x: auto;
background-color: var(--prompt-black); background-color: var(--term-black);
} }
.line-context { .line-context {

View File

@ -1,6 +1,6 @@
.line { .line {
margin: 0; margin: 0;
padding: var(--termpad) var(--termpad) calc(var(--termpad) + 1px) calc(var(--termpad) * 2); padding: calc(var(--termpad) * 2) var(--termpad) calc(var(--termpad) * 2 + 1px) calc(var(--termpad) * 3);
display: flex; display: flex;
overflow: hidden; overflow: hidden;
flex-shrink: 0; flex-shrink: 0;
@ -177,7 +177,7 @@
visibility: visible; visibility: visible;
} }
.line-icon + .line-icon { .line-icon + .line-icon {p
margin-left: 5px; margin-left: 5px;
} }
@ -193,7 +193,7 @@
} }
.meta.meta-line1 { .meta.meta-line1 {
color: var(--line-meta-text-color); color: var(--term-gray);
} }
.meta.meta-line2 { .meta.meta-line2 {
@ -280,6 +280,10 @@
color: var(--term-text-white); color: var(--term-text-white);
cursor: pointer; cursor: pointer;
} }
.meta-cmdtext {
color: var(--term-bright-white);
}
} }
.cmdtext-expanded-wrapper { .cmdtext-expanded-wrapper {

View File

@ -231,7 +231,7 @@ class LineCmd extends React.Component<
<React.Fragment> <React.Fragment>
<div key="meta2" className="meta meta-line2"> <div key="meta2" className="meta meta-line2">
<div className="metapart-mono cmdtext"> <div className="metapart-mono cmdtext">
<Prompt rptr={cmd.remote} festate={cmd.getRemoteFeState()} /> <Prompt rptr={cmd.remote} festate={cmd.getRemoteFeState()} color={true} />
</div> </div>
</div> </div>
<div key="meta3" className="meta meta-line3 cmdtext-expanded-wrapper"> <div key="meta3" className="meta meta-line3 cmdtext-expanded-wrapper">
@ -244,9 +244,9 @@ class LineCmd extends React.Component<
return ( return (
<div key="meta2" className="meta meta-line2" ref={this.cmdTextRef}> <div key="meta2" className="meta meta-line2" ref={this.cmdTextRef}>
<div className="metapart-mono cmdtext"> <div className="metapart-mono cmdtext">
<Prompt rptr={cmd.remote} festate={cmd.getRemoteFeState()} /> <Prompt rptr={cmd.remote} festate={cmd.getRemoteFeState()} color={true} />
<span> </span> <span> </span>
<span>{lineutil.getSingleLineCmdText(cmd.getCmdStr())}</span> <span className="meta-cmdtext">{lineutil.getSingleLineCmdText(cmd.getCmdStr())}</span>
</div> </div>
<If condition={this.isOverflow.get() || isMultiLine}> <If condition={this.isOverflow.get() || isMultiLine}>
<div className="cmdtext-overflow" onClick={this.handleExpandCmd}> <div className="cmdtext-overflow" onClick={this.handleExpandCmd}>

View File

@ -22,7 +22,7 @@
.line-sep-labeled { .line-sep-labeled {
display: flex; display: flex;
align-items: center; align-items: center;
color: var(--line-meta-text-color); color: var(--term-gray);
font-family: var(--termfontfamily); font-family: var(--termfontfamily);
line-height: var(--termlineheight); line-height: var(--termlineheight);
font-size: var(--termfontsize); font-size: var(--termfontsize);

View File

@ -68,19 +68,24 @@
--tab-pink: rgb(224, 86, 119); --tab-pink: rgb(224, 86, 119);
--tab-white: rgb(255, 255, 255); --tab-white: rgb(255, 255, 255);
// prompt colors // term colors
--prompt-black: rgb(0, 0, 0); --term-black: #000000;
--prompt-white: rgb(211, 215, 207); --term-red: #cc0000;
--prompt-orange: rgb(239, 113, 59); --term-green: #4e9a06;
--prompt-blue: rgb(52, 101, 164); --term-yellow: #c4a000;
--prompt-bright-black: rgb(85, 87, 83); --term-blue: #3465a4;
--prompt-bright-red: rgb(239, 41, 41); --term-magenta: #75507b;
--prompt-bright-green: rgb(88, 193, 66); --term-cyan: #06989a;
--prompt-bright-yellow: rgb(252, 233, 79); --term-white: #d3d7cf;
--prompt-bright-blue: rgb(50, 175, 255); --term-bright-black: #555753;
--prompt-bright-magenta: rgb(173, 127, 168); --term-bright-red: #ef2929;
--prompt-bright-cyan: rgb(52, 226, 226); --term-bright-green: #58c142;
--prompt-bright-white: rgb(255, 255, 255); --term-bright-yellow: #fce94f;
--term-bright-blue: #32afff;
--term-bright-magenta: #ad7fa8;
--term-bright-cyan: #34e2e2;
--term-bright-white: #ffffff;
--term-gray: rgb(139, 145, 138); // not an official terminal color
// button colors // button colors
--button-text-color: rgb(255, 255, 255); --button-text-color: rgb(255, 255, 255);
@ -164,7 +169,6 @@
--line-svg-hover-fill-color: #eceeec; --line-svg-hover-fill-color: #eceeec;
--line-selected-border-color: rgb(193, 195, 193); --line-selected-border-color: rgb(193, 195, 193);
--line-separator-color: rgb(126, 126, 126); --line-separator-color: rgb(126, 126, 126);
--line-meta-line1-color: rgb(150, 152, 150);
--line-error-color: #cc0000; --line-error-color: #cc0000;
--line-warning-color: #ffa500; --line-warning-color: #ffa500;
--line-base-soft-blue-color: #729fcf; --line-base-soft-blue-color: #729fcf;
@ -176,7 +180,6 @@
--line-error-bg-color: rgba(200, 0, 0, 0.1); --line-error-bg-color: rgba(200, 0, 0, 0.1);
--line-error-border-left-color: rgba(204, 0, 0, 0.8); --line-error-border-left-color: rgba(204, 0, 0, 0.8);
--line-simple-text-color: rgba(236, 238, 236, 0.6); --line-simple-text-color: rgba(236, 238, 236, 0.6);
--line-meta-text-color: rgb(139, 145, 138);
--line-meta-user-color: rgba(140, 184, 232); --line-meta-user-color: rgba(140, 184, 232);
--line-svg-color: rgba(236, 238, 236, 0.6); --line-svg-color: rgba(236, 238, 236, 0.6);
--line-svg-hover-color: rgba(236, 238, 236, 1); --line-svg-hover-color: rgba(236, 238, 236, 1);
@ -201,11 +204,9 @@
// cmdinput colors // cmdinput colors
--cmdinput-textarea-bg-color: #171717; --cmdinput-textarea-bg-color: #171717;
--cmdinput-text-error-color: rgb(239, 41, 41); --cmdinput-text-error-color: rgb(239, 41, 41);
--cmdinput-history-title-color: rgb(114, 159, 207); --cmdinput-title-color: rgb(114, 159, 207);
--cmdinput-remote-title-color: rgb(6, 152, 154);
--cmdinput-history-item-error-color: rgb(220, 119, 118); --cmdinput-history-item-error-color: rgb(220, 119, 118);
--cmdinput-history-item-selected-error-color: rgb(247, 148, 148); --cmdinput-history-item-selected-error-color: rgb(247, 148, 148);
--cmdinput-remote-field-control-color: rgb(0, 0, 0);
--cmdinput-warning-color: rgb(255, 165, 0); --cmdinput-warning-color: rgb(255, 165, 0);
--cmdinput-button-bg-color: rgb(88, 193, 66); --cmdinput-button-bg-color: rgb(88, 193, 66);
--cmdinput-comment-button-bg-color: rgb(57, 113, 255); --cmdinput-comment-button-bg-color: rgb(57, 113, 255);

View File

@ -5,9 +5,10 @@
position: absolute; position: absolute;
bottom: 0; bottom: 0;
width: 100%; width: 100%;
padding: var(--termfontsize); padding: calc(var(--termpad) * 2) calc(var(--termpad) * 2) calc(var(--termpad) * 2) calc(var(--termpad) * 3 - 1px);
z-index: 100; z-index: 100;
border-top: 1px solid var(--app-border-color); border-top: 1px solid var(--app-border-color);
background-color: var(--app-bg-color);
&.active { &.active {
} }
@ -60,6 +61,10 @@
flex-grow: 1; flex-grow: 1;
} }
.base-cmdinput:not(:first-child) {
margin-top: var(--termpad);
}
.cmd-input-context { .cmd-input-context {
color: #fff; color: #fff;
white-space: nowrap; white-space: nowrap;
@ -162,12 +167,12 @@
} }
&.inputmode-global .cmd-quick-context .button { &.inputmode-global .cmd-quick-context .button {
color: var(--app-black); color: var(--app-bg-color);
background-color: var(--cmdinput-button-bg-color) !important; background-color: var(--cmdinput-button-bg-color) !important;
} }
&.inputmode-comment .cmd-quick-context .button { &.inputmode-comment .cmd-quick-context .button {
color: var(--app-black); color: var(--app-bg-color);
background-color: var(--cmdinput-comment-button-bg-color) !important; background-color: var(--cmdinput-comment-button-bg-color) !important;
} }
@ -284,8 +289,8 @@
z-index: 102; z-index: 102;
top: 5px; top: 5px;
left: 0; left: 0;
background-color: var(--app-black); background-color: var(--app-bg-color);
color: var(--cmdinput-history-title-color); color: var(--cmdinput-title-color);
padding-bottom: 4px; padding-bottom: 4px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -359,12 +364,35 @@
overflow-y: auto; overflow-y: auto;
margin-bottom: var(--termpad); margin-bottom: var(--termpad);
.info-title {
position: absolute;
z-index: 102;
top: 5px;
left: 0;
background-color: var(--app-bg-color);
color: var(--cmdinput-title-color);
padding-bottom: 4px;
padding-left: calc(var(--termpad) * 2);
display: flex;
flex-direction: row;
width: 100%;
overflow-x: auto;
border-bottom: 1px solid var(--app-border-color);
}
.info-title + .info-msg,
.info-title + .info-lines,
.info-title + .info-comps,
.info-title + .info-error {
margin-top: 24px;
}
.info-msg { .info-msg {
color: var(--cmdinput-history-title-color); color: var(--cmdinput-history-title-color);
padding-bottom: 2px; padding-bottom: 2px;
a { a {
color: var(--prompt-blue); color: var(--term-blue);
} }
} }
@ -394,7 +422,7 @@
} }
.metacmd-comp { .metacmd-comp {
color: var(--prompt-bright-green); color: var(--term-bright-green);
} }
} }
@ -402,109 +430,5 @@
color: var(--cmdinput-text-error-color); color: var(--cmdinput-text-error-color);
padding-bottom: 2px; padding-bottom: 2px;
} }
.info-remote-showall {
table.remotes-table {
th {
color: var(--app-text-color);
font-weight: bold;
}
th,
td {
padding: 3px 8px 3px 8px;
}
td {
cursor: pointer;
}
tr:hover td {
background-color: #333;
}
}
}
.info-remote {
color: #d3d7cf;
.info-remote-title {
font-weight: bold;
color: var(--cmdinput-remote-title-color);
}
.info-error,
.info-msg {
margin-top: 5px;
padding: 5px;
}
.remote-field {
display: flex;
flex-direction: row;
.remote-field-def {
white-space: pre;
width: 120px;
}
.remote-field-val {
white-space: pre;
display: flex;
flex-direction: row;
}
}
.remote-input-field {
display: flex;
flex-direction: row;
height: 25px;
align-items: center;
.remote-field-label {
white-space: pre;
width: 140px;
font-weight: bold;
color: var(--app-text-primary-color);
}
.undo-icon {
margin-left: 4px;
cursor: pointer;
padding: 2px;
}
.remote-field-control {
&.text-input {
input[type="text"],
input[type="number"],
input[type="password"] {
background-color: var(--app-black);
color: var(--app-text-color);
width: 200px;
}
}
&.checkbox-input {
input[type="checkbox"] {
position: relative;
top: 3px;
}
}
&.select-input {
select {
width: 200px;
background-color: var(--app-black);
color: var(--app-text-color);
}
}
}
}
}
.info-remote-showall {
color: #d3d7cf;
}
} }
} }

View File

@ -15,7 +15,6 @@ import { TextAreaInput } from "./textareainput";
import { InfoMsg } from "./infomsg"; import { InfoMsg } from "./infomsg";
import { HistoryInfo } from "./historyinfo"; import { HistoryInfo } from "./historyinfo";
import { Prompt } from "@/common/prompt/prompt"; import { Prompt } from "@/common/prompt/prompt";
import { ReactComponent as ExecIcon } from "@/assets/icons/exec.svg";
import { RotateIcon } from "@/common/icons/icons"; import { RotateIcon } from "@/common/icons/icons";
import { AIChat } from "./aichat"; import { AIChat } from "./aichat";
@ -182,38 +181,40 @@ class CmdInput extends React.Component<{}, {}> {
</div> </div>
</div> </div>
</If> </If>
<div key="prompt" className="cmd-input-context"> <div key="base-cmdinput" className="base-cmdinput">
<div className="has-text-white"> <div key="prompt" className="cmd-input-context">
<span ref={this.promptRef}> <div className="has-text-white">
<Prompt rptr={rptr} festate={feState} /> <span ref={this.promptRef}>
</span> <Prompt rptr={rptr} festate={feState} color={true} />
</div> </span>
<If condition={numRunningLines > 0}> </div>
<div onClick={() => this.toggleFilter(screen)} className="cmd-input-filter"> <If condition={numRunningLines > 0}>
{numRunningLines} <div onClick={() => this.toggleFilter(screen)} className="cmd-input-filter">
<div className="avatar"> {numRunningLines}
<RotateIcon className="warning spin" /> <div className="avatar">
<RotateIcon className="warning spin" />
</div>
</div> </div>
</div> </If>
</If> </div>
</div> <div
<div key="input"
key="input" className={cn(
className={cn( "cmd-input-field field has-addons",
"cmd-input-field field has-addons", inputMode != null ? "inputmode-" + inputMode : null
inputMode != null ? "inputmode-" + inputMode : null )}
)} >
> <If condition={inputMode != null}>
<If condition={inputMode != null}> <div className="control cmd-quick-context">
<div className="control cmd-quick-context"> <div className="button is-static">{inputMode}</div>
<div className="button is-static">{inputMode}</div> </div>
</div> </If>
</If> <TextAreaInput
<TextAreaInput key={textAreaInputKey}
key={textAreaInputKey} screen={screen}
screen={screen} onHeightChange={this.handleInnerHeightUpdate}
onHeightChange={this.handleInnerHeightUpdate} />
/> </div>
</div> </div>
</div> </div>
); );

View File

@ -53,6 +53,9 @@ class InfoMsg extends React.Component<{}, {}> {
titleStr = infoMsg.infotitle; titleStr = infoMsg.infotitle;
} }
let activeScreen = model.getActiveScreen(); let activeScreen = model.getActiveScreen();
if (!infoShow) {
return null;
}
return ( return (
<div className="cmd-input-info" style={{ display: infoShow ? "block" : "none" }}> <div className="cmd-input-info" style={{ display: infoShow ? "block" : "none" }}>
<If condition={infoMsg?.infotitle}> <If condition={infoMsg?.infotitle}>
@ -68,14 +71,6 @@ class InfoMsg extends React.Component<{}, {}> {
<If condition={!infoMsg.infomsghtml}>{infoMsg.infomsg}</If> <If condition={!infoMsg.infomsghtml}>{infoMsg.infomsg}</If>
</div> </div>
</If> </If>
<If condition={infoMsg?.websharelink && activeScreen != null}>
<div key="infomsg" className="info-msg">
started sharing screen at{" "}
<a target="_blank" href={makeExternLink(activeScreen.getWebShareUrl())} rel={"noopener"}>
[link]
</a>
</div>
</If>
<If condition={infoMsg?.infolines}> <If condition={infoMsg?.infolines}>
<div key="infolines" className="info-lines"> <div key="infolines" className="info-lines">
<For index="idx" each="line" of={infoMsg.infolines}> <For index="idx" each="line" of={infoMsg.infolines}>

View File

@ -64,10 +64,6 @@ class ScreenTab extends React.Component<
<i title="archived" className="fa-sharp fa-solid fa-box-archive" /> <i title="archived" className="fa-sharp fa-solid fa-box-archive" />
) : null; ) : null;
let webShared = screen.isWebShared() ? (
<i title="shared to web" className="fa-sharp fa-solid fa-share-nodes web-share-icon" />
) : null;
const statusIndicatorLevel = screen.statusIndicator.get(); const statusIndicatorLevel = screen.statusIndicator.get();
const runningCommands = screen.numRunningCmds.get() > 0; const runningCommands = screen.numRunningCmds.get() > 0;
@ -94,7 +90,6 @@ class ScreenTab extends React.Component<
</CenteredIcon> </CenteredIcon>
<div className="tab-name truncate"> <div className="tab-name truncate">
{archived} {archived}
{webShared}
{screen.name.get()} {screen.name.get()}
</div> </div>
<div className="end-icons"> <div className="end-icons">

View File

@ -6,7 +6,7 @@
font-weight: normal; font-weight: normal;
.openai-role { .openai-role {
color: var(--prompt-bright-green); color: var(--term-bright-green);
font-weight: bold; font-weight: bold;
width: 100px; width: 100px;
flex-shrink: 0; flex-shrink: 0;