Remove left indent for tab-bar for non-Mac targets and when in full screen (#128)

This adds a new global atom to track whether a window is in full screen.
It also updates the behavior of the tab bar so that it will only add an
extra left indent on macOS windows that are not in full screen.
Otherwise, the indent will be much smaller.
This commit is contained in:
Evan Simkowitz 2024-07-22 13:33:10 -07:00 committed by GitHub
parent 27266fc912
commit 0fbb42863c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 72 additions and 32 deletions

View File

@ -15,7 +15,7 @@ import { debounce } from "throttle-debounce";
import * as util from "util";
import winston from "winston";
import * as services from "../frontend/app/store/services";
import { WSServerEndpointVarName, WebServerEndpointVarName, getWebServerEndpoint } from "../frontend/util/endpoints";
import { getWebServerEndpoint, WebServerEndpointVarName, WSServerEndpointVarName } from "../frontend/util/endpoints";
import * as keyutil from "../frontend/util/keyutil";
import { fireAndForget } from "../frontend/util/util";
@ -35,7 +35,7 @@ const waveSrvReady: Promise<boolean> = new Promise((resolve, _) => {
let globalIsQuitting = false;
let globalIsStarting = true;
const isDev = !electron.app.isPackaged;
const isDev = !electronApp.isPackaged;
const isDevVite = isDev && process.env.ELECTRON_RENDERER_URL;
if (isDev) {
process.env[WaveDevVarName] = "1";
@ -183,7 +183,7 @@ function runWaveSrv(): Promise<boolean> {
const addrs = /ws:([a-z0-9.:]+) web:([a-z0-9.:]+)/gm.exec(line);
if (addrs == null) {
console.log("error parsing WAVESRV-ESTART line", line);
electron.app.quit();
electronApp.quit();
return;
}
process.env[WSServerEndpointVarName] = addrs[1];
@ -352,6 +352,12 @@ function createBrowserWindow(clientId: string, waveWindow: WaveWindow): WaveBrow
console.log("focus", waveWindow.oid);
services.ClientService.FocusWindow(waveWindow.oid);
});
win.on("enter-full-screen", async () => {
win.webContents.send("fullscreen-change", true);
});
win.on("leave-full-screen", async () => {
win.webContents.send("fullscreen-change", false);
});
win.on("close", (e) => {
if (globalIsQuitting) {
return;
@ -390,7 +396,7 @@ function isWindowFullyVisible(bounds: electron.Rectangle): boolean {
const displays = electron.screen.getAllDisplays();
// Helper function to check if a point is inside any display
function isPointInDisplay(x, y) {
function isPointInDisplay(x: number, y: number) {
for (const display of displays) {
const { x: dx, y: dy, width, height } = display.bounds;
if (x >= dx && x < dx + width && y >= dy && y < dy + height) {
@ -620,25 +626,25 @@ function makeAppMenu() {
electron.Menu.setApplicationMenu(menu);
}
electron.app.on("window-all-closed", () => {
electronApp.on("window-all-closed", () => {
if (unamePlatform !== "darwin") {
electron.app.quit();
electronApp.quit();
}
});
electron.app.on("before-quit", () => {
electronApp.on("before-quit", () => {
globalIsQuitting = true;
});
process.on("SIGINT", () => {
console.log("Caught SIGINT, shutting down");
electron.app.quit();
electronApp.quit();
});
process.on("SIGHUP", () => {
console.log("Caught SIGHUP, shutting down");
electron.app.quit();
electronApp.quit();
});
process.on("SIGTERM", () => {
console.log("Caught SIGTERM, shutting down");
electron.app.quit();
electronApp.quit();
});
let caughtException = false;
process.on("uncaughtException", (error) => {
@ -648,7 +654,7 @@ process.on("uncaughtException", (error) => {
logger.error("Uncaught Exception, shutting down: ", error);
caughtException = true;
// Optionally, handle cleanup or exit the app
electron.app.quit();
electronApp.quit();
});
// ====== AUTO-UPDATER ====== //

View File

@ -8,7 +8,7 @@ contextBridge.exposeInMainWorld("api", {
getCursorPoint: () => ipcRenderer.sendSync("getCursorPoint"),
openNewWindow: () => ipcRenderer.send("openNewWindow"),
showContextMenu: (menu, position) => ipcRenderer.send("contextmenu-show", menu, position),
onContextMenuClick: (callback) => ipcRenderer.on("contextmenu-click", callback),
onContextMenuClick: (callback) => ipcRenderer.on("contextmenu-click", (_event, id) => callback(id)),
downloadFile: (filePath) => ipcRenderer.send("download", { filePath }),
openExternal: (url) => {
if (url && typeof url === "string") {
@ -18,6 +18,8 @@ contextBridge.exposeInMainWorld("api", {
}
},
getEnv: (varName) => ipcRenderer.sendSync("getEnv", varName),
onFullScreenChange: (callback) =>
ipcRenderer.on("fullscreen-change", (_event, isFullScreen) => callback(isFullScreen)),
});
// Custom event for "new-window"

View File

@ -4,7 +4,7 @@
import { Workspace } from "@/app/workspace/workspace";
import { getLayoutStateAtomForTab, globalLayoutTransformsMap } from "@/faraday/lib/layoutAtom";
import { ContextMenuModel } from "@/store/contextmenu";
import { WOS, atoms, globalStore, setBlockFocus } from "@/store/global";
import { PLATFORM, WOS, atoms, globalStore, setBlockFocus } from "@/store/global";
import * as services from "@/store/services";
import * as keyutil from "@/util/keyutil";
import * as layoututil from "@/util/layoututil";
@ -15,6 +15,7 @@ import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import { CenteredDiv } from "./element/quickelems";
import clsx from "clsx";
import "overlayscrollbars/overlayscrollbars.css";
import "./app.less";
import "./term.less";
@ -96,7 +97,7 @@ function switchTab(offset: number) {
services.ObjectService.SetActiveTab(newActiveTabId);
}
var transformRegexp = /translate3d\(\s*([0-9.]+)px\s*,\s*([0-9.]+)px,\s*0\)/;
const transformRegexp = /translate3d\(\s*([0-9.]+)px\s*,\s*([0-9.]+)px,\s*0\)/;
function parseFloatFromCSS(s: string | number): number {
if (typeof s == "number") {
@ -247,8 +248,10 @@ const AppInner = () => {
document.removeEventListener("keydown", staticKeyDownHandler);
};
}, []);
const isFullScreen = jotai.useAtomValue(atoms.isFullScreen);
return (
<div className="mainapp" onContextMenu={handleContextMenu}>
<div className={clsx("mainapp", PLATFORM, { fullscreen: isFullScreen })} onContextMenu={handleContextMenu}>
<DndProvider backend={HTML5Backend}>
<Workspace />
</DndProvider>

View File

@ -49,6 +49,16 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
return uiContext;
}) as jotai.Atom<UIContext>;
const isFullScreenAtom = jotai.atom(false) as jotai.PrimitiveAtom<boolean>;
try {
getApi().onFullScreenChange((isFullScreen) => {
console.log("fullscreen change", isFullScreen);
globalStore.set(isFullScreenAtom, isFullScreen);
});
} catch (_) {
// do nothing
}
const clientAtom: jotai.Atom<Client> = jotai.atom((get) => {
const clientId = get(clientIdAtom);
if (clientId == null) {
@ -99,6 +109,7 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
tabAtom: tabAtom,
activeTabId: activeTabIdAtom,
userInput: userInputAtom,
isFullScreen: isFullScreenAtom,
};
}

View File

@ -44,7 +44,7 @@
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform: translate3d(-50%, -50%, 0);
user-select: none;
z-index: 3;
font-size: 11px;
@ -63,7 +63,7 @@
position: absolute;
top: 50%;
right: 0px;
transform: translateY(-50%);
transform: translate3d(0, -50%, 0);
width: 20px;
height: 20px;
display: flex;

View File

@ -1,15 +1,31 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
.tab-bar-wrapper {
--default-indent: 10px;
--darwin-not-fullscreen-indent: 74px;
}
.darwin:not(.fullscreen) .tab-bar-wrapper {
.tab-bar {
margin-left: var(--darwin-not-fullscreen-indent);
}
.window-drag.left {
width: var(--darwin-not-fullscreen-indent);
}
}
.tab-bar-wrapper {
position: relative;
// border-bottom: 1px solid var(--border-color);
user-select: none;
display: flex;
flex-direction: row;
.tab-bar {
position: relative; // Needed for absolute positioning of child tabs
margin-left: 100px;
margin-left: var(--default-indent);
height: 33px;
// 36 is the width of add tab button
// 100 is offset from the left, for macOS window controls and dragging
@ -19,10 +35,9 @@
}
.add-tab-btn {
width: 36px;
width: 22px;
height: 100%;
cursor: pointer;
position: absolute;
font-size: 14px;
text-align: center;
user-select: none;
@ -36,6 +51,8 @@
}
i {
overflow: hidden;
margin-top: 5px;
font-size: 11px;
}
}
@ -43,10 +60,6 @@
.window-drag {
position: absolute;
height: 100%;
&.left {
width: 100px;
}
}
// Customize scrollbar styles

View File

@ -69,6 +69,8 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => {
const windowData = useAtomValue(atoms.waveWindow);
const { activetabid } = windowData;
const isFullScreen = useAtomValue(atoms.isFullScreen);
let prevDelta: number;
let prevDragDirection: string;
@ -145,7 +147,7 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => {
tabRefs.current.forEach((ref, index) => {
if (ref.current) {
ref.current.style.width = `${newTabWidth}px`;
ref.current.style.transform = `translateX(${index * newTabWidth}px)`;
ref.current.style.transform = `translate3d(${index * newTabWidth}px,0,0)`;
}
});
@ -173,9 +175,9 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => {
const lastTabRect = lastTabRef.current.getBoundingClientRect();
addButton.style.position = "absolute";
if (newScrollable) {
addButton.style.transform = `translateX(${tabBarRect.left + tabBarWidth + 1}px)`;
addButton.style.transform = `translate3d(${tabBarRect.left + tabBarWidth + 1}px,0,0)`;
} else {
addButton.style.transform = `translateX(${lastTabRect.right + 1}px)`;
addButton.style.transform = `translate3d(${lastTabRect.right + 1}px,0,0)`;
}
}
// Update dragger right position if needed
@ -183,12 +185,12 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => {
if (draggerRight && addButton) {
const addButtonRect = addButton.getBoundingClientRect();
const targetPos = addButtonRect.left + addButtonRect.width;
draggerRight.style.transform = `translateX(${targetPos}px)`;
draggerRight.style.transform = `translate3d(${targetPos}px,0,0)`;
draggerRight.style.width = `${document.documentElement.offsetWidth - targetPos}px`;
}
debouncedUpdateTabPositions();
}, [tabIds]);
}, [tabIds, isFullScreen]);
useEffect(() => {
window.addEventListener("resize", () => handleResizeTabs());
@ -324,7 +326,7 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => {
currentX = Math.min(Math.max(currentX, minLeft), maxRight);
}
ref.current!.style.transform = `translateX(${currentX}px)`;
ref.current!.style.transform = `translate3d(${currentX}px,0,0)`;
ref.current!.style.zIndex = "100";
const tabIndex = draggingTabDataRef.current.tabIndex;
@ -350,7 +352,7 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => {
tabIds.forEach((localTabId, index) => {
const ref = tabRefs.current.find((ref) => ref.current.dataset.tabId === localTabId);
if (ref.current && localTabId !== tabId) {
ref.current.style.transform = `translateX(${index * tabWidth}px)`;
ref.current.style.transform = `translate3d(${index * tabWidth}px,0,0)`;
ref.current.classList.add("animate");
}
});
@ -369,7 +371,7 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => {
const ref = tabRefs.current.find((ref) => ref.current.dataset.tabId === draggingTab);
if (ref.current) {
ref.current.classList.add("animate");
ref.current.style.transform = `translateX(${finalLeftPosition}px)`;
ref.current.style.transform = `translate3d(${finalLeftPosition}px,0,0)`;
}
if (dragged) {

View File

@ -16,6 +16,7 @@ declare global {
tabAtom: jotai.Atom<Tab>; // driven from WOS
activeTabId: jotai.Atom<string>; // derrived from windowDataAtom
userInput: jotai.PrimitiveAtom<Array<UserInputRequest>>;
isFullScreen: jotai.PrimitiveAtom<boolean>;
};
type TabLayoutData = {
@ -41,6 +42,7 @@ declare global {
onIframeNavigate: (callback: (url: string) => void) => void;
downloadFile: (path: string) => void;
openExternal: (url: string) => void;
onFullScreenChange: (callback: (isFullScreen: boolean) => void) => void;
};
type ElectronContextMenuItem = {

View File

@ -28,6 +28,7 @@ loadFonts();
(window as any).WOS = WOS;
(window as any).globalStore = globalStore;
(window as any).WshServer = WshServer;
(window as any).isFullScreen = false;
document.title = `The Next Wave (${windowId.substring(0, 8)})`;