Pe 179 refactoring UI code (#25)

* refactored main JS files

* modals have been refactored

* lines and renderer refactored

* all refactoring done. ready for reskinning
This commit is contained in:
anandamarsh
2023-09-23 21:05:06 -07:00
committed by GitHub
parent faeab0790a
commit a25c7b4286
52 changed files with 3927 additions and 3403 deletions
+1 -2
View File
@@ -12,7 +12,6 @@ node_modules/.bin/webpack --watch --config webpack.dev.js
node_modules/.bin/webpack --config webpack.dev.js
```
```bash
# @scripthaus command webpack-electron-watch
# @scripthaus cd :playbook
@@ -64,7 +63,7 @@ node_modules/.bin/webpack --config webpack.share.prod.js
```bash
# @scripthaus command typecheck
# @scripthaus cd :playbook
node_modules/.bin/tsc --jsx preserve --noEmit --esModuleInterop --target ES5 --experimentalDecorators --downlevelIteration src/prompt.ts
node_modules/.bin/tsc --jsx preserve --noEmit --esModuleInterop --target ES5 --experimentalDecorators --downlevelIteration src/index.ts
```
```bash
+41
View File
@@ -1,3 +1,44 @@
@import "../index.less";
.info-message {
position: relative;
font-weight: normal;
font-size: 12px;
color: @term-white;
.message-content {
position: absolute;
display: none;
flex-direction: row;
align-items: flex-start;
top: -6px;
left: -6px;
padding: 5px;
border: 1px solid #777;
background-color: #444;
border-radius: 5px;
z-index: 5;
overflow: hidden;
.info-icon {
margin-right: 5px;
width: 12px;
flex-shrink: 0;
}
.info-children {
flex: 1 0 0;
overflow: hidden;
}
}
&:hover {
.message-content {
display: flex;
}
}
}
.cmdstr-code {
position: relative;
display: flex;
+4 -3
View File
@@ -1,13 +1,14 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import cn from "classnames";
import { If, For, When, Otherwise, Choose } from "tsx-control-statements/components";
import type { RemoteType } from "./types";
import { If } from "tsx-control-statements/components";
import type { RemoteType } from "../types";
import "./common.less";
type OV<V> = mobx.IObservableValue<V>;
-4
View File
@@ -1,4 +0,0 @@
import { sprintf } from "sprintf-js";
import { Database } from "better-sqlite3";
let DB = new Database();
+641
View File
File diff suppressed because it is too large Load Diff
+1 -4
View File
@@ -2,10 +2,7 @@ import * as mobx from "mobx";
import * as React from "react";
import { createRoot } from "react-dom/client";
import { sprintf } from "sprintf-js";
import { Terminal } from "xterm";
import { Main } from "./main";
import { GlobalModel } from "./model";
import { v4 as uuidv4 } from "uuid";
import { Main } from "./main/Main";
import { loadFonts } from "./util";
import * as DOMPurify from "dompurify";
-36
View File
@@ -1,36 +0,0 @@
@keyframes loader-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes fade-in {
0% {
opacity: 0;
}
80% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-in-out {
0% {
opacity: 0;
}
50% {
opacity: 0.5;
}
100% {
opacity: 0;
}
}
-2298
View File
File diff suppressed because it is too large Load Diff
+140
View File
@@ -0,0 +1,140 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import dayjs from "dayjs";
import type { ContextMenuOpts } from "../types";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../model";
import { isBlank } from "../util";
import { BookmarksView } from "./bookmarks/bookmarks";
import { WebShareView } from "../webshare/webshare-client-view";
import { HistoryView } from "./history/history";
import { ScreenSettingsModal, SessionSettingsModal, LineSettingsModal, ClientSettingsModal } from "./modals/settings";
import { RemotesModal } from "../remotes/remotes";
import { TosModal } from "./modals/Modals";
import { SessionView } from "./sessionview/SessionView";
import { MainSideBar } from "./sidebar/MainSideBar";
import { DisconnectedModal, ClientStopModal, AlertModal, WelcomeModal } from "./modals/Modals";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class Main extends React.Component<{}, {}> {
dcWait: OV<boolean> = mobx.observable.box(false, { name: "dcWait" });
constructor(props: any) {
super(props);
}
@boundMethod
handleContextMenu(e: any) {
let isInNonTermInput = false;
let activeElem = document.activeElement;
if (activeElem != null && activeElem.nodeName == "TEXTAREA") {
if (!activeElem.classList.contains("xterm-helper-textarea")) {
isInNonTermInput = true;
}
}
if (activeElem != null && activeElem.nodeName == "INPUT" && activeElem.getAttribute("type") == "text") {
isInNonTermInput = true;
}
let opts: ContextMenuOpts = {};
if (isInNonTermInput) {
opts.showCut = true;
}
let sel = window.getSelection();
if (!isBlank(sel.toString())) {
GlobalModel.contextEditMenu(e, opts);
} else {
if (isInNonTermInput) {
GlobalModel.contextEditMenu(e, opts);
}
}
}
@boundMethod
updateDcWait(val: boolean): void {
mobx.action(() => {
this.dcWait.set(val);
})();
}
render() {
let screenSettingsModal = GlobalModel.screenSettingsModal.get();
let sessionSettingsModal = GlobalModel.sessionSettingsModal.get();
let lineSettingsModal = GlobalModel.lineSettingsModal.get();
let clientSettingsModal = GlobalModel.clientSettingsModal.get();
let remotesModal = GlobalModel.remotesModalModel.isOpen();
let disconnected = !GlobalModel.ws.open.get() || !GlobalModel.localServerRunning.get();
let hasClientStop = GlobalModel.getHasClientStop();
let dcWait = this.dcWait.get();
if (disconnected || hasClientStop) {
if (!dcWait) {
setTimeout(() => this.updateDcWait(true), 1500);
}
return (
<div id="main" onContextMenu={this.handleContextMenu}>
<div className="main-content">
<MainSideBar />
<div className="session-view" />
</div>
<If condition={dcWait}>
<If condition={disconnected}>
<DisconnectedModal />
</If>
<If condition={!disconnected && hasClientStop}>
<ClientStopModal />
</If>
</If>
</div>
);
}
if (dcWait) {
setTimeout(() => this.updateDcWait(false), 0);
}
return (
<div id="main" onContextMenu={this.handleContextMenu}>
<div className="main-content">
<MainSideBar />
<SessionView />
<HistoryView />
<BookmarksView />
<WebShareView />
</div>
<AlertModal />
<If condition={GlobalModel.needsTos()}>
<TosModal />
</If>
<If condition={GlobalModel.welcomeModalOpen.get()}>
<WelcomeModal />
</If>
<If condition={screenSettingsModal != null}>
<ScreenSettingsModal
key={screenSettingsModal.sessionId + ":" + screenSettingsModal.screenId}
sessionId={screenSettingsModal.sessionId}
screenId={screenSettingsModal.screenId}
/>
</If>
<If condition={sessionSettingsModal != null}>
<SessionSettingsModal key={sessionSettingsModal} sessionId={sessionSettingsModal} />
</If>
<If condition={lineSettingsModal != null}>
<LineSettingsModal key={String(lineSettingsModal)} linenum={lineSettingsModal} />
</If>
<If condition={clientSettingsModal}>
<ClientSettingsModal />
</If>
<If condition={remotesModal}>
<RemotesModal model={GlobalModel.remotesModalModel} />
</If>
</div>
);
}
}
export { Main };
+99
View File
@@ -0,0 +1,99 @@
@import "../../index.less";
.bookmarks-view {
.bookmarks-list {
color: white;
margin: 4px 10px 5px 5px;
.no-bookmarks {
color: @term-white;
padding: 30px 10px 35px 10px;
border-bottom: 1px solid white;
}
}
.bookmark {
border-bottom: 1px solid #777;
padding: 4px 5px 8px 15px;
margin-bottom: 4px;
position: relative;
display: flex;
flex-direction: row;
max-width: 100%;
.focus-indicator {
top: 0;
height: calc(100% - 4px);
}
&.is-editing {
padding-top: 8px;
padding-bottom: 12px;
}
&.pending-delete {
background-color: #522;
}
.bookmark-content,
.bookmark-edit {
flex-grow: 1;
max-width: calc(100% - 50px);
}
label {
color: white;
margin-bottom: 4px;
}
textarea {
width: 80%;
min-width: 50%;
color: white;
background-color: black;
&.mono-font {
.mono-font(12px);
}
}
.bookmark-id-div {
display: none;
position: absolute;
color: #666;
right: 5px;
bottom: 2px;
.mono-font(8px);
}
&:hover .bookmark-id-div {
display: block;
}
.bookmark-controls {
display: flex;
flex-direction: row;
font-size: 16px;
visibility: hidden;
color: @term-white;
.bookmark-control:first-child {
margin-left: 0;
}
.bookmark-control {
margin-left: 10px;
cursor: pointer;
padding: 2px;
&:hover {
color: @term-bright-white;
}
}
}
&:hover .bookmark-controls {
visibility: visible;
}
}
}
@@ -1,15 +1,14 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import { v4 as uuidv4 } from "uuid";
import dayjs from "dayjs";
import { If, For, When, Otherwise, Choose } from "tsx-control-statements/components";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import type { BookmarkType } from "./types";
import { GlobalModel, GlobalCommandRunner } from "./model";
import { CmdStrCode, Markdown } from "./elements";
import type { BookmarkType } from "../../types";
import { GlobalModel } from "../../model";
import { CmdStrCode, Markdown } from "../../common/common";
import "./bookmarks.less";
@mobxReact.observer
class Bookmark extends React.Component<{ bookmark: BookmarkType }, {}> {
@@ -1,57 +1,4 @@
.alt-view {
background-color: #111;
overflow-y: auto;
flex-grow: 1;
.alt-title {
margin: 20px 10px 0px 5px;
padding-left: 10px;
padding-bottom: 12px;
.mono-font(1.5rem);
color: @term-bright-white;
border-bottom: 1px solid white;
}
.alt-list {
color: white;
margin: 4px 10px 5px 5px;
border-bottom: 1px solid white;
}
.no-content {
color: @term-white;
padding: 30px 10px 35px 10px;
border-bottom: 1px solid white;
}
.close-button {
position: absolute;
padding: 4px;
font-size: 24px;
color: #aaa;
right: 15px;
top: 18px;
cursor: pointer;
&:hover {
color: #fff;
}
}
.alt-help {
color: @term-white;
margin-top: 20px;
display: flex;
flex-direction: row;
align-items: center;
font-size: 12px;
margin-bottom: 10px;
.help-entry {
margin-left: 20px;
}
}
}
@import "../../index.less";
.history-view {
color: #ccc;
@@ -418,140 +365,3 @@
}
}
}
.webshare-view {
.webshare-item {
padding: 4px 5px 8px 15px;
margin-bottom: 4px;
border-top: 1px solid white;
display: flex;
flex-direction: row;
position: relative;
min-height: 55px;
align-items: center;
&:first-child {
border-top: 0;
}
.webshare-vic {
width: 200px;
.webshare-vic-link {
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}
.actions {
display: flex;
flex-direction: row;
gap: 10px;
}
&:hover {
background-color: #222;
}
}
}
.bookmarks-view {
.bookmarks-list {
color: white;
margin: 4px 10px 5px 5px;
.no-bookmarks {
color: @term-white;
padding: 30px 10px 35px 10px;
border-bottom: 1px solid white;
}
}
.bookmark {
border-bottom: 1px solid #777;
padding: 4px 5px 8px 15px;
margin-bottom: 4px;
position: relative;
display: flex;
flex-direction: row;
max-width: 100%;
.focus-indicator {
top: 0;
height: calc(100% - 4px);
}
&.is-editing {
padding-top: 8px;
padding-bottom: 12px;
}
&.pending-delete {
background-color: #522;
}
.bookmark-content,
.bookmark-edit {
flex-grow: 1;
max-width: calc(100% - 50px);
}
label {
color: white;
margin-bottom: 4px;
}
textarea {
width: 80%;
min-width: 50%;
color: white;
background-color: black;
&.mono-font {
.mono-font(12px);
}
}
.bookmark-id-div {
display: none;
position: absolute;
color: #666;
right: 5px;
bottom: 2px;
.mono-font(8px);
}
&:hover .bookmark-id-div {
display: block;
}
.bookmark-controls {
display: flex;
flex-direction: row;
font-size: 16px;
visibility: hidden;
color: @term-white;
.bookmark-control:first-child {
margin-left: 0;
}
.bookmark-control {
margin-left: 10px;
cursor: pointer;
padding: 2px;
&:hover {
color: @term-bright-white;
}
}
}
&:hover .bookmark-controls {
visibility: visible;
}
}
}
@@ -5,13 +5,15 @@ import { If, For, When, Otherwise, Choose } from "tsx-control-statements/compone
import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, Cmd } from "./model";
import { HistoryItem, RemotePtrType, LineType, CmdDataType } from "./types";
import { GlobalModel, GlobalCommandRunner, Cmd } from "../../model";
import { HistoryItem, RemotePtrType, LineType, CmdDataType } from "../../types";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import customParseFormat from "dayjs/plugin/customParseFormat";
import { Line } from "./linecomps";
import { CmdStrCode } from "./elements";
import { Line } from "../line/linecomps";
import { CmdStrCode } from "../../common/common";
import "./history.less";
dayjs.extend(customParseFormat);
dayjs.extend(localizedFormat);
@@ -5,9 +5,9 @@ import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { If, For, When, Otherwise, Choose } from "tsx-control-statements/components";
import { GlobalModel, GlobalCommandRunner, Session, Cmd, ScreenLines, Screen, getTermPtyData } from "./model";
import { windowWidthToCols, windowHeightToRows, termHeightFromRows, termWidthFromCols } from "./textmeasure";
import { If } from "tsx-control-statements/components";
import { GlobalModel, GlobalCommandRunner, Cmd, getTermPtyData } from "../../model";
import { termHeightFromRows } from "../../textmeasure";
import type {
LineType,
CmdDataType,
@@ -21,18 +21,18 @@ import type {
LineHeightChangeCallbackType,
RendererModelInitializeParams,
RendererModel,
} from "./types";
} from "../../types";
import cn from "classnames";
import { TermWrap } from "./term";
import type { LineContainerModel } from "./model";
import { renderCmdText } from "./elements";
import { SimpleBlobRendererModel, SimpleBlobRenderer } from "./simplerenderer";
import { FullRenderer } from "./fullrenderer";
import { isBlank } from "./util";
import { PluginModel } from "./plugins";
import { PtyDataBuffer } from "./ptydata";
import type { LineContainerModel } from "../../model";
import { renderCmdText } from "../../common/common";
import { SimpleBlobRenderer } from "./renderer/simplerenderer";
import { FullRenderer } from "./renderer/fullrenderer";
import { isBlank } from "../../util";
import { PluginModel } from "../../plugins/plugins";
import * as lineutil from "./lineutil";
import "./lines.less";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
+2 -4
View File
@@ -1,3 +1,5 @@
@import "../../index.less";
.line.line-text {
flex-direction: row;
padding-top: 5px;
@@ -465,10 +467,6 @@
border-radius: 3px;
}
}
&:hover .cmd-hints {
display: flex;
}
}
.line.line-invalid {
@@ -8,10 +8,12 @@ import cn from "classnames";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { debounce, throttle } from "throttle-debounce";
import * as T from "./types";
import * as util from "./util";
import * as T from "../../types";
import * as util from "../../util";
import * as lineutil from "./lineutil";
import "./lines.less";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>;
@@ -1,7 +1,7 @@
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { isBlank, getDateStr } from "./util";
import { LineType, WebLine, RendererContext } from "./types";
import { isBlank, getDateStr } from "../../util";
import { LineType, WebLine, RendererContext } from "../../types";
dayjs.extend(localizedFormat);
@@ -1,25 +1,12 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import { If, For, When, Otherwise, Choose } from "tsx-control-statements/components";
import type {
RendererModelInitializeParams,
TermOptsType,
RendererContext,
RendererOpts,
SimpleBlobRendererComponent,
RendererModelContainerApi,
RendererPluginType,
PtyDataType,
RendererModel,
RendererOptsUpdate,
LineType,
TermContextUnion,
RendererContainerType,
} from "./types";
import { PacketDataBuffer } from "./ptydata";
} from "../../../types";
import { debounce, throttle } from "throttle-debounce";
type OV<V> = mobx.IObservableValue<V>;
@@ -19,12 +19,12 @@ import type {
LineType,
TermContextUnion,
RendererContainerType,
} from "./types";
import * as T from "./types";
import { PacketDataBuffer } from "./ptydata";
} from "../../../types";
import * as T from "../../../types";
import { PacketDataBuffer } from "../../../ptydata";
import { debounce, throttle } from "throttle-debounce";
import * as util from "./util";
import { GlobalModel } from "./model";
import * as util from "../../../util";
import { GlobalModel } from "../../../model";
type OV<V> = mobx.IObservableValue<V>;
type CV<V> = mobx.IComputedValue<V>;
+357
View File
@@ -0,0 +1,357 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../../model";
import { Markdown } from "../../common/common";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class DisconnectedModal extends React.Component<{}, {}> {
logRef: any = React.createRef();
showLog: mobx.IObservableValue<boolean> = mobx.observable.box(false);
@boundMethod
restartServer() {
GlobalModel.restartLocalServer();
}
@boundMethod
tryReconnect() {
GlobalModel.ws.connectNow("manual");
}
componentDidMount() {
if (this.logRef.current != null) {
this.logRef.current.scrollTop = this.logRef.current.scrollHeight;
}
}
componentDidUpdate() {
if (this.logRef.current != null) {
this.logRef.current.scrollTop = this.logRef.current.scrollHeight;
}
}
@boundMethod
handleShowLog(): void {
mobx.action(() => {
this.showLog.set(!this.showLog.get());
})();
}
render() {
let model = GlobalModel;
let logLine: string = null;
let idx: number = 0;
return (
<div className="prompt-modal disconnected-modal modal is-active">
<div className="modal-background"></div>
<div className="modal-content">
<div className="message-header">
<div className="modal-title">Prompt Client Disconnected</div>
</div>
<If condition={this.showLog.get()}>
<div className="inner-content">
<div className="ws-log" ref={this.logRef}>
<For each="logLine" index="idx" of={GlobalModel.ws.wsLog}>
<div key={idx} className="ws-logline">
{logLine}
</div>
</For>
</div>
</div>
</If>
<footer>
<div className="footer-text-link" style={{ marginLeft: 10 }} onClick={this.handleShowLog}>
<If condition={!this.showLog.get()}>
<i className="fa-sharp fa-solid fa-plus" /> Show Log
</If>
<If condition={this.showLog.get()}>
<i className="fa-sharp fa-solid fa-minus" /> Hide Log
</If>
</div>
<div className="flex-spacer" />
<button onClick={this.tryReconnect} className="button">
<span className="icon">
<i className="fa-sharp fa-solid fa-rotate" />
</span>
<span>Try Reconnect</span>
</button>
<button onClick={this.restartServer} className="button is-danger" style={{ marginLeft: 10 }}>
<span className="icon">
<i className="fa-sharp fa-solid fa-triangle-exclamation" />
</span>
<span>Restart Server</span>
</button>
</footer>
</div>
</div>
);
}
}
@mobxReact.observer
class ClientStopModal extends React.Component<{}, {}> {
@boundMethod
refreshClient() {
GlobalModel.refreshClient();
}
render() {
let model = GlobalModel;
let cdata = model.clientData.get();
let title = "Client Not Ready";
return (
<div className="prompt-modal client-stop-modal modal is-active">
<div className="modal-background"></div>
<div className="modal-content">
<div className="message-header">
<div className="modal-title">[prompt] {title}</div>
</div>
<div className="inner-content">
<If condition={cdata == null}>
<div>Cannot get client data.</div>
</If>
</div>
<footer>
<button onClick={this.refreshClient} className="button">
<span className="icon">
<i className="fa-sharp fa-solid fa-rotate" />
</span>
<span>Hard Refresh Client</span>
</button>
</footer>
</div>
</div>
);
}
}
@mobxReact.observer
class LoadingSpinner extends React.Component<{}, {}> {
render() {
return (
<div className="loading-spinner">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
);
}
}
@mobxReact.observer
class AlertModal extends React.Component<{}, {}> {
@boundMethod
closeModal(): void {
GlobalModel.cancelAlert();
}
@boundMethod
handleOK(): void {
GlobalModel.confirmAlert();
}
render() {
let message = GlobalModel.alertMessage.get();
if (message == null) {
return null;
}
let title = message.title ?? (message.confirm ? "Confirm" : "Alert");
let isConfirm = message.confirm;
return (
<div className="modal prompt-modal is-active alert-modal">
<div className="modal-background" />
<div className="modal-content">
<header>
<p className="modal-title">
<i className="fa-sharp fa-solid fa-triangle-exclamation" /> {title}
</p>
<div className="close-icon">
<i onClick={this.closeModal} className="fa-sharp fa-solid fa-times" />
</div>
</header>
<If condition={message.markdown}>
<Markdown text={message.message} extraClassName="inner-content" />
</If>
<If condition={!message.markdown}>
<div className="inner-content content">
<p>{message.message}</p>
</div>
</If>
<footer>
<If condition={isConfirm}>
<div onClick={this.closeModal} className="button is-prompt-cancel is-outlined is-small">
Cancel
</div>
<div onClick={this.handleOK} className="button is-prompt-green is-outlined is-small">
OK
</div>
</If>
<If condition={!isConfirm}>
<div onClick={this.handleOK} className="button is-prompt-green is-small">
OK
</div>
</If>
</footer>
</div>
</div>
);
}
}
@mobxReact.observer
class WelcomeModal extends React.Component<{}, {}> {
totalPages: number = 3;
pageNum: OV<number> = mobx.observable.box(1, { name: "welcome-pagenum" });
@boundMethod
closeModal(): void {
mobx.action(() => {
GlobalModel.welcomeModalOpen.set(false);
})();
}
@boundMethod
goNext(): void {
mobx.action(() => {
this.pageNum.set(this.pageNum.get() + 1);
})();
}
@boundMethod
goPrev(): void {
mobx.action(() => {
this.pageNum.set(this.pageNum.get() - 1);
})();
}
renderDot(num: number): any {
if (num == this.pageNum.get()) {
return <i key={String(num)} className="fa-sharp fa-solid fa-circle" />;
}
return <i key={String(num)} className="fa-sharp fa-regular fa-circle" />;
}
renderDots(): any {
let elems: any = [];
for (let i = 1; i <= this.totalPages; i++) {
let elem = this.renderDot(i);
elems.push(elem);
}
return elems;
}
render() {
let pageNum = this.pageNum.get();
return (
<div className={cn("modal welcome-modal prompt-modal is-active")}>
<div className="modal-background" />
<div className="modal-content">
<header>
<div className="modal-title">welcome to [prompt]</div>
<div className="close-icon">
<i onClick={this.closeModal} className="fa-sharp fa-solid fa-times" />
</div>
</header>
<div className={cn("inner-content content", { "is-hidden": pageNum != 1 })}>
<p>
Prompt is a new terminal to help save you time and keep your command-line life organized.
Here's a couple quick tips to get your started!
</p>
</div>
<footer>
<If condition={pageNum > 1}>
<button className={cn("button is-dark prev-button is-small")} onClick={this.goPrev}>
<span className="icon is-small">
<i className="fa-sharp fa-regular fa-angle-left" />
</span>
<span>Prev</span>
</button>
</If>
<If condition={pageNum == 1}>
<div className="prev-spacer" />
</If>
<div className="flex-spacer" />
<div className="dots">{this.renderDots()}</div>
<div className="flex-spacer" />
<If condition={pageNum < this.totalPages}>
<button className="button is-dark next-button is-small" onClick={this.goNext}>
<span>Next</span>
<span className="icon is-small">
<i className="fa-sharp fa-regular fa-angle-right" />
</span>
</button>
</If>
<If condition={pageNum == this.totalPages}>
<button className="button is-dark next-button is-small" onClick={this.closeModal}>
<span>Done</span>
</button>
</If>
</footer>
</div>
</div>
);
}
}
@mobxReact.observer
class TosModal extends React.Component<{}, {}> {
@boundMethod
acceptTos(): void {
GlobalCommandRunner.clientAcceptTos();
}
render() {
return (
<div className={cn("modal tos-modal prompt-modal is-active")}>
<div className="modal-background" />
<div className="modal-content">
<header>
<div className="modal-title">Welcome to [prompt]</div>
</header>
<div className="inner-content">
<div className="content">
<p>Thank you for downloading Prompt!</p>
<p>
Prompt is a new terminal designed to help you save time and organize your command life.
Prompt is currently in beta. If you'd like to give feedback, run into problems, have
questions, or need help, please join the Prompt{" "}
<a target="_blank" href={util.makeExternLink("https://discord.gg/XfvZ334gwU")}>
discord&nbsp;server
</a>
.
</p>
<p>
Prompt is free to use, no email or registration required (unless you're using the cloud
features).
</p>
<p>
<a target="_blank" href={util.makeExternLink("https://www.commandline.dev/tos.html")}>
Full Terms of Service
</a>
</p>
</div>
</div>
<footer>
<div className="flex-spacer" />
<div onClick={this.acceptTos} className="button is-prompt-green is-outlined is-small">
Accept Terms of Service
</div>
</footer>
</div>
</div>
);
}
}
export { WelcomeModal, LoadingSpinner, ClientStopModal, AlertModal, DisconnectedModal, TosModal };

Some files were not shown because too many files have changed in this diff Show More