MainView UI updates (history, connections, settings, bookmarks) (#339)

* slight tab update

* sidebar separator / hightlight color restored

* fix mainviews, lots of history view fixes

* more mainview changes.  update for bottom-border, fix bookmarks
This commit is contained in:
Mike Sawka 2024-02-26 15:28:59 -08:00 committed by GitHub
parent 01e4106aa7
commit b120a7952d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 252 additions and 302 deletions

View File

@ -240,21 +240,6 @@ a.a-block {
flex-direction: row;
height: 100%;
position: relative;
.history-view,
.bookmarks-view,
.plugins-view,
.connections-view {
flex-grow: 1;
display: flex;
flex-direction: column;
margin-right: 0.5em;
position: relative;
&.is-hidden {
display: none;
}
overflow: auto;
}
}
}
@ -649,27 +634,39 @@ a.a-block {
}
}
.view {
background-color: var(--session-bg-color);
.mainview {
flex-grow: 1;
display: flex;
flex-direction: column;
position: relative;
overflow: auto;
margin-bottom: 10px;
margin-right: 10px;
border-radius: 8px;
border: 1px solid rgba(241, 246, 243, 0.08);
border-radius: 0 var(--app-border-radius) var(--app-border-radius) var(--app-border-radius);
border-bottom: 1px solid var(--app-border-color);
border-right: 1px solid var(--app-border-color);
border-left: 1px solid var(--app-border-color);
background-color: black;
&.is-hidden {
display: none;
}
.header {
margin: 24px 18px;
-webkit-app-region: drag;
padding: 24px 18px;
margin: 0;
display: flex;
justify-content: space-between;
align-items: center;
.close-div {
-webkit-app-region: no-drag;
font-size: 1.5em;
}
&.bottom-border {
border-bottom: 1px solid white;
padding-bottom: 20px;
margin-bottom: 20px;
}
}
}

View File

@ -1,31 +1,4 @@
.bookmarks-view {
background-color: var(--session-bg-color);
.close-button {
position: absolute;
right: 1em;
top: 0.8em;
cursor: pointer;
width: 1.5em;
height: 1.5em;
border-radius: 50%;
svg {
width: 1.5em;
height: 1.5em;
fill: var(--app-text-color);
}
}
.header {
margin: 1.5em 1.5em 0.5em;
.bookmarks-title {
margin-bottom: 0.5em;
font-weight: bold;
font-size: 1.5em;
}
}
.icon {
width: 1em;
height: 1em;

View File

@ -10,7 +10,6 @@ import cn from "classnames";
import { GlobalModel } from "@/models";
import { CmdStrCode, Markdown } from "@/common/elements";
import { ReactComponent as XmarkIcon } from "@/assets/icons/line/xmark.svg";
import { ReactComponent as CopyIcon } from "@/assets/icons/favourites/copy.svg";
import { ReactComponent as PenIcon } from "@/assets/icons/favourites/pen.svg";
import { ReactComponent as TrashIcon } from "@/assets/icons/favourites/trash.svg";
@ -204,11 +203,11 @@ class BookmarksView extends React.Component<{}, {}> {
let idx: number = 0;
let bookmark: BookmarkType = null;
return (
<div className={cn("bookmarks-view", { "is-hidden": isHidden })}>
<div className="header">
<div className="bookmarks-title">Favorites</div>
<div className="close-button hoverEffect" title="Close (Escape)" onClick={this.closeView}>
<XmarkIcon className={"icon"} />
<div className={cn("mainview", "bookmarks-view", { "is-hidden": isHidden })}>
<div className="header bottom-border">
<div className="bookmarks-title text-primary">Favorites</div>
<div className="close-div hoverEffect" title="Close (Escape)" onClick={this.closeView}>
<i className="fa-sharp fa-solid fa-xmark"></i>
</div>
</div>
<div className="bookmarks-list">

View File

@ -1,27 +1,6 @@
@import "@/common/themes/themes.less";
.clientsettings-view {
background-color: var(--session-bg-color);
flex-grow: 1;
display: flex;
flex-direction: column;
position: relative;
overflow: auto;
margin-bottom: 10px;
margin-right: 10px;
border-radius: 8px;
border: 1px solid rgba(241, 246, 243, 0.08);
background: rgba(13, 13, 13, 0.85);
.header {
margin: 24px 18px;
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20px;
border-bottom: 1px solid white;
}
.content {
padding: 0 18px 0 30px;
}

View File

@ -148,8 +148,8 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
const curFontFamily = GlobalModel.getTermFontFamily();
return (
<div className={cn("view clientsettings-view")}>
<header className="header">
<div className={cn("mainview", "clientsettings-view")}>
<header className="header bottom-border">
<div className="clientsettings-title text-primary">Client Settings</div>
<div className="close-div hoverEffect" title="Close (Escape)" onClick={this.handleClose}>
<i className="fa-sharp fa-solid fa-xmark"></i>

View File

@ -130,8 +130,8 @@ class ConnectionsView extends React.Component<{ model: RemotesModel }, { hovered
let item: RemoteType = null;
return (
<div className={cn("view connections-view")}>
<header className="header">
<div className={cn("mainview", "connections-view")}>
<header className="header bottom-border">
<div className="connections-title text-primary">Connections</div>
<div className="close-div hoverEffect" title="Close (Escape)" onClick={this.handleClose}>
<i className="fa-sharp fa-solid fa-xmark"></i>

View File

@ -1,11 +1,16 @@
@import "@/common/themes/themes.less";
.history-view {
background-color: var(--session-bg-color);
padding-bottom: 10px;
.header {
padding: 18px 18px;
}
.icon {
width: 1.3em !important;
width: 2em !important;
height: 1.3em !important;
padding-left: 5px;
fill: var(--app-text-color);
}
@ -55,19 +60,18 @@
}
}
.header {
margin: 1.5em 1.5em 0.5em;
.history-title {
margin-bottom: 0.5em;
font-weight: bold;
font-size: 1.5em;
}
}
.history-search {
flex-grow: 1;
margin-top: 5px;
padding: 0 10px 10px 10px;
input {
border: none;
border-radius: 4px;
font-size: 1em;
padding: 0.5em 1em;
background-color: @background-session-components;
color: @base-color;
}
.main-search {
.field {
@ -169,6 +173,7 @@
margin-left: 10px;
align-items: center;
height: 32px;
flex-shrink: 0;
.is-hidden {
display: none;
@ -251,6 +256,12 @@
margin: 20px 50px 20px 20px;
}
.history-scroll-region {
flex-grow: 1;
min-height: 200px;
overflow-y: auto;
}
.history-table {
margin: 0px 10px 10px 10px;
table-layout: fixed;

View File

@ -424,126 +424,127 @@ class HistoryView extends React.Component<{}, {}> {
const width = window.innerWidth - 6 - GlobalModel.mainSidebarModel.getWidth();
return (
<div
className={cn("history-view", "view", { "is-hidden": isHidden })}
className={cn("history-view", "mainview", { "is-hidden": isHidden })}
style={{
width: `${width}px`,
}}
>
<div className="header">
<div className="history-title">History</div>
<div className="history-search">
<div className="main-search field">
<TextField
placeholder="Exact String Search"
onChange={this.changeSearchText}
onKeyDown={this.searchKeyDown}
decoration={{ startDecoration: <SearchIcon className="icon" /> }}
/>
</div>
<div className="advanced-search">
<div
className={cn("dropdown", "session-dropdown", {
"is-active": this.sessionDropdownActive.get(),
})}
>
<div onClick={this.toggleSessionDropdown}>
<span className="label">
{hvm.searchSessionId.get() == null
? "Limit Workspace"
: formatSessionName(snames, hvm.searchSessionId.get())}
</span>
<AngleDownIcon className="icon" />
</div>
<div className="dropdown-menu" role="menu">
<div className="dropdown-content has-background-black-ter">
<div
onClick={() => this.clickLimitSession(null)}
key="all"
className="dropdown-item"
>
(all workspaces)
</div>
<For each="sessionId" of={sessionIds}>
<div
onClick={() => this.clickLimitSession(sessionId)}
key={sessionId}
className="dropdown-item"
>
#{snames[sessionId]}
</div>
</For>
</div>
</div>
</div>
<div
className={cn("dropdown", "remote-dropdown", {
"is-active": this.remoteDropdownActive.get(),
})}
>
<div onClick={this.toggleRemoteDropdown}>
<span className="label">
{hvm.searchRemoteId.get() == null
? "Limit Remote"
: formatRemoteName(rnames, { remoteid: hvm.searchRemoteId.get() })}
</span>
<AngleDownIcon className="icon" />
</div>
<div className="dropdown-menu" role="menu">
<div className="dropdown-content has-background-black-ter">
<div
onClick={() => this.clickLimitRemote(null)}
key="all"
className="dropdown-item"
>
(all remotes)
</div>
<For each="remoteId" of={remoteIds}>
<div
onClick={() => this.clickLimitRemote(remoteId)}
key={remoteId}
className="dropdown-item"
>
[{rnames[remoteId]}]
</div>
</For>
</div>
</div>
</div>
<div className="fromts">
<div className="fromts-text">From:&nbsp;</div>
<div className="hoverEffect">
<input
type="date"
onChange={this.handleFromTsChange}
value={this.searchFromTsInputValue()}
/>
</div>
</div>
<div
className="filter-cmds search-checkbox hoverEffect"
title="Filter common commands like 'ls' and 'cd' from the results"
>
<div className="checkbox-container">
<input
onChange={this.toggleFilterCmds}
type="checkbox"
checked={hvm.searchFilterCmds.get()}
/>
</div>
<div onClick={this.toggleFilterCmds} className="checkbox-text">
Filter Cmds
</div>
</div>
<div onClick={this.resetAllFilters} className="button reset-button hoverEffect">
Reset All
</div>
</div>
</div>
<header key="header" className="header">
<div className="clientsettings-title text-primary">History</div>
<div className="close-div hoverEffect" title="Close (Escape)" onClick={this.clickCloseHandler}>
<XmarkIcon />
<i className="fa-sharp fa-solid fa-xmark"></i>
</div>
</header>
<div key="search" className="history-search">
<div className="main-search field">
<TextField
placeholder="Exact String Search"
onChange={this.changeSearchText}
onKeyDown={this.searchKeyDown}
decoration={{ startDecoration: <SearchIcon className="icon" /> }}
/>
</div>
<div className="advanced-search">
<div
className={cn("dropdown", "session-dropdown", {
"is-active": this.sessionDropdownActive.get(),
})}
>
<div onClick={this.toggleSessionDropdown}>
<span className="label">
{hvm.searchSessionId.get() == null
? "Limit Workspace"
: formatSessionName(snames, hvm.searchSessionId.get())}
</span>
<AngleDownIcon className="icon" />
</div>
<div className="dropdown-menu" role="menu">
<div className="dropdown-content has-background-black-ter">
<div
onClick={() => this.clickLimitSession(null)}
key="all"
className="dropdown-item"
>
(all workspaces)
</div>
<For each="sessionId" of={sessionIds}>
<div
onClick={() => this.clickLimitSession(sessionId)}
key={sessionId}
className="dropdown-item"
>
#{snames[sessionId]}
</div>
</For>
</div>
</div>
</div>
<div
className={cn("dropdown", "remote-dropdown", {
"is-active": this.remoteDropdownActive.get(),
})}
>
<div onClick={this.toggleRemoteDropdown}>
<span className="label">
{hvm.searchRemoteId.get() == null
? "Limit Remote"
: formatRemoteName(rnames, { remoteid: hvm.searchRemoteId.get() })}
</span>
<AngleDownIcon className="icon" />
</div>
<div className="dropdown-menu" role="menu">
<div className="dropdown-content has-background-black-ter">
<div
onClick={() => this.clickLimitRemote(null)}
key="all"
className="dropdown-item"
>
(all remotes)
</div>
<For each="remoteId" of={remoteIds}>
<div
onClick={() => this.clickLimitRemote(remoteId)}
key={remoteId}
className="dropdown-item"
>
[{rnames[remoteId]}]
</div>
</For>
</div>
</div>
</div>
<div className="fromts">
<div className="fromts-text">From:&nbsp;</div>
<div className="hoverEffect">
<input
type="date"
onChange={this.handleFromTsChange}
value={this.searchFromTsInputValue()}
/>
</div>
</div>
<div
className="filter-cmds search-checkbox hoverEffect"
title="Filter common commands like 'ls' and 'cd' from the results"
>
<div className="checkbox-container">
<input
onChange={this.toggleFilterCmds}
type="checkbox"
checked={hvm.searchFilterCmds.get()}
/>
</div>
<div onClick={this.toggleFilterCmds} className="checkbox-text">
Filter Cmds
</div>
</div>
<div onClick={this.resetAllFilters} className="button reset-button hoverEffect">
Reset All
</div>
</div>
</div>
<div className={cn("control-bar", "is-top", { "is-hidden": items.length == 0 })}>
<div key="control1" className={cn("control-bar", "is-top", { "is-hidden": items.length == 0 })}>
<div className="control-checkbox" onClick={this.handleControlCheckbox} title="Toggle Selection">
<HistoryCheckbox
checked={numSelected > 0 && numSelected == items.length}
@ -581,75 +582,84 @@ class HistoryView extends React.Component<{}, {}> {
<ChevronRightIcon className="icon" />
</div>
</div>
<table className="history-table" cellSpacing="0" cellPadding="0" border={0} ref={this.tableRef}>
<tbody>
<For index="idx" each="item" of={items}>
<tr
key={item.historyid}
className={cn("history-item", { "is-selected": hvm.selectedItems.get(item.historyid) })}
>
<td className="selectbox" onClick={() => this.handleSelect(item.historyid)}>
<HistoryCheckbox checked={hvm.selectedItems.get(item.historyid)} />
</td>
<td className="cmdstr">
<HistoryCmdStr
cmdstr={item.cmdstr}
onUse={() => this.handleUse(item)}
onCopy={() => this.handleCopy(item)}
isCopied={this.copiedItemId.get() == item.historyid}
fontSize="normal"
limitHeight={true}
/>
</td>
<td className="workspace text-standard">{formatSSName(snames, scrnames, item)}</td>
<td className="remote text-standard">{formatRemoteName(rnames, item.remote)}</td>
<td className="ts text-standard">{getHistoryViewTs(nowDate, item.ts)}</td>
<td className="downarrow" onClick={() => this.activateItem(item.historyid)}>
<If condition={activeItemId != item.historyid}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
>
<path
d="M12.1297 6.62492C12.3999 6.93881 12.3645 7.41237 12.0506 7.68263L8.48447 10.7531C8.20296 10.9955 7.78645 10.9952 7.50519 10.7526L3.94636 7.68213C3.63274 7.41155 3.59785 6.93796 3.86843 6.62434C4.13901 6.31072 4.6126 6.27583 4.92622 6.54641L7.99562 9.19459L11.0719 6.54591C11.3858 6.27565 11.8594 6.31102 12.1297 6.62492Z"
fill="#C3C8C2"
/>
</svg>
</If>
<If condition={activeItemId == item.historyid}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
>
<path
d="M3.87035 9.37508C3.60009 9.06119 3.63546 8.58763 3.94936 8.31737L7.51553 5.24692C7.79704 5.00455 8.21355 5.00476 8.49481 5.24742L12.0536 8.31787C12.3673 8.58845 12.4022 9.06204 12.1316 9.37566C11.861 9.68928 11.3874 9.72417 11.0738 9.45359L8.00438 6.80541L4.92806 9.45409C4.61416 9.72435 4.14061 9.68898 3.87035 9.37508Z"
fill="#C3C8C2"
/>
</svg>
</If>
</td>
</tr>
<If condition={activeItemId == item.historyid}>
<tr className="active-history-item">
<td colSpan={6}>
<LineContainer
key={activeItemId}
historyId={activeItemId}
width={this.tableWidth.get()}
<If condition={items.length == 0}>
<div key="no-items" className="no-items">
<div>No History Items Found</div>
</div>
</If>
<div key="hsr" className="history-scroll-region">
<table className="history-table" cellSpacing="0" cellPadding="0" border={0} ref={this.tableRef}>
<tbody>
<For index="idx" each="item" of={items}>
<tr
key={item.historyid}
className={cn("history-item", {
"is-selected": hvm.selectedItems.get(item.historyid),
})}
>
<td className="selectbox" onClick={() => this.handleSelect(item.historyid)}>
<HistoryCheckbox checked={hvm.selectedItems.get(item.historyid)} />
</td>
<td className="cmdstr">
<HistoryCmdStr
cmdstr={item.cmdstr}
onUse={() => this.handleUse(item)}
onCopy={() => this.handleCopy(item)}
isCopied={this.copiedItemId.get() == item.historyid}
fontSize="normal"
limitHeight={true}
/>
</td>
<td className="workspace text-standard">{formatSSName(snames, scrnames, item)}</td>
<td className="remote text-standard">{formatRemoteName(rnames, item.remote)}</td>
<td className="ts text-standard">{getHistoryViewTs(nowDate, item.ts)}</td>
<td className="downarrow" onClick={() => this.activateItem(item.historyid)}>
<If condition={activeItemId != item.historyid}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
>
<path
d="M12.1297 6.62492C12.3999 6.93881 12.3645 7.41237 12.0506 7.68263L8.48447 10.7531C8.20296 10.9955 7.78645 10.9952 7.50519 10.7526L3.94636 7.68213C3.63274 7.41155 3.59785 6.93796 3.86843 6.62434C4.13901 6.31072 4.6126 6.27583 4.92622 6.54641L7.99562 9.19459L11.0719 6.54591C11.3858 6.27565 11.8594 6.31102 12.1297 6.62492Z"
fill="#C3C8C2"
/>
</svg>
</If>
<If condition={activeItemId == item.historyid}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
>
<path
d="M3.87035 9.37508C3.60009 9.06119 3.63546 8.58763 3.94936 8.31737L7.51553 5.24692C7.79704 5.00455 8.21355 5.00476 8.49481 5.24742L12.0536 8.31787C12.3673 8.58845 12.4022 9.06204 12.1316 9.37566C11.861 9.68928 11.3874 9.72417 11.0738 9.45359L8.00438 6.80541L4.92806 9.45409C4.61416 9.72435 4.14061 9.68898 3.87035 9.37508Z"
fill="#C3C8C2"
/>
</svg>
</If>
</td>
</tr>
</If>
</For>
</tbody>
</table>
<div className={cn("control-bar", { "is-hidden": items.length == 0 || !hasMore })}>
<If condition={activeItemId == item.historyid}>
<tr className="active-history-item">
<td colSpan={6}>
<LineContainer
key={activeItemId}
historyId={activeItemId}
width={this.tableWidth.get()}
/>
</td>
</tr>
</If>
</For>
</tbody>
</table>
</div>
<div key="control2" className={cn("control-bar", { "is-hidden": items.length == 0 || !hasMore })}>
<div className="spacer" />
<div className="showing-text">
Showing {offset + 1}-{offset + items.length}
@ -668,14 +678,6 @@ class HistoryView extends React.Component<{}, {}> {
<ChevronRightIcon className="icon" />
</div>
</div>
<If condition={items.length == 0}>
<div className="no-items">
<div>No History Items Found</div>
</div>
</If>
<div className="alt-help">
<div className="help-entry">[Esc] to Close</div>
</div>
</div>
);
}

View File

@ -125,6 +125,8 @@
// sidebar colors
--sidebar-dev-bg-color: rgb(21, 23, 48);
--sidebar-settings-color: rgb(255, 255, 255);
--sidebar-separator-color: var(--app-border-color);
--sidebar-highlight-color: rgba(241, 246, 243, 0.08);
// line colors
--line-sidebar-message-color: rgb(196, 160, 0);

View File

@ -16,7 +16,7 @@
.title-bar-drag {
-webkit-app-region: drag;
height: 20px;
height: 30px;
position: absolute;
top: 0;
left: 0;
@ -126,9 +126,7 @@
border-bottom: 1px solid var(--sidebar-separator-color);
.item {
&.active {
background: var(--sidebar-separator-color);
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4), 0px 0px 0.5px 0px rgba(0, 0, 0, 0.5),
0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
background-color: var(--sidebar-highlight-color);
}
.index {
font-size: 10px;

View File

@ -250,12 +250,11 @@
.screen-tab {
display: flex;
flex-direction: row;
height: 3em;
min-width: 13.6em;
max-width: 13.6em;
align-items: center;
cursor: pointer;
padding: 0 8px 0 8px;
padding: 8px 8px 4px 8px; // extra 4px of tab padding to account for horizontal scrollbar (to make tab text look centered)
.front-icon {
.positional-icon-visible;
@ -306,7 +305,7 @@
cursor: pointer;
display: flex;
align-items: center;
height: 37px;
height: 100%;
.icon {
height: 2rem;
@ -318,7 +317,8 @@
.tabs-end-spacer {
flex-grow: 1;
min-width: 20px;
min-width: 30px;
-webkit-app-region: drag;
height: 100%;
}
}

View File

@ -1,18 +1,7 @@
@import "@/common/themes/themes.less";
.session-view {
flex-grow: 1;
display: flex;
flex-direction: column;
position: relative;
&.is-hidden {
display: none;
}
border-radius: 0 var(--app-border-radius) var(--app-border-radius) var(--app-border-radius);
border-bottom: 1px solid var(--app-border-color);
border-right: 1px solid var(--app-border-color);
border-left: 1px solid var(--app-border-color);
background-color: black;
overflow: hidden;
.center-message {
display: flex;

View File

@ -45,7 +45,7 @@ class WorkspaceView extends React.Component<{}, {}> {
return (
<div
className={cn("session-view", { "is-hidden": isHidden })}
className={cn("mainview", "session-view", { "is-hidden": isHidden })}
data-sessionid={session.sessionId}
style={{
width: `${width}px`,