Fix logo not being visible in auxiliary views when sidebar is collapsed (#347)

This commit is contained in:
Evan Simkowitz 2024-02-27 18:21:00 -08:00 committed by GitHub
parent 3f83441868
commit 314932d402
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 186 additions and 206 deletions

View File

@ -250,6 +250,36 @@ a.a-block {
}
}
.logo-button-container {
width: 105px;
flex-shrink: 0;
position: absolute;
z-index: 25;
top: 7px;
left: 0px;
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
-webkit-app-region: drag;
pointer-events: none;
.logo-button {
width: 25px;
height: 25px;
margin-right: 6px;
cursor: pointer;
user-select: none;
-webkit-app-region: no-drag;
pointer-events: all;
&:hover {
background-color: #333;
border-radius: 4px;
}
}
}
.copied-indicator {
position: absolute;
top: 0;
@ -641,42 +671,6 @@ a.a-block {
}
}
.mainview {
flex-grow: 1;
display: flex;
flex-direction: column;
position: relative;
border-radius: 0 var(--app-border-radius) var(--app-border-radius) 0;
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 {
-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;
}
}
}
.settings-field {
display: flex;
flex-direction: row;

View File

@ -8,7 +8,7 @@ import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "@/models";
import { GlobalCommandRunner, GlobalModel } from "@/models";
import { isBlank } from "@/util/util";
import { WorkspaceView } from "./workspace/workspaceview";
import { PluginsView } from "./pluginsview/pluginsview";
@ -20,6 +20,7 @@ import { MainSideBar } from "./sidebar/sidebar";
import { DisconnectedModal, ClientStopModal } from "./common/modals";
import { ModalsProvider } from "./common/modals/provider";
import { ErrorBoundary } from "./common/error/errorboundary";
import cn from "classnames";
import "./app.less";
dayjs.extend(localizedFormat);
@ -37,7 +38,7 @@ class App extends React.Component<{}, {}> {
@boundMethod
handleContextMenu(e: any) {
let isInNonTermInput = false;
let activeElem = document.activeElement;
const activeElem = document.activeElement;
if (activeElem != null && activeElem.nodeName == "TEXTAREA") {
if (!activeElem.classList.contains("xterm-helper-textarea")) {
isInNonTermInput = true;
@ -46,17 +47,13 @@ class App extends React.Component<{}, {}> {
if (activeElem != null && activeElem.nodeName == "INPUT" && activeElem.getAttribute("type") == "text") {
isInNonTermInput = true;
}
let opts: ContextMenuOpts = {};
const opts: ContextMenuOpts = {};
if (isInNonTermInput) {
opts.showCut = true;
}
let sel = window.getSelection();
if (!isBlank(sel?.toString())) {
const sel = window.getSelection();
if (!isBlank(sel?.toString()) || isInNonTermInput) {
GlobalModel.contextEditMenu(e, opts);
} else {
if (isInNonTermInput) {
GlobalModel.contextEditMenu(e, opts);
}
}
}
@ -67,13 +64,19 @@ class App extends React.Component<{}, {}> {
})();
}
@boundMethod
openSidebar() {
const width = GlobalModel.mainSidebarModel.getWidth(true);
GlobalCommandRunner.clientSetSidebar(width, false);
}
render() {
let remotesModel = GlobalModel.remotesModel;
let disconnected = !GlobalModel.ws.open.get() || !GlobalModel.waveSrvRunning.get();
let hasClientStop = GlobalModel.getHasClientStop();
let dcWait = this.dcWait.get();
let platform = GlobalModel.getPlatform();
let clientData = GlobalModel.clientData.get();
const remotesModel = GlobalModel.remotesModel;
const disconnected = !GlobalModel.ws.open.get() || !GlobalModel.waveSrvRunning.get();
const hasClientStop = GlobalModel.getHasClientStop();
const dcWait = this.dcWait.get();
const platform = GlobalModel.getPlatform();
const clientData = GlobalModel.clientData.get();
// Previously, this is done in sidebar.tsx but it causes flicker when clientData is null cos screen-view shifts around.
// Doing it here fixes the flicker cos app is not rendered until clientData is populated.
@ -106,14 +109,22 @@ class App extends React.Component<{}, {}> {
setTimeout(() => this.updateDcWait(false), 0);
}
// used to force a full reload of the application
let renderVersion = GlobalModel.renderVersion.get();
const renderVersion = GlobalModel.renderVersion.get();
const sidebarCollapsed = GlobalModel.mainSidebarModel.getCollapsed();
return (
<div
key={"version-" + renderVersion}
id="main"
className={"platform-" + platform}
className={cn("platform-" + platform, { "sidebar-collapsed": sidebarCollapsed })}
onContextMenu={this.handleContextMenu}
>
<If condition={sidebarCollapsed}>
<div key="logo-button" className="logo-button-container">
<div className="logo-button" onClick={this.openSidebar}>
<img src="public/logos/wave-logo.png" alt="logo" />
</div>
</div>
</If>
<div ref={this.mainContentRef} className="main-content">
<MainSideBar parentRef={this.mainContentRef} clientData={clientData} />
<ErrorBoundary>

View File

@ -16,6 +16,7 @@ import { ReactComponent as TrashIcon } from "@/assets/icons/favourites/trash.svg
import { ReactComponent as FavoritesIcon } from "@/assets/icons/favourites.svg";
import "./bookmarks.less";
import { MainView } from "../common/elements/mainview";
type BookmarkProps = {
bookmark: BookmarkType;
@ -23,10 +24,6 @@ type BookmarkProps = {
@mobxReact.observer
class Bookmark extends React.Component<BookmarkProps, {}> {
constructor(props: BookmarkProps) {
super(props);
}
@boundMethod
handleDeleteClick(): void {
let { bookmark } = this.props;
@ -45,14 +42,12 @@ class Bookmark extends React.Component<BookmarkProps, {}> {
handleEditCancel(): void {
let model = GlobalModel.bookmarksModel;
model.cancelEdit();
return;
}
@boundMethod
handleEditUpdate(): void {
let model = GlobalModel.bookmarksModel;
model.confirmEdit();
return;
}
@boundMethod
@ -185,31 +180,15 @@ class Bookmark extends React.Component<BookmarkProps, {}> {
@mobxReact.observer
class BookmarksView extends React.Component<{}, {}> {
constructor(props: {}) {
super(props);
}
@boundMethod
closeView(): void {
GlobalModel.bookmarksModel.closeView();
}
render() {
let isHidden = GlobalModel.activeMainView.get() != "bookmarks";
const isHidden = GlobalModel.activeMainView.get() != "bookmarks";
if (isHidden) {
return null;
}
let bookmarks = GlobalModel.bookmarksModel.bookmarks;
let idx: number = 0;
let bookmark: BookmarkType = null;
return (
<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>
<MainView viewName="bookmarks" title="Bookmarks" onClose={GlobalModel.bookmarksModel.closeView}>
<div className="bookmarks-list">
<For index="idx" each="bookmark" of={bookmarks}>
<Bookmark key={bookmark.bookmarkid} bookmark={bookmark} />
@ -238,7 +217,7 @@ class BookmarksView extends React.Component<{}, {}> {
</div>
</div>
</If>
</div>
</MainView>
);
}
}

View File

@ -12,6 +12,7 @@ import { commandRtnHandler, isBlank } from "@/util/util";
import * as appconst from "@/app/appconst";
import "./clientsettings.less";
import { MainView } from "../common/elements/mainview";
@mobxReact.observer
class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
@ -105,11 +106,6 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
})();
}
@boundMethod
handleClose(): void {
GlobalModel.clientSettingsViewModel.closeView();
}
@boundMethod
handleChangeShortcut(newShortcut: string): void {
const prtn = GlobalCommandRunner.setGlobalShortcut(newShortcut);
@ -148,13 +144,11 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
const curFontFamily = GlobalModel.getTermFontFamily();
return (
<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>
</div>
</header>
<MainView
viewName="clientsettings"
title="Client Settings"
onClose={GlobalModel.clientSettingsViewModel.closeView}
>
<div className="content">
<div className="settings-field">
<div className="settings-label">Term Font Size</div>
@ -259,7 +253,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
</div>
<SettingsError errorMessage={this.errorMessage} />
</div>
</div>
</MainView>
);
}
}

View File

@ -0,0 +1,55 @@
.mainview {
flex-grow: 1;
display: flex;
flex-direction: column;
position: relative;
border-radius: 0 var(--app-border-radius) var(--app-border-radius) 0;
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: var(--app-bg-color);
&.is-hidden {
display: none;
}
.header {
-webkit-app-region: drag;
display: flex;
justify-content: space-between;
flex-direction: row;
line-height: var(--screentabs-height);
vertical-align: middle;
padding: 0 10px 0 10px;
margin: 0;
.title {
font-size: 1.5em;
padding: 0 10px;
vertical-align: middle;
line-height: var(--screentabs-height);
color: var(--term-white);
margin: 0;
}
.close-div {
-webkit-app-region: no-drag;
font-size: 1.5em;
}
}
.bottom-border {
border-bottom: 1px solid var(--app-border-color);
margin-bottom: 10px;
}
}
// This ensures the tab bar does not collide with the floating logo. The floating logo sits above the sidebar when it is not collapsed, so no additional margin is needed in that case.
// More margin is given on macOS to account for the traffic light buttons
#main.platform-darwin.sidebar-collapsed .header {
margin-left: var(--floating-logo-width-darwin);
}
#main:not(.platform-darwin).sidebar-collapsed .header {
margin-left: var(--floating-logo-width);
}

View File

@ -0,0 +1,38 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import * as mobxReact from "mobx-react";
import cn from "classnames";
import { GlobalModel } from "@/models";
import "./mainview.less";
@mobxReact.observer
class MainView extends React.Component<{
viewName: string;
title: string;
onClose: () => void;
children: React.ReactNode;
}> {
render() {
// TODO: This is a workaround for History view not honoring the sidebar width. This is rooted in the table width for the history view, which uses `calc(100%-20px)`. To properly fix this, History view needs a full overhaul.
const width = window.innerWidth - 6 - GlobalModel.mainSidebarModel.getWidth();
return (
<div className={cn("mainview", `${this.props.viewName}-view`)} style={{ maxWidth: width }}>
<div className="header-container bottom-border">
<header className="header">
<div className="title text-primary">{this.props.title}</div>
<div className="close-div hoverEffect" title="Close (Escape)" onClick={this.props.onClose}>
<i className="fa-sharp fa-solid fa-xmark"></i>
</div>
</header>
</div>
{this.props.children}
</div>
);
}
}
export { MainView };

View File

View File

View File

@ -12,6 +12,7 @@ import { Button, Status, ShowWaveShellInstallPrompt } from "@/common/elements";
import * as util from "@/util/util";
import "./connections.less";
import { MainView } from "../common/elements/mainview";
@mobxReact.observer
class ConnectionsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
@ -97,11 +98,6 @@ class ConnectionsView extends React.Component<{ model: RemotesModel }, { hovered
}
}
@boundMethod
handleClose(): void {
GlobalModel.connectionViewModel.closeView();
}
componentDidMount() {
if (this.tableRef.current != null) {
this.tableRszObs = new ResizeObserver(this.handleTableResize.bind(this));
@ -130,13 +126,7 @@ class ConnectionsView extends React.Component<{ model: RemotesModel }, { hovered
let item: RemoteType = null;
return (
<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>
</div>
</header>
<MainView viewName="connections" title="Connections" onClose={GlobalModel.connectionViewModel.closeView}>
<table
className="connections-table"
cellSpacing="0"
@ -209,7 +199,7 @@ class ConnectionsView extends React.Component<{ model: RemotesModel }, { hovered
<div>No Connections Items Found</div>
</div>
</If>
</div>
</MainView>
);
}
}

View File

@ -1,10 +1,6 @@
.history-view {
padding-bottom: 10px;
.header {
padding: 18px 18px;
}
.icon {
width: 2em !important;
height: 1.3em !important;
@ -43,23 +39,7 @@
top: 0.5em;
}
.close-div {
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);
}
}
.history-search {
flex-grow: 1;
padding: 0 10px 10px 10px;
input {

View File

@ -28,6 +28,7 @@ import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
import { ReactComponent as CopyIcon } from "@/assets/icons/history/copy.svg";
import "./history.less";
import { MainView } from "../common/elements/mainview";
dayjs.extend(customParseFormat);
dayjs.extend(localizedFormat);
@ -178,11 +179,6 @@ class HistoryView extends React.Component<{}, {}> {
remoteDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "remoteDropdownActive" });
copiedItemId: OV<string> = mobx.observable.box(null, { name: "copiedItemId" });
@boundMethod
clickCloseHandler(): void {
GlobalModel.historyViewModel.closeView();
}
@boundMethod
handleNext() {
GlobalModel.historyViewModel.goNext();
@ -206,7 +202,6 @@ class HistoryView extends React.Component<{}, {}> {
if (checkKeyPressed(waveEvent, "Enter")) {
e.preventDefault();
GlobalModel.historyViewModel.submitSearch();
return;
}
}
@ -229,10 +224,9 @@ class HistoryView extends React.Component<{}, {}> {
let numSelected = hvm.selectedItems.size;
if (numSelected > 0) {
hvm.selectedItems.clear();
return;
} else {
for (let i = 0; i < hvm.items.length; i++) {
hvm.selectedItems.set(hvm.items[i].historyid, true);
for (const element of hvm.items) {
hvm.selectedItems.set(element.historyid, true);
}
}
})();
@ -302,7 +296,6 @@ class HistoryView extends React.Component<{}, {}> {
return;
}
hvm.setFromDate(e.target.value);
return;
}
@boundMethod
@ -399,7 +392,6 @@ class HistoryView extends React.Component<{}, {}> {
return null;
}
let hvm = GlobalModel.historyViewModel;
let idx: number = 0;
let item: HistoryItem = null;
let items = hvm.items.slice();
let nowDate = new Date();
@ -410,32 +402,13 @@ class HistoryView extends React.Component<{}, {}> {
let offset = hvm.offset.get();
let numSelected = hvm.selectedItems.size;
let activeItemId = hvm.activeItem.get();
let activeItem = hvm.getHistoryItemById(activeItemId);
let activeLine: LineType = null;
if (activeItem != null) {
activeLine = hvm.getLineById(activeItem.lineid);
}
let sessionIds = Object.keys(snames);
let sessionId: string = null;
let remoteIds = Object.keys(rnames);
let remoteId: string = null;
// TODO: something is weird with how we calculate width for views. Before, history view was not honoring tab width. This fix is copied from workspaceview.tsx, which had a similar issue.
const width = window.innerWidth - 6 - GlobalModel.mainSidebarModel.getWidth();
return (
<div
className={cn("history-view", "mainview", { "is-hidden": isHidden })}
style={{
width: `${width}px`,
}}
>
<header key="header" className="header">
<div className="clientsettings-title text-primary">History</div>
<div className="close-div hoverEffect" title="Close (Escape)" onClick={this.clickCloseHandler}>
<i className="fa-sharp fa-solid fa-xmark"></i>
</div>
</header>
<MainView viewName="history" title="History" onClose={GlobalModel.historyViewModel.closeView}>
<div key="search" className="history-search">
<div className="main-search field">
<TextField
@ -678,14 +651,13 @@ class HistoryView extends React.Component<{}, {}> {
<ChevronRightIcon className="icon" />
</div>
</div>
</div>
</MainView>
);
}
}
class LineContainer extends React.Component<{ historyId: string; width: number }, {}> {
line: LineType;
cmd: Cmd;
historyItem: HistoryItem;
visible: OV<boolean> = mobx.observable.box(true);
overrideCollapsed: OV<boolean> = mobx.observable.box(false);
@ -698,7 +670,6 @@ class LineContainer extends React.Component<{ historyId: string; width: number }
return;
}
this.line = hvm.getLineById(this.historyItem.lineid);
this.cmd = hvm.getCmdById(this.historyItem.lineid);
}
@boundMethod

View File

@ -26,6 +26,11 @@
--screentabs-font-weight: 300;
--screentabs-selected-font-weight: 300;
// floating logo settings
--floating-logo-width-darwin: 110px;
--floating-logo-width: 40px;
--floating-logo-height: var(--screentabs-height);
// global colors
--app-accent-color: rgb(88, 193, 66);
--app-error-color: rgb(204, 0, 0);

View File

@ -8,7 +8,6 @@ import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, Screen } from "@/models";
import { ActionsIcon, StatusIndicator, CenteredIcon } from "@/common/icons/icons";
import { renderCmdText } from "@/elements";
import { ReactComponent as SquareIcon } from "@/assets/icons/tab/square.svg";
import * as constants from "@/app/appconst";
import { Reorder } from "framer-motion";

View File

@ -91,34 +91,6 @@
overflow: hidden;
height: var(--screentabs-height);
&.sidebar-collapsed .logo-button-container {
width: 105px;
flex-shrink: 0;
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
-webkit-app-region: drag;
.logo-button {
width: 25px;
height: 25px;
margin-right: 6px;
cursor: pointer;
user-select: none;
-webkit-app-region: no-drag;
&:hover {
background-color: #333;
border-radius: 4px;
}
}
}
.logo-button {
width: 20px;
}
&:hover {
z-index: 200;
}
@ -206,3 +178,13 @@
height: 100%;
}
}
// This ensures the tab bar does not collide with the floating logo. The floating logo sits above the sidebar when it is not collapsed, so no additional margin is needed in that case.
// More margin is given on macOS to account for the traffic light buttons
#main.platform-darwin.sidebar-collapsed .screen-tabs-container {
margin-left: var(--floating-logo-width-darwin);
}
#main:not(.platform-darwin).sidebar-collapsed .screen-tabs-container {
margin-left: var(--floating-logo-width);
}

View File

@ -168,12 +168,6 @@ class ScreenTabs extends React.Component<
// For touchpad events, do nothing and let the browser handle it
}
@boundMethod
openSidebar() {
const width = GlobalModel.mainSidebarModel.getWidth(true);
GlobalCommandRunner.clientSetSidebar(width, false);
}
render() {
let { showingScreens } = this.state;
let { session } = this.props;
@ -183,20 +177,8 @@ class ScreenTabs extends React.Component<
let screen: Screen | null = null;
let index = 0;
let activeScreenId = this.getActiveScreenId();
const sidebarCollapsed = GlobalModel.mainSidebarModel.getCollapsed();
return (
<div
className={cn("screen-tabs-container", {
"sidebar-collapsed": sidebarCollapsed,
})}
>
<If condition={sidebarCollapsed}>
<div key="logo-button" className="logo-button-container">
<div className="logo-button" onClick={this.openSidebar}>
<img src="public/logos/wave-logo.png" alt="logo" />
</div>
</div>
</If>
<div className="screen-tabs-container">
{/* Inner container ensures that hovering over the scrollbar doesn't trigger the hover effect on the tabs. This prevents weird flickering of the icons when the mouse is moved over the scrollbar. */}
<div
key="container-inner"