mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
prettier all the files
This commit is contained in:
+9
-10
@@ -1,9 +1,9 @@
|
||||
var AllowedFirstParts = {
|
||||
"package.json": true,
|
||||
"dist": true,
|
||||
"static": true,
|
||||
"node_modules": true,
|
||||
"bin": true,
|
||||
dist: true,
|
||||
static: true,
|
||||
node_modules: true,
|
||||
bin: true,
|
||||
};
|
||||
|
||||
var AllowedNodeModules = {
|
||||
@@ -39,7 +39,6 @@ function ignoreFn(path) {
|
||||
if (!AllowedNodeModules[nodeModule]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -75,19 +74,19 @@ module.exports = {
|
||||
rebuildConfig: {},
|
||||
makers: [
|
||||
{
|
||||
name: '@electron-forge/maker-squirrel',
|
||||
name: "@electron-forge/maker-squirrel",
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-zip',
|
||||
platforms: ['darwin'],
|
||||
name: "@electron-forge/maker-zip",
|
||||
platforms: ["darwin"],
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-deb',
|
||||
name: "@electron-forge/maker-deb",
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-rpm',
|
||||
name: "@electron-forge/maker-rpm",
|
||||
config: {},
|
||||
},
|
||||
],
|
||||
|
||||
+98
-54
@@ -1,48 +1,48 @@
|
||||
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 { 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, When, Otherwise, Choose } 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, GlobalCommandRunner } from "./model";
|
||||
import { CmdStrCode, Markdown } from "./elements";
|
||||
|
||||
@mobxReact.observer
|
||||
class Bookmark extends React.Component<{bookmark : BookmarkType}, {}> {
|
||||
class Bookmark extends React.Component<{ bookmark: BookmarkType }, {}> {
|
||||
@boundMethod
|
||||
handleDeleteClick() : void {
|
||||
let {bookmark} = this.props;
|
||||
handleDeleteClick(): void {
|
||||
let { bookmark } = this.props;
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
model.handleDeleteBookmark(bookmark.bookmarkid);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleEditClick() : void {
|
||||
let {bookmark} = this.props;
|
||||
handleEditClick(): void {
|
||||
let { bookmark } = this.props;
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
model.handleEditBookmark(bookmark.bookmarkid);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleEditCancel() : void {
|
||||
handleEditCancel(): void {
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
model.cancelEdit();
|
||||
return;
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleEditUpdate() : void {
|
||||
handleEditUpdate(): void {
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
model.confirmEdit();
|
||||
return;
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleDescChange(e : any) : void {
|
||||
handleDescChange(e: any): void {
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
mobx.action(() => {
|
||||
model.tempDesc.set(e.target.value);
|
||||
@@ -50,7 +50,7 @@ class Bookmark extends React.Component<{bookmark : BookmarkType}, {}> {
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleCmdChange(e : any) : void {
|
||||
handleCmdChange(e: any): void {
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
mobx.action(() => {
|
||||
model.tempCmd.set(e.target.value);
|
||||
@@ -58,57 +58,76 @@ class Bookmark extends React.Component<{bookmark : BookmarkType}, {}> {
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleClick() : void {
|
||||
let {bookmark} = this.props;
|
||||
handleClick(): void {
|
||||
let { bookmark } = this.props;
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
model.selectBookmark(bookmark.bookmarkid);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleUse() : void {
|
||||
let {bookmark} = this.props;
|
||||
handleUse(): void {
|
||||
let { bookmark } = this.props;
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
model.useBookmark(bookmark.bookmarkid);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickCopy() : void {
|
||||
clickCopy(): void {
|
||||
let bm = this.props.bookmark;
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
model.handleCopyBookmark(bm.bookmarkid);
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
let bm = this.props.bookmark;
|
||||
let model = GlobalModel.bookmarksModel;
|
||||
let isSelected = (model.activeBookmark.get() == bm.bookmarkid);
|
||||
let isSelected = model.activeBookmark.get() == bm.bookmarkid;
|
||||
let markdown = bm.description ?? "";
|
||||
let hasDesc = markdown != "";
|
||||
let isEditing = (model.editingBookmark.get() == bm.bookmarkid);
|
||||
let isCopied = mobx.computed(() => (model.copiedIndicator.get() == bm.bookmarkid)).get();
|
||||
let isEditing = model.editingBookmark.get() == bm.bookmarkid;
|
||||
let isCopied = mobx.computed(() => model.copiedIndicator.get() == bm.bookmarkid).get();
|
||||
if (isEditing) {
|
||||
return (
|
||||
<div data-bookmarkid={bm.bookmarkid} className={cn("bookmark focus-parent is-editing", {"pending-delete": model.pendingDelete.get() == bm.bookmarkid})}>
|
||||
<div className={cn("focus-indicator", {"active": isSelected})}/>
|
||||
<div
|
||||
data-bookmarkid={bm.bookmarkid}
|
||||
className={cn("bookmark focus-parent is-editing", {
|
||||
"pending-delete": model.pendingDelete.get() == bm.bookmarkid,
|
||||
})}
|
||||
>
|
||||
<div className={cn("focus-indicator", { active: isSelected })} />
|
||||
<div className="bookmark-edit">
|
||||
<div className="field">
|
||||
<label className="label">Description (markdown)</label>
|
||||
<div className="control">
|
||||
<textarea className="textarea mono-font" rows={6} value={model.tempDesc.get()} onChange={this.handleDescChange}/>
|
||||
<textarea
|
||||
className="textarea mono-font"
|
||||
rows={6}
|
||||
value={model.tempDesc.get()}
|
||||
onChange={this.handleDescChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label className="label">Command</label>
|
||||
<div className="control">
|
||||
<textarea className="textarea mono-font" rows={3} value={model.tempCmd.get()} onChange={this.handleCmdChange}/>
|
||||
<textarea
|
||||
className="textarea mono-font"
|
||||
rows={3}
|
||||
value={model.tempCmd.get()}
|
||||
onChange={this.handleCmdChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field is-grouped">
|
||||
<div className="control">
|
||||
<button className="button is-link" onClick={this.handleEditUpdate}>Update</button>
|
||||
<button className="button is-link" onClick={this.handleEditUpdate}>
|
||||
Update
|
||||
</button>
|
||||
</div>
|
||||
<div className="control">
|
||||
<button className="button" onClick={this.handleEditCancel}>Cancel</button>
|
||||
<button className="button" onClick={this.handleEditCancel}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -116,18 +135,34 @@ class Bookmark extends React.Component<{bookmark : BookmarkType}, {}> {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className={cn("bookmark focus-parent", {"pending-delete": model.pendingDelete.get() == bm.bookmarkid})} onClick={this.handleClick}>
|
||||
<div className={cn("focus-indicator", {"active": isSelected})}/>
|
||||
<div
|
||||
className={cn("bookmark focus-parent", {
|
||||
"pending-delete": model.pendingDelete.get() == bm.bookmarkid,
|
||||
})}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<div className={cn("focus-indicator", { active: isSelected })} />
|
||||
<div className="bookmark-id-div">{bm.bookmarkid.substr(0, 8)}</div>
|
||||
<div className="bookmark-content">
|
||||
<If condition={hasDesc}>
|
||||
<Markdown text={markdown}/>
|
||||
<Markdown text={markdown} />
|
||||
</If>
|
||||
<CmdStrCode cmdstr={bm.cmdstr} onUse={this.handleUse} onCopy={this.clickCopy} isCopied={isCopied} fontSize="large" limitHeight={false}/>
|
||||
<CmdStrCode
|
||||
cmdstr={bm.cmdstr}
|
||||
onUse={this.handleUse}
|
||||
onCopy={this.clickCopy}
|
||||
isCopied={isCopied}
|
||||
fontSize="large"
|
||||
limitHeight={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="bookmark-controls">
|
||||
<div className="bookmark-control" onClick={this.handleEditClick}><i className="fa-sharp fa-solid fa-pen"/></div>
|
||||
<div className="bookmark-control" onClick={this.handleDeleteClick}><i className="fa-sharp fa-solid fa-trash"/></div>
|
||||
<div className="bookmark-control" onClick={this.handleEditClick}>
|
||||
<i className="fa-sharp fa-solid fa-pen" />
|
||||
</div>
|
||||
<div className="bookmark-control" onClick={this.handleDeleteClick}>
|
||||
<i className="fa-sharp fa-solid fa-trash" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -137,44 +172,53 @@ class Bookmark extends React.Component<{bookmark : BookmarkType}, {}> {
|
||||
@mobxReact.observer
|
||||
class BookmarksView extends React.Component<{}, {}> {
|
||||
@boundMethod
|
||||
closeView() : void {
|
||||
closeView(): void {
|
||||
GlobalModel.bookmarksModel.closeView();
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
let isHidden = (GlobalModel.activeMainView.get() != "bookmarks");
|
||||
let isHidden = GlobalModel.activeMainView.get() != "bookmarks";
|
||||
if (isHidden) {
|
||||
return null;
|
||||
}
|
||||
let bookmarks = GlobalModel.bookmarksModel.bookmarks;
|
||||
let idx : number = 0;
|
||||
let bookmark : BookmarkType = null;
|
||||
let idx: number = 0;
|
||||
let bookmark: BookmarkType = null;
|
||||
return (
|
||||
<div className={cn("bookmarks-view", "alt-view", {"is-hidden": isHidden})}>
|
||||
<div className="close-button" onClick={this.closeView}><i className="fa-sharp fa-solid fa-xmark"></i></div>
|
||||
<div className={cn("bookmarks-view", "alt-view", { "is-hidden": isHidden })}>
|
||||
<div className="close-button" onClick={this.closeView}>
|
||||
<i className="fa-sharp fa-solid fa-xmark"></i>
|
||||
</div>
|
||||
<div className="alt-title">
|
||||
<i className="fa-sharp fa-solid fa-bookmark" style={{marginRight: 10}}/>
|
||||
<i className="fa-sharp fa-solid fa-bookmark" style={{ marginRight: 10 }} />
|
||||
BOOKMARKS
|
||||
</div>
|
||||
<div className="bookmarks-list">
|
||||
<For index="idx" each="bookmark" of={bookmarks}>
|
||||
<Bookmark key={bookmark.bookmarkid} bookmark={bookmark}/>
|
||||
<Bookmark key={bookmark.bookmarkid} bookmark={bookmark} />
|
||||
</For>
|
||||
<If condition={bookmarks.length == 0}>
|
||||
<div className="no-content">
|
||||
No Bookmarks.<br/>
|
||||
Use the <i className="fa-sharp fa-solid fa-bookmark"/> icon on commands to add your first bookmark.
|
||||
No Bookmarks.
|
||||
<br />
|
||||
Use the <i className="fa-sharp fa-solid fa-bookmark" /> icon on commands to add your first
|
||||
bookmark.
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
<If condition={bookmarks.length > 0}>
|
||||
<div className="alt-help">
|
||||
<div className="help-entry">
|
||||
[Enter] to Use Bookmark<br/>
|
||||
[Backspace/Delete]x2 or <i className="fa-sharp fa-solid fa-trash"/> to Delete<br/>
|
||||
[Arrow Up]/[Arrow Down]/[PageUp]/[PageDown] to Move in List<br/>
|
||||
[e] or <i className="fa-sharp fa-solid fa-pen"/> to Edit<br/>
|
||||
[c] or <i className="fa-sharp fa-regular fa-copy"/> to Copy<br/>
|
||||
[Enter] to Use Bookmark
|
||||
<br />
|
||||
[Backspace/Delete]x2 or <i className="fa-sharp fa-solid fa-trash" /> to Delete
|
||||
<br />
|
||||
[Arrow Up]/[Arrow Down]/[PageUp]/[PageDown] to Move in List
|
||||
<br />
|
||||
[e] or <i className="fa-sharp fa-solid fa-pen" /> to Edit
|
||||
<br />
|
||||
[c] or <i className="fa-sharp fa-regular fa-copy" /> to Copy
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
</If>
|
||||
@@ -183,4 +227,4 @@ class BookmarksView extends React.Component<{}, {}> {
|
||||
}
|
||||
}
|
||||
|
||||
export {BookmarksView};
|
||||
export { BookmarksView };
|
||||
|
||||
+20
-14
@@ -1,4 +1,5 @@
|
||||
.cmd-input-info, .cmd-history {
|
||||
.cmd-input-info,
|
||||
.cmd-history {
|
||||
&::-webkit-scrollbar {
|
||||
background-color: #777;
|
||||
width: 5px;
|
||||
@@ -15,7 +16,7 @@
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: @term-white;
|
||||
|
||||
|
||||
.message-content {
|
||||
position: absolute;
|
||||
display: none;
|
||||
@@ -41,7 +42,7 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
.message-content {
|
||||
display: flex;
|
||||
@@ -95,7 +96,7 @@
|
||||
}
|
||||
|
||||
.remote-name {
|
||||
.mono-font(14px)
|
||||
.mono-font(14px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +122,7 @@
|
||||
|
||||
.cmd-input-field {
|
||||
position: relative;
|
||||
|
||||
|
||||
.cmd-input-control {
|
||||
line-height: 0;
|
||||
}
|
||||
@@ -141,7 +142,8 @@
|
||||
resize: none;
|
||||
overflow-wrap: anywhere;
|
||||
|
||||
&:active, &:focus {
|
||||
&:active,
|
||||
&:focus {
|
||||
border-color: white !important;
|
||||
}
|
||||
|
||||
@@ -259,7 +261,7 @@
|
||||
flex-shrink: 1;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 5px;
|
||||
|
||||
|
||||
.info-msg {
|
||||
.mono-font(14px, 400);
|
||||
color: @soft-blue;
|
||||
@@ -289,7 +291,7 @@
|
||||
flex-wrap: wrap;
|
||||
padding-bottom: 5px;
|
||||
.mono-font(14px, 400);
|
||||
|
||||
|
||||
.info-comp {
|
||||
min-width: 200px;
|
||||
color: @term-white;
|
||||
@@ -317,8 +319,9 @@
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
th, td {
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 3px 8px 3px 8px;
|
||||
}
|
||||
|
||||
@@ -341,7 +344,8 @@
|
||||
color: @term-cyan;
|
||||
}
|
||||
|
||||
.info-error, .info-msg {
|
||||
.info-error,
|
||||
.info-msg {
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
}
|
||||
@@ -354,7 +358,7 @@
|
||||
white-space: pre;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
|
||||
.remote-field-val {
|
||||
white-space: pre;
|
||||
display: flex;
|
||||
@@ -386,7 +390,9 @@
|
||||
}
|
||||
|
||||
&.text-input {
|
||||
input[type=text], input[type=number], input[type=password] {
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="password"] {
|
||||
background-color: black;
|
||||
color: white;
|
||||
width: 200px;
|
||||
@@ -394,7 +400,7 @@
|
||||
}
|
||||
|
||||
&.checkbox-input {
|
||||
input[type=checkbox] {
|
||||
input[type="checkbox"] {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
+30
-25
@@ -49,7 +49,7 @@
|
||||
min-width: 100px;
|
||||
overflow: auto;
|
||||
border-left: 1px solid #777;
|
||||
|
||||
|
||||
code {
|
||||
flex-shrink: 0;
|
||||
min-width: 100px;
|
||||
@@ -66,7 +66,7 @@
|
||||
position: relative;
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
|
||||
|
||||
.inner-copy {
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
.terminal-wrapper {
|
||||
position: relative;
|
||||
|
||||
|
||||
.term-block {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -126,7 +126,7 @@
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: white;
|
||||
}
|
||||
@@ -138,7 +138,7 @@
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #555;
|
||||
}
|
||||
@@ -206,7 +206,8 @@ body .xterm .xterm-viewport {
|
||||
}
|
||||
}
|
||||
|
||||
.button.is-plain, .button.is-prompt-cancel {
|
||||
.button.is-plain,
|
||||
.button.is-prompt-cancel {
|
||||
background-color: #222;
|
||||
color: @term-white;
|
||||
|
||||
@@ -238,7 +239,7 @@ body .xterm .xterm-viewport {
|
||||
.mono-font(10px);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
|
||||
.hint-item {
|
||||
padding: 0px 5px 0px 5px;
|
||||
border-radius: 0 0 3px 3px;
|
||||
@@ -252,7 +253,7 @@ body .xterm .xterm-viewport {
|
||||
.hint-item.color-green {
|
||||
color: black;
|
||||
background-color: @tab-green;
|
||||
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
@@ -263,11 +264,11 @@ body .xterm .xterm-viewport {
|
||||
background-color: @tab-green;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
|
||||
.hint-item.color-white {
|
||||
color: black;
|
||||
background-color: @term-white;
|
||||
|
||||
|
||||
&:hover {
|
||||
background-color: @term-bright-white;
|
||||
}
|
||||
@@ -282,7 +283,7 @@ body .xterm .xterm-viewport {
|
||||
.hint-item.color-blue {
|
||||
color: black;
|
||||
background-color: @tab-blue;
|
||||
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
@@ -426,11 +427,11 @@ body .xterm .xterm-viewport {
|
||||
div:nth-child(1) {
|
||||
animation-delay: -0.45s;
|
||||
}
|
||||
|
||||
|
||||
div:nth-child(2) {
|
||||
animation-delay: -0.3s;
|
||||
}
|
||||
|
||||
|
||||
div:nth-child(3) {
|
||||
animation-delay: -0.15s;
|
||||
}
|
||||
@@ -457,19 +458,20 @@ body .xterm .xterm-viewport {
|
||||
background-color: #171717;
|
||||
outline: 2px solid #171717;
|
||||
|
||||
&:hover, &:focus {
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: @term-white;
|
||||
background-color: #333;
|
||||
outline: 2px solid #333;
|
||||
}
|
||||
|
||||
|
||||
&.connect-button {
|
||||
color: @term-green;
|
||||
&:hover {
|
||||
color: @term-green;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.disconnect-button {
|
||||
color: @term-red;
|
||||
&:hover {
|
||||
@@ -499,7 +501,8 @@ body .xterm .xterm-viewport {
|
||||
}
|
||||
|
||||
&.disabled-button {
|
||||
&:hover, &:focus {
|
||||
&:hover,
|
||||
&:focus {
|
||||
outline: none;
|
||||
background-color: #171717;
|
||||
}
|
||||
@@ -521,12 +524,13 @@ body .xterm .xterm-viewport {
|
||||
display: block;
|
||||
background-color: #666 !important;
|
||||
}
|
||||
|
||||
&.active, &.active.selected {
|
||||
|
||||
&.active,
|
||||
&.active.selected {
|
||||
display: block;
|
||||
background-color: @tab-blue !important;
|
||||
}
|
||||
|
||||
|
||||
&.active.selected.fg-focus {
|
||||
display: block;
|
||||
background-color: @tab-green !important;
|
||||
@@ -540,7 +544,7 @@ body .xterm .xterm-viewport {
|
||||
|
||||
#main .term-prompt {
|
||||
font-size: 14px;
|
||||
|
||||
|
||||
i {
|
||||
margin-right: 3px;
|
||||
}
|
||||
@@ -561,7 +565,7 @@ body .xterm .xterm-viewport {
|
||||
|
||||
.term-prompt-remote {
|
||||
color: @term-bright-green;
|
||||
|
||||
|
||||
&.color-green {
|
||||
color: @term-bright-green;
|
||||
}
|
||||
@@ -611,18 +615,19 @@ body .xterm .xterm-viewport {
|
||||
top: -3px;
|
||||
color: #c4a000;
|
||||
|
||||
&.status-init, &.status-disconnected {
|
||||
&.status-init,
|
||||
&.status-disconnected {
|
||||
color: #c4a000;
|
||||
}
|
||||
|
||||
&.status-connecting {
|
||||
color: #c4a000;
|
||||
}
|
||||
|
||||
|
||||
&.status-connected {
|
||||
color: #4e9a06;
|
||||
}
|
||||
|
||||
|
||||
&.status-error {
|
||||
color: #cc0000;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {Database} from "better-sqlite3";
|
||||
import { sprintf } from "sprintf-js";
|
||||
import { Database } from "better-sqlite3";
|
||||
|
||||
let DB = new Database();
|
||||
|
||||
+126
-67
@@ -1,31 +1,41 @@
|
||||
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 { 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, For, When, Otherwise, Choose } from "tsx-control-statements/components";
|
||||
import type { RemoteType } from "./types";
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
|
||||
function renderCmdText(text : string) : any {
|
||||
function renderCmdText(text: string): any {
|
||||
return <span>⌘{text}</span>;
|
||||
}
|
||||
|
||||
class CmdStrCode extends React.Component<{cmdstr : string, onUse : () => void, onCopy : () => void, isCopied : boolean, fontSize : "normal" | "large", limitHeight : boolean}, {}> {
|
||||
class CmdStrCode extends React.Component<
|
||||
{
|
||||
cmdstr: string;
|
||||
onUse: () => void;
|
||||
onCopy: () => void;
|
||||
isCopied: boolean;
|
||||
fontSize: "normal" | "large";
|
||||
limitHeight: boolean;
|
||||
},
|
||||
{}
|
||||
> {
|
||||
@boundMethod
|
||||
handleUse(e : any) {
|
||||
handleUse(e: any) {
|
||||
e.stopPropagation();
|
||||
if (this.props.onUse != null) {
|
||||
this.props.onUse()
|
||||
this.props.onUse();
|
||||
}
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleCopy(e : any) {
|
||||
handleCopy(e: any) {
|
||||
e.stopPropagation();
|
||||
if (this.props.onCopy != null) {
|
||||
this.props.onCopy();
|
||||
@@ -33,21 +43,23 @@ class CmdStrCode extends React.Component<{cmdstr : string, onUse : () => void, o
|
||||
}
|
||||
|
||||
render() {
|
||||
let {isCopied, cmdstr, fontSize, limitHeight} = this.props;
|
||||
let { isCopied, cmdstr, fontSize, limitHeight } = this.props;
|
||||
return (
|
||||
<div className={cn("cmdstr-code", {"is-large": (fontSize == "large")}, {"limit-height": limitHeight})}>
|
||||
<div className={cn("cmdstr-code", { "is-large": fontSize == "large" }, { "limit-height": limitHeight })}>
|
||||
<If condition={isCopied}>
|
||||
<div key="copied" className="copied-indicator">
|
||||
<div>copied</div>
|
||||
</div>
|
||||
</If>
|
||||
<div key="use" className="use-button" title="Use Command" onClick={this.handleUse}><i className="fa-sharp fa-solid fa-check"/></div>
|
||||
<div key="use" className="use-button" title="Use Command" onClick={this.handleUse}>
|
||||
<i className="fa-sharp fa-solid fa-check" />
|
||||
</div>
|
||||
<div key="code" className="code-div">
|
||||
<code>{cmdstr}</code>
|
||||
</div>
|
||||
<div key="copy" className="copy-control">
|
||||
<div className="inner-copy" onClick={this.handleCopy}>
|
||||
<i title="copy" className="fa-sharp fa-regular fa-copy"/>
|
||||
<i title="copy" className="fa-sharp fa-regular fa-copy" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -55,27 +67,27 @@ class CmdStrCode extends React.Component<{cmdstr : string, onUse : () => void, o
|
||||
}
|
||||
}
|
||||
|
||||
class Toggle extends React.Component<{checked : boolean, onChange : (value : boolean) => void}, {}> {
|
||||
class Toggle extends React.Component<{ checked: boolean; onChange: (value: boolean) => void }, {}> {
|
||||
@boundMethod
|
||||
handleChange(e : any) : void {
|
||||
let {onChange} = this.props;
|
||||
handleChange(e: any): void {
|
||||
let { onChange } = this.props;
|
||||
if (onChange != null) {
|
||||
onChange(e.target.checked);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<label className="checkbox-toggle">
|
||||
<input type="checkbox" checked={this.props.checked} onChange={this.handleChange}/>
|
||||
<span className="slider"/>
|
||||
<input type="checkbox" checked={this.props.checked} onChange={this.handleChange} />
|
||||
<span className="slider" />
|
||||
</label>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class RemoteStatusLight extends React.Component<{remote : RemoteType}, {}> {
|
||||
class RemoteStatusLight extends React.Component<{ remote: RemoteType }, {}> {
|
||||
render() {
|
||||
let remote = this.props.remote;
|
||||
let status = "error";
|
||||
@@ -84,24 +96,32 @@ class RemoteStatusLight extends React.Component<{remote : RemoteType}, {}> {
|
||||
status = remote.status;
|
||||
wfp = remote.waitingforpassword;
|
||||
}
|
||||
let icon = "fa-sharp fa-solid fa-circle"
|
||||
let icon = "fa-sharp fa-solid fa-circle";
|
||||
if (status == "connecting") {
|
||||
icon = (wfp ? "fa-sharp fa-solid fa-key" : "fa-sharp fa-solid fa-rotate");
|
||||
icon = wfp ? "fa-sharp fa-solid fa-key" : "fa-sharp fa-solid fa-rotate";
|
||||
}
|
||||
return (
|
||||
<i className={cn("remote-status", icon, "status-" + status)}/>
|
||||
);
|
||||
return <i className={cn("remote-status", icon, "status-" + status)} />;
|
||||
}
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class InlineSettingsTextEdit extends React.Component<{text : string, value : string, onChange : (val : string) => void, maxLength : number, placeholder : string, showIcon? : boolean}, {}> {
|
||||
isEditing : OV<boolean> = mobx.observable.box(false, {name: "inlineedit-isEditing"});
|
||||
tempText : OV<string>;
|
||||
shouldFocus : boolean = false;
|
||||
inputRef : React.RefObject<any> = React.createRef();
|
||||
class InlineSettingsTextEdit extends React.Component<
|
||||
{
|
||||
text: string;
|
||||
value: string;
|
||||
onChange: (val: string) => void;
|
||||
maxLength: number;
|
||||
placeholder: string;
|
||||
showIcon?: boolean;
|
||||
},
|
||||
{}
|
||||
> {
|
||||
isEditing: OV<boolean> = mobx.observable.box(false, { name: "inlineedit-isEditing" });
|
||||
tempText: OV<string>;
|
||||
shouldFocus: boolean = false;
|
||||
inputRef: React.RefObject<any> = React.createRef();
|
||||
|
||||
componentDidUpdate() : void {
|
||||
componentDidUpdate(): void {
|
||||
if (this.shouldFocus) {
|
||||
this.shouldFocus = false;
|
||||
if (this.inputRef.current != null) {
|
||||
@@ -111,14 +131,14 @@ class InlineSettingsTextEdit extends React.Component<{text : string, value : str
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleChangeText(e : any) : void {
|
||||
handleChangeText(e: any): void {
|
||||
mobx.action(() => {
|
||||
this.tempText.set(e.target.value);
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
confirmChange() : void {
|
||||
confirmChange(): void {
|
||||
mobx.action(() => {
|
||||
let newText = this.tempText.get();
|
||||
this.isEditing.set(false);
|
||||
@@ -128,7 +148,7 @@ class InlineSettingsTextEdit extends React.Component<{text : string, value : str
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
cancelChange() : void {
|
||||
cancelChange(): void {
|
||||
mobx.action(() => {
|
||||
this.isEditing.set(false);
|
||||
this.tempText = null;
|
||||
@@ -136,7 +156,7 @@ class InlineSettingsTextEdit extends React.Component<{text : string, value : str
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleKeyDown(e : any) : void {
|
||||
handleKeyDown(e: any): void {
|
||||
if (e.code == "Enter") {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -153,36 +173,64 @@ class InlineSettingsTextEdit extends React.Component<{text : string, value : str
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickEdit() : void {
|
||||
clickEdit(): void {
|
||||
mobx.action(() => {
|
||||
this.isEditing.set(true);
|
||||
this.shouldFocus = true;
|
||||
this.tempText = mobx.observable.box(this.props.value, {name: "inlineedit-tempText"});
|
||||
this.tempText = mobx.observable.box(this.props.value, { name: "inlineedit-tempText" });
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
if (this.isEditing.get()) {
|
||||
return (
|
||||
<div className={cn("settings-input inline-edit", "edit-active")}>
|
||||
<div className="field has-addons">
|
||||
<div className="control">
|
||||
<input ref={this.inputRef} className="input" type="text" onKeyDown={this.handleKeyDown} placeholder={this.props.placeholder} onChange={this.handleChangeText} value={this.tempText.get()} maxLength={this.props.maxLength}/>
|
||||
<input
|
||||
ref={this.inputRef}
|
||||
className="input"
|
||||
type="text"
|
||||
onKeyDown={this.handleKeyDown}
|
||||
placeholder={this.props.placeholder}
|
||||
onChange={this.handleChangeText}
|
||||
value={this.tempText.get()}
|
||||
maxLength={this.props.maxLength}
|
||||
/>
|
||||
</div>
|
||||
<div className="control">
|
||||
<div onClick={this.cancelChange} title="Cancel (Esc)" className="button is-prompt-danger is-outlined is-small"><span className="icon is-small"><i className="fa-sharp fa-solid fa-xmark"/></span></div>
|
||||
<div
|
||||
onClick={this.cancelChange}
|
||||
title="Cancel (Esc)"
|
||||
className="button is-prompt-danger is-outlined is-small"
|
||||
>
|
||||
<span className="icon is-small">
|
||||
<i className="fa-sharp fa-solid fa-xmark" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="control">
|
||||
<div onClick={this.confirmChange} title="Confirm (Enter)" className="button is-prompt-green is-outlined is-small"><span className="icon is-small"><i className="fa-sharp fa-solid fa-check"/></span></div>
|
||||
<div
|
||||
onClick={this.confirmChange}
|
||||
title="Confirm (Enter)"
|
||||
className="button is-prompt-green is-outlined is-small"
|
||||
>
|
||||
<span className="icon is-small">
|
||||
<i className="fa-sharp fa-solid fa-check" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return (
|
||||
<div onClick={this.clickEdit} className={cn("settings-input inline-edit", "edit-not-active")}>
|
||||
{this.props.text}<If condition={this.props.showIcon}> <i className="fa-sharp fa-solid fa-pen"/></If>
|
||||
{this.props.text}
|
||||
<If condition={this.props.showIcon}>
|
||||
{" "}
|
||||
<i className="fa-sharp fa-solid fa-pen" />
|
||||
</If>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -190,16 +238,16 @@ class InlineSettingsTextEdit extends React.Component<{text : string, value : str
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class InfoMessage extends React.Component<{width : number, children : React.ReactNode}> {
|
||||
class InfoMessage extends React.Component<{ width: number; children: React.ReactNode }> {
|
||||
render() {
|
||||
return (
|
||||
<div className="info-message">
|
||||
<div className="message-icon">
|
||||
<i className="fa-sharp fa-solid fa-circle-info"/>
|
||||
<i className="fa-sharp fa-solid fa-circle-info" />
|
||||
</div>
|
||||
<div className="message-content" style={{width: this.props.width}}>
|
||||
<div className="message-content" style={{ width: this.props.width }}>
|
||||
<div className="info-icon">
|
||||
<i className="fa-sharp fa-solid fa-circle-info"/>
|
||||
<i className="fa-sharp fa-solid fa-circle-info" />
|
||||
</div>
|
||||
<div className="info-children">{this.props.children}</div>
|
||||
</div>
|
||||
@@ -208,25 +256,25 @@ class InfoMessage extends React.Component<{width : number, children : React.Reac
|
||||
}
|
||||
}
|
||||
|
||||
function LinkRenderer(props : any) : any {
|
||||
function LinkRenderer(props: any): any {
|
||||
let newUrl = "https://extern?" + encodeURIComponent(props.href);
|
||||
return <a href={newUrl} target="_blank">{props.children}</a>
|
||||
}
|
||||
|
||||
function HeaderRenderer(props : any, hnum : number) : any {
|
||||
return (
|
||||
<div className={cn("title", "is-" + hnum)}>{props.children}</div>
|
||||
<a href={newUrl} target="_blank">
|
||||
{props.children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function CodeRenderer(props : any) : any {
|
||||
return (
|
||||
<code className={cn({"inline": props.inline})}>{props.children}</code>
|
||||
);
|
||||
function HeaderRenderer(props: any, hnum: number): any {
|
||||
return <div className={cn("title", "is-" + hnum)}>{props.children}</div>;
|
||||
}
|
||||
|
||||
function CodeRenderer(props: any): any {
|
||||
return <code className={cn({ inline: props.inline })}>{props.children}</code>;
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class Markdown extends React.Component<{text : string, style? : any, extraClassName? : string}, {}> {
|
||||
class Markdown extends React.Component<{ text: string; style?: any; extraClassName?: string }, {}> {
|
||||
render() {
|
||||
let text = this.props.text;
|
||||
let markdownComponents = {
|
||||
@@ -241,16 +289,16 @@ class Markdown extends React.Component<{text : string, style? : any, extraClassN
|
||||
};
|
||||
return (
|
||||
<div className={cn("markdown content", this.props.extraClassName)} style={this.props.style}>
|
||||
<ReactMarkdown children={text} remarkPlugins={[remarkGfm]} components={markdownComponents}/>
|
||||
<ReactMarkdown children={text} remarkPlugins={[remarkGfm]} components={markdownComponents} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class SettingsError extends React.Component<{errorMessage : OV<string>}, {}> {
|
||||
class SettingsError extends React.Component<{ errorMessage: OV<string> }, {}> {
|
||||
@boundMethod
|
||||
dismissError() : void {
|
||||
dismissError(): void {
|
||||
mobx.action(() => {
|
||||
this.props.errorMessage.set(null);
|
||||
})();
|
||||
@@ -263,11 +311,22 @@ class SettingsError extends React.Component<{errorMessage : OV<string>}, {}> {
|
||||
return (
|
||||
<div className="settings-field settings-error">
|
||||
<div>Error: {this.props.errorMessage.get()}</div>
|
||||
<div className="flex-spacer"/>
|
||||
<div onClick={this.dismissError} className="error-dismiss"><i className="fa-sharp fa-solid fa-xmark"/></div>
|
||||
<div className="flex-spacer" />
|
||||
<div onClick={this.dismissError} className="error-dismiss">
|
||||
<i className="fa-sharp fa-solid fa-xmark" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {CmdStrCode, Toggle, renderCmdText, RemoteStatusLight, InlineSettingsTextEdit, InfoMessage, Markdown, SettingsError};
|
||||
export {
|
||||
CmdStrCode,
|
||||
Toggle,
|
||||
renderCmdText,
|
||||
RemoteStatusLight,
|
||||
InlineSettingsTextEdit,
|
||||
InfoMessage,
|
||||
Markdown,
|
||||
SettingsError,
|
||||
};
|
||||
|
||||
+99
-91
@@ -3,12 +3,12 @@ import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
import fetch from "node-fetch";
|
||||
import * as child_process from "node:child_process";
|
||||
import {debounce} from "throttle-debounce";
|
||||
import {handleJsonFetchResponse} from "./util";
|
||||
import { debounce } from "throttle-debounce";
|
||||
import { handleJsonFetchResponse } from "./util";
|
||||
import * as winston from "winston";
|
||||
import * as util from "util";
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
import { sprintf } from "sprintf-js";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
const PromptAppPathVarName = "PROMPT_APP_PATH";
|
||||
const PromptDevVarName = "PROMPT_DEV";
|
||||
@@ -16,10 +16,10 @@ const AuthKeyFile = "prompt.authkey";
|
||||
const DevServerEndpoint = "http://127.0.0.1:8090";
|
||||
const ProdServerEndpoint = "http://127.0.0.1:1619";
|
||||
|
||||
let isDev = (process.env[PromptDevVarName] != null);
|
||||
let isDev = process.env[PromptDevVarName] != null;
|
||||
let scHome = getPromptHomeDir();
|
||||
ensureDir(scHome);
|
||||
let DistDir = (isDev ? "dist-dev" : "dist");
|
||||
let DistDir = isDev ? "dist-dev" : "dist";
|
||||
let GlobalAuthKey = "";
|
||||
let instanceId = uuidv4();
|
||||
let oldConsoleLog = console.log;
|
||||
@@ -31,18 +31,16 @@ let wasInFg = true;
|
||||
let unamePlatform = process.platform;
|
||||
let unameArch = process.arch;
|
||||
if (unameArch == "x64") {
|
||||
unameArch = "amd64"
|
||||
unameArch = "amd64";
|
||||
}
|
||||
let logger;
|
||||
let loggerConfig = {
|
||||
level: "info",
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({format: "YYYY-MM-DD HH:mm:ss"}),
|
||||
winston.format.printf(info => `${info.timestamp} ${info.message}`),
|
||||
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
||||
winston.format.printf((info) => `${info.timestamp} ${info.message}`)
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.File({filename: path.join(scHome, "prompt-app.log"), level: "info"}),
|
||||
],
|
||||
transports: [new winston.transports.File({ filename: path.join(scHome, "prompt-app.log"), level: "info" })],
|
||||
};
|
||||
if (isDev) {
|
||||
loggerConfig.transports.push(new winston.transports.Console());
|
||||
@@ -51,18 +49,25 @@ logger = winston.createLogger(loggerConfig);
|
||||
function log(...msg) {
|
||||
try {
|
||||
logger.info(util.format(...msg));
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
oldConsoleLog(...msg);
|
||||
}
|
||||
}
|
||||
console.log = log;
|
||||
console.log(sprintf("prompt-app starting, PROMPT_HOME=%s, apppath=%s arch=%s/%s", scHome, getAppBasePath(), unamePlatform, unameArch));
|
||||
console.log(
|
||||
sprintf(
|
||||
"prompt-app starting, PROMPT_HOME=%s, apppath=%s arch=%s/%s",
|
||||
scHome,
|
||||
getAppBasePath(),
|
||||
unamePlatform,
|
||||
unameArch
|
||||
)
|
||||
);
|
||||
if (isDev) {
|
||||
console.log("prompt-app PROMPT_DEV set");
|
||||
}
|
||||
let app = electron.app;
|
||||
app.setName((isDev ? "Prompt (Dev)" : "Prompt"));
|
||||
app.setName(isDev ? "Prompt (Dev)" : "Prompt");
|
||||
let localServerProc = null;
|
||||
let localServerShouldRestart = false;
|
||||
|
||||
@@ -78,7 +83,7 @@ function getPromptHomeDir() {
|
||||
if (homeDir == null) {
|
||||
homeDir = "/";
|
||||
}
|
||||
scHome = path.join(homeDir, (isDev ? "prompt-dev" : "prompt"));
|
||||
scHome = path.join(homeDir, isDev ? "prompt-dev" : "prompt");
|
||||
}
|
||||
return scHome;
|
||||
}
|
||||
@@ -116,7 +121,7 @@ function getLocalServerCwd() {
|
||||
}
|
||||
|
||||
function ensureDir(dir) {
|
||||
fs.mkdirSync(dir, {recursive: true, mode: 0o700});
|
||||
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
||||
}
|
||||
|
||||
function readAuthKey() {
|
||||
@@ -124,7 +129,7 @@ function readAuthKey() {
|
||||
let authKeyFileName = path.join(homeDir, AuthKeyFile);
|
||||
if (!fs.existsSync(authKeyFileName)) {
|
||||
let authKeyStr = String(uuidv4());
|
||||
fs.writeFileSync(authKeyFileName, authKeyStr, {mode: 0o600});
|
||||
fs.writeFileSync(authKeyFileName, authKeyStr, { mode: 0o600 });
|
||||
return authKeyStr;
|
||||
}
|
||||
let authKeyData = fs.readFileSync(authKeyFileName);
|
||||
@@ -141,10 +146,7 @@ let menuTemplate = [
|
||||
},
|
||||
{
|
||||
label: "File",
|
||||
submenu: [
|
||||
{role: "close"},
|
||||
{role: "forceReload"},
|
||||
],
|
||||
submenu: [{ role: "close" }, { role: "forceReload" }],
|
||||
},
|
||||
{
|
||||
role: "editMenu",
|
||||
@@ -162,11 +164,11 @@ electron.Menu.setApplicationMenu(menu);
|
||||
|
||||
let MainWindow = null;
|
||||
|
||||
function getMods(input : any) {
|
||||
return {meta: input.meta, shift: input.shift, ctrl: input.control, alt: input.alt};
|
||||
function getMods(input: any) {
|
||||
return { meta: input.meta, shift: input.shift, ctrl: input.control, alt: input.alt };
|
||||
}
|
||||
|
||||
function shNavHandler(event : any, url : any) {
|
||||
function shNavHandler(event: any, url: any) {
|
||||
console.log("navigation", url);
|
||||
event.preventDefault();
|
||||
}
|
||||
@@ -181,9 +183,9 @@ function createMainWindow(clientData) {
|
||||
webPreferences: {
|
||||
preload: path.join(getAppBasePath(), DistDir, "preload.js"),
|
||||
},
|
||||
backgroundColor: '#000',
|
||||
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.webContents.on("before-input-event", (e, input) => {
|
||||
if (win.isFocused()) {
|
||||
@@ -202,11 +204,10 @@ function createMainWindow(clientData) {
|
||||
e.preventDefault();
|
||||
if (!input.alt) {
|
||||
win.webContents.send("i-cmd", mods);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
win.webContents.toggleDevTools();
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
if (input.code == "KeyR" && input.meta) {
|
||||
@@ -255,18 +256,24 @@ function createMainWindow(clientData) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
win.webContents.send("digit-cmd", {digit: digitNum}, mods);
|
||||
win.webContents.send("digit-cmd", { digit: digitNum }, mods);
|
||||
}
|
||||
if ((input.code == "BracketRight" || input.code == "BracketLeft") && input.meta) {
|
||||
let rel = (input.code == "BracketRight" ? 1 : -1);
|
||||
win.webContents.send("bracket-cmd", {relative: rel}, mods);
|
||||
let rel = input.code == "BracketRight" ? 1 : -1;
|
||||
win.webContents.send("bracket-cmd", { relative: rel }, mods);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
});
|
||||
win.webContents.on("will-navigate", shNavHandler);
|
||||
win.on("resized", debounce(400, (e) => mainResizeHandler(e, win)));
|
||||
win.on("moved", debounce(400, (e) => mainResizeHandler(e, win)));
|
||||
win.on(
|
||||
"resized",
|
||||
debounce(400, (e) => mainResizeHandler(e, win))
|
||||
);
|
||||
win.on(
|
||||
"moved",
|
||||
debounce(400, (e) => mainResizeHandler(e, win))
|
||||
);
|
||||
win.on("focus", () => {
|
||||
wasInFg = true;
|
||||
wasActive = true;
|
||||
@@ -278,13 +285,11 @@ function createMainWindow(clientData) {
|
||||
e.preventDefault();
|
||||
if (url.startsWith("https://docs.getprompt.dev/")) {
|
||||
electron.shell.openExternal(url);
|
||||
}
|
||||
else if (url.startsWith("https://discord.gg/")) {
|
||||
} else if (url.startsWith("https://discord.gg/")) {
|
||||
electron.shell.openExternal(url);
|
||||
}
|
||||
else if (url.startsWith("https://extern/?")) {
|
||||
} else if (url.startsWith("https://extern/?")) {
|
||||
let qmark = url.indexOf("?");
|
||||
let param = url.substr(qmark+1);
|
||||
let param = url.substr(qmark + 1);
|
||||
let newUrl = decodeURIComponent(param);
|
||||
electron.shell.openExternal(newUrl);
|
||||
}
|
||||
@@ -298,18 +303,20 @@ function mainResizeHandler(e, win) {
|
||||
}
|
||||
let bounds = win.getBounds();
|
||||
console.log("resize/move", win.getBounds());
|
||||
let winSize = {width: bounds.width, height: bounds.height, top: bounds.y, left: bounds.x};
|
||||
let winSize = { width: bounds.width, height: bounds.height, top: bounds.y, left: bounds.x };
|
||||
let url = getBaseHostPort() + "/api/set-winsize";
|
||||
let fetchHeaders = getFetchHeaders();
|
||||
fetch(url, {method: "post", body: JSON.stringify(winSize), headers: fetchHeaders}).then((resp) => handleJsonFetchResponse(url, resp)).catch((err) => {
|
||||
console.log("error setting winsize", err)
|
||||
});
|
||||
fetch(url, { method: "post", body: JSON.stringify(winSize), headers: fetchHeaders })
|
||||
.then((resp) => handleJsonFetchResponse(url, resp))
|
||||
.catch((err) => {
|
||||
console.log("error setting winsize", err);
|
||||
});
|
||||
}
|
||||
|
||||
function calcBounds(clientData) {
|
||||
let primaryDisplay = electron.screen.getPrimaryDisplay();
|
||||
let pdBounds = primaryDisplay.bounds;
|
||||
let size = {x: 50, y: 50, width: pdBounds.width-150, height: pdBounds.height-150};
|
||||
let size = { x: 50, y: 50, width: pdBounds.width - 150, height: pdBounds.height - 150 };
|
||||
if (clientData != null && clientData.winsize != null && clientData.winsize.width > 0) {
|
||||
let cwinSize = clientData.winsize;
|
||||
if (cwinSize.width > 0) {
|
||||
@@ -346,8 +353,8 @@ function calcBounds(clientData) {
|
||||
return size;
|
||||
}
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") app.quit();
|
||||
});
|
||||
|
||||
electron.ipcMain.on("get-id", (event) => {
|
||||
@@ -366,7 +373,7 @@ electron.ipcMain.on("get-authkey", (event) => {
|
||||
});
|
||||
|
||||
electron.ipcMain.on("local-server-status", (event) => {
|
||||
event.returnValue = (localServerProc != null);
|
||||
event.returnValue = localServerProc != null;
|
||||
return;
|
||||
});
|
||||
|
||||
@@ -375,8 +382,7 @@ electron.ipcMain.on("restart-server", (event) => {
|
||||
localServerProc.kill();
|
||||
localServerShouldRestart = true;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
runLocalServer();
|
||||
}
|
||||
event.returnValue = true;
|
||||
@@ -391,9 +397,9 @@ electron.ipcMain.on("reload-window", (event) => {
|
||||
return;
|
||||
});
|
||||
|
||||
function getContextMenu() : any {
|
||||
function getContextMenu(): any {
|
||||
let menu = new electron.Menu();
|
||||
let menuItem = new electron.MenuItem({label: "Testing", click: () => console.log("click testing!")});
|
||||
let menuItem = new electron.MenuItem({ label: "Testing", click: () => console.log("click testing!") });
|
||||
menu.append(menuItem);
|
||||
return menu;
|
||||
}
|
||||
@@ -404,32 +410,35 @@ function getFetchHeaders() {
|
||||
};
|
||||
}
|
||||
|
||||
async function getClientDataPoll(loopNum : number) {
|
||||
let lastTime = (loopNum >= 6);
|
||||
async function getClientDataPoll(loopNum: number) {
|
||||
let lastTime = loopNum >= 6;
|
||||
let cdata = await getClientData(!lastTime, loopNum);
|
||||
if (lastTime || cdata != null) {
|
||||
return cdata;
|
||||
}
|
||||
await sleep(1000);
|
||||
return getClientDataPoll(loopNum+1);
|
||||
return getClientDataPoll(loopNum + 1);
|
||||
}
|
||||
|
||||
function getClientData(willRetry : boolean, retryNum : number) {
|
||||
function getClientData(willRetry: boolean, retryNum: number) {
|
||||
let url = getBaseHostPort() + "/api/get-client-data";
|
||||
let fetchHeaders = getFetchHeaders();
|
||||
return fetch(url, {headers: fetchHeaders}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
||||
if (data == null) {
|
||||
return fetch(url, { headers: fetchHeaders })
|
||||
.then((resp) => handleJsonFetchResponse(url, resp))
|
||||
.then((data) => {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return data.data;
|
||||
})
|
||||
.catch((err) => {
|
||||
if (willRetry) {
|
||||
console.log("error getting client-data from local-server, will retry", "(" + retryNum + ")");
|
||||
return null;
|
||||
}
|
||||
console.log("error getting client-data from local-server, failed: ", err);
|
||||
return null;
|
||||
}
|
||||
return data.data;
|
||||
}).catch((err) => {
|
||||
if (willRetry) {
|
||||
console.log("error getting client-data from local-server, will retry", "(" + retryNum + ")");
|
||||
return null;
|
||||
}
|
||||
console.log("error getting client-data from local-server, failed: ", err);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function sendLSSC() {
|
||||
@@ -479,23 +488,23 @@ function runLocalServer() {
|
||||
});
|
||||
proc.on("error", (e) => {
|
||||
console.log("error running local-server", e);
|
||||
})
|
||||
proc.stdout.on("data", output => {
|
||||
});
|
||||
proc.stdout.on("data", (output) => {
|
||||
return;
|
||||
});
|
||||
proc.stderr.on("data", output => {
|
||||
proc.stderr.on("data", (output) => {
|
||||
return;
|
||||
});
|
||||
return rtnPromise;
|
||||
}
|
||||
|
||||
electron.ipcMain.on("context-screen", (event, {screenId}, {x, y}) => {
|
||||
electron.ipcMain.on("context-screen", (event, { screenId }, { x, y }) => {
|
||||
console.log("context-screen", screenId);
|
||||
let menu = getContextMenu();
|
||||
menu.popup({x, y});
|
||||
menu.popup({ x, y });
|
||||
});
|
||||
|
||||
electron.ipcMain.on("context-editmenu", (event, {x, y}, opts) => {
|
||||
electron.ipcMain.on("context-editmenu", (event, { x, y }, opts) => {
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
@@ -503,22 +512,21 @@ electron.ipcMain.on("context-editmenu", (event, {x, y}, opts) => {
|
||||
let menu = new electron.Menu();
|
||||
let menuItem = null;
|
||||
if (opts.showCut) {
|
||||
menuItem = new electron.MenuItem({label: "Cut", role: "cut"});
|
||||
menuItem = new electron.MenuItem({ label: "Cut", role: "cut" });
|
||||
menu.append(menuItem);
|
||||
}
|
||||
menuItem = new electron.MenuItem({label: "Copy", role: "copy"});
|
||||
menuItem = new electron.MenuItem({ label: "Copy", role: "copy" });
|
||||
menu.append(menuItem);
|
||||
menuItem = new electron.MenuItem({label: "Paste", role: "paste"});
|
||||
menuItem = new electron.MenuItem({ label: "Paste", role: "paste" });
|
||||
menu.append(menuItem);
|
||||
menu.popup({x, y});
|
||||
menu.popup({ x, y });
|
||||
});
|
||||
|
||||
async function createMainWindowWrap() {
|
||||
let clientData = null;
|
||||
try {
|
||||
clientData = await getClientDataPoll(1);
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
console.log("error getting local-server clientdata", e.toString());
|
||||
}
|
||||
MainWindow = createMainWindow(clientData);
|
||||
@@ -532,14 +540,16 @@ async function sleep(ms) {
|
||||
}
|
||||
|
||||
function logActiveState() {
|
||||
let activeState = {fg: wasInFg, active: wasActive, open: true};
|
||||
let activeState = { fg: wasInFg, active: wasActive, open: true };
|
||||
let url = getBaseHostPort() + "/api/log-active-state";
|
||||
let fetchHeaders = getFetchHeaders();
|
||||
fetch(url, {method: "post", body: JSON.stringify(activeState), headers: fetchHeaders}).then((resp) => handleJsonFetchResponse(url, resp)).catch((err) => {
|
||||
console.log("error logging active state", err)
|
||||
});
|
||||
fetch(url, { method: "post", body: JSON.stringify(activeState), headers: fetchHeaders })
|
||||
.then((resp) => handleJsonFetchResponse(url, resp))
|
||||
.catch((err) => {
|
||||
console.log("error logging active state", err);
|
||||
});
|
||||
// for next iteration
|
||||
wasInFg = (MainWindow != null && MainWindow.isFocused());
|
||||
wasInFg = MainWindow != null && MainWindow.isFocused();
|
||||
wasActive = false;
|
||||
}
|
||||
|
||||
@@ -561,17 +571,15 @@ function runActiveTimer() {
|
||||
GlobalAuthKey = readAuthKey();
|
||||
try {
|
||||
await runLocalServer();
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
console.log(e.toString());
|
||||
}
|
||||
setTimeout(runActiveTimer, 5000); // start active timer, wait 5s just to be safe
|
||||
await app.whenReady();
|
||||
await createMainWindowWrap();
|
||||
app.on('activate', () => {
|
||||
app.on("activate", () => {
|
||||
if (electron.BrowserWindow.getAllWindows().length === 0) {
|
||||
createMainWindowWrap().then();
|
||||
}
|
||||
})
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
+44
-24
@@ -1,37 +1,60 @@
|
||||
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";
|
||||
import {debounce, throttle} from "throttle-debounce";
|
||||
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";
|
||||
import { debounce, throttle } from "throttle-debounce";
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
type CV<V> = mobx.IComputedValue<V>;
|
||||
|
||||
@mobxReact.observer
|
||||
class FullRenderer extends React.Component<{rendererContainer : RendererContainerType, lineId : string, plugin : RendererPluginType, onHeightChange : () => void, initParams : RendererModelInitializeParams}, {}> {
|
||||
model : RendererModel;
|
||||
wrapperDivRef : React.RefObject<any> = React.createRef();
|
||||
rszObs : ResizeObserver;
|
||||
updateHeight_debounced : (newHeight : number) => void;
|
||||
class FullRenderer extends React.Component<
|
||||
{
|
||||
rendererContainer: RendererContainerType;
|
||||
lineId: string;
|
||||
plugin: RendererPluginType;
|
||||
onHeightChange: () => void;
|
||||
initParams: RendererModelInitializeParams;
|
||||
},
|
||||
{}
|
||||
> {
|
||||
model: RendererModel;
|
||||
wrapperDivRef: React.RefObject<any> = React.createRef();
|
||||
rszObs: ResizeObserver;
|
||||
updateHeight_debounced: (newHeight: number) => void;
|
||||
|
||||
constructor(props : any) {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
let {rendererContainer, lineId, plugin, initParams} = this.props;
|
||||
let { rendererContainer, lineId, plugin, initParams } = this.props;
|
||||
this.model = plugin.modelCtor();
|
||||
this.model.initialize(initParams);
|
||||
rendererContainer.registerRenderer(lineId, this.model);
|
||||
this.updateHeight_debounced = debounce(1000, this.updateHeight.bind(this));
|
||||
}
|
||||
|
||||
updateHeight(newHeight : number) : void {
|
||||
updateHeight(newHeight: number): void {
|
||||
this.model.updateHeight(newHeight);
|
||||
}
|
||||
|
||||
handleResize(entries : ResizeObserverEntry[]) : void {
|
||||
handleResize(entries: ResizeObserverEntry[]): void {
|
||||
if (this.props.onHeightChange) {
|
||||
this.props.onHeightChange();
|
||||
}
|
||||
@@ -51,13 +74,13 @@ class FullRenderer extends React.Component<{rendererContainer : RendererContaine
|
||||
this.rszObs = new ResizeObserver(this.handleResize.bind(this));
|
||||
this.rszObs.observe(this.wrapperDivRef.current);
|
||||
}
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
this.checkRszObs();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
let {rendererContainer, lineId} = this.props;
|
||||
let { rendererContainer, lineId } = this.props;
|
||||
rendererContainer.unloadRenderer(lineId);
|
||||
if (this.rszObs != null) {
|
||||
this.rszObs.disconnect();
|
||||
@@ -70,20 +93,17 @@ class FullRenderer extends React.Component<{rendererContainer : RendererContaine
|
||||
}
|
||||
|
||||
render() {
|
||||
let {plugin} = this.props;
|
||||
let { plugin } = this.props;
|
||||
let Comp = plugin.fullComponent;
|
||||
if (Comp == null) {
|
||||
<div ref={this.wrapperDivRef}>
|
||||
(no component found in plugin)
|
||||
</div>
|
||||
<div ref={this.wrapperDivRef}>(no component found in plugin)</div>;
|
||||
}
|
||||
return (
|
||||
<div ref={this.wrapperDivRef}>
|
||||
<Comp model={this.model}/>
|
||||
<Comp model={this.model} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {FullRenderer};
|
||||
|
||||
export { FullRenderer };
|
||||
|
||||
+253
-130
File diff suppressed because it is too large
Load Diff
+1013
-1147
File diff suppressed because it is too large
Load Diff
+16
-12
@@ -60,19 +60,20 @@
|
||||
.line-minimise:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
.line-icon + .line-icon {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
.line-icon.active {
|
||||
visibility: visible;
|
||||
display: block;
|
||||
|
||||
i.fa-star, i.fa-thumb-tack {
|
||||
|
||||
i.fa-star,
|
||||
i.fa-thumb-tack {
|
||||
color: @term-bright-yellow;
|
||||
}
|
||||
|
||||
|
||||
i.fa-bookmark {
|
||||
color: @term-bright-blue;
|
||||
}
|
||||
@@ -251,7 +252,7 @@
|
||||
&.rtnstate {
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
|
||||
.status-icon {
|
||||
font-size: 8px;
|
||||
position: absolute;
|
||||
@@ -341,8 +342,10 @@
|
||||
margin-top: 1px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.ts, .termopts, .renderer {
|
||||
|
||||
.ts,
|
||||
.termopts,
|
||||
.renderer {
|
||||
display: flex;
|
||||
color: #aaa;
|
||||
margin-top: 5px;
|
||||
@@ -383,7 +386,7 @@
|
||||
padding-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.metapart-mono {
|
||||
color: #ddd;
|
||||
margin-left: 8px;
|
||||
@@ -391,7 +394,7 @@
|
||||
white-space: nowrap;
|
||||
.mono-font(14px);
|
||||
}
|
||||
|
||||
|
||||
.cmdtext {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
@@ -471,8 +474,9 @@
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.line-sep::before, .line-sep::after {
|
||||
content: '';
|
||||
.line-sep::before,
|
||||
.line-sep::after {
|
||||
content: "";
|
||||
height: 2px;
|
||||
background-color: #ccc;
|
||||
flex-grow: 1;
|
||||
|
||||
+122
-110
@@ -1,13 +1,13 @@
|
||||
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 { sprintf } from "sprintf-js";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import { If, For, When, Otherwise, Choose } from "tsx-control-statements/components";
|
||||
import cn from "classnames";
|
||||
import dayjs from "dayjs";
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||
import {debounce, throttle} from "throttle-debounce";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import { debounce, throttle } from "throttle-debounce";
|
||||
import * as T from "./types";
|
||||
import * as util from "./util";
|
||||
import * as lineutil from "./lineutil";
|
||||
@@ -15,45 +15,57 @@ import * as lineutil from "./lineutil";
|
||||
dayjs.extend(localizedFormat);
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
type OArr<V> = mobx.IObservableArray<V>;
|
||||
type OMap<K,V> = mobx.ObservableMap<K,V>;
|
||||
type OMap<K, V> = mobx.ObservableMap<K, V>;
|
||||
|
||||
const LinesVisiblePadding = 500;
|
||||
|
||||
type ScreenInterface = {
|
||||
setAnchorFields(anchorLine : number, anchorOffset : number, reason : string) : void,
|
||||
getSelectedLine() : number,
|
||||
getAnchor() : {anchorLine : number, anchorOffset : number},
|
||||
}
|
||||
setAnchorFields(anchorLine: number, anchorOffset: number, reason: string): void;
|
||||
getSelectedLine(): number;
|
||||
getAnchor(): { anchorLine: number; anchorOffset: number };
|
||||
};
|
||||
|
||||
// <Line key={line.lineid} line={line} screen={screen} width={width} visible={this.visibleMap.get(lineNumStr)} staticRender={this.staticRender.get()} onHeightChange={this.onHeightChange} overrideCollapsed={this.collapsedMap.get(lineNumStr)} topBorder={topBorder} renderMode={renderMode}/>;
|
||||
|
||||
type LineCompFactory = (props : T.LineFactoryProps) => JSX.Element;
|
||||
type LineCompFactory = (props: T.LineFactoryProps) => JSX.Element;
|
||||
|
||||
@mobxReact.observer
|
||||
class LinesView extends React.Component<{screen : ScreenInterface, width : number, lines : T.LineInterface[], renderMode : T.RenderModeType, lineFactory : LineCompFactory}, {}> {
|
||||
rszObs : ResizeObserver;
|
||||
linesRef : React.RefObject<any>;
|
||||
staticRender : OV<boolean> = mobx.observable.box(true, {name: "static-render"});
|
||||
lastOffsetHeight : number = 0;
|
||||
lastOffsetWidth : number = 0;
|
||||
ignoreNextScroll : boolean = false;
|
||||
visibleMap : Map<string, OV<boolean>>; // linenum => OV<vis>
|
||||
collapsedMap : Map<string, OV<boolean>>; // linenum => OV<collapsed>
|
||||
lastLinesLength : number = 0;
|
||||
lastSelectedLine : number = 0;
|
||||
class LinesView extends React.Component<
|
||||
{
|
||||
screen: ScreenInterface;
|
||||
width: number;
|
||||
lines: T.LineInterface[];
|
||||
renderMode: T.RenderModeType;
|
||||
lineFactory: LineCompFactory;
|
||||
},
|
||||
{}
|
||||
> {
|
||||
rszObs: ResizeObserver;
|
||||
linesRef: React.RefObject<any>;
|
||||
staticRender: OV<boolean> = mobx.observable.box(true, { name: "static-render" });
|
||||
lastOffsetHeight: number = 0;
|
||||
lastOffsetWidth: number = 0;
|
||||
ignoreNextScroll: boolean = false;
|
||||
visibleMap: Map<string, OV<boolean>>; // linenum => OV<vis>
|
||||
collapsedMap: Map<string, OV<boolean>>; // linenum => OV<collapsed>
|
||||
lastLinesLength: number = 0;
|
||||
lastSelectedLine: number = 0;
|
||||
|
||||
computeAnchorLine_throttled : () => void;
|
||||
computeVisibleMap_debounced : () => void;
|
||||
computeAnchorLine_throttled: () => void;
|
||||
computeVisibleMap_debounced: () => void;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.linesRef = React.createRef();
|
||||
this.computeAnchorLine_throttled = throttle(100, this.computeAnchorLine.bind(this), {noLeading: true, noTrailing: false});
|
||||
this.computeAnchorLine_throttled = throttle(100, this.computeAnchorLine.bind(this), {
|
||||
noLeading: true,
|
||||
noTrailing: false,
|
||||
});
|
||||
this.visibleMap = new Map();
|
||||
this.collapsedMap = new Map();
|
||||
this.computeVisibleMap_debounced = debounce(1000, this.computeVisibleMap.bind(this));
|
||||
}
|
||||
|
||||
|
||||
@boundMethod
|
||||
scrollHandler() {
|
||||
let linesElem = this.linesRef.current;
|
||||
@@ -74,8 +86,8 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
this.computeAnchorLine_throttled(); // only do this when we're not ignoring the scroll
|
||||
}
|
||||
|
||||
computeAnchorLine() : void {
|
||||
let {screen} = this.props;
|
||||
computeAnchorLine(): void {
|
||||
let { screen } = this.props;
|
||||
let linesElem = this.linesRef.current;
|
||||
if (linesElem == null) {
|
||||
screen.setAnchorFields(null, 0, "no-lines");
|
||||
@@ -89,8 +101,8 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
let scrollTop = linesElem.scrollTop;
|
||||
let height = linesElem.clientHeight;
|
||||
let containerBottom = scrollTop + height;
|
||||
let anchorElem : HTMLElement = null;
|
||||
for (let i=lineElemArr.length-1; i >= 0; i--) {
|
||||
let anchorElem: HTMLElement = null;
|
||||
for (let i = lineElemArr.length - 1; i >= 0; i--) {
|
||||
let lineElem = lineElemArr[i];
|
||||
let bottomPos = lineElem.offsetTop + lineElem.offsetHeight;
|
||||
if (anchorElem == null && (bottomPos <= containerBottom || lineElem.offsetTop <= scrollTop)) {
|
||||
@@ -106,26 +118,26 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
screen.setAnchorFields(anchorLineNum, anchorOffset, "computeAnchorLine");
|
||||
}
|
||||
|
||||
computeVisibleMap() : void {
|
||||
computeVisibleMap(): void {
|
||||
let linesElem = this.linesRef.current;
|
||||
if (linesElem == null) {
|
||||
return;
|
||||
}
|
||||
if (linesElem.offsetParent == null) {
|
||||
return; // handles when parent is set to display:none (is-hidden)
|
||||
return; // handles when parent is set to display:none (is-hidden)
|
||||
}
|
||||
let lineElemArr = linesElem.querySelectorAll(".line");
|
||||
if (lineElemArr == null) {
|
||||
return;
|
||||
}
|
||||
if (linesElem.clientHeight == 0) {
|
||||
return; // when linesElem is collapsed (or display:none)
|
||||
return; // when linesElem is collapsed (or display:none)
|
||||
}
|
||||
let containerTop = linesElem.scrollTop - LinesVisiblePadding;
|
||||
let containerBot = linesElem.scrollTop + linesElem.clientHeight + LinesVisiblePadding;
|
||||
let newMap = new Map<string, boolean>();
|
||||
// console.log("computevismap", linesElem.scrollTop, linesElem.clientHeight, containerTop + "-" + containerBot);
|
||||
for (let i=0; i<lineElemArr.length; i++) {
|
||||
for (let i = 0; i < lineElemArr.length; i++) {
|
||||
let lineElem = lineElemArr[i];
|
||||
let lineTop = lineElem.offsetTop;
|
||||
let lineBot = lineElem.offsetTop + lineElem.offsetHeight;
|
||||
@@ -134,7 +146,7 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
isVis = true;
|
||||
}
|
||||
if (lineBot >= containerTop && lineBot <= containerBot) {
|
||||
isVis = true
|
||||
isVis = true;
|
||||
}
|
||||
// console.log("line", lineElem.dataset.linenum, "top=" + lineTop, "bot=" + lineTop, isVis);
|
||||
let lineNumInt = parseInt(lineElem.dataset.linenum);
|
||||
@@ -146,7 +158,7 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
for (let [k, v] of newMap) {
|
||||
let oldVal = this.visibleMap.get(k);
|
||||
if (oldVal == null) {
|
||||
oldVal = mobx.observable.box(v, {name: "lines-vis-map"});
|
||||
oldVal = mobx.observable.box(v, { name: "lines-vis-map" });
|
||||
this.visibleMap.set(k, oldVal);
|
||||
}
|
||||
if (oldVal.get() != v) {
|
||||
@@ -161,11 +173,11 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
})();
|
||||
}
|
||||
|
||||
printVisMap() : void {
|
||||
printVisMap(): void {
|
||||
let visMap = this.visibleMap;
|
||||
let lines = this.props.lines;
|
||||
let visLines : string[] = [];
|
||||
for (let i=0; i<lines.length; i++) {
|
||||
let visLines: string[] = [];
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let linenum = String(lines[i].linenum);
|
||||
if (visMap.get(linenum).get()) {
|
||||
visLines.push(linenum);
|
||||
@@ -174,18 +186,18 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
console.log("vislines", visLines);
|
||||
}
|
||||
|
||||
restoreAnchorOffset(reason : string) : void {
|
||||
let {lines} = this.props;
|
||||
restoreAnchorOffset(reason: string): void {
|
||||
let { lines } = this.props;
|
||||
let linesElem = this.linesRef.current;
|
||||
if (linesElem == null) {
|
||||
return;
|
||||
}
|
||||
let anchor = this.getAnchor();
|
||||
let anchorElem = linesElem.querySelector(sprintf(".line[data-linenum=\"%d\"]", anchor.anchorLine));
|
||||
let anchorElem = linesElem.querySelector(sprintf('.line[data-linenum="%d"]', anchor.anchorLine));
|
||||
if (anchorElem == null) {
|
||||
return;
|
||||
}
|
||||
let isLastLine = (anchor.anchorIndex == lines.length-1);
|
||||
let isLastLine = anchor.anchorIndex == lines.length - 1;
|
||||
let scrollTop = linesElem.scrollTop;
|
||||
let height = linesElem.clientHeight;
|
||||
let containerBottom = scrollTop + height;
|
||||
@@ -203,17 +215,16 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() : void {
|
||||
let {screen, lines} = this.props;
|
||||
componentDidMount(): void {
|
||||
let { screen, lines } = this.props;
|
||||
let linesElem = this.linesRef.current;
|
||||
let anchor = this.getAnchor();
|
||||
if (anchor.anchorIndex == lines.length-1) {
|
||||
if (anchor.anchorIndex == lines.length - 1) {
|
||||
if (linesElem != null) {
|
||||
linesElem.scrollTop = linesElem.scrollHeight;
|
||||
}
|
||||
this.computeAnchorLine();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.restoreAnchorOffset("re-mount");
|
||||
}
|
||||
this.lastSelectedLine = screen.getSelectedLine();
|
||||
@@ -225,21 +236,21 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
this.rszObs.observe(linesElem);
|
||||
}
|
||||
mobx.action(() => {
|
||||
this.staticRender.set(false)
|
||||
this.staticRender.set(false);
|
||||
this.computeVisibleMap();
|
||||
})();
|
||||
}
|
||||
|
||||
getLineElem(lineNum : number) : HTMLElement {
|
||||
getLineElem(lineNum: number): HTMLElement {
|
||||
let linesElem = this.linesRef.current;
|
||||
if (linesElem == null) {
|
||||
return null;
|
||||
}
|
||||
let elem = linesElem.querySelector(sprintf(".line[data-linenum=\"%d\"]", lineNum));
|
||||
let elem = linesElem.querySelector(sprintf('.line[data-linenum="%d"]', lineNum));
|
||||
return elem;
|
||||
}
|
||||
|
||||
getLineViewInfo(lineNum : number) : {height: number, topOffset: number, botOffset: number, anchorOffset: number} {
|
||||
getLineViewInfo(lineNum: number): { height: number; topOffset: number; botOffset: number; anchorOffset: number } {
|
||||
let linesElem = this.linesRef.current;
|
||||
if (linesElem == null) {
|
||||
return null;
|
||||
@@ -260,22 +271,20 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
let lineBot = lineElem.offsetTop + lineElem.offsetHeight;
|
||||
if (lineTop < containerTop) {
|
||||
rtn.topOffset = lineTop - containerTop;
|
||||
}
|
||||
else if (lineTop > containerBot) {
|
||||
} else if (lineTop > containerBot) {
|
||||
rtn.topOffset = lineTop - containerBot;
|
||||
}
|
||||
if (lineBot < containerTop) {
|
||||
rtn.botOffset = lineBot - containerTop;
|
||||
}
|
||||
else if (lineBot > containerBot) {
|
||||
} else if (lineBot > containerBot) {
|
||||
rtn.botOffset = lineBot - containerBot;
|
||||
}
|
||||
rtn.anchorOffset = containerBot - lineBot;
|
||||
return rtn;
|
||||
}
|
||||
|
||||
updateSelectedLine() : void {
|
||||
let {screen, lines} = this.props;
|
||||
updateSelectedLine(): void {
|
||||
let { screen, lines } = this.props;
|
||||
let linesElem = this.linesRef.current;
|
||||
if (linesElem == null) {
|
||||
return null;
|
||||
@@ -288,45 +297,41 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
this.setLineVisible(newLine, true);
|
||||
// console.log("update selected line", this.lastSelectedLine, "=>", newLine, sprintf("anchor=%d:%d", screen.anchorLine, screen.anchorOffset));
|
||||
let viewInfo = this.getLineViewInfo(newLine);
|
||||
let isFirst = (lidx.index == 0);
|
||||
let isLast = (lidx.index == lines.length-1);
|
||||
let offsetDelta = (isLast ? 10 : (isFirst ? -28 : 0));
|
||||
let isFirst = lidx.index == 0;
|
||||
let isLast = lidx.index == lines.length - 1;
|
||||
let offsetDelta = isLast ? 10 : isFirst ? -28 : 0;
|
||||
if (viewInfo == null) {
|
||||
screen.setAnchorFields(newLine, 0+offsetDelta, "updateSelectedLine");
|
||||
}
|
||||
else if (viewInfo.botOffset > 0) {
|
||||
screen.setAnchorFields(newLine, 0 + offsetDelta, "updateSelectedLine");
|
||||
} else if (viewInfo.botOffset > 0) {
|
||||
linesElem.scrollTop = linesElem.scrollTop + viewInfo.botOffset + offsetDelta;
|
||||
this.ignoreNextScroll = true;
|
||||
screen.setAnchorFields(newLine, offsetDelta, "updateSelectedLine");
|
||||
}
|
||||
else if (viewInfo.topOffset < 0) {
|
||||
} else if (viewInfo.topOffset < 0) {
|
||||
linesElem.scrollTop = linesElem.scrollTop + viewInfo.topOffset + offsetDelta;
|
||||
this.ignoreNextScroll = true;
|
||||
let newOffset = linesElem.clientHeight - viewInfo.height;
|
||||
screen.setAnchorFields(newLine, newOffset, "updateSelectedLine");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
screen.setAnchorFields(newLine, viewInfo.anchorOffset, "updateSelectedLine");
|
||||
}
|
||||
// console.log("new anchor", screen.getAnchorStr());
|
||||
}
|
||||
|
||||
setLineVisible(lineNum : number, vis : boolean) : void {
|
||||
setLineVisible(lineNum: number, vis: boolean): void {
|
||||
mobx.action(() => {
|
||||
let key = String(lineNum);
|
||||
let visObj = this.visibleMap.get(key);
|
||||
if (visObj == null) {
|
||||
visObj = mobx.observable.box(true, {name: "lines-vis-map"});
|
||||
visObj = mobx.observable.box(true, { name: "lines-vis-map" });
|
||||
this.visibleMap.set(key, visObj);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
visObj.set(true);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) : void {
|
||||
let {screen, lines} = this.props;
|
||||
componentDidUpdate(prevProps, prevState, snapshot): void {
|
||||
let { screen, lines } = this.props;
|
||||
if (screen.getSelectedLine() != this.lastSelectedLine) {
|
||||
this.updateSelectedLine();
|
||||
this.lastSelectedLine = screen.getSelectedLine();
|
||||
@@ -335,13 +340,13 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() : void {
|
||||
componentWillUnmount(): void {
|
||||
if (this.rszObs != null) {
|
||||
this.rszObs.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
handleResize(entries : any) {
|
||||
handleResize(entries: any) {
|
||||
let linesElem = this.linesRef.current;
|
||||
if (linesElem == null) {
|
||||
return;
|
||||
@@ -359,7 +364,7 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
onHeightChange(lineNum : number, newHeight : number, oldHeight : number) : void {
|
||||
onHeightChange(lineNum: number, newHeight: number, oldHeight: number): void {
|
||||
if (oldHeight == null) {
|
||||
return;
|
||||
}
|
||||
@@ -368,81 +373,87 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
this.computeVisibleMap_debounced();
|
||||
}
|
||||
|
||||
hasTopBorder(lines : T.LineInterface[], idx : number) : boolean {
|
||||
hasTopBorder(lines: T.LineInterface[], idx: number): boolean {
|
||||
if (idx == 0) {
|
||||
return false;
|
||||
}
|
||||
let curLineNumStr = String(lines[idx].linenum);
|
||||
let prevLineNumStr = String(lines[idx-1].linenum);
|
||||
let prevLineNumStr = String(lines[idx - 1].linenum);
|
||||
return !this.collapsedMap.get(curLineNumStr).get() || !this.collapsedMap.get(prevLineNumStr).get();
|
||||
}
|
||||
|
||||
getDateSepStr(lines : T.LineInterface[], idx : number, prevStr : string, todayStr : string, yesterdayStr : string) : string {
|
||||
getDateSepStr(
|
||||
lines: T.LineInterface[],
|
||||
idx: number,
|
||||
prevStr: string,
|
||||
todayStr: string,
|
||||
yesterdayStr: string
|
||||
): string {
|
||||
let curLineDate = new Date(lines[idx].ts);
|
||||
let curLineFormat = dayjs(curLineDate).format("ddd YYYY-MM-DD");
|
||||
if (idx == 0) {
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
let prevLineDate = new Date(lines[idx].ts);
|
||||
let prevLineFormat = dayjs(prevLineDate).format("YYYY-MM-DD");
|
||||
return null;
|
||||
}
|
||||
|
||||
findClosestLineIndex(lineNum : number) : {line : T.LineInterface, index : number} {
|
||||
let {lines} = this.props;
|
||||
findClosestLineIndex(lineNum: number): { line: T.LineInterface; index: number } {
|
||||
let { lines } = this.props;
|
||||
if (lines.length == 0) {
|
||||
throw new Error("invalid lines, cannot have 0 length in LinesView");
|
||||
}
|
||||
if (lineNum == null || lineNum == 0) {
|
||||
return {line: lines[lines.length-1], index: lines.length-1};
|
||||
return { line: lines[lines.length - 1], index: lines.length - 1 };
|
||||
}
|
||||
// todo: bsearch
|
||||
// lines is sorted by linenum
|
||||
for (let idx=0; idx<lines.length; idx++) {
|
||||
for (let idx = 0; idx < lines.length; idx++) {
|
||||
let line = lines[idx];
|
||||
if (line.linenum >= lineNum) {
|
||||
return {line: line, index: idx};
|
||||
return { line: line, index: idx };
|
||||
}
|
||||
}
|
||||
return {line: lines[lines.length-1], index: lines.length-1};
|
||||
return { line: lines[lines.length - 1], index: lines.length - 1 };
|
||||
}
|
||||
|
||||
getAnchor() : {anchorLine : number, anchorOffset : number, anchorIndex : number} {
|
||||
let {screen, lines} = this.props;
|
||||
getAnchor(): { anchorLine: number; anchorOffset: number; anchorIndex: number } {
|
||||
let { screen, lines } = this.props;
|
||||
let anchor = screen.getAnchor();
|
||||
if (anchor.anchorLine == null || anchor.anchorLine == 0) {
|
||||
return {anchorLine: lines[lines.length-1].linenum, anchorOffset: 0, anchorIndex: lines.length-1};
|
||||
return { anchorLine: lines[lines.length - 1].linenum, anchorOffset: 0, anchorIndex: lines.length - 1 };
|
||||
}
|
||||
let lidx = this.findClosestLineIndex(anchor.anchorLine);
|
||||
if (lidx.line.linenum == anchor.anchorLine) {
|
||||
return {anchorLine: anchor.anchorLine, anchorOffset: anchor.anchorOffset, anchorIndex: lidx.index};
|
||||
return { anchorLine: anchor.anchorLine, anchorOffset: anchor.anchorOffset, anchorIndex: lidx.index };
|
||||
}
|
||||
return {anchorLine: lidx.line.linenum, anchorOffset: 0, anchorIndex: lidx.index};
|
||||
return { anchorLine: lidx.line.linenum, anchorOffset: 0, anchorIndex: lidx.index };
|
||||
}
|
||||
render() {
|
||||
let {screen, width, lines, renderMode} = this.props;
|
||||
let selectedLine = screen.getSelectedLine(); // for re-rendering
|
||||
let line : T.LineInterface = null;
|
||||
for (let i=0; i<lines.length; i++) {
|
||||
let { screen, width, lines, renderMode } = this.props;
|
||||
let selectedLine = screen.getSelectedLine(); // for re-rendering
|
||||
let line: T.LineInterface = null;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let key = String(lines[i].linenum);
|
||||
let visObs = this.visibleMap.get(key);
|
||||
if (visObs == null) {
|
||||
this.visibleMap.set(key, mobx.observable.box(false, {name: "lines-vis-map"}));
|
||||
this.visibleMap.set(key, mobx.observable.box(false, { name: "lines-vis-map" }));
|
||||
}
|
||||
let collObs = this.collapsedMap.get(key);
|
||||
if (collObs == null) {
|
||||
this.collapsedMap.set(key, mobx.observable.box(false, {name: "lines-collapsed-map"}));
|
||||
this.collapsedMap.set(key, mobx.observable.box(false, { name: "lines-collapsed-map" }));
|
||||
}
|
||||
}
|
||||
let lineElements : any = [];
|
||||
let lineElements: any = [];
|
||||
let todayStr = util.getTodayStr();
|
||||
let yesterdayStr = util.getYesterdayStr();
|
||||
let prevDateStr : string = null;
|
||||
let prevDateStr: string = null;
|
||||
let anchor = this.getAnchor();
|
||||
let startIdx = util.boundInt(anchor.anchorIndex-50, 0, lines.length-1);
|
||||
let endIdx = util.boundInt(anchor.anchorIndex+50, 0, lines.length-1);
|
||||
let startIdx = util.boundInt(anchor.anchorIndex - 50, 0, lines.length - 1);
|
||||
let endIdx = util.boundInt(anchor.anchorIndex + 50, 0, lines.length - 1);
|
||||
// console.log("render", anchor, "[" + startIdx + "," + endIdx + "]");
|
||||
for (let idx=startIdx; idx <= endIdx; idx++) {
|
||||
for (let idx = startIdx; idx <= endIdx; idx++) {
|
||||
let line = lines[idx];
|
||||
let lineNumStr = String(line.linenum);
|
||||
let dateSepStr = null;
|
||||
@@ -452,10 +463,14 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
}
|
||||
prevDateStr = curDateStr;
|
||||
if (dateSepStr != null) {
|
||||
let sepElem = (<div key={"sep-" + line.lineid} className="line-sep">{dateSepStr}</div>);
|
||||
let sepElem = (
|
||||
<div key={"sep-" + line.lineid} className="line-sep">
|
||||
{dateSepStr}
|
||||
</div>
|
||||
);
|
||||
lineElements.push(sepElem);
|
||||
}
|
||||
let topBorder = (dateSepStr == null) && this.hasTopBorder(lines, idx);
|
||||
let topBorder = dateSepStr == null && this.hasTopBorder(lines, idx);
|
||||
let lineProps = {
|
||||
key: line.lineid,
|
||||
line: line,
|
||||
@@ -471,10 +486,7 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
// let lineElem = <Line key={line.lineid} line={line} screen={screen} width={width} visible={this.visibleMap.get(lineNumStr)} staticRender={this.staticRender.get()} onHeightChange={this.onHeightChange} overrideCollapsed={this.collapsedMap.get(lineNumStr)} topBorder={topBorder} renderMode={renderMode}/>;
|
||||
lineElements.push(lineElem);
|
||||
}
|
||||
let linesClass = cn(
|
||||
"lines",
|
||||
(renderMode == "normal" ? "lines-expanded" : "lines-collapsed"),
|
||||
);
|
||||
let linesClass = cn("lines", renderMode == "normal" ? "lines-expanded" : "lines-collapsed");
|
||||
return (
|
||||
<div key="lines" className={linesClass} onScroll={this.scrollHandler} ref={this.linesRef}>
|
||||
<div className="lines-spacer"></div>
|
||||
@@ -484,4 +496,4 @@ class LinesView extends React.Component<{screen : ScreenInterface, width : numbe
|
||||
}
|
||||
}
|
||||
|
||||
export {LinesView};
|
||||
export { LinesView };
|
||||
|
||||
+31
-23
@@ -1,18 +1,18 @@
|
||||
import dayjs from "dayjs";
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||
import {isBlank, getDateStr} from "./util";
|
||||
import {LineType, WebLine, RendererContext} from "./types";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import { isBlank, getDateStr } from "./util";
|
||||
import { LineType, WebLine, RendererContext } from "./types";
|
||||
|
||||
dayjs.extend(localizedFormat)
|
||||
dayjs.extend(localizedFormat);
|
||||
|
||||
function getRendererType(line : LineType|WebLine) : "terminal" | "plugin" {
|
||||
function getRendererType(line: LineType | WebLine): "terminal" | "plugin" {
|
||||
if (isBlank(line.renderer) || line.renderer == "terminal") {
|
||||
return "terminal";
|
||||
}
|
||||
return "plugin";
|
||||
}
|
||||
|
||||
function getLineDateStr(todayDate : string, yesterdayDate : string, ts : number) : string {
|
||||
function getLineDateStr(todayDate: string, yesterdayDate: string, ts: number): string {
|
||||
let lineDate = new Date(ts);
|
||||
let dateStr = getDateStr(lineDate);
|
||||
if (dateStr == todayDate) {
|
||||
@@ -24,36 +24,34 @@ function getLineDateStr(todayDate : string, yesterdayDate : string, ts : number)
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
function getLineDateTimeStr(ts : number) : string {
|
||||
function getLineDateTimeStr(ts: number): string {
|
||||
let lineDate = new Date(ts);
|
||||
let nowDate = new Date();
|
||||
|
||||
|
||||
if (nowDate.getFullYear() != lineDate.getFullYear()) {
|
||||
return dayjs(lineDate).format("ddd L LTS");
|
||||
}
|
||||
else if (nowDate.getMonth() != lineDate.getMonth() || nowDate.getDate() != lineDate.getDate()) {
|
||||
let yesterdayDate = (new Date());
|
||||
yesterdayDate.setDate(yesterdayDate.getDate()-1);
|
||||
} else if (nowDate.getMonth() != lineDate.getMonth() || nowDate.getDate() != lineDate.getDate()) {
|
||||
let yesterdayDate = new Date();
|
||||
yesterdayDate.setDate(yesterdayDate.getDate() - 1);
|
||||
if (yesterdayDate.getMonth() == lineDate.getMonth() && yesterdayDate.getDate() == lineDate.getDate()) {
|
||||
return "Yesterday " + dayjs(lineDate).format("LTS");;
|
||||
return "Yesterday " + dayjs(lineDate).format("LTS");
|
||||
}
|
||||
return dayjs(lineDate).format("ddd L LTS");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return dayjs(lineDate).format("LTS");
|
||||
}
|
||||
}
|
||||
|
||||
function isMultiLineCmdText(cmdText : string) : boolean {
|
||||
function isMultiLineCmdText(cmdText: string): boolean {
|
||||
if (cmdText == null) {
|
||||
return false;
|
||||
}
|
||||
cmdText = cmdText.trim();
|
||||
let nlIdx = cmdText.indexOf("\n");
|
||||
return (nlIdx != -1);
|
||||
return nlIdx != -1;
|
||||
}
|
||||
|
||||
function getFullCmdText(cmdText : string) {
|
||||
function getFullCmdText(cmdText: string) {
|
||||
if (cmdText == null) {
|
||||
return "(none)";
|
||||
}
|
||||
@@ -61,7 +59,7 @@ function getFullCmdText(cmdText : string) {
|
||||
return cmdText;
|
||||
}
|
||||
|
||||
function getSingleLineCmdText(cmdText : string) {
|
||||
function getSingleLineCmdText(cmdText: string) {
|
||||
if (cmdText == null) {
|
||||
return "(none)";
|
||||
}
|
||||
@@ -73,7 +71,7 @@ function getSingleLineCmdText(cmdText : string) {
|
||||
return cmdText;
|
||||
}
|
||||
|
||||
function getRendererContext(line : LineType) : RendererContext {
|
||||
function getRendererContext(line: LineType): RendererContext {
|
||||
return {
|
||||
screenId: line.screenid,
|
||||
lineId: line.lineid,
|
||||
@@ -81,7 +79,7 @@ function getRendererContext(line : LineType) : RendererContext {
|
||||
};
|
||||
}
|
||||
|
||||
function getWebRendererContext(line : WebLine) : RendererContext {
|
||||
function getWebRendererContext(line: WebLine): RendererContext {
|
||||
return {
|
||||
screenId: line.screenid,
|
||||
lineId: line.lineid,
|
||||
@@ -89,8 +87,18 @@ function getWebRendererContext(line : WebLine) : RendererContext {
|
||||
};
|
||||
}
|
||||
|
||||
function cmdStatusIsRunning(status : string) : boolean {
|
||||
function cmdStatusIsRunning(status: string): boolean {
|
||||
return status == "running" || status == "detached";
|
||||
}
|
||||
|
||||
export {getRendererType, getLineDateStr, getLineDateTimeStr, isMultiLineCmdText, getFullCmdText, getSingleLineCmdText, getRendererContext, getWebRendererContext, cmdStatusIsRunning};
|
||||
export {
|
||||
getRendererType,
|
||||
getLineDateStr,
|
||||
getLineDateTimeStr,
|
||||
isMultiLineCmdText,
|
||||
getFullCmdText,
|
||||
getSingleLineCmdText,
|
||||
getRendererContext,
|
||||
getWebRendererContext,
|
||||
cmdStatusIsRunning,
|
||||
};
|
||||
|
||||
+695
-397
File diff suppressed because it is too large
Load Diff
+13
-13
@@ -4,7 +4,7 @@
|
||||
z-index: 105;
|
||||
|
||||
.modal-background {
|
||||
background-color: rgba(10,10,10,.6);
|
||||
background-color: rgba(10, 10, 10, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
background-color: black;
|
||||
height: 250px;
|
||||
overflow: auto;
|
||||
|
||||
|
||||
.ws-logline {
|
||||
.mono-font(12px);
|
||||
color: @term-white;
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
.modal.alert-modal {
|
||||
z-index: 205;
|
||||
|
||||
|
||||
footer {
|
||||
justify-content: center;
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
.modal-content {
|
||||
min-width: 850px;
|
||||
}
|
||||
|
||||
|
||||
.inner-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -209,7 +209,7 @@
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:first-child {
|
||||
border-top: 0;
|
||||
}
|
||||
@@ -291,9 +291,8 @@
|
||||
i.fa-check {
|
||||
color: @term-green;
|
||||
}
|
||||
|
||||
|
||||
&.is-ok {
|
||||
|
||||
}
|
||||
|
||||
.message-row {
|
||||
@@ -316,7 +315,7 @@
|
||||
.update-auth-button {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
.update-auth-button {
|
||||
visibility: visible;
|
||||
@@ -328,7 +327,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.auth-editing, &.create-remote {
|
||||
&.auth-editing,
|
||||
&.create-remote {
|
||||
.settings-field.align-top {
|
||||
align-items: flex-start;
|
||||
|
||||
@@ -366,11 +366,11 @@
|
||||
.settings-input input {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
|
||||
.dropdown .dropdown-trigger button {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
.dropdown .dropdown-item {
|
||||
font-size: 12px;
|
||||
padding: 5px 5px 5px 12px;
|
||||
@@ -525,7 +525,7 @@
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
input {
|
||||
padding: 4px;
|
||||
border-radius: 3px;
|
||||
@@ -534,7 +534,7 @@
|
||||
.control {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
.tab-color-icon.color-green {
|
||||
color: desaturate(@tab-green, 30%);
|
||||
}
|
||||
|
||||
+23
-14
@@ -1,25 +1,25 @@
|
||||
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 { sprintf } from "sprintf-js";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import { If, For, When, Otherwise, Choose } from "tsx-control-statements/components";
|
||||
import cn from "classnames";
|
||||
import {GlobalModel, GlobalCommandRunner} from "./model";
|
||||
import { GlobalModel, GlobalCommandRunner } from "./model";
|
||||
import * as util from "./util";
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
|
||||
class TosModal extends React.Component<{}, {}> {
|
||||
@boundMethod
|
||||
acceptTos() : void {
|
||||
acceptTos(): void {
|
||||
GlobalCommandRunner.clientAcceptTos();
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={cn("modal tos-modal prompt-modal is-active")}>
|
||||
<div className="modal-background"/>
|
||||
<div className="modal-background" />
|
||||
<div className="modal-content">
|
||||
<header>
|
||||
<div className="modal-title">Welcome to [prompt]</div>
|
||||
@@ -29,20 +29,29 @@ class TosModal extends React.Component<{}, {}> {
|
||||
<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 server</a>.
|
||||
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 server
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
Prompt is free to use, no email or registration required (unless you're using the cloud features).
|
||||
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.getprompt.dev/tos.html")}>Full Terms of Service</a>
|
||||
<a target="_blank" href={util.makeExternLink("https://www.getprompt.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>
|
||||
<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>
|
||||
@@ -50,4 +59,4 @@ class TosModal extends React.Component<{}, {}> {
|
||||
}
|
||||
}
|
||||
|
||||
export {TosModal};
|
||||
export { TosModal };
|
||||
|
||||
+3635
-4043
File diff suppressed because it is too large
Load Diff
+70
-74
@@ -8,103 +8,99 @@ import { isBlank } from "./util";
|
||||
import { sprintf } from "sprintf-js";
|
||||
|
||||
const ImagePlugin: RendererPluginType = {
|
||||
name: "image",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["image/*"],
|
||||
simpleComponent: SimpleImageRenderer,
|
||||
name: "image",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["image/*"],
|
||||
simpleComponent: SimpleImageRenderer,
|
||||
};
|
||||
|
||||
const MarkdownPlugin: RendererPluginType = {
|
||||
name: "markdown",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["text/markdown"],
|
||||
simpleComponent: SimpleMarkdownRenderer,
|
||||
name: "markdown",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["text/markdown"],
|
||||
simpleComponent: SimpleMarkdownRenderer,
|
||||
};
|
||||
|
||||
const JsonPlugin: RendererPluginType = {
|
||||
name: "json",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["application/json"],
|
||||
simpleComponent: SimpleJsonRenderer,
|
||||
name: "json",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["application/json"],
|
||||
simpleComponent: SimpleJsonRenderer,
|
||||
};
|
||||
|
||||
const CodePlugin: RendererPluginType = {
|
||||
name: "code",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["text/plain"],
|
||||
simpleComponent: SourceCodeRenderer,
|
||||
name: "code",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["text/plain"],
|
||||
simpleComponent: SourceCodeRenderer,
|
||||
};
|
||||
|
||||
const OpenAIPlugin: RendererPluginType = {
|
||||
name: "openai",
|
||||
rendererType: "full",
|
||||
heightType: "pixels",
|
||||
dataType: "model",
|
||||
collapseType: "remove",
|
||||
hidePrompt: true,
|
||||
globalCss: null,
|
||||
mimeTypes: ["application/json"],
|
||||
fullComponent: OpenAIRenderer,
|
||||
modelCtor: () => new OpenAIRendererModel(),
|
||||
name: "openai",
|
||||
rendererType: "full",
|
||||
heightType: "pixels",
|
||||
dataType: "model",
|
||||
collapseType: "remove",
|
||||
hidePrompt: true,
|
||||
globalCss: null,
|
||||
mimeTypes: ["application/json"],
|
||||
fullComponent: OpenAIRenderer,
|
||||
modelCtor: () => new OpenAIRendererModel(),
|
||||
};
|
||||
|
||||
class PluginModelClass {
|
||||
rendererPlugins: RendererPluginType[] = [];
|
||||
rendererPlugins: RendererPluginType[] = [];
|
||||
|
||||
registerRendererPlugin(plugin: RendererPluginType) {
|
||||
if (isBlank(plugin.name)) {
|
||||
throw new Error("invalid plugin, no name");
|
||||
registerRendererPlugin(plugin: RendererPluginType) {
|
||||
if (isBlank(plugin.name)) {
|
||||
throw new Error("invalid plugin, no name");
|
||||
}
|
||||
if (plugin.name == "terminal" || plugin.name == "none") {
|
||||
throw new Error(sprintf("invalid plugin, name '%s' is reserved", plugin.name));
|
||||
}
|
||||
let existingPlugin = this.getRendererPluginByName(plugin.name);
|
||||
if (existingPlugin != null) {
|
||||
throw new Error(sprintf("plugin with name %s already registered", plugin.name));
|
||||
}
|
||||
this.rendererPlugins.push(plugin);
|
||||
}
|
||||
if (plugin.name == "terminal" || plugin.name == "none") {
|
||||
throw new Error(
|
||||
sprintf("invalid plugin, name '%s' is reserved", plugin.name)
|
||||
);
|
||||
}
|
||||
let existingPlugin = this.getRendererPluginByName(plugin.name);
|
||||
if (existingPlugin != null) {
|
||||
throw new Error(
|
||||
sprintf("plugin with name %s already registered", plugin.name)
|
||||
);
|
||||
}
|
||||
this.rendererPlugins.push(plugin);
|
||||
}
|
||||
|
||||
getRendererPluginByName(name: string): RendererPluginType {
|
||||
for (let i = 0; i < this.rendererPlugins.length; i++) {
|
||||
let plugin = this.rendererPlugins[i];
|
||||
if (plugin.name == name) {
|
||||
return plugin;
|
||||
}
|
||||
getRendererPluginByName(name: string): RendererPluginType {
|
||||
for (let i = 0; i < this.rendererPlugins.length; i++) {
|
||||
let plugin = this.rendererPlugins[i];
|
||||
if (plugin.name == name) {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let PluginModel: PluginModelClass = null;
|
||||
if ((window as any).PluginModel == null) {
|
||||
PluginModel = new PluginModelClass();
|
||||
PluginModel.registerRendererPlugin(ImagePlugin);
|
||||
PluginModel.registerRendererPlugin(MarkdownPlugin);
|
||||
PluginModel.registerRendererPlugin(JsonPlugin);
|
||||
PluginModel.registerRendererPlugin(CodePlugin);
|
||||
PluginModel.registerRendererPlugin(OpenAIPlugin);
|
||||
(window as any).PluginModel = PluginModel;
|
||||
PluginModel = new PluginModelClass();
|
||||
PluginModel.registerRendererPlugin(ImagePlugin);
|
||||
PluginModel.registerRendererPlugin(MarkdownPlugin);
|
||||
PluginModel.registerRendererPlugin(JsonPlugin);
|
||||
PluginModel.registerRendererPlugin(CodePlugin);
|
||||
PluginModel.registerRendererPlugin(OpenAIPlugin);
|
||||
(window as any).PluginModel = PluginModel;
|
||||
}
|
||||
|
||||
export { PluginModel };
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
let {contextBridge, ipcRenderer} = require("electron");
|
||||
let { contextBridge, ipcRenderer } = require("electron");
|
||||
|
||||
contextBridge.exposeInMainWorld("api", {
|
||||
getId: () => ipcRenderer.sendSync("get-id"),
|
||||
|
||||
+186
-186
@@ -47,259 +47,259 @@
|
||||
// global settings / overrides
|
||||
|
||||
:root {
|
||||
--fa-style-family: "Font Awesome 6 Sharp";
|
||||
--fa-style-family: "Font Awesome 6 Sharp";
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#app,
|
||||
#main {
|
||||
background-color: #000;
|
||||
height: 100vh;
|
||||
background-color: #000;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.content {
|
||||
a:hover {
|
||||
color: #485fc7;
|
||||
}
|
||||
a:hover {
|
||||
color: #485fc7;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
background-color: #777;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background-color: #777;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: white;
|
||||
background: white;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// main layout
|
||||
#main {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.main-content {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: black;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
|
||||
.session-view,
|
||||
.history-view,
|
||||
.bookmarks-view {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 300px;
|
||||
position: relative;
|
||||
|
||||
&.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.screen-view {
|
||||
flex-grow: 1;
|
||||
border-right: 1px solid #ccc;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.window-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
.rendermode-tag {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background-color: rgba(78, 154, 6, 0.65);
|
||||
color: black;
|
||||
padding: 2px 8px 2px 4px;
|
||||
border-bottom-left-radius: 5px;
|
||||
z-index: 10;
|
||||
font-size: 12px;
|
||||
|
||||
&.is-active {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.render-mode {
|
||||
padding-top: 2px;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
color: #ccc;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.share-tag {
|
||||
color: #ccc;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 40%;
|
||||
background-color: darken(rgb(0, 177, 10), 20%);
|
||||
padding: 2px 8px 2px 4px;
|
||||
z-index: 11;
|
||||
font-size: 12px;
|
||||
/* border-radius: 0 0 5px 5px; */
|
||||
opacity: 0.8;
|
||||
.main-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.share-tag-link {
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.share-tag-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
opacity: 1;
|
||||
padding: 20px;
|
||||
width: 250px;
|
||||
border: 1px solid #ccc;
|
||||
border-top: 0;
|
||||
|
||||
.share-tag-link {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.window-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
flex-direction: row;
|
||||
background-color: black;
|
||||
height: 100%;
|
||||
color: #ccc;
|
||||
.mono-font();
|
||||
|
||||
code {
|
||||
background-color: black;
|
||||
color: #4e9a06;
|
||||
.session-view,
|
||||
.history-view,
|
||||
.bookmarks-view {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 300px;
|
||||
position: relative;
|
||||
|
||||
&.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.should-fade {
|
||||
opacity: 1;
|
||||
animation: fade-in 2.5s;
|
||||
.screen-view {
|
||||
flex-grow: 1;
|
||||
border-right: 1px solid #ccc;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.window-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
.rendermode-tag {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background-color: rgba(78, 154, 6, 0.65);
|
||||
color: black;
|
||||
padding: 2px 8px 2px 4px;
|
||||
border-bottom-left-radius: 5px;
|
||||
z-index: 10;
|
||||
font-size: 12px;
|
||||
|
||||
&.is-active {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.render-mode {
|
||||
padding-top: 2px;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
color: #ccc;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.share-tag {
|
||||
color: #ccc;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 40%;
|
||||
background-color: darken(rgb(0, 177, 10), 20%);
|
||||
padding: 2px 8px 2px 4px;
|
||||
z-index: 11;
|
||||
font-size: 12px;
|
||||
/* border-radius: 0 0 5px 5px; */
|
||||
opacity: 0.8;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.share-tag-link {
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.share-tag-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
opacity: 1;
|
||||
padding: 20px;
|
||||
width: 250px;
|
||||
border: 1px solid #ccc;
|
||||
border-top: 0;
|
||||
|
||||
.share-tag-link {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.window-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
color: #ccc;
|
||||
.mono-font();
|
||||
|
||||
code {
|
||||
background-color: black;
|
||||
color: #4e9a06;
|
||||
}
|
||||
|
||||
&.should-fade {
|
||||
opacity: 1;
|
||||
animation: fade-in 2.5s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remote-field .remote-status {
|
||||
top: 4px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.image-renderer {
|
||||
padding: 10px;
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
padding: 10px;
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.renderer-container {
|
||||
.error-container {
|
||||
color: @term-red;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
}
|
||||
.error-container {
|
||||
color: @term-red;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.scroller {
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.renderer-container.code-renderer {
|
||||
margin-top: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.renderer-container.json-renderer {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown-renderer .markdown {
|
||||
padding: 5px;
|
||||
line-height: 1.5;
|
||||
width: fit-content;
|
||||
padding: 5px;
|
||||
line-height: 1.5;
|
||||
width: fit-content;
|
||||
|
||||
blockquote {
|
||||
background-color: #222;
|
||||
}
|
||||
blockquote {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
code {
|
||||
background-color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #222;
|
||||
margin: 2px 10px 6px 10px;
|
||||
padding: 4px 4px 4px 6px;
|
||||
}
|
||||
pre {
|
||||
background-color: #222;
|
||||
margin: 2px 10px 6px 10px;
|
||||
padding: 4px 4px 4px 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.openai-renderer {
|
||||
.openai-message {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
.openai-message {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
|
||||
.openai-role {
|
||||
color: @term-bright-green;
|
||||
font-weight: bold;
|
||||
width: 100px;
|
||||
}
|
||||
.openai-role {
|
||||
color: @term-bright-green;
|
||||
font-weight: bold;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.openai-role.openai-role-assistant {
|
||||
color: @term-bright-white;
|
||||
}
|
||||
.openai-role.openai-role-assistant {
|
||||
color: @term-bright-white;
|
||||
}
|
||||
|
||||
.openai-content-user {
|
||||
white-space: pre;
|
||||
color: white;
|
||||
}
|
||||
.openai-content-user {
|
||||
white-space: pre;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.openai-content-assistant {
|
||||
color: white;
|
||||
}
|
||||
.openai-content-assistant {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.openai-role-error {
|
||||
color: @term-bright-red;
|
||||
}
|
||||
.openai-role-error {
|
||||
color: @term-bright-red;
|
||||
}
|
||||
|
||||
.openai-content-error {
|
||||
color: @term-bright-red;
|
||||
.openai-content-error {
|
||||
color: @term-bright-red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user