From 07e0b53b17e50e65fbdb3e35cd3901e4819ff60f Mon Sep 17 00:00:00 2001 From: Red J Adaya Date: Fri, 15 Mar 2024 13:59:55 +0800 Subject: [PATCH] Rght sidebar (#461) * init * model * pass model * increase snap threshold * move saving of state to model. backend implementation * fix wrong clientdata prop * right header space for right sidebar toggles * button component refactor * set default classname to primary * remove debugging code * hide trigger for now * disable right sidebar in production (only show on dev for now) --- public/themes/default.css | 4 + src/app/app.less | 19 ++++ src/app/app.tsx | 46 ++++++-- src/app/common/elements/button.less | 12 ++- src/app/common/elements/button.tsx | 37 +------ src/app/common/elements/iconbutton.tsx | 21 ---- src/app/common/elements/index.tsx | 1 - src/app/common/elements/modal.tsx | 13 ++- src/app/common/elements/resizablesidebar.tsx | 57 +++++----- src/app/common/modals/alert.tsx | 2 +- src/app/common/modals/clientstop.tsx | 2 +- src/app/common/modals/disconnected.tsx | 4 +- .../common/modals/viewremoteconndetail.tsx | 20 ++-- src/app/connections/connections.tsx | 4 +- src/app/magiclayout.ts | 10 +- src/app/sidebar/{sidebar.less => main.less} | 0 src/app/sidebar/{sidebar.tsx => main.tsx} | 3 +- src/app/sidebar/right.less | 28 +++++ src/app/sidebar/right.tsx | 46 ++++++++ src/app/workspace/screen/screenview.tsx | 2 +- src/app/workspace/screen/tabs.less | 13 ++- src/app/workspace/workspaceview.tsx | 6 +- src/models/commandrunner.ts | 9 +- src/models/index.ts | 2 + src/models/mainsidebar.ts | 9 ++ src/models/model.ts | 4 +- src/models/rightsidebar.ts | 100 ++++++++++++++++++ src/models/sidebar.ts | 13 +++ src/plugins/code/code.tsx | 4 +- src/types/custom.d.ts | 4 + wavesrv/pkg/cmdrunner/cmdrunner.go | 60 ++++++++++- wavesrv/pkg/sstore/sstore.go | 1 + 32 files changed, 414 insertions(+), 142 deletions(-) delete mode 100644 src/app/common/elements/iconbutton.tsx rename src/app/sidebar/{sidebar.less => main.less} (100%) rename src/app/sidebar/{sidebar.tsx => main.tsx} (99%) create mode 100644 src/app/sidebar/right.less create mode 100644 src/app/sidebar/right.tsx create mode 100644 src/models/rightsidebar.ts create mode 100644 src/models/sidebar.ts diff --git a/public/themes/default.css b/public/themes/default.css index 84789e91..33c1af4a 100644 --- a/public/themes/default.css +++ b/public/themes/default.css @@ -44,6 +44,10 @@ --floating-logo-width: 40px; --floating-logo-height: var(--screentabs-height); + /* right sidebar triggers */ + --floating-right-sidebar-triggers-width-darwin: 50px; + --floating-right-sidebar-triggers-width: 40px; + /* global colors */ --app-bg-color: black; --app-accent-color: rgb(88, 193, 66); diff --git a/src/app/app.less b/src/app/app.less index 71d22ecc..929b3294 100644 --- a/src/app/app.less +++ b/src/app/app.less @@ -302,6 +302,25 @@ a.a-block { } } +.right-sidebar-triggers { + position: absolute; + z-index: 25; + right: 0px; + display: flex; + flex-direction: row; + align-items: center; + pointer-events: none; + height: 38px; + padding: 0 5px; + + .right-sidebar-trigger { + cursor: pointer; + user-select: none; + -webkit-app-region: no-drag; + pointer-events: all; + } +} + .copied-indicator { position: absolute; top: 0; diff --git a/src/app/app.tsx b/src/app/app.tsx index de6910e6..a5745c9d 100644 --- a/src/app/app.tsx +++ b/src/app/app.tsx @@ -16,10 +16,12 @@ import { BookmarksView } from "./bookmarks/bookmarks"; import { HistoryView } from "./history/history"; import { ConnectionsView } from "./connections/connections"; import { ClientSettingsView } from "./clientsettings/clientsettings"; -import { MainSideBar } from "./sidebar/sidebar"; -import { DisconnectedModal, ClientStopModal } from "./common/modals"; -import { ModalsProvider } from "./common/modals/provider"; -import { ErrorBoundary } from "./common/error/errorboundary"; +import { MainSideBar } from "./sidebar/main"; +import { RightSideBar } from "./sidebar/right"; +import { DisconnectedModal, ClientStopModal } from "@/modals"; +import { ModalsProvider } from "@/modals/provider"; +import { Button } from "@/elements"; +import { ErrorBoundary } from "@/common/error/errorboundary"; import cn from "classnames"; import "./app.less"; @@ -65,9 +67,17 @@ class App extends React.Component<{}, {}> { } @boundMethod - openSidebar() { - const width = GlobalModel.mainSidebarModel.getWidth(true); - GlobalCommandRunner.clientSetSidebar(width, false); + openMainSidebar() { + const mainSidebarModel = GlobalModel.mainSidebarModel; + const width = mainSidebarModel.getWidth(true); + mainSidebarModel.saveState(width, false); + } + + @boundMethod + openRightSidebar() { + const rightSidebarModel = GlobalModel.rightSidebarModel; + const width = rightSidebarModel.getWidth(true); + rightSidebarModel.saveState(width, false); } render() { @@ -110,23 +120,36 @@ class App extends React.Component<{}, {}> { } // used to force a full reload of the application const renderVersion = GlobalModel.renderVersion.get(); - const sidebarCollapsed = GlobalModel.mainSidebarModel.getCollapsed(); + const mainSidebarCollapsed = GlobalModel.mainSidebarModel.getCollapsed(); + const rightSidebarCollapsed = GlobalModel.rightSidebarModel.getCollapsed(); + const activeMainView = GlobalModel.activeMainView.get(); const lightDarkClass = GlobalModel.isThemeDark() ? "is-dark" : "is-light"; return (
- +
-
+
logo
+ +
+ +
+
@@ -137,6 +160,7 @@ class App extends React.Component<{}, {}> { +
diff --git a/src/app/common/elements/button.less b/src/app/common/elements/button.less index d37b0034..d6090577 100644 --- a/src/app/common/elements/button.less +++ b/src/app/common/elements/button.less @@ -5,7 +5,6 @@ font: inherit; cursor: pointer; outline: inherit; - display: flex; padding: 6px 16px; align-items: center; @@ -15,7 +14,8 @@ line-height: 1.5; &.primary { - background: none; + color: var(--form-element-text-color); + background: var(--form-element-primary-color); i { fill: var(--form-element-primary-color); @@ -31,11 +31,12 @@ } &.outlined { + background: none; border: 1px solid var(--form-element-primary-color); } &.ghost { - // Styles for .ghost are already defined above + background: none; } &:hover { @@ -46,6 +47,9 @@ &.secondary { color: var(--form-element-text-color); background: none; + color: var(--form-element-text-color); + background: var(--form-element-secondary-color); + box-shadow: none; &.solid { color: var(--form-element-text-color); @@ -54,10 +58,12 @@ } &.outlined { + background: none; border: 1px solid var(--form-element-secondary-color); } &.ghost { + background: none; padding: 6px 10px; i { diff --git a/src/app/common/elements/button.tsx b/src/app/common/elements/button.tsx index 253ef226..d411f47b 100644 --- a/src/app/common/elements/button.tsx +++ b/src/app/common/elements/button.tsx @@ -1,24 +1,15 @@ -// Copyright 2023, Command Line Inc. -// SPDX-License-Identifier: Apache-2.0 - import * as React from "react"; import { boundMethod } from "autobind-decorator"; import cn from "classnames"; import "./button.less"; -type ButtonVariantType = "outlined" | "solid" | "ghost"; -type ButtonThemeType = "primary" | "secondary"; - interface ButtonProps { - theme?: ButtonThemeType; children: React.ReactNode; onClick?: () => void; disabled?: boolean; - variant?: ButtonVariantType; leftIcon?: React.ReactNode; rightIcon?: React.ReactNode; - color?: string; style?: React.CSSProperties; autoFocus?: boolean; className?: string; @@ -27,10 +18,8 @@ interface ButtonProps { class Button extends React.Component { static defaultProps = { - theme: "primary", - variant: "solid", - color: "", style: {}, + className: "primary", }; @boundMethod @@ -41,31 +30,11 @@ class Button extends React.Component { } render() { - const { - leftIcon, - rightIcon, - theme, - children, - disabled, - variant, - color, - style, - autoFocus, - termInline, - className, - } = this.props; + const { leftIcon, rightIcon, children, disabled, style, autoFocus, termInline, className } = this.props; return ( - ); - } -} - -export default IconButton; - -export { IconButton }; diff --git a/src/app/common/elements/index.tsx b/src/app/common/elements/index.tsx index 7096d328..ed4210c1 100644 --- a/src/app/common/elements/index.tsx +++ b/src/app/common/elements/index.tsx @@ -3,7 +3,6 @@ export { Checkbox } from "./checkbox"; export { CmdStrCode } from "./cmdstrcode"; export { renderCmdText } from "./cmdtext"; export { Dropdown } from "./dropdown"; -export { IconButton } from "./iconbutton"; export { InlineSettingsTextEdit } from "./inlinesettingstextedit"; export { InputDecoration } from "./inputdecoration"; export { LinkButton } from "./linkbutton"; diff --git a/src/app/common/elements/modal.tsx b/src/app/common/elements/modal.tsx index f05d27c2..187992a6 100644 --- a/src/app/common/elements/modal.tsx +++ b/src/app/common/elements/modal.tsx @@ -6,7 +6,6 @@ import * as mobx from "mobx"; import { If } from "tsx-control-statements/components"; import ReactDOM from "react-dom"; import { Button } from "./button"; -import { IconButton } from "./iconbutton"; import "./modal.less"; @@ -19,9 +18,9 @@ const ModalHeader: React.FC = ({ onClose, title }) => (
{
{title}
} - +
); @@ -36,11 +35,15 @@ interface ModalFooterProps { const ModalFooter: React.FC = ({ onCancel, onOk, cancelLabel = "Cancel", okLabel = "Ok" }) => (
{onCancel && ( - )} - {onOk && } + {onOk && ( + + )}
); diff --git a/src/app/common/elements/resizablesidebar.tsx b/src/app/common/elements/resizablesidebar.tsx index 187b994c..b28a45c8 100644 --- a/src/app/common/elements/resizablesidebar.tsx +++ b/src/app/common/elements/resizablesidebar.tsx @@ -6,7 +6,7 @@ import * as mobxReact from "mobx-react"; import * as mobx from "mobx"; import { boundMethod } from "autobind-decorator"; import cn from "classnames"; -import { GlobalModel, GlobalCommandRunner } from "@/models"; +import { GlobalCommandRunner, SidebarModel } from "@/models"; import { MagicLayout } from "@/app/magiclayout"; import "./resizablesidebar.less"; @@ -14,6 +14,7 @@ import "./resizablesidebar.less"; interface ResizableSidebarProps { parentRef: React.RefObject; position: "left" | "right"; + model: SidebarModel; enableSnap?: boolean; className?: string; children?: (toggleCollapsed: () => void) => React.ReactNode; @@ -32,7 +33,7 @@ class ResizableSidebar extends React.Component { startResizing(event: React.MouseEvent) { event.preventDefault(); - const { parentRef, position } = this.props; + const { parentRef, position, model } = this.props; const parentRect = parentRef.current?.getBoundingClientRect(); if (!parentRect) return; @@ -43,17 +44,16 @@ class ResizableSidebar extends React.Component { this.startX = event.clientX - parentRect.left; } - const mainSidebarModel = GlobalModel.mainSidebarModel; - const collapsed = mainSidebarModel.getCollapsed(); + const collapsed = model.getCollapsed(); - this.resizeStartWidth = mainSidebarModel.getWidth(); + this.resizeStartWidth = model.getWidth(); document.addEventListener("mousemove", this.onMouseMove); document.addEventListener("mouseup", this.stopResizing); document.body.style.cursor = "col-resize"; mobx.action(() => { - mainSidebarModel.setTempWidthAndTempCollapsed(this.resizeStartWidth, collapsed); - mainSidebarModel.isDragging.set(true); + model.setTempWidthAndTempCollapsed(this.resizeStartWidth, collapsed); + model.isDragging.set(true); })(); } @@ -61,11 +61,10 @@ class ResizableSidebar extends React.Component { onMouseMove(event: MouseEvent) { event.preventDefault(); - const { parentRef, enableSnap, position } = this.props; + const { parentRef, enableSnap, position, model } = this.props; const parentRect = parentRef.current?.getBoundingClientRect(); - const mainSidebarModel = GlobalModel.mainSidebarModel; - if (!mainSidebarModel.isDragging.get() || !parentRect) return; + if (!model.isDragging.get() || !parentRect) return; let delta: number, newWidth: number; @@ -100,34 +99,27 @@ class ResizableSidebar extends React.Component { if (newWidth - dragResistance > minWidth && newWidth < snapPoint && dragDirection == "+") { newWidth = snapPoint; - mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, false); + model.setTempWidthAndTempCollapsed(newWidth, false); } else if (newWidth + dragResistance < snapPoint && dragDirection == "-") { newWidth = minWidth; - mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, true); + model.setTempWidthAndTempCollapsed(newWidth, true); } else if (newWidth > snapPoint) { - mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, false); + model.setTempWidthAndTempCollapsed(newWidth, false); } } else { if (newWidth <= MagicLayout.MainSidebarMinWidth) { - mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, true); + model.setTempWidthAndTempCollapsed(newWidth, true); } else { - mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, false); + model.setTempWidthAndTempCollapsed(newWidth, false); } } } @boundMethod stopResizing() { - let mainSidebarModel = GlobalModel.mainSidebarModel; + const { model } = this.props; - GlobalCommandRunner.clientSetSidebar( - mainSidebarModel.tempWidth.get(), - mainSidebarModel.tempCollapsed.get() - ).finally(() => { - mobx.action(() => { - mainSidebarModel.isDragging.set(false); - })(); - }); + model.saveState(model.tempWidth.get(), model.tempCollapsed.get()); document.removeEventListener("mousemove", this.onMouseMove); document.removeEventListener("mouseup", this.stopResizing); @@ -136,19 +128,18 @@ class ResizableSidebar extends React.Component { @boundMethod toggleCollapsed() { - const mainSidebarModel = GlobalModel.mainSidebarModel; + const { model } = this.props; - const tempCollapsed = mainSidebarModel.getCollapsed(); - const width = mainSidebarModel.getWidth(true); - mainSidebarModel.setTempWidthAndTempCollapsed(width, !tempCollapsed); - GlobalCommandRunner.clientSetSidebar(width, !tempCollapsed); + const tempCollapsed = model.getCollapsed(); + const width = model.getWidth(true); + model.setTempWidthAndTempCollapsed(width, !tempCollapsed); + model.saveState(width, !tempCollapsed); } render() { - const { className, children } = this.props; - const mainSidebarModel = GlobalModel.mainSidebarModel; - const width = mainSidebarModel.getWidth(); - const isCollapsed = mainSidebarModel.getCollapsed(); + const { className, children, model } = this.props; + const width = model.getWidth(); + const isCollapsed = model.getCollapsed(); return (
diff --git a/src/app/common/modals/alert.tsx b/src/app/common/modals/alert.tsx index 714869ae..a0fb5fb5 100644 --- a/src/app/common/modals/alert.tsx +++ b/src/app/common/modals/alert.tsx @@ -54,7 +54,7 @@ class AlertModal extends React.Component<{}, {}> {
-
); const connectButton = ( - ); const tryReconnectButton = ( - ); let updateAuthButton = ( - ); let cancelInstallButton = ( - ); let installNowButton = ( - ); let archiveButton = ( - ); const reinstallButton = ( - ); @@ -207,7 +207,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> { } if (remote.sshconfigsrc == "sshconfig-import") { archiveButton = ( -
+
+ + )} + + ); + } +} + +export { RightSideBar }; diff --git a/src/app/workspace/screen/screenview.tsx b/src/app/workspace/screen/screenview.tsx index 3d1c4924..a5424ba0 100644 --- a/src/app/workspace/screen/screenview.tsx +++ b/src/app/workspace/screen/screenview.tsx @@ -325,7 +325,7 @@ class ScreenSidebar extends React.Component<{ screen: Screen; width: string }, {
-
diff --git a/src/app/workspace/screen/tabs.less b/src/app/workspace/screen/tabs.less index 4c6be25a..f113100c 100644 --- a/src/app/workspace/screen/tabs.less +++ b/src/app/workspace/screen/tabs.less @@ -189,10 +189,19 @@ // 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 { +#main.platform-darwin.mainsidebar-collapsed .screen-tabs-container { margin-left: var(--floating-logo-width-darwin); } -#main:not(.platform-darwin).sidebar-collapsed .screen-tabs-container { +#main:not(.platform-darwin).mainsidebar-collapsed .screen-tabs-container { margin-left: var(--floating-logo-width); } + +// This ensures the tab bar does not collide with the right sidebar triggers. +#main.platform-darwin.rightsidebar-collapsed .screen-tabs-container { + margin-right: var(--floating-right-sidebar-triggers-width-darwin); +} + +#main:not(.platform-darwin).rightsidebar-collapsed .screen-tabs-container { + margin-left: var(--floating-right-sidebar-triggers-width); +} diff --git a/src/app/workspace/workspaceview.tsx b/src/app/workspace/workspaceview.tsx index eee8db51..717a91b5 100644 --- a/src/app/workspace/workspaceview.tsx +++ b/src/app/workspace/workspaceview.tsx @@ -39,16 +39,12 @@ class WorkspaceView extends React.Component<{}, {}> { let isHidden = GlobalModel.activeMainView.get() != "session"; let mainSidebarModel = GlobalModel.mainSidebarModel; - // Has to calc manually because when tabs overflow, the width of the session view is increased for some reason causing inconsistent width. - // 6px is the right margin of session view. - let width = window.innerWidth - 6 - mainSidebarModel.getWidth(); - return (
diff --git a/src/models/commandrunner.ts b/src/models/commandrunner.ts index 5b57a0c4..364094db 100644 --- a/src/models/commandrunner.ts +++ b/src/models/commandrunner.ts @@ -399,9 +399,14 @@ class CommandRunner { return GlobalModel.submitCommand("client", "setconfirmflag", [flag, valueStr], kwargs, false); } - clientSetSidebar(width: number, collapsed: boolean): Promise { + clientSetMainSidebar(width: number, collapsed: boolean): Promise { let kwargs = { nohist: "1", width: `${width}`, collapsed: collapsed ? "1" : "0" }; - return GlobalModel.submitCommand("client", "setsidebar", null, kwargs, false); + return GlobalModel.submitCommand("client", "setmainsidebar", null, kwargs, false); + } + + clientSetRightSidebar(width: number, collapsed: boolean): Promise { + let kwargs = { nohist: "1", width: `${width}`, collapsed: collapsed ? "1" : "0" }; + return GlobalModel.submitCommand("client", "setrightsidebar", null, kwargs, false); } editBookmark(bookmarkId: string, desc: string, cmdstr: string) { diff --git a/src/models/index.ts b/src/models/index.ts index d4d05197..0fb91807 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,3 +1,4 @@ +export type { SidebarModel } from "./sidebar"; export * from "./global"; export * from "./model"; export { BookmarksModel } from "./bookmarks"; @@ -6,6 +7,7 @@ export { Cmd } from "./cmd"; export { ConnectionsViewModel } from "./connectionsview"; export { InputModel } from "./input"; export { MainSidebarModel } from "./mainsidebar"; +export { RightSidebarModel } from "./rightsidebar"; export { ModalsModel } from "./modals"; export { PluginsModel } from "./plugins"; export { RemotesModel } from "./remotes"; diff --git a/src/models/mainsidebar.ts b/src/models/mainsidebar.ts index dce8bf2a..b5503aa3 100644 --- a/src/models/mainsidebar.ts +++ b/src/models/mainsidebar.ts @@ -4,6 +4,7 @@ import * as mobx from "mobx"; import { MagicLayout } from "@/app/magiclayout"; import { Model } from "./model"; +import { GlobalCommandRunner } from "@/models"; class MainSidebarModel { globalModel: Model = null; @@ -80,6 +81,14 @@ class MainSidebarModel { } return collapsed; } + + saveState(width: number, collapsed: boolean): void { + GlobalCommandRunner.clientSetMainSidebar(width, collapsed).finally(() => { + mobx.action(() => { + this.isDragging.set(false); + })(); + }); + } } export { MainSidebarModel }; diff --git a/src/models/model.ts b/src/models/model.ts index 52bc48c4..04d7a29f 100644 --- a/src/models/model.ts +++ b/src/models/model.ts @@ -13,7 +13,6 @@ import { isModKeyPress, isBlank, } from "@/util/util"; -import { loadFonts } from "@/util/fontutil"; import { loadTheme } from "@/util/themeutil"; import { WSControl } from "./ws"; import { cmdStatusIsRunning } from "@/app/line/lineutil"; @@ -31,6 +30,7 @@ import { ClientSettingsViewModel } from "./clientsettingsview"; import { RemotesModel } from "./remotes"; import { ModalsModel } from "./modals"; import { MainSidebarModel } from "./mainsidebar"; +import { RightSidebarModel } from "./rightsidebar"; import { Screen } from "./screen"; import { Cmd } from "./cmd"; import { GlobalCommandRunner } from "./global"; @@ -117,6 +117,7 @@ class Model { clientSettingsViewModel: ClientSettingsViewModel; modalsModel: ModalsModel; mainSidebarModel: MainSidebarModel; + rightSidebarModel: RightSidebarModel; clientData: OV = mobx.observable.box(null, { name: "clientData", }); @@ -156,6 +157,7 @@ class Model { this.remotesModel = new RemotesModel(this); this.modalsModel = new ModalsModel(); this.mainSidebarModel = new MainSidebarModel(this); + this.rightSidebarModel = new RightSidebarModel(this); const isWaveSrvRunning = getApi().getWaveSrvStatus(); this.waveSrvRunning = mobx.observable.box(isWaveSrvRunning, { name: "model-wavesrv-running", diff --git a/src/models/rightsidebar.ts b/src/models/rightsidebar.ts new file mode 100644 index 00000000..0a712e5c --- /dev/null +++ b/src/models/rightsidebar.ts @@ -0,0 +1,100 @@ +// Copyright 2023, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import * as mobx from "mobx"; +import { MagicLayout } from "@/app/magiclayout"; +import { Model } from "./model"; +import { GlobalCommandRunner } from "@/models"; + +interface SidebarModel {} + +class RightSidebarModel implements SidebarModel { + globalModel: Model = null; + tempWidth: OV = mobx.observable.box(null, { + name: "RightSidebarModel-tempWidth", + }); + tempCollapsed: OV = mobx.observable.box(null, { + name: "RightSidebarModel-tempCollapsed", + }); + isDragging: OV = mobx.observable.box(false, { + name: "RightSidebarModel-isDragging", + }); + + constructor(globalModel: Model) { + this.globalModel = globalModel; + } + + setTempWidthAndTempCollapsed(newWidth: number, newCollapsed: boolean): void { + const width = Math.max(MagicLayout.RightSidebarMinWidth, Math.min(newWidth, MagicLayout.RightSidebarMaxWidth)); + + mobx.action(() => { + this.tempWidth.set(width); + this.tempCollapsed.set(newCollapsed); + })(); + } + + /** + * Gets the intended width for the sidebar. If the sidebar is being dragged, returns the tempWidth. If the sidebar is collapsed, returns the default width. + * @param ignoreCollapse If true, returns the persisted width even if the sidebar is collapsed. + * @returns The intended width for the sidebar or the default width if the sidebar is collapsed. Can be overridden using ignoreCollapse. + */ + getWidth(ignoreCollapse: boolean = false): number { + const clientData = this.globalModel.clientData.get(); + let width = clientData?.clientopts?.rightsidebar?.width ?? MagicLayout.RightSidebarDefaultWidth; + if (this.isDragging.get()) { + if (this.tempWidth.get() == null && width == null) { + return MagicLayout.RightSidebarDefaultWidth; + } + if (this.tempWidth.get() == null) { + return width; + } + return this.tempWidth.get(); + } + // Set by CLI and collapsed + if (this.getCollapsed()) { + if (ignoreCollapse) { + return width; + } else { + return MagicLayout.RightSidebarMinWidth; + } + } else { + if (width <= MagicLayout.RightSidebarMinWidth) { + width = MagicLayout.RightSidebarDefaultWidth; + } + const snapPoint = MagicLayout.RightSidebarMinWidth + MagicLayout.RightSidebarSnapThreshold; + if (width < snapPoint || width > MagicLayout.RightSidebarMaxWidth) { + width = MagicLayout.RightSidebarDefaultWidth; + } + } + return width; + } + + getCollapsed(): boolean { + // disable right sidebar in production + if (!this.globalModel.isDev) { + return true; + } + const clientData = this.globalModel.clientData.get(); + const collapsed = clientData?.clientopts?.rightsidebar?.collapsed; + if (this.isDragging.get()) { + if (this.tempCollapsed.get() == null && collapsed == null) { + return false; + } + if (this.tempCollapsed.get() == null) { + return collapsed; + } + return this.tempCollapsed.get(); + } + return collapsed; + } + + saveState(width: number, collapsed: boolean): void { + GlobalCommandRunner.clientSetRightSidebar(width, collapsed).finally(() => { + mobx.action(() => { + this.isDragging.set(false); + })(); + }); + } +} + +export { RightSidebarModel }; diff --git a/src/models/sidebar.ts b/src/models/sidebar.ts new file mode 100644 index 00000000..b6b1792b --- /dev/null +++ b/src/models/sidebar.ts @@ -0,0 +1,13 @@ +import { Model } from "./model"; + +export interface SidebarModel { + readonly globalModel: Model; + readonly tempWidth: OV; + readonly tempCollapsed: OV; + readonly isDragging: OV; + + setTempWidthAndTempCollapsed(newWidth: number, newCollapsed: boolean): void; + getWidth(ignoreCollapse?: boolean): number; + getCollapsed(): boolean; + saveState(width: number, collapsed: boolean): void; +} diff --git a/src/plugins/code/code.tsx b/src/plugins/code/code.tsx index 542d90ef..46aae004 100644 --- a/src/plugins/code/code.tsx +++ b/src/plugins/code/code.tsx @@ -433,7 +433,7 @@ class SourceCodeRenderer extends React.Component< return ( <> -