Pe 107 global changes (#26)

* chaged background etc. now making font changes

* need to go component by component now
This commit is contained in:
anandamarsh 2023-09-27 15:03:08 -07:00 committed by GitHub
parent a25c7b4286
commit b1820224d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 545 additions and 966 deletions

View File

@ -3,7 +3,7 @@
.info-message { .info-message {
position: relative; position: relative;
font-weight: normal; font-weight: normal;
font-size: 12px;
color: @term-white; color: @term-white;
.message-content { .message-content {
@ -52,7 +52,6 @@
} }
.code-div code { .code-div code {
.mono-font(14px);
} }
} }
@ -68,7 +67,7 @@
flex-grow: 0; flex-grow: 0;
padding: 3px; padding: 3px;
border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px;
font-size: 12px;
height: 22px; height: 22px;
width: 22px; width: 22px;
display: flex; display: flex;
@ -76,7 +75,7 @@
justify-content: center; justify-content: center;
align-self: flex-start; align-self: flex-start;
cursor: pointer; cursor: pointer;
background-color: black; background-color: @term-black;
&:hover { &:hover {
background-color: #777; background-color: #777;
@ -84,7 +83,7 @@
} }
.code-div { .code-div {
background-color: black; background-color: @term-black;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
min-width: 100px; min-width: 100px;
@ -94,11 +93,10 @@
code { code {
flex-shrink: 0; flex-shrink: 0;
min-width: 100px; min-width: 100px;
color: white; color: @term-white;
.mono-font(12px);
white-space: pre; white-space: pre;
padding: 2px 8px 2px 8px; padding: 2px 8px 2px 8px;
background-color: black; background-color: @term-black;
} }
} }
@ -112,16 +110,16 @@
position: absolute; position: absolute;
bottom: -1px; bottom: -1px;
right: -20px; right: -20px;
font-size: 9px;
padding: 2px; padding: 2px;
padding-left: 4px; padding-left: 4px;
cursor: pointer; cursor: pointer;
width: 20px; width: 20px;
background-color: black; background-color: @term-black;
border: 1px solid #333; border: 1px solid #333;
color: #777; color: #777;
&:hover { &:hover {
color: white; color: @term-white;
} }
} }
} }
@ -130,7 +128,6 @@
visibility: visible !important; visibility: visible !important;
} }
} }
.terminal-wrapper { .terminal-wrapper {
position: relative; position: relative;
@ -223,7 +220,7 @@ body .xterm .xterm-viewport {
width: 18px; width: 18px;
left: 3px; left: 3px;
bottom: 3px; bottom: 3px;
background-color: white; background-color: @term-white;
transition: 0.5s; transition: 0.5s;
border-radius: 50%; border-radius: 50%;
} }
@ -277,7 +274,6 @@ body .xterm .xterm-viewport {
} }
.cmd-hints { .cmd-hints {
.mono-font(10px);
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -292,22 +288,22 @@ body .xterm .xterm-viewport {
} }
.hint-item.color-green { .hint-item.color-green {
color: black; color: @term-black;
background-color: @tab-green; background-color: @tab-green;
&:hover { &:hover {
color: white; color: @term-white;
} }
} }
.hint-item.color-nohover-green { .hint-item.color-nohover-green {
color: black; color: @term-black;
background-color: @tab-green; background-color: @tab-green;
cursor: default; cursor: default;
} }
.hint-item.color-white { .hint-item.color-white {
color: black; color: @term-black;
background-color: @term-white; background-color: @term-white;
&:hover { &:hover {
@ -316,22 +312,22 @@ body .xterm .xterm-viewport {
} }
.hint-item.color-nohover-white { .hint-item.color-nohover-white {
color: black; color: @term-black;
background-color: @term-white; background-color: @term-white;
cursor: default; cursor: default;
} }
.hint-item.color-blue { .hint-item.color-blue {
color: black; color: @term-black;
background-color: @tab-blue; background-color: @tab-blue;
&:hover { &:hover {
color: white; color: @term-white;
} }
} }
.hint-item.color-nohover-blue { .hint-item.color-nohover-blue {
color: black; color: @term-black;
background-color: @tab-blue; background-color: @tab-blue;
cursor: default; cursor: default;
} }
@ -342,9 +338,8 @@ body .xterm .xterm-viewport {
margin-bottom: 10px; margin-bottom: 10px;
code { code {
background-color: black; background-color: @term-black;
color: white; color: @term-white;
.mono-font();
padding: 5px; padding: 5px;
} }
@ -354,14 +349,13 @@ body .xterm .xterm-viewport {
} }
.title { .title {
color: white; color: @term-white;
margin-top: 16px; margin-top: 16px;
line-height: 1.25;
margin-bottom: 8px; margin-bottom: 8px;
} }
strong { strong {
color: white; color: @term-white;
} }
a { a {
@ -370,7 +364,7 @@ body .xterm .xterm-viewport {
table { table {
tr th { tr th {
color: white; color: @term-white;
} }
} }
@ -399,26 +393,20 @@ body .xterm .xterm-viewport {
} }
.title.is-1 { .title.is-1 {
font-size: 32px;
border-bottom: 1px solid #777; border-bottom: 1px solid #777;
padding-bottom: 6px; padding-bottom: 6px;
} }
.title.is-2 { .title.is-2 {
font-size: 24px;
border-bottom: 1px solid #777; border-bottom: 1px solid #777;
padding-bottom: 6px; padding-bottom: 6px;
} }
.title.is-3 { .title.is-3 {
font-size: 20px;
} }
.title.is-4 { .title.is-4 {
font-size: 16px;
} }
.title.is-5 { .title.is-5 {
font-size: 14px;
} }
.title.is-6 { .title.is-6 {
font-size: 14px;
} }
} }
@ -432,14 +420,13 @@ body .xterm .xterm-viewport {
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: white; background-color: @term-white;
opacity: 0; opacity: 0;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
pointer-events: none; pointer-events: none;
.mono-font(12px);
animation-name: fade-in-out; animation-name: fade-in-out;
animation-duration: 0.3s; animation-duration: 0.3s;
} }
@ -483,17 +470,12 @@ body .xterm .xterm-viewport {
z-index: -1; z-index: -1;
top: -5000px; top: -5000px;
.mono {
.mono-font();
}
.pre { .pre {
white-space: pre; white-space: pre;
} }
} }
.text-button { .text-button {
.mono-font(12px, 700);
color: @term-white; color: @term-white;
cursor: pointer; cursor: pointer;
background-color: #171717; background-color: #171717;
@ -584,8 +566,6 @@ body .xterm .xterm-viewport {
} }
#main .term-prompt { #main .term-prompt {
font-size: 14px;
i { i {
margin-right: 3px; margin-right: 3px;
} }
@ -650,7 +630,6 @@ body .xterm .xterm-viewport {
} }
.remote-status { .remote-status {
font-size: 8px;
margin-right: 5px; margin-right: 5px;
position: relative; position: relative;
top: -3px; top: -3px;

View File

@ -0,0 +1,189 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { If } from "tsx-control-statements/components";
import { GlobalModel } from "../../model";
import { termHeightFromRows } from "../../util/textmeasure";
import type { LineType } from "../../types";
import cn from "classnames";
import type { LineContainerModel } from "../../model";
import * as lineutil from "../../main/line/lineutil";
import "./terminal.less";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>;
type OMap<K, V> = mobx.ObservableMap<K, V>;
@mobxReact.observer
class TerminalRenderer extends React.Component<
{
screen: LineContainerModel;
line: LineType;
width: number;
staticRender: boolean;
visible: OV<boolean>;
onHeightChange: () => void;
collapsed: boolean;
},
{}
> {
termLoaded: mobx.IObservableValue<boolean> = mobx.observable.box(false, {
name: "linecmd-term-loaded",
});
elemRef: React.RefObject<any> = React.createRef();
termRef: React.RefObject<any> = React.createRef();
constructor(props) {
super(props);
}
componentDidMount() {
this.componentDidUpdate(null, null, null);
}
componentWillUnmount() {
if (this.termLoaded.get()) {
this.unloadTerminal(true);
}
}
getSnapshotBeforeUpdate(prevProps, prevState): { height: number } {
let elem = this.elemRef.current;
if (elem == null) {
return { height: 0 };
}
return { height: elem.offsetHeight };
}
componentDidUpdate(prevProps, prevState, snapshot: { height: number }): void {
if (this.props.onHeightChange == null) {
return;
}
let { line } = this.props;
let curHeight = 0;
let elem = this.elemRef.current;
if (elem != null) {
curHeight = elem.offsetHeight;
}
if (snapshot == null) {
snapshot = { height: 0 };
}
if (snapshot.height != curHeight) {
this.props.onHeightChange();
// console.log("term-render height change: ", line.linenum, snapshot.height, "=>", curHeight);
}
this.checkLoad();
}
checkLoad(): void {
let { line, staticRender, visible, collapsed } = this.props;
if (staticRender) {
return;
}
let vis = visible && visible.get() && !collapsed;
let curVis = this.termLoaded.get();
if (vis && !curVis) {
this.loadTerminal();
} else if (!vis && curVis) {
this.unloadTerminal(false);
}
}
loadTerminal(): void {
let { screen, line } = this.props;
let model = GlobalModel;
let cmd = screen.getCmd(line);
if (cmd == null) {
return;
}
let termElem = this.termRef.current;
if (termElem == null) {
console.log("cannot load terminal, no term elem found", line);
return;
}
screen.loadTerminalRenderer(termElem, line, cmd, this.props.width);
mobx.action(() => this.termLoaded.set(true))();
}
unloadTerminal(unmount: boolean): void {
let { screen, line } = this.props;
screen.unloadRenderer(line.lineid);
if (!unmount) {
mobx.action(() => this.termLoaded.set(false))();
let termElem = this.termRef.current;
if (termElem != null) {
termElem.replaceChildren();
}
}
}
@boundMethod
clickTermBlock(e: any) {
let { screen, line } = this.props;
let model = GlobalModel;
let termWrap = screen.getTermWrap(line.lineid);
if (termWrap != null) {
termWrap.giveFocus();
}
}
render() {
let { screen, line, width, staticRender, visible, collapsed } = this.props;
let isVisible = visible.get(); // for reaction
let isPhysicalFocused = mobx
.computed(() => screen.getIsFocused(line.linenum), {
name: "computed-getIsFocused",
})
.get();
let isFocused = mobx
.computed(
() => {
let screenFocusType = screen.getFocusType();
return isPhysicalFocused && screenFocusType == "cmd";
},
{ name: "computed-isFocused" }
)
.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());
let termLoaded = this.termLoaded.get();
return (
<div
ref={this.elemRef}
key="term-wrap"
className={cn(
"terminal-wrapper",
{ focus: isFocused },
{ "cmd-done": !cmd.isRunning() },
{ "zero-height": termHeight == 0 },
{ collapsed: collapsed }
)}
>
<If condition={!isFocused}>
<div key="term-block" className="term-block" onClick={this.clickTermBlock}></div>
</If>
<div
key="term-connectelem"
className="terminal-connectelem"
ref={this.termRef}
data-lineid={line.lineid}
style={{ height: termHeight }}
></div>
<If condition={!termLoaded}>
<div key="term-loading" className="terminal-loading-message">
...
</div>
</If>
</div>
);
}
}
export { TerminalRenderer };

View File

@ -1,5 +1,5 @@
import * as mobx from "mobx"; import * as mobx from "mobx";
import { incObs } from "./util"; import { incObs } from "../../util/util";
type OV<V> = mobx.IObservableValue<V>; type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>; type OArr<V> = mobx.IObservableArray<V>;

View File

@ -2,10 +2,17 @@ import * as mobx from "mobx";
import { Terminal } from "xterm"; import { Terminal } from "xterm";
import { sprintf } from "sprintf-js"; import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator"; import { boundMethod } from "autobind-decorator";
import { v4 as uuidv4 } from "uuid"; import { windowWidthToCols, windowHeightToRows } from "../../util/textmeasure";
import { termHeightFromRows, windowWidthToCols, windowHeightToRows } from "./textmeasure"; import { boundInt } from "../../util/util";
import { boundInt } from "./util"; import type {
import type { TermContextUnion, TermOptsType, TermWinSize, RendererContext, WindowSize, PtyDataType } from "./types"; TermContextUnion,
TermOptsType,
TermWinSize,
RendererContext,
WindowSize,
PtyDataType,
} from "../../types";
import { getTheme } from "../../themes";
type DataUpdate = { type DataUpdate = {
data: Uint8Array; data: Uint8Array;
@ -77,15 +84,13 @@ class TermWrap {
let cols = windowWidthToCols(opts.winSize.width, opts.fontSize); let cols = windowWidthToCols(opts.winSize.width, opts.fontSize);
this.termSize = { rows: opts.termOpts.rows, cols: cols }; this.termSize = { rows: opts.termOpts.rows, cols: cols };
} }
let theme = { const { terminal } = getTheme();
foreground: "#d3d7cf",
};
this.terminal = new Terminal({ this.terminal = new Terminal({
rows: this.termSize.rows, rows: this.termSize.rows,
cols: this.termSize.cols, cols: this.termSize.cols,
fontSize: opts.fontSize, fontSize: opts.fontSize,
fontFamily: "JetBrains Mono", theme: { foreground: terminal.foreground, background: terminal.background },
theme: theme, /*fontFamily: "JetBrains Mono", @check:font */
}); });
this.terminal._core._inputHandler._parser.setErrorHandler((state) => { this.terminal._core._inputHandler._parser.setErrorHandler((state) => {
this.numParseErrors++; this.numParseErrors++;

View File

@ -1,4 +1,7 @@
@import "../../index.less";
/** /**
* Adapted from xterm.css
* Copyright (c) 2014 The xterm.js authors. All rights reserved. * Copyright (c) 2014 The xterm.js authors. All rights reserved.
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
* https://github.com/chjj/term.js * https://github.com/chjj/term.js
@ -79,7 +82,7 @@
.xterm .composition-view { .xterm .composition-view {
/* TODO: Composition position got messed up somewhere */ /* TODO: Composition position got messed up somewhere */
background: #000; background: #000;
color: #FFF; color: #fff;
display: none; display: none;
position: absolute; position: absolute;
white-space: nowrap; white-space: nowrap;
@ -122,7 +125,6 @@
position: absolute; position: absolute;
top: 0; top: 0;
left: -9999em; left: -9999em;
line-height: normal;
} }
.xterm.enable-mouse-events { .xterm.enable-mouse-events {
@ -166,33 +168,53 @@
opacity: 1 !important; opacity: 1 !important;
} }
.xterm-underline-1 { text-decoration: underline; } .xterm-underline-1 {
.xterm-underline-2 { text-decoration: double underline; } text-decoration: underline;
.xterm-underline-3 { text-decoration: wavy underline; } }
.xterm-underline-4 { text-decoration: dotted underline; } .xterm-underline-2 {
.xterm-underline-5 { text-decoration: dashed underline; } text-decoration: double underline;
}
.xterm-underline-3 {
text-decoration: wavy underline;
}
.xterm-underline-4 {
text-decoration: dotted underline;
}
.xterm-underline-5 {
text-decoration: dashed underline;
}
.xterm-overline { .xterm-overline {
text-decoration: overline; text-decoration: overline;
} }
.xterm-overline.xterm-underline-1 { text-decoration: overline underline; } .xterm-overline.xterm-underline-1 {
.xterm-overline.xterm-underline-2 { text-decoration: overline double underline; } text-decoration: overline underline;
.xterm-overline.xterm-underline-3 { text-decoration: overline wavy underline; } }
.xterm-overline.xterm-underline-4 { text-decoration: overline dotted underline; } .xterm-overline.xterm-underline-2 {
.xterm-overline.xterm-underline-5 { text-decoration: overline dashed underline; } text-decoration: overline double underline;
}
.xterm-overline.xterm-underline-3 {
text-decoration: overline wavy underline;
}
.xterm-overline.xterm-underline-4 {
text-decoration: overline dotted underline;
}
.xterm-overline.xterm-underline-5 {
text-decoration: overline dashed underline;
}
.xterm-strikethrough { .xterm-strikethrough {
text-decoration: line-through; text-decoration: line-through;
} }
.xterm-screen .xterm-decoration-container .xterm-decoration { .xterm-screen .xterm-decoration-container .xterm-decoration {
z-index: 6; z-index: 6;
position: absolute; position: absolute;
} }
.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer { .xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer {
z-index: 7; z-index: 7;
} }
.xterm-decoration-overview-ruler { .xterm-decoration-overview-ruler {

View File

@ -4,7 +4,7 @@ import * as fs from "fs";
import fetch from "node-fetch"; import fetch from "node-fetch";
import * as child_process from "node:child_process"; import * as child_process from "node:child_process";
import { debounce } from "throttle-debounce"; import { debounce } from "throttle-debounce";
import { handleJsonFetchResponse } from "./util"; import { handleJsonFetchResponse } from "./util/util";
import * as winston from "winston"; import * as winston from "winston";
import * as util from "util"; import * as util from "util";
import { sprintf } from "sprintf-js"; import { sprintf } from "sprintf-js";
@ -201,12 +201,12 @@ function createMainWindow(clientData) {
let win = new electron.BrowserWindow({ let win = new electron.BrowserWindow({
x: bounds.x, x: bounds.x,
y: bounds.y, y: bounds.y,
titleBarStyle: "hiddenInset",
width: bounds.width, width: bounds.width,
height: bounds.height, height: bounds.height,
webPreferences: { webPreferences: {
preload: path.join(getAppBasePath(), DistDir, "preload.js"), preload: path.join(getAppBasePath(), DistDir, "preload.js"),
}, },
backgroundColor: "#000",
}); });
let indexHtml = isDev ? "index-dev.html" : "index.html"; let indexHtml = isDev ? "index-dev.html" : "index.html";
win.loadFile(path.join(getAppBasePath(), "static", indexHtml)); win.loadFile(path.join(getAppBasePath(), "static", indexHtml));

Binary file not shown.

View File

@ -1,3 +1,7 @@
@base-color: #eceeec;
@base-background: rgba(21, 23, 21, 1);
@base-background-dev: rgba(21, 23, 21, 1);
@term-black: #000000; @term-black: #000000;
@term-red: #cc0000; @term-red: #cc0000;
@term-green: #4e9a06; @term-green: #4e9a06;
@ -34,20 +38,38 @@
@active-menu-color: rgb(0, 71, 171); @active-menu-color: rgb(0, 71, 171);
@import "utils.less"; @font-face {
font-family: "Martian Mono";
// global settings / overrides src: url("./fonts/MartianMono-VariableFont_wdth,wght.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
:root { :root {
--fa-style-family: "Font Awesome 6 Sharp"; --fa-style-family: "Font Awesome 6 Sharp";
} }
html, html,
body, body {
#app, overflow: hidden;
#main { font-family: "Martian Mono", sans-serif;
background-color: #000; font-size: 12.5px;
height: 100vh; font-weight: 300;
line-height: 20px;
background: @base-background;
color: @base-color;
}
#title-bar {
-webkit-app-region: drag;
height: 30px;
width: 100%;
position: absolute;
top: 0;
left: 0;
}
.is-dev #title-bar {
background: @base-background-dev;
} }
.content { .content {
@ -56,10 +78,6 @@ body,
} }
} }
body {
overflow: hidden;
}
body::-webkit-scrollbar { body::-webkit-scrollbar {
display: none; display: none;
} }
@ -78,16 +96,35 @@ input[type="checkbox"] {
cursor: pointer; cursor: pointer;
} }
.display-none {
display: none;
}
.flex-spacer {
flex-grow: 1;
}
.flex-centered-row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
a.a-block {
display: block;
}
// main layout // main layout
#main { #main {
height: 100vh; margin-top: 30px;
height: calc(100vh - 30px);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.main-content { .main-content {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
background-color: black;
height: 100%; height: 100%;
.session-view, .session-view,
@ -120,38 +157,37 @@ input[type="checkbox"] {
top: 0; top: 0;
right: 0; right: 0;
background-color: rgba(78, 154, 6, 0.65); background-color: rgba(78, 154, 6, 0.65);
color: black; color: @term-black;
padding: 2px 8px 2px 4px; padding: 2px 8px 2px 4px;
border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
z-index: 10; z-index: 10;
font-size: 12px;
&.is-active { &.is-active {
color: #ccc; color: @term-white;
} }
.render-mode { .render-mode {
padding-top: 2px; padding-top: 2px;
font-size: 16px;
position: relative; position: relative;
cursor: pointer; cursor: pointer;
color: #ccc; color: @term-white;
&:hover { &:hover {
color: white; color: @term-white;
} }
} }
} }
.share-tag { .share-tag {
color: #ccc; color: @term-white;
position: absolute; position: absolute;
top: 0; top: 0;
left: 40%; left: 40%;
background-color: darken(rgb(0, 177, 10), 20%); background-color: darken(rgb(0, 177, 10), 20%);
padding: 2px 8px 2px 4px; padding: 2px 8px 2px 4px;
z-index: 11; z-index: 11;
font-size: 12px;
/* border-radius: 0 0 5px 5px; */ /* border-radius: 0 0 5px 5px; */
opacity: 0.8; opacity: 0.8;
display: flex; display: flex;
@ -164,7 +200,6 @@ input[type="checkbox"] {
&:hover { &:hover {
.share-tag-title { .share-tag-title {
font-size: 14px;
font-weight: bold; font-weight: bold;
} }
opacity: 1; opacity: 1;
@ -189,11 +224,10 @@ input[type="checkbox"] {
width: 100%; width: 100%;
padding: 10px; padding: 10px;
height: 100%; height: 100%;
color: #ccc; color: @term-white;
.mono-font();
code { code {
background-color: black; background-color: @term-black;
color: #4e9a06; color: #4e9a06;
} }
@ -206,169 +240,19 @@ input[type="checkbox"] {
} }
} }
.remote-field .remote-status {
top: 4px;
}
.terminal-wrapper {
position: relative;
.term-block {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: transparent;
z-index: 10;
}
.xterm-screen {
&::-webkit-scrollbar {
display: none;
}
}
&.focus .xterm {
.xterm-screen {
overflow-y: scroll;
overscroll-behavior: contain;
}
.xterm-viewport {
overscroll-behavior: contain;
}
}
&.focus .xterm-viewport {
&::-webkit-scrollbar {
background-color: #777;
width: 5px;
height: 5px;
}
&::-webkit-scrollbar-thumb {
background: white;
}
}
.xterm-viewport {
&::-webkit-scrollbar {
background-color: #222;
width: 5px;
height: 5px;
}
&::-webkit-scrollbar-thumb {
background: #555;
}
}
}
body .xterm .xterm-viewport {
overflow-y: auto;
width: calc(100% + 5px);
}
.checkbox-toggle {
position: relative;
display: inline-block;
width: 40px;
height: 23px;
input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
content: "";
cursor: pointer;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: #333;
transition: 0.5s;
border-radius: 33px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
transition: 0.5s;
border-radius: 50%;
}
input:checked + .slider {
background-color: @term-green;
}
input:checked + .slider:before {
transform: translateX(18px);
}
}
.button.is-prompt-green {
background-color: #222;
color: @term-white;
&:hover {
background-color: @term-green;
color: @term-bright-white;
}
}
.button.is-plain,
.button.is-prompt-cancel {
background-color: #222;
color: @term-white;
&:hover {
background-color: #666;
color: @term-bright-white;
}
}
.button.is-prompt-danger {
background-color: #222;
color: @term-white;
&:hover {
background-color: @tab-red;
color: @term-bright-white;
}
}
.button.is-inline-height {
height: 22px;
}
.button input.confirm-checkbox {
margin-right: 5px;
}
.copied-indicator { .copied-indicator {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: white; background-color: @term-white;
opacity: 0; opacity: 0;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
pointer-events: none; pointer-events: none;
.mono-font(12px);
animation-name: fade-in-out; animation-name: fade-in-out;
animation-duration: 0.3s; animation-duration: 0.3s;
} }
@ -412,17 +296,12 @@ body .xterm .xterm-viewport {
z-index: -1; z-index: -1;
top: -5000px; top: -5000px;
.mono {
.mono-font();
}
.pre { .pre {
white-space: pre; white-space: pre;
} }
} }
.text-button { .text-button {
.mono-font(12px, 700);
color: @term-white; color: @term-white;
cursor: pointer; cursor: pointer;
background-color: #171717; background-color: #171717;
@ -513,8 +392,6 @@ body .xterm .xterm-viewport {
} }
#main .term-prompt { #main .term-prompt {
font-size: 14px;
i { i {
margin-right: 3px; margin-right: 3px;
} }
@ -579,7 +456,6 @@ body .xterm .xterm-viewport {
} }
.remote-status { .remote-status {
font-size: 8px;
margin-right: 5px; margin-right: 5px;
position: relative; position: relative;
top: -3px; top: -3px;

View File

@ -3,7 +3,7 @@ import * as React from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import { sprintf } from "sprintf-js"; import { sprintf } from "sprintf-js";
import { Main } from "./main/Main"; import { Main } from "./main/Main";
import { loadFonts } from "./util"; import { loadFonts } from "./util/util";
import * as DOMPurify from "dompurify"; import * as DOMPurify from "dompurify";
// @ts-ignore // @ts-ignore
@ -17,14 +17,11 @@ document.addEventListener("DOMContentLoaded", () => {
let reactElem = React.createElement(Main, null, null); let reactElem = React.createElement(Main, null, null);
let elem = document.getElementById("app"); let elem = document.getElementById("app");
let root = createRoot(elem); let root = createRoot(elem);
let isFontLoaded = document.fonts.check("12px 'JetBrains Mono'"); // @check:font
if (isFontLoaded) { // let isFontLoaded = document.fonts.check("12px 'JetBrains Mono'");
document.fonts.ready.then(() => {
root.render(reactElem); root.render(reactElem);
} else { });
document.fonts.ready.then(() => {
root.render(reactElem);
});
}
}); });
(window as any).mobx = mobx; (window as any).mobx = mobx;

View File

@ -7,17 +7,17 @@ import dayjs from "dayjs";
import type { ContextMenuOpts } from "../types"; import type { ContextMenuOpts } from "../types";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../model"; import { GlobalModel } from "../model";
import { isBlank } from "../util"; import { isBlank } from "../util/util";
import { BookmarksView } from "./bookmarks/bookmarks"; import { BookmarksView } from "./bookmarks/bookmarks";
import { WebShareView } from "../webshare/webshare-client-view"; import { WebShareView } from "../webshare/webshare-client-view";
import { HistoryView } from "./history/history"; import { HistoryView } from "./history/history";
import { ScreenSettingsModal, SessionSettingsModal, LineSettingsModal, ClientSettingsModal } from "./modals/settings"; import { ScreenSettingsModal, SessionSettingsModal, LineSettingsModal, ClientSettingsModal } from "./modals/settings";
import { RemotesModal } from "../remotes/remotes"; import { RemotesModal } from "../remotes/remotes";
import { TosModal } from "./modals/Modals"; import { TosModal } from "./modals/Modals";
import { SessionView } from "./sessionview/SessionView"; import { SessionView } from "./sessionview/SessionView";
import { MainSideBar } from "./sidebar/MainSideBar"; import { MainSideBar } from "./sidebar/MainSideBar";
import { DisconnectedModal, ClientStopModal, AlertModal, WelcomeModal } from "./modals/Modals"; import { DisconnectedModal, ClientStopModal, AlertModal, WelcomeModal } from "./modals/Modals";
import "../index.less";
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);
@ -29,6 +29,7 @@ class Main extends React.Component<{}, {}> {
constructor(props: any) { constructor(props: any) {
super(props); super(props);
if (GlobalModel.isDev) document.body.className = "is-dev";
} }
@boundMethod @boundMethod

View File

@ -2,7 +2,7 @@
.bookmarks-view { .bookmarks-view {
.bookmarks-list { .bookmarks-list {
color: white; color: @term-white;
margin: 4px 10px 5px 5px; margin: 4px 10px 5px 5px;
.no-bookmarks { .no-bookmarks {
@ -42,19 +42,15 @@
} }
label { label {
color: white; color: @term-white;
margin-bottom: 4px; margin-bottom: 4px;
} }
textarea { textarea {
width: 80%; width: 80%;
min-width: 50%; min-width: 50%;
color: white; color: @term-white;
background-color: black; background-color: @term-black;
&.mono-font {
.mono-font(12px);
}
} }
.bookmark-id-div { .bookmark-id-div {
@ -63,7 +59,6 @@
color: #666; color: #666;
right: 5px; right: 5px;
bottom: 2px; bottom: 2px;
.mono-font(8px);
} }
&:hover .bookmark-id-div { &:hover .bookmark-id-div {
@ -73,7 +68,7 @@
.bookmark-controls { .bookmark-controls {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
font-size: 16px;
visibility: hidden; visibility: hidden;
color: @term-white; color: @term-white;

View File

@ -99,7 +99,7 @@ class Bookmark extends React.Component<{ bookmark: BookmarkType }, {}> {
<label className="label">Description (markdown)</label> <label className="label">Description (markdown)</label>
<div className="control"> <div className="control">
<textarea <textarea
className="textarea mono-font" className="textarea"
rows={6} rows={6}
value={model.tempDesc.get()} value={model.tempDesc.get()}
onChange={this.handleDescChange} onChange={this.handleDescChange}
@ -110,7 +110,7 @@ class Bookmark extends React.Component<{ bookmark: BookmarkType }, {}> {
<label className="label">Command</label> <label className="label">Command</label>
<div className="control"> <div className="control">
<textarea <textarea
className="textarea mono-font" className="textarea"
rows={3} rows={3}
value={model.tempCmd.get()} value={model.tempCmd.get()}
onChange={this.handleCmdChange} onChange={this.handleCmdChange}

View File

@ -1,11 +1,10 @@
@import "../../index.less"; @import "../../index.less";
.history-view { .history-view {
color: #ccc; color: @term-white;
.close-div { .close-div {
padding-top: 10px; padding-top: 10px;
font-size: 24px;
i { i {
padding: 5px 5px 5px 10px; padding: 5px 5px 5px 10px;
@ -25,17 +24,16 @@
.history-title { .history-title {
margin-top: 5px; margin-top: 5px;
.mono-font(1.5rem);
font-weight: bold; font-weight: bold;
color: white; color: @term-white;
} }
input { input {
background-color: #333; background-color: #333;
color: white; color: @term-white;
i { i {
color: white; color: @term-white;
} }
} }
} }
@ -63,7 +61,7 @@
.session-dropdown, .session-dropdown,
.remote-dropdown { .remote-dropdown {
.dropdown-item { .dropdown-item {
color: white; color: @term-white;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background-color: #666; background-color: #666;
@ -84,7 +82,7 @@
margin-left: 15px; margin-left: 15px;
border: 1px solid #777; border: 1px solid #777;
padding: 5px 10px 5px 10px; padding: 5px 10px 5px 10px;
font-size: 12px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
@ -105,7 +103,6 @@
} }
.fromts { .fromts {
font-size: 12px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
@ -118,7 +115,7 @@
.reset-button { .reset-button {
cursor: pointer; cursor: pointer;
margin-left: 15px; margin-left: 15px;
font-size: 12px;
border: 1px solid #777; border: 1px solid #777;
padding: 5px 10px 5px 10px; padding: 5px 10px 5px 10px;
@ -150,12 +147,12 @@
.control-checkbox { .control-checkbox {
cursor: pointer; cursor: pointer;
color: #777; color: #777;
font-size: 18px;
width: 24px; width: 24px;
margin-left: 14px; margin-left: 14px;
&:hover { &:hover {
color: white; color: @term-white;
} }
} }
@ -163,7 +160,6 @@
cursor: pointer; cursor: pointer;
color: #aaa; color: #aaa;
margin-left: 10px; margin-left: 10px;
font-size: 14px;
&.is-disabled { &.is-disabled {
cursor: default; cursor: default;
@ -174,7 +170,7 @@
} }
&:hover { &:hover {
color: white; color: @term-white;
} }
&.delete-button.is-active { &.delete-button.is-active {
@ -187,14 +183,13 @@
} }
.showing-text { .showing-text {
font-size: 16px;
margin-right: 10px; margin-right: 10px;
} }
.showing-btn { .showing-btn {
padding: 0 5px 0 5px; padding: 0 5px 0 5px;
cursor: pointer; cursor: pointer;
font-size: 16px;
font-weight: bold; font-weight: bold;
&.is-disabled { &.is-disabled {
@ -213,7 +208,6 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
.mono-font(14px);
padding: 30px 0 30px 0; padding: 30px 0 30px 0;
border: 1px solid white; border: 1px solid white;
border-radius: 3px; border-radius: 3px;
@ -232,11 +226,10 @@
.line-container { .line-container {
padding: 0px 10px 10px 10px; padding: 0px 10px 10px 10px;
overflow-x: auto; overflow-x: auto;
background-color: black; background-color: @term-black;
} }
.line-context { .line-context {
.mono-font(12px);
margin-left: 20px; margin-left: 20px;
margin-bottom: 10px; margin-bottom: 10px;
margin-top: 10px; margin-top: 10px;
@ -245,10 +238,10 @@
.vic-btn { .vic-btn {
cursor: pointer; cursor: pointer;
color: #ccc; color: @term-white;
&:hover { &:hover {
color: white; color: @term-white;
} }
} }
} }
@ -258,7 +251,6 @@
} }
.line-container.no-line { .line-container.no-line {
.mono-font(12px);
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
@ -299,14 +291,14 @@
td.selectbox { td.selectbox {
flex: 0 0 auto; flex: 0 0 auto;
flex-basis: 24px; flex-basis: 24px;
font-size: 14px;
cursor: pointer; cursor: pointer;
} }
td.bookmark { td.bookmark {
flex: 0 0 auto; flex: 0 0 auto;
flex-basis: 20px; flex-basis: 20px;
font-size: 14px;
cursor: pointer; cursor: pointer;
i { i {
@ -317,21 +309,18 @@
} }
td.ts { td.ts {
font-size: 12px;
flex: 0 0 auto; flex: 0 0 auto;
flex-basis: 65px; flex-basis: 65px;
font-weight: bold; font-weight: bold;
} }
td.session { td.session {
font-size: 12px;
flex: 0 0 auto; flex: 0 0 auto;
flex-basis: 120px; flex-basis: 120px;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
td.remote { td.remote {
.mono-font(12px);
flex: 0 0 auto; flex: 0 0 auto;
flex-basis: 150px; flex-basis: 150px;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -341,8 +330,7 @@
} }
td.cmdstr { td.cmdstr {
.mono-font(12px); color: @term-white;
color: white;
flex: 1 0 0; flex: 1 0 0;
padding-left: 20px; padding-left: 20px;
border-radius: 3px; border-radius: 3px;

View File

@ -7,7 +7,7 @@ import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import { If } from "tsx-control-statements/components"; import { If } from "tsx-control-statements/components";
import { GlobalModel, GlobalCommandRunner, Cmd, getTermPtyData } from "../../model"; import { GlobalModel, GlobalCommandRunner, Cmd, getTermPtyData } from "../../model";
import { termHeightFromRows } from "../../textmeasure"; import { termHeightFromRows } from "../../util/textmeasure";
import type { import type {
LineType, LineType,
CmdDataType, CmdDataType,
@ -27,7 +27,8 @@ import type { LineContainerModel } from "../../model";
import { renderCmdText } from "../../common/common"; import { renderCmdText } from "../../common/common";
import { SimpleBlobRenderer } from "./renderer/simplerenderer"; import { SimpleBlobRenderer } from "./renderer/simplerenderer";
import { FullRenderer } from "./renderer/fullrenderer"; import { FullRenderer } from "./renderer/fullrenderer";
import { isBlank } from "../../util"; import { TerminalRenderer } from "../../common/terminal/Terminal";
import { isBlank } from "../../util/util";
import { PluginModel } from "../../plugins/plugins"; import { PluginModel } from "../../plugins/plugins";
import * as lineutil from "./lineutil"; import * as lineutil from "./lineutil";
@ -997,170 +998,4 @@ class LineText extends React.Component<
} }
} }
@mobxReact.observer
class TerminalRenderer extends React.Component<
{
screen: LineContainerModel;
line: LineType;
width: number;
staticRender: boolean;
visible: OV<boolean>;
onHeightChange: () => void;
collapsed: boolean;
},
{}
> {
termLoaded: mobx.IObservableValue<boolean> = mobx.observable.box(false, {
name: "linecmd-term-loaded",
});
elemRef: React.RefObject<any> = React.createRef();
termRef: React.RefObject<any> = React.createRef();
constructor(props) {
super(props);
}
componentDidMount() {
this.componentDidUpdate(null, null, null);
}
componentWillUnmount() {
if (this.termLoaded.get()) {
this.unloadTerminal(true);
}
}
getSnapshotBeforeUpdate(prevProps, prevState): { height: number } {
let elem = this.elemRef.current;
if (elem == null) {
return { height: 0 };
}
return { height: elem.offsetHeight };
}
componentDidUpdate(prevProps, prevState, snapshot: { height: number }): void {
if (this.props.onHeightChange == null) {
return;
}
let { line } = this.props;
let curHeight = 0;
let elem = this.elemRef.current;
if (elem != null) {
curHeight = elem.offsetHeight;
}
if (snapshot == null) {
snapshot = { height: 0 };
}
if (snapshot.height != curHeight) {
this.props.onHeightChange();
// console.log("term-render height change: ", line.linenum, snapshot.height, "=>", curHeight);
}
this.checkLoad();
}
checkLoad(): void {
let { line, staticRender, visible, collapsed } = this.props;
if (staticRender) {
return;
}
let vis = visible && visible.get() && !collapsed;
let curVis = this.termLoaded.get();
if (vis && !curVis) {
this.loadTerminal();
} else if (!vis && curVis) {
this.unloadTerminal(false);
}
}
loadTerminal(): void {
let { screen, line } = this.props;
let model = GlobalModel;
let cmd = screen.getCmd(line);
if (cmd == null) {
return;
}
let termElem = this.termRef.current;
if (termElem == null) {
console.log("cannot load terminal, no term elem found", line);
return;
}
screen.loadTerminalRenderer(termElem, line, cmd, this.props.width);
mobx.action(() => this.termLoaded.set(true))();
}
unloadTerminal(unmount: boolean): void {
let { screen, line } = this.props;
screen.unloadRenderer(line.lineid);
if (!unmount) {
mobx.action(() => this.termLoaded.set(false))();
let termElem = this.termRef.current;
if (termElem != null) {
termElem.replaceChildren();
}
}
}
@boundMethod
clickTermBlock(e: any) {
let { screen, line } = this.props;
let model = GlobalModel;
let termWrap = screen.getTermWrap(line.lineid);
if (termWrap != null) {
termWrap.giveFocus();
}
}
render() {
let { screen, line, width, staticRender, visible, collapsed } = this.props;
let isVisible = visible.get(); // for reaction
let isPhysicalFocused = mobx
.computed(() => screen.getIsFocused(line.linenum), {
name: "computed-getIsFocused",
})
.get();
let isFocused = mobx
.computed(
() => {
let screenFocusType = screen.getFocusType();
return isPhysicalFocused && screenFocusType == "cmd";
},
{ name: "computed-isFocused" }
)
.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());
let termLoaded = this.termLoaded.get();
return (
<div
ref={this.elemRef}
key="term-wrap"
className={cn(
"terminal-wrapper",
{ focus: isFocused },
{ "cmd-done": !cmd.isRunning() },
{ "zero-height": termHeight == 0 },
{ collapsed: collapsed }
)}
>
<If condition={!isFocused}>
<div key="term-block" className="term-block" onClick={this.clickTermBlock}></div>
</If>
<div
key="term-connectelem"
className="terminal-connectelem"
ref={this.termRef}
data-lineid={line.lineid}
style={{ height: termHeight }}
></div>
<If condition={!termLoaded}>
<div key="term-loading" className="terminal-loading-message">
...
</div>
</If>
</div>
);
}
}
export { Line, Prompt }; export { Line, Prompt };

View File

@ -11,7 +11,6 @@
margin-left: 10px; margin-left: 10px;
.text { .text {
font-size: 1rem;
color: #ddd; color: #ddd;
} }
} }
@ -24,13 +23,11 @@
} }
.line .load-error-text { .line .load-error-text {
.mono-font();
color: @term-red; color: @term-red;
padding-top: 5px; padding-top: 5px;
} }
.line .renderer-loading { .line .renderer-loading {
.mono-font();
color: @term-white; color: @term-white;
padding-top: 5px; padding-top: 5px;
} }
@ -64,7 +61,6 @@
visibility: hidden; visibility: hidden;
cursor: pointer; cursor: pointer;
padding: 3px; padding: 3px;
font-size: 1.5rem;
} }
.line-icon-show { .line-icon-show {
@ -72,11 +68,11 @@
} }
.line-bookmark:hover { .line-bookmark:hover {
color: white; color: @term-white;
} }
.line-minimise:hover { .line-minimise:hover {
color: white; color: @term-white;
} }
.line-icon + .line-icon { .line-icon + .line-icon {
@ -118,15 +114,12 @@
.loading-div { .loading-div {
height: 20px; height: 20px;
margin-left: 50px; margin-left: 50px;
.mono-font();
} }
} }
.terminal-wrapper { .terminal-wrapper {
background-color: #000;
padding: 2px 10px 5px 4px; padding: 2px 10px 5px 4px;
margin: 4px 8px 0 -4px; margin: 4px 8px 0 -4px;
align-self: flex-start;
&.zero-height { &.zero-height {
padding: 0; padding: 0;
@ -151,7 +144,6 @@
top: calc(40% - 8px); top: calc(40% - 8px);
left: 50px; left: 50px;
height: 20px; height: 20px;
.mono-font();
} }
} }
@ -161,11 +153,11 @@
.cmd-rtnstate-label { .cmd-rtnstate-label {
position: relative; position: relative;
z-index: 2; z-index: 2;
.mono-font(9px);
margin-left: 10px; margin-left: 10px;
padding: 2px 5px 2px 5px; padding: 2px 5px 2px 5px;
color: #666; color: #666;
background-color: black; background-color: @term-black;
display: inline-block; display: inline-block;
} }
@ -180,7 +172,6 @@
.cmd-rtnstate-diff { .cmd-rtnstate-diff {
color: @term-white; color: @term-white;
.mono-font();
white-space: pre; white-space: pre;
margin-left: 15px; margin-left: 15px;
} }
@ -191,7 +182,6 @@
margin: 0px 5px 0px 5px; margin: 0px 5px 0px 5px;
padding: 5px 5px 0px 12px; padding: 5px 5px 0px 12px;
display: flex; display: flex;
line-height: 1.25;
overflow: hidden; overflow: hidden;
flex-shrink: 0; flex-shrink: 0;
position: relative; position: relative;
@ -207,12 +197,10 @@
.ts { .ts {
display: flex; display: flex;
color: #aaa; color: #aaa;
.mono-font(11px);
} }
} }
.simple-line-status { .simple-line-status {
.mono-font(12px);
color: #aaa; color: #aaa;
i { i {
@ -226,7 +214,7 @@
&.has-rtnstate { &.has-rtnstate {
.linenum { .linenum {
color: white; color: @term-white;
font-weight: bold; font-weight: bold;
} }
} }
@ -272,8 +260,8 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-weight: bold; font-weight: bold;
color: white; color: @term-white;
font-size: 16px;
border-radius: 5px; border-radius: 5px;
position: relative; position: relative;
@ -282,29 +270,24 @@
} }
.status-icon { .status-icon {
font-size: 8px;
position: absolute; position: absolute;
top: 2px; top: 2px;
right: 2px; right: 2px;
} }
.comment-icon { .comment-icon {
font-size: 10px;
position: absolute; position: absolute;
top: 0px; top: 0px;
right: -4px; right: -4px;
} }
&.num-4 { &.num-4 {
font-size: 13px;
} }
&.num-5 { &.num-5 {
font-size: 11px;
} }
&.num-6 { &.num-6 {
font-size: 9px;
} }
&.status-done { &.status-done {
@ -341,7 +324,7 @@
.status-icon { .status-icon {
top: 3px; top: 3px;
right: 3px; right: 3px;
color: white; color: @term-white;
} }
} }
} }
@ -357,7 +340,7 @@
.meta { .meta {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
font-size: 1rem;
margin-top: -4px; margin-top: -4px;
.simple-line-status { .simple-line-status {
@ -377,17 +360,16 @@
display: flex; display: flex;
color: #aaa; color: #aaa;
margin-top: 5px; margin-top: 5px;
.mono-font(11px);
} }
.renderer { .renderer {
color: #aaa; color: #aaa;
margin-left: 3px; margin-left: 3px;
margin-top: 5px; margin-top: 5px;
.mono-font(11px);
i { i {
display: inline-block; display: inline-block;
font-size: 9px;
margin-right: 2px; margin-right: 2px;
margin-top: 2px; margin-top: 2px;
} }
@ -396,7 +378,7 @@
.settings { .settings {
display: none; display: none;
color: #aaa; color: #aaa;
font-size: 11px;
margin-left: 5px; margin-left: 5px;
margin-top: 5px; margin-top: 5px;
cursor: pointer; cursor: pointer;
@ -405,7 +387,7 @@
.termopts { .termopts {
color: #aaa; color: #aaa;
margin-top: 5px; margin-top: 5px;
.mono-font(11px);
display: none; display: none;
.resize-button { .resize-button {
@ -420,12 +402,11 @@
margin-left: 8px; margin-left: 8px;
margin-top: 4px; margin-top: 4px;
white-space: nowrap; white-space: nowrap;
.mono-font(14px);
} }
.cmdtext { .cmdtext {
color: #fff; color: #fff;
font-size: 16px;
font-weight: bold; font-weight: bold;
overflow: hidden; overflow: hidden;
margin-left: 0; margin-left: 0;
@ -434,9 +415,9 @@
.cmdtext-overflow { .cmdtext-overflow {
flex-shrink: 0; flex-shrink: 0;
padding-right: 2px; padding-right: 2px;
color: white; color: @term-white;
cursor: pointer; cursor: pointer;
.mono-font(16px);
margin-top: 4px; margin-top: 4px;
} }
} }
@ -451,8 +432,8 @@
.cmdtext-expanded { .cmdtext-expanded {
white-space: pre; white-space: pre;
.mono-font(14px);
color: white; color: @term-white;
padding-bottom: 5px; padding-bottom: 5px;
} }
} }
@ -494,7 +475,7 @@
.line-sep { .line-sep {
display: flex; display: flex;
align-items: center; align-items: center;
.mono-font(11px);
color: #aaa; color: #aaa;
} }
@ -502,7 +483,7 @@
.line-sep::after { .line-sep::after {
content: ""; content: "";
height: 2px; height: 2px;
background-color: #ccc; background-color: @term-white;
flex-grow: 1; flex-grow: 1;
} }

View File

@ -9,7 +9,7 @@ import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import { debounce, throttle } from "throttle-debounce"; import { debounce, throttle } from "throttle-debounce";
import * as T from "../../types"; import * as T from "../../types";
import * as util from "../../util"; import * as util from "../../util/util";
import * as lineutil from "./lineutil"; import * as lineutil from "./lineutil";
import "./lines.less"; import "./lines.less";

View File

@ -1,6 +1,6 @@
import dayjs from "dayjs"; import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import { isBlank, getDateStr } from "../../util"; import { isBlank, getDateStr } from "../../util/util";
import { LineType, WebLine, RendererContext } from "../../types"; import { LineType, WebLine, RendererContext } from "../../types";
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);

View File

@ -21,9 +21,9 @@ import type {
RendererContainerType, RendererContainerType,
} from "../../../types"; } from "../../../types";
import * as T from "../../../types"; import * as T from "../../../types";
import { PacketDataBuffer } from "../../../ptydata"; import { PacketDataBuffer } from "../../../terminal/ptydata";
import { debounce, throttle } from "throttle-debounce"; import { debounce, throttle } from "throttle-debounce";
import * as util from "../../../util"; import * as util from "../../../util/util";
import { GlobalModel } from "../../../model"; import { GlobalModel } from "../../../model";
type OV<V> = mobx.IObservableValue<V>; type OV<V> = mobx.IObservableValue<V>;

View File

@ -16,7 +16,6 @@
} }
.content { .content {
.mono-font(13px);
} }
} }
@ -24,7 +23,6 @@
.modal-content { .modal-content {
footer { footer {
.footer-text-link { .footer-text-link {
.mono-font(12px);
color: @term-white; color: @term-white;
cursor: pointer; cursor: pointer;
} }
@ -34,12 +32,11 @@
.inner-content { .inner-content {
.ws-log { .ws-log {
padding: 5px; padding: 5px;
background-color: black; background-color: @term-black;
height: 250px; height: 250px;
overflow: auto; overflow: auto;
.ws-logline { .ws-logline {
.mono-font(12px);
color: @term-white; color: @term-white;
} }
} }
@ -61,7 +58,6 @@
.progress-text { .progress-text {
color: @term-white; color: @term-white;
align-self: center; align-self: center;
font-size: 12px;
} }
} }
} }
@ -98,7 +94,7 @@
.dropdown { .dropdown {
.dropdown-menu .dropdown-content { .dropdown-menu .dropdown-content {
.dropdown-item { .dropdown-item {
color: white; color: @term-white;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background-color: #333; background-color: #333;
@ -128,7 +124,6 @@
.modal-title { .modal-title {
color: @prompt-green; color: @prompt-green;
.mono-font(24px);
} }
.close-icon { .close-icon {
@ -138,7 +133,6 @@
cursor: pointer; cursor: pointer;
padding: 3px; padding: 3px;
color: #aaa; color: #aaa;
font-size: 20px;
&:hover { &:hover {
color: #fff; color: #fff;
@ -187,8 +181,6 @@
} }
.dots { .dots {
font-size: 10px;
i { i {
margin-left: 5px; margin-left: 5px;
} }
@ -208,19 +200,17 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
font-size: 14px;
&.settings-field.sub-field { &.settings-field.sub-field {
.settings-label { .settings-label {
font-weight: normal; font-weight: normal;
font-size: 13px;
text-align: right; text-align: right;
padding-right: 20px; padding-right: 20px;
} }
} }
&.settings-error { &.settings-error {
font-size: 14px;
color: @term-red; color: @term-red;
margin-top: 20px; margin-top: 20px;
padding: 10px; padding: 10px;
@ -273,7 +263,6 @@
input.input { input.input {
padding: 0; padding: 0;
height: 20px; height: 20px;
font-size: 12px;
} }
.button { .button {
@ -287,7 +276,6 @@
} }
.control { .control {
font-size: 12px;
} }
.tab-color-icon.color-green { .tab-color-icon.color-green {
@ -330,14 +318,12 @@
} }
.tab-color-cur { .tab-color-cur {
font-size: 12px;
width: 100px; width: 100px;
} }
.tab-color-select { .tab-color-select {
cursor: pointer; cursor: pointer;
margin: 5px; margin: 5px;
line-height: 1;
&:hover { &:hover {
outline: 2px solid white; outline: 2px solid white;
} }
@ -346,7 +332,7 @@
.action-text { .action-text {
margin-left: 20px; margin-left: 20px;
font-size: 12px;
color: @term-red; color: @term-red;
} }

View File

@ -8,7 +8,7 @@ import { GlobalModel, GlobalCommandRunner, TabColors } from "../../model";
import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage } from "../../common/common"; import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage } from "../../common/common";
import { LineType, RendererPluginType, ClientDataType, CommandRtnType } from "../../types"; import { LineType, RendererPluginType, ClientDataType, CommandRtnType } from "../../types";
import { PluginModel } from "../../plugins/plugins"; import { PluginModel } from "../../plugins/plugins";
import * as util from "../../util"; import * as util from "../../util/util";
import "./modals.less"; import "./modals.less";

View File

@ -9,7 +9,7 @@ import dayjs from "dayjs";
import type { HistoryItem, HistoryQueryOpts } from "../../types"; import type { HistoryItem, HistoryQueryOpts } from "../../types";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../../model"; import { GlobalModel } from "../../model";
import { isBlank } from "../../util"; import { isBlank } from "../../util/util";
import "./sessionview.less"; import "./sessionview.less";
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);

View File

@ -5,7 +5,7 @@ import cn from "classnames";
import dayjs from "dayjs"; import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../../model"; import { GlobalModel } from "../../model";
import { makeExternLink } from "../../util"; import { makeExternLink } from "../../util/util";
import "./sessionview.less"; import "./sessionview.less";
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);

View File

@ -4,8 +4,8 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator"; import { boundMethod } from "autobind-decorator";
import cn from "classnames"; import cn from "classnames";
import { GlobalModel, GlobalCommandRunner } from "../../model"; import { GlobalModel, GlobalCommandRunner } from "../../model";
import { getMonoFontSize } from "../../textmeasure"; import { getMonoFontSize } from "../../util/textmeasure";
import { isModKeyPress, hasNoModifiers } from "../../util"; import { isModKeyPress, hasNoModifiers } from "../../util/util";
import "./sessionview.less"; import "./sessionview.less";
function pageSize(div: any): number { function pageSize(div: any): number {

View File

@ -52,14 +52,12 @@
flex-direction: row; flex-direction: row;
color: @term-yellow; color: @term-yellow;
align-items: center; align-items: center;
font-size: 14px;
.button { .button {
margin-left: 10px; margin-left: 10px;
} }
.remote-name { .remote-name {
.mono-font(14px);
} }
} }
@ -68,7 +66,7 @@
top: 5px; top: 5px;
right: 5px; right: 5px;
color: @term-white; color: @term-white;
font-size: 12px;
padding: 5px; padding: 5px;
cursor: pointer; cursor: pointer;
} }
@ -78,7 +76,6 @@
} }
.cmd-input-context { .cmd-input-context {
.mono-font();
color: #fff; color: #fff;
white-space: nowrap; white-space: nowrap;
} }
@ -86,10 +83,6 @@
.cmd-input-field { .cmd-input-field {
position: relative; position: relative;
.cmd-input-control {
line-height: 0;
}
.cmd-hints { .cmd-hints {
position: absolute; position: absolute;
bottom: -14px; bottom: -14px;
@ -97,9 +90,8 @@
} }
textarea { textarea {
color: white; color: @term-white;
background-color: black; background-color: @term-black;
.mono-font();
padding-bottom: calc(0.5em - 1px); padding-bottom: calc(0.5em - 1px);
padding-top: calc(0.5em - 1px); padding-top: calc(0.5em - 1px);
resize: none; resize: none;
@ -107,7 +99,7 @@
&:active, &:active,
&:focus { &:focus {
border-color: white !important; border-color: @term-white !important;
} }
&.display-disabled { &.display-disabled {
@ -122,18 +114,17 @@
} }
.cmd-quick-context .button { .cmd-quick-context .button {
.mono-font();
background-color: #000 !important; background-color: #000 !important;
color: white; color: @term-white;
} }
&.inputmode-global .cmd-quick-context .button { &.inputmode-global .cmd-quick-context .button {
color: black; color: @term-black;
background-color: @tab-green !important; background-color: @tab-green !important;
} }
&.inputmode-comment .cmd-quick-context .button { &.inputmode-comment .cmd-quick-context .button {
color: black; color: @term-black;
background-color: @tab-blue !important; background-color: @tab-blue !important;
} }
@ -154,8 +145,7 @@
z-index: 102; z-index: 102;
top: 5px; top: 5px;
left: 20px; left: 20px;
background-color: black; background-color: @term-black;
.mono-font(12px, 700);
color: @soft-blue; color: @soft-blue;
padding-bottom: 4px; padding-bottom: 4px;
display: flex; display: flex;
@ -184,7 +174,7 @@
.history-items { .history-items {
margin-top: 24px; margin-top: 24px;
color: @term-white; color: @term-white;
.mono-font(12px);
padding-bottom: 6px; padding-bottom: 6px;
.history-line { .history-line {
@ -226,7 +216,6 @@
margin-bottom: 5px; margin-bottom: 5px;
.info-msg { .info-msg {
.mono-font(14px, 400);
color: @soft-blue; color: @soft-blue;
padding-bottom: 2px; padding-bottom: 2px;
@ -236,13 +225,11 @@
} }
.info-title { .info-title {
.mono-font(14px, 700);
color: @soft-blue; color: @soft-blue;
padding-bottom: 2px; padding-bottom: 2px;
} }
.info-lines { .info-lines {
.mono-font(12px);
color: @term-white; color: @term-white;
white-space: pre; white-space: pre;
padding-bottom: 6px; padding-bottom: 6px;
@ -253,7 +240,6 @@
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
padding-bottom: 5px; padding-bottom: 5px;
.mono-font(14px, 400);
.info-comp { .info-comp {
min-width: 200px; min-width: 200px;
@ -271,7 +257,6 @@
} }
.info-error { .info-error {
.mono-font(14px, 700);
color: @term-red; color: @term-red;
padding-bottom: 2px; padding-bottom: 2px;
} }
@ -279,7 +264,7 @@
.info-remote-showall { .info-remote-showall {
table.remotes-table { table.remotes-table {
th { th {
color: white; color: @term-white;
font-weight: bold; font-weight: bold;
} }
@ -300,7 +285,6 @@
.info-remote { .info-remote {
color: #d3d7cf; color: #d3d7cf;
.mono-font(12px);
.info-remote-title { .info-remote-title {
font-weight: bold; font-weight: bold;
@ -356,8 +340,8 @@
input[type="text"], input[type="text"],
input[type="number"], input[type="number"],
input[type="password"] { input[type="password"] {
background-color: black; background-color: @term-black;
color: white; color: @term-white;
width: 200px; width: 200px;
} }
} }
@ -372,8 +356,8 @@
&.select-input { &.select-input {
select { select {
width: 200px; width: 200px;
background-color: black; background-color: @term-black;
color: white; color: @term-white;
} }
} }
} }
@ -382,7 +366,6 @@
.info-remote-showall { .info-remote-showall {
color: #d3d7cf; color: #d3d7cf;
.mono-font(12px);
} }
} }
} }

View File

@ -8,7 +8,7 @@
background-color: @tab-green; background-color: @tab-green;
} }
&.is-active { &.is-active {
color: white; color: @term-white;
background-color: @tab-green; background-color: @tab-green;
} }
} }
@ -20,7 +20,7 @@
background-color: @tab-orange; background-color: @tab-orange;
} }
&.is-active { &.is-active {
color: black; color: @term-black;
background-color: @tab-orange; background-color: @tab-orange;
} }
} }
@ -32,7 +32,7 @@
background-color: @tab-red; background-color: @tab-red;
} }
&.is-active { &.is-active {
color: white; color: @term-white;
background-color: @tab-red; background-color: @tab-red;
} }
} }
@ -45,7 +45,7 @@
} }
&.is-active { &.is-active {
background-color: @tab-yellow; background-color: @tab-yellow;
color: black; color: @term-black;
box-shadow: 0 3px 0 #fff inset, 0 4px 0 #000 inset; box-shadow: 0 3px 0 #fff inset, 0 4px 0 #000 inset;
} }
} }
@ -57,7 +57,7 @@
background-color: @tab-blue; background-color: @tab-blue;
} }
&.is-active { &.is-active {
color: white; color: @term-white;
background-color: @tab-blue; background-color: @tab-blue;
} }
} }
@ -69,7 +69,7 @@
background-color: @tab-magenta; background-color: @tab-magenta;
} }
&.is-active { &.is-active {
color: white; color: @term-white;
background-color: @tab-magenta; background-color: @tab-magenta;
} }
} }
@ -81,7 +81,7 @@
background-color: @tab-cyan; background-color: @tab-cyan;
} }
&.is-active { &.is-active {
color: black; color: @term-black;
background-color: @tab-cyan; background-color: @tab-cyan;
} }
} }
@ -93,7 +93,7 @@
background-color: @tab-white; background-color: @tab-white;
} }
&.is-active { &.is-active {
color: black; color: @term-black;
background-color: @tab-white; background-color: @tab-white;
box-shadow: 0 3px 0 #fff inset, 0 4px 0 #000 inset; box-shadow: 0 3px 0 #fff inset, 0 4px 0 #000 inset;
} }
@ -106,7 +106,7 @@
background-color: @tab-black; background-color: @tab-black;
} }
&.is-active { &.is-active {
color: white; color: @term-white;
background-color: @tab-black; background-color: @tab-black;
} }
} }
@ -167,12 +167,11 @@
height: 30px; height: 30px;
min-width: 80px; min-width: 80px;
width: 150px; width: 150px;
line-height: 1;
flex-shrink: 1; flex-shrink: 1;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-size: 12px;
font-weight: 500; font-weight: 500;
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
@ -201,7 +200,6 @@
} }
.tab-index { .tab-index {
font-size: 11px;
position: absolute; position: absolute;
right: 2px; right: 2px;
top: 4px; top: 4px;
@ -236,7 +234,6 @@
right: 3px; right: 3px;
padding-left: 4px; padding-left: 4px;
i { i {
font-size: 15px;
} }
} }
} }
@ -254,9 +251,9 @@
.screen-tab.new-screen { .screen-tab.new-screen {
width: 30px; width: 30px;
min-width: 30px; min-width: 30px;
background-color: black; background-color: @term-black;
border-right: none; border-right: none;
color: #ccc; color: @term-white;
cursor: pointer; cursor: pointer;
&:hover { &:hover {

View File

@ -10,7 +10,7 @@ import type * as T from "../../types";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel, GlobalCommandRunner, Session } from "../../model"; import { GlobalModel, GlobalCommandRunner, Session } from "../../model";
import { sortAndFilterRemotes, isBlank } from "../../util"; import { sortAndFilterRemotes, isBlank } from "../../util/util";
import { RemoteStatusLight } from "../../common/common"; import { RemoteStatusLight } from "../../common/common";
@ -159,18 +159,6 @@ class MainSideBar extends React.Component<{}, {}> {
let mainView = GlobalModel.activeMainView.get(); let mainView = GlobalModel.activeMainView.get();
return ( return (
<div className={cn("main-sidebar", { collapsed: isCollapsed }, { "is-dev": GlobalModel.isDev })}> <div className={cn("main-sidebar", { collapsed: isCollapsed }, { "is-dev": GlobalModel.isDev })}>
<div className="logo-header">
<h1
className={cn(
"title",
"prompt-logo-small",
{ collapsed: isCollapsed },
{ "is-dev": GlobalModel.isDev }
)}
>
{isCollapsed ? "[p]" : "[prompt]"}
</h1>
</div>
<div className="collapse-container"> <div className="collapse-container">
<div className="arrow-container" onClick={this.toggleCollapsed}> <div className="arrow-container" onClick={this.toggleCollapsed}>
<If condition={!isCollapsed}> <If condition={!isCollapsed}>

View File

@ -7,35 +7,6 @@
border-bottom: 2px solid #ddd; border-bottom: 2px solid #ddd;
margin-left: -4px; margin-left: -4px;
margin-right: -5px; margin-right: -5px;
.title.prompt-logo-small {
padding-left: 5px;
padding-top: 8px;
padding-bottom: 8px;
margin-bottom: 0;
.mono-font(1.5rem);
background-color: darken(rgb(0, 177, 10), 30%);
color: rgb(0, 177, 10);
position: relative;
white-space: nowrap;
overflow: hidden;
flex-shrink: 0;
&.is-dev {
background-color: darken(rgb(177, 0, 10), 30%);
}
&.collapsed {
padding-left: 1px;
}
.title-cursor {
position: relative;
bottom: 3px;
left: 3px;
.mono-font(1.2rem);
}
}
} }
.main-sidebar { .main-sidebar {
@ -45,15 +16,9 @@
overflow-x: hidden; overflow-x: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
color: #ddd;
position: relative; position: relative;
background-color: darken(rgb(0, 177, 10), 30%);
flex-shrink: 0; flex-shrink: 0;
&.is-dev {
background-color: darken(rgb(177, 0, 10), 30%);
}
.menu { .menu {
padding-top: 10px; padding-top: 10px;
display: flex; display: flex;
@ -69,43 +34,15 @@
} }
a:hover { a:hover {
color: white; color: @term-white;
} }
} }
.menu-label { .menu-label {
color: #bbb; color: @base-color;
a {
color: #bbb;
}
}
p.menu-label {
margin-bottom: 0px;
} }
.menu-list { .menu-list {
li.new-session,
li.add-remote {
a {
color: #666;
font-size: 13px;
}
.fa {
font-size: 10px;
}
}
li {
.mono-font();
}
li.menu-loading-message {
.mono-font();
}
li.menu-history, li.menu-history,
li.menu-bookmarks, li.menu-bookmarks,
li.menu-settings, li.menu-settings,
@ -144,11 +81,11 @@
} }
&:hover .session-gear { &:hover .session-gear {
color: #ccc; color: @term-white;
visibility: visible; visibility: visible;
&:hover { &:hover {
color: white; color: @term-white;
} }
} }
} }
@ -161,7 +98,6 @@
.menu-list li.remote-menu-item { .menu-list li.remote-menu-item {
a { a {
.mono-font(11px);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -169,12 +105,10 @@
} }
.menu-list li a { .menu-list li a {
color: #bbb;
white-space: nowrap; white-space: nowrap;
padding: 3px 5px 3px 12px; padding: 3px 5px 3px 12px;
vertical-align: middle; vertical-align: middle;
position: relative; position: relative;
font-size: 13px;
.user-status { .user-status {
position: absolute !important; position: absolute !important;
@ -189,39 +123,25 @@
vertical-align: middle; vertical-align: middle;
} }
.session-num {
color: #777;
font-size: 10px;
}
&.is-active .small-text { &.is-active .small-text {
color: white; color: @term-white;
}
.small-text {
color: #777;
font-size: 10px;
} }
&.is-active { &.is-active {
color: #ddd;
font-weight: bold; font-weight: bold;
background-color: @active-menu-color; background-color: @active-menu-color;
.session-num { .session-num {
color: #aaa;
font-weight: normal; font-weight: normal;
} }
} }
.sub-label { .sub-label {
font-size: 12px;
font-style: italic; font-style: italic;
} }
&.activity { &.activity {
font-weight: bold; font-weight: bold;
color: #ddd;
.tag { .tag {
margin-left: 4px; margin-left: 4px;
@ -232,24 +152,15 @@
} }
&.is-active:hover { &.is-active:hover {
background-color: #3273dc;
} }
&:hover { &:hover {
background-color: #444;
color: #ddd;
} }
.status { .status {
font-size: 8px;
margin-right: 5px; margin-right: 5px;
position: relative; position: relative;
top: -3px; top: -3px;
color: #4e9a06;
&.offline {
color: #cc0000;
}
} }
} }
@ -271,20 +182,18 @@
top: 42px; top: 42px;
.arrow-container { .arrow-container {
color: #777;
padding: 5px; padding: 5px;
cursor: pointer; cursor: pointer;
&:hover {
color: #ddd;
}
} }
} }
} }
.is-dev .main-sidebar {
background: @base-background-dev;
}
.menu-list .remote-status.status-connecting { .menu-list .remote-status.status-connecting {
position: relative; position: relative;
top: 0px; top: 0px;
font-size: 12px;
margin-left: -3px; margin-left: -3px;
} }

View File

@ -10,8 +10,8 @@ import {
genMergeSimpleData, genMergeSimpleData,
boundInt, boundInt,
isModKeyPress, isModKeyPress,
} from "./util"; } from "./util/util";
import { TermWrap } from "./term"; import { TermWrap } from "./common/terminal/term";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import type { import type {
SessionDataType, SessionDataType,
@ -68,7 +68,7 @@ import {
windowHeightToRows, windowHeightToRows,
termWidthFromCols, termWidthFromCols,
termHeightFromRows, termHeightFromRows,
} from "./textmeasure"; } from "./util/textmeasure";
import dayjs from "dayjs"; import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import customParseFormat from "dayjs/plugin/customParseFormat"; import customParseFormat from "dayjs/plugin/customParseFormat";

View File

@ -330,7 +330,7 @@ class SourceCodeRenderer extends React.Component<
options={{ options={{
scrollBeyondLastLine: false, scrollBeyondLastLine: false,
fontSize: GlobalModel.termFontSize.get(), fontSize: GlobalModel.termFontSize.get(),
fontFamily: "JetBrains Mono", /* fontFamily: "JetBrains Mono", @check:font */
readOnly: !this.getAllowEditing(), readOnly: !this.getAllowEditing(),
}} }}
onChange={this.handleEditorChange} onChange={this.handleEditorChange}
@ -405,7 +405,7 @@ class SourceCodeRenderer extends React.Component<
className="message" className="message"
style={{ style={{
fontSize: GlobalModel.termFontSize.get(), fontSize: GlobalModel.termFontSize.get(),
fontFamily: "JetBrains Mono", /* fontFamily: "JetBrains Mono", @check:font */
background: `${this.state.message.status === "error" ? "red" : "#4e9a06"}`, background: `${this.state.message.status === "error" ? "red" : "#4e9a06"}`,
}} }}
> >
@ -432,7 +432,7 @@ class SourceCodeRenderer extends React.Component<
className="renderer-container code-renderer" className="renderer-container code-renderer"
style={{ style={{
fontSize: GlobalModel.termFontSize.get(), fontSize: GlobalModel.termFontSize.get(),
fontFamily: "JetBrains Mono", /* fontFamily: "JetBrains Mono", @check:font */
color: "white", color: "white",
}} }}
> >

View File

@ -6,7 +6,7 @@ import { boundMethod } from "autobind-decorator";
import { If, For, When, Otherwise, Choose } from "tsx-control-statements/components"; import { If, For, When, Otherwise, Choose } from "tsx-control-statements/components";
import * as T from "../types"; import * as T from "../types";
import { sprintf } from "sprintf-js"; import { sprintf } from "sprintf-js";
import { isBlank } from "../util"; import { isBlank } from "../util/util";
import mustache from "mustache"; import mustache from "mustache";
import * as DOMPurify from "dompurify"; import * as DOMPurify from "dompurify";
import { GlobalModel } from "../model"; import { GlobalModel } from "../model";

View File

@ -4,8 +4,7 @@ import * as mobxReact from "mobx-react";
import * as T from "../types"; import * as T from "../types";
import { debounce } from "throttle-debounce"; import { debounce } from "throttle-debounce";
import { boundMethod } from "autobind-decorator"; import { boundMethod } from "autobind-decorator";
import { sprintf } from "sprintf-js"; import { PacketDataBuffer } from "../common/terminal/ptydata";
import { PacketDataBuffer } from "../ptydata";
import { Markdown } from "../common/common"; import { Markdown } from "../common/common";
import "./plugins.less"; import "./plugins.less";

View File

@ -9,13 +9,12 @@
margin: 20px 10px 0px 5px; margin: 20px 10px 0px 5px;
padding-left: 10px; padding-left: 10px;
padding-bottom: 12px; padding-bottom: 12px;
.mono-font(1.5rem);
color: @term-bright-white; color: @term-bright-white;
border-bottom: 1px solid white; border-bottom: 1px solid white;
} }
.alt-list { .alt-list {
color: white; color: @term-white;
margin: 4px 10px 5px 5px; margin: 4px 10px 5px 5px;
border-bottom: 1px solid white; border-bottom: 1px solid white;
} }
@ -29,7 +28,7 @@
.close-button { .close-button {
position: absolute; position: absolute;
padding: 4px; padding: 4px;
font-size: 24px;
color: #aaa; color: #aaa;
right: 15px; right: 15px;
top: 18px; top: 18px;
@ -46,7 +45,7 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
font-size: 12px;
margin-bottom: 10px; margin-bottom: 10px;
.help-entry { .help-entry {
@ -65,7 +64,7 @@
.renderer-container { .renderer-container {
.error-container { .error-container {
color: @term-red; color: @term-red;
font-size: 14px;
padding: 5px; padding: 5px;
} }
@ -78,9 +77,9 @@
.dropdown { .dropdown {
background: #dbdbdb; background: #dbdbdb;
color: black; color: @term-black;
border-radius: 6px 6px 0 0; border-radius: 6px 6px 0 0;
font-size: 10px;
padding: 2px 0 5px 5px; padding: 2px 0 5px 5px;
outline: none; outline: none;
} }
@ -114,7 +113,6 @@
.hint-item { .hint-item {
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
padding: 3px 9px 2px 8px; padding: 3px 9px 2px 8px;
line-height: 19px;
text-align: center; text-align: center;
} }
section { section {
@ -125,10 +123,10 @@
background-color: rgb(200, 200, 200); background-color: rgb(200, 200, 200);
} }
.preview:hover { .preview:hover {
background-color: white !important; background-color: @term-white !important;
} }
.save-enabled { .save-enabled {
color: white; color: @term-white;
background-color: #4e9a06; background-color: #4e9a06;
} }
.save-disabled { .save-disabled {
@ -140,24 +138,23 @@
background-color: #aaaea7; background-color: #aaaea7;
} }
.close { .close {
color: white; color: @term-white;
background-color: #9e0000; background-color: #9e0000;
} }
.message { .message {
color: white; color: @term-white;
border-radius: 6px; border-radius: 6px;
margin-bottom: 1rem; margin-bottom: 1rem;
padding: 4px 1rem; padding: 4px 1rem;
max-width: 80vw; max-width: 80vw;
} }
.readonly { .readonly {
.mono-font(12px);
position: absolute; position: absolute;
top: calc(1.5rem + 3px); top: calc(1.5rem + 3px);
right: 10rem; right: 10rem;
border-radius: 5px; border-radius: 5px;
background-color: @term-bright-red; background-color: @term-bright-red;
color: white; color: @term-white;
z-index: 1; z-index: 1;
padding: 0 6px 2px; padding: 0 6px 2px;
} }
@ -173,7 +170,6 @@
.hint-item { .hint-item {
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
padding: 3px 9px 2px 8px; padding: 3px 9px 2px 8px;
line-height: 15px;
text-align: center; text-align: center;
} }
.refresh-button { .refresh-button {
@ -184,7 +180,6 @@
.renderer-container .content { .renderer-container .content {
padding: 5px; padding: 5px;
line-height: 1.5;
width: fit-content; width: fit-content;
blockquote { blockquote {
@ -193,7 +188,6 @@
code { code {
background-color: #222; background-color: #222;
font-size: 14px;
} }
pre { pre {
@ -230,11 +224,11 @@
.openai-content-user { .openai-content-user {
white-space: pre; white-space: pre;
color: white; color: @term-white;
} }
.openai-content-assistant { .openai-content-assistant {
color: white; color: @term-white;
} }
.openai-role-error { .openai-role-error {
@ -252,9 +246,8 @@
margin-bottom: 10px; margin-bottom: 10px;
code { code {
background-color: black; background-color: @term-black;
color: white; color: @term-white;
.mono-font();
padding: 5px; padding: 5px;
} }
@ -264,14 +257,13 @@
} }
.title { .title {
color: white; color: @term-white;
margin-top: 16px; margin-top: 16px;
line-height: 1.25;
margin-bottom: 8px; margin-bottom: 8px;
} }
strong { strong {
color: white; color: @term-white;
} }
a { a {
@ -280,7 +272,7 @@
table { table {
tr th { tr th {
color: white; color: @term-white;
} }
} }
@ -309,26 +301,20 @@
} }
.title.is-1 { .title.is-1 {
font-size: 32px;
border-bottom: 1px solid #777; border-bottom: 1px solid #777;
padding-bottom: 6px; padding-bottom: 6px;
} }
.title.is-2 { .title.is-2 {
font-size: 24px;
border-bottom: 1px solid #777; border-bottom: 1px solid #777;
padding-bottom: 6px; padding-bottom: 6px;
} }
.title.is-3 { .title.is-3 {
font-size: 20px;
} }
.title.is-4 { .title.is-4 {
font-size: 16px;
} }
.title.is-5 { .title.is-5 {
font-size: 14px;
} }
.title.is-6 { .title.is-6 {
font-size: 14px;
} }
} }

View File

@ -4,7 +4,7 @@ import { SimpleMarkdownRenderer } from "./markdown";
import { SourceCodeRenderer } from "./code"; import { SourceCodeRenderer } from "./code";
import { SimpleMustacheRenderer } from "./mustache"; import { SimpleMustacheRenderer } from "./mustache";
import { OpenAIRenderer, OpenAIRendererModel } from "./openai"; import { OpenAIRenderer, OpenAIRendererModel } from "./openai";
import { isBlank } from "../util"; import { isBlank } from "../util/util";
import { sprintf } from "sprintf-js"; import { sprintf } from "sprintf-js";
const ImagePlugin: RendererPluginType = { const ImagePlugin: RendererPluginType = {

View File

@ -27,7 +27,6 @@
cursor: pointer; cursor: pointer;
&.add-remote { &.add-remote {
font-size: 13px;
padding: 10px 5px 10px 5px; padding: 10px 5px 10px 5px;
} }
@ -39,7 +38,7 @@
background-color: @active-menu-color; background-color: @active-menu-color;
.remote-name .remote-name-secondary { .remote-name .remote-name-secondary {
color: white; color: @term-white;
} }
} }
@ -56,12 +55,10 @@
flex-grow: 1; flex-grow: 1;
.remote-name-primary { .remote-name-primary {
font-size: 12px;
font-weight: bold; font-weight: bold;
} }
.remote-name-secondary { .remote-name-secondary {
font-size: 11px;
color: #777; color: #777;
} }
} }
@ -71,7 +68,7 @@
.remote-detail { .remote-detail {
padding: 10px; padding: 10px;
flex-grow: 1; flex-grow: 1;
font-size: 12px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -84,13 +81,12 @@
} }
.detail-subtitle { .detail-subtitle {
font-size: 18px;
margin-bottom: 10px; margin-bottom: 10px;
margin-top: 10px; margin-top: 10px;
} }
.title { .title {
color: white; color: @term-white;
padding-bottom: 8px; padding-bottom: 8px;
margin-bottom: 0; margin-bottom: 0;
border-bottom: 1px solid #777; border-bottom: 1px solid #777;
@ -183,7 +179,7 @@
.settings-field .settings-input .undo-icon { .settings-field .settings-input .undo-icon {
cursor: pointer; cursor: pointer;
font-size: 18px;
margin-left: 5px; margin-left: 5px;
} }
@ -201,11 +197,9 @@
} }
.dropdown .dropdown-trigger button { .dropdown .dropdown-trigger button {
font-size: 12px;
} }
.dropdown .dropdown-item { .dropdown .dropdown-item {
font-size: 12px;
padding: 5px 5px 5px 12px; padding: 5px 5px 5px 12px;
} }
@ -239,10 +233,9 @@
top: 0; top: 0;
right: 0; right: 0;
background-color: @term-red; background-color: @term-red;
color: white; color: @term-white;
z-index: 110; z-index: 110;
padding: 4px; padding: 4px;
.mono-font(10px);
} }
} }
} }

View File

@ -7,8 +7,8 @@ import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, RemotesModalModel } from "../model"; import { GlobalModel, GlobalCommandRunner, RemotesModalModel } from "../model";
import { Toggle, RemoteStatusLight, InfoMessage } from "../common/common"; import { Toggle, RemoteStatusLight, InfoMessage } from "../common/common";
import { RemoteType, RemoteEditType } from "../types"; import { RemoteType, RemoteEditType } from "../types";
import * as util from "../util"; import * as util from "../util/util";
import * as textmeasure from "../textmeasure"; import * as textmeasure from "../util/textmeasure";
import "./remotes.less"; import "./remotes.less";

15
src/themes.ts Normal file
View File

@ -0,0 +1,15 @@
/**
* The file contains barebones of styling to appy themes to Prompt.
* @TODO: Find a way to change the theme system-wide. atm, we are captruing colors in main.less
*/
const themes = [
{
id: "default",
terminal: { foreground: "#eceeec", background: "rgba(21, 23, 21, 1)" },
},
];
const getTheme = (_id = "default") => themes.find(({ id }) => id === _id);
export { getTheme };

View File

@ -2,7 +2,7 @@ import * as mobx from "mobx";
import { sprintf } from "sprintf-js"; import { sprintf } from "sprintf-js";
import dayjs from "dayjs"; import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import type { RemoteType } from "./types"; import type { RemoteType } from "../types";
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);
@ -264,6 +264,7 @@ function incObs(inum: mobx.IObservableValue<number>) {
})(); })();
} }
// @check:font
function loadFonts() { function loadFonts() {
let jbmFontNormal = new FontFace("JetBrains Mono", "url('static/fonts/jetbrains-mono-v13-latin-regular.woff2')", { let jbmFontNormal = new FontFace("JetBrains Mono", "url('static/fonts/jetbrains-mono-v13-latin-regular.woff2')", {
style: "normal", style: "normal",

View File

@ -1,91 +0,0 @@
.mono-font(@size: inherit, @weight: inherit) {
font-family: "JetBrains Mono", monospace;
font-size: @size;
font-weight: @weight;
}
.monofont-thin {
.mono-font(inherit, 200);
}
.monofont-normal {
.mono-font(inherit, 400);
}
.monofont-bold {
.mono-font(inherit, 700);
}
.display-none {
display: none;
}
.bold {
font-weight: bold;
}
.term-black {
color: @term-black;
}
.term-red {
color: @term-red;
}
.term-green {
color: @term-green;
}
.term-yellow {
color: @term-yellow;
}
.term-blue {
color: @term-blue;
}
.term-magenta {
color: @term-magenta;
}
.term-cyan {
color: @term-cyan;
}
.term-white {
color: @term-white;
}
.term-bright-white {
color: @term-bright-white;
}
.term-bright-green {
color: @term-bright-green;
}
.term-bright-red {
color: @term-bright-red;
}
.flex-spacer {
flex-grow: 1;
}
.flex-centered-row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.flex-centered-col {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
a.a-block {
display: block;
}

View File

@ -9,7 +9,7 @@ import { If, For, When, Otherwise, Choose } from "tsx-control-statements/compone
import cn from "classnames"; import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, Screen } from "../model"; import { GlobalModel, GlobalCommandRunner, Screen } from "../model";
import { WebStopShareConfirmMarkdown } from "../main/modals/settings"; import { WebStopShareConfirmMarkdown } from "../main/modals/settings";
import * as util from "../util"; import * as util from "../util/util";
import "./webshare.less"; import "./webshare.less";

View File

@ -13,15 +13,14 @@ body.prompt-webshare #main {
flex-shrink: 0; flex-shrink: 0;
.logo-text { .logo-text {
.mono-font(32px);
a { a {
color: @prompt-green; color: @prompt-green;
} }
} }
.screen-name { .screen-name {
color: white; color: @term-white;
.mono-font(24px);
margin-left: 20px; margin-left: 20px;
} }
@ -39,7 +38,7 @@ body.prompt-webshare #main {
padding-left: 20px; padding-left: 20px;
padding-right: 20px; padding-right: 20px;
background-color: darken(@prompt-green, 30%); background-color: darken(@prompt-green, 30%);
color: white; color: @term-white;
.screen-sharename { .screen-sharename {
font-weight: bold; font-weight: bold;
@ -49,7 +48,7 @@ body.prompt-webshare #main {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
color: @term-white; color: @term-white;
font-size: 13px;
align-items: center; align-items: center;
div:first-child { div:first-child {
@ -92,7 +91,6 @@ body.prompt-webshare #main {
flex-shrink: 0; flex-shrink: 0;
.footer-copy { .footer-copy {
font-size: 12px;
} }
a { a {
@ -100,10 +98,10 @@ body.prompt-webshare #main {
} }
} }
color: white; color: @term-white;
#app { #app {
color: white; color: @term-white;
} }
.lines .line-sep { .lines .line-sep {
@ -114,7 +112,6 @@ body.prompt-webshare #main {
.lines .line.line-cmd { .lines .line.line-cmd {
.line-icon.copy-icon { .line-icon.copy-icon {
color: @term-white; color: @term-white;
font-size: 18px;
&:hover { &:hover {
color: @term-bright-white; color: @term-bright-white;

View File

@ -20,6 +20,7 @@ document.addEventListener("DOMContentLoaded", () => {
let elem = document.getElementById("app"); let elem = document.getElementById("app");
let root = createRoot(elem); let root = createRoot(elem);
let reactElem = React.createElement(WebShareMain, null, null); let reactElem = React.createElement(WebShareMain, null, null);
// @check:font
let isFontLoaded = document.fonts.check("12px 'JetBrains Mono'"); let isFontLoaded = document.fonts.check("12px 'JetBrains Mono'");
if (isFontLoaded) { if (isFontLoaded) {
root.render(reactElem); root.render(reactElem);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2023 Fonticons, Inc.
*/
:host,:root{--fa-style-family-sharp:"Font Awesome 6 Sharp";--fa-font-sharp-regular:normal 400 1em/1 "Font Awesome 6 Sharp"}@font-face{font-family:"Font Awesome 6 Sharp";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-sharp-regular-400.woff2) format("woff2"),url(../webfonts/fa-sharp-regular-400.ttf) format("truetype")}.fa-regular,.fasr{font-weight:400}

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2023 Fonticons, Inc.
*/
:host,:root{--fa-style-family-sharp:"Font Awesome 6 Sharp";--fa-font-sharp-solid:normal 900 1em/1 "Font Awesome 6 Sharp"}@font-face{font-family:"Font Awesome 6 Sharp";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-sharp-solid-900.woff2) format("woff2"),url(../webfonts/fa-sharp-solid-900.ttf) format("truetype")}.fa-solid,.fass{font-weight:900}

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2023 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Pro";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Pro"}@font-face{font-family:"Font Awesome 6 Pro";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}

View File

@ -1,19 +1,16 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<base href="../"> <base href="../" />
<script charset="UTF-8" src="dist-dev/prompt.js"></script> <script charset="UTF-8" src="dist-dev/prompt.js"></script>
<link rel="stylesheet" href="static/bulma-0.9.4.min.css"> <link rel="stylesheet" href="static/bulma-0.9.4.min.css" />
<link rel="stylesheet" href="static/fontawesome/css/fontawesome.min.css"> <link rel="stylesheet" href="static/xterm.css" />
<link rel="stylesheet" href="static/fontawesome/css/brands.min.css"> <link rel="stylesheet" href="dist-dev/prompt.css" />
<link rel="stylesheet" href="static/fontawesome/css/sharp-solid.min.css"> </head>
<link rel="stylesheet" href="static/fontawesome/css/sharp-regular.min.css"> <body>
<link rel="stylesheet" href="static/xterm.css" /> <div id="measure"></div>
<link rel="stylesheet" href="dist-dev/prompt.css" /> <div id="title-bar"></div>
</head> <div id="app"></div>
<body> </body>
<div id="measure"></div>
<div id="app"></div>
</body>
</html> </html>

View File

@ -1,19 +1,16 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<base href="../"> <base href="../" />
<script charset="UTF-8" src="dist/prompt.js"></script> <script charset="UTF-8" src="dist/prompt.js"></script>
<link rel="stylesheet" href="static/bulma-0.9.4.min.css"> <link rel="stylesheet" href="static/bulma-0.9.4.min.css" />
<link rel="stylesheet" href="static/fontawesome/css/fontawesome.min.css"> <link rel="stylesheet" href="static/xterm.css" />
<link rel="stylesheet" href="static/fontawesome/css/brands.min.css"> <link rel="stylesheet" href="dist/prompt.css" />
<link rel="stylesheet" href="static/fontawesome/css/sharp-solid.min.css"> </head>
<link rel="stylesheet" href="static/fontawesome/css/sharp-regular.min.css"> <body>
<link rel="stylesheet" href="static/xterm.css" /> <div id="measure"></div>
<link rel="stylesheet" href="dist/prompt.css" /> <div id="title-bar"></div>
</head> <div id="app"></div>
<body> </body>
<div id="measure"></div>
<div id="app"></div>
</body>
</html> </html>

View File

@ -1,22 +1,17 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>[prompt] Shared Terminal Session</title> <title>[prompt] Shared Terminal Session</title>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<base href="/"> <base href="/" />
<script charset="UTF-8" src="/dist-dev/webshare.js"></script> <script charset="UTF-8" src="/dist-dev/webshare.js"></script>
<link rel="stylesheet" href="/static/bulma-0.9.4.min.css"> <link rel="stylesheet" href="/static/bulma-0.9.4.min.css" />
<link rel="stylesheet" href="/static/fontawesome/css/fontawesome.min.css"> <link rel="stylesheet" href="/static/xterm.css" />
<link rel="stylesheet" href="/static/fontawesome/css/brands.min.css"> <link rel="stylesheet" href="/dist-dev/webshare.css" />
<link rel="stylesheet" href="/static/fontawesome/css/sharp-solid.min.css"> </head>
<link rel="stylesheet" href="/static/fontawesome/css/sharp-regular.min.css"> <body class="prompt-webshare">
<link rel="stylesheet" href="/static/xterm.css" /> <div id="measure"></div>
<link rel="stylesheet" href="/dist-dev/webshare.css" /> <div id="title-bar"></div>
</head> <div id="app"></div>
<body class="prompt-webshare"> </body>
<div id="measure"></div>
<div id="app"></div>
</body>
</html> </html>

View File

@ -1,22 +1,17 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>[prompt] Shared Terminal Session</title> <title>[prompt] Shared Terminal Session</title>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<base href="/"> <base href="/" />
<script charset="UTF-8" src="/dist/webshare.js"></script> <script charset="UTF-8" src="/dist/webshare.js"></script>
<link rel="stylesheet" href="/static/bulma-0.9.4.min.css"> <link rel="stylesheet" href="/static/bulma-0.9.4.min.css" />
<link rel="stylesheet" href="/static/fontawesome/css/fontawesome.min.css"> <link rel="stylesheet" href="/static/xterm.css" />
<link rel="stylesheet" href="/static/fontawesome/css/brands.min.css"> <link rel="stylesheet" href="/dist/webshare.css" />
<link rel="stylesheet" href="/static/fontawesome/css/sharp-solid.min.css"> </head>
<link rel="stylesheet" href="/static/fontawesome/css/sharp-regular.min.css"> <body class="prompt-webshare">
<link rel="stylesheet" href="/static/xterm.css" /> <div id="measure"></div>
<link rel="stylesheet" href="/dist/webshare.css" /> <div id="title-bar"></div>
</head> <div id="app"></div>
<body class="prompt-webshare"> </body>
<div id="measure"></div>
<div id="app"></div>
</body>
</html> </html>