feat: narrow-window behavior — sidebar auto-close, chrome wrap, 640px floor

The sidebar no longer squeezes the page when the window narrows; the
page itself never goes below a comfortable floor (owner decisions,
2026-09-17: 640px min, widen-window on toggle, auto-restore):

- minWidth 640 / minHeight 600 on the BrowserWindow (macOS enforces)
- Below SIDEBAR_AUTOCLOSE (928 = 640 + 288 sidebar) the sidebar
  auto-closes, and auto-RESTORES when the window widens past it again —
  both fall out of one expression: rendered = pref && !narrow, where
  pref is the persisted user choice. Manual closes persist and stay
  closed; auto-close never touches the preference.
- Opening the sidebar while narrow asks the shell to widen the window
  to 928 first (new lh:expand-window IPC, preload.cjs contextBridge —
  the renderer's first and only Electron bridge): the toggle is never a
  dead button, and the layout never has to survive narrow + sidebar.
  In the plain browser there is no suppression and no widening — a
  narrow tab opens the sidebar if the user says so.
- Graph chrome row wraps: max-w-[calc(100%-9rem)] + flex-wrap keeps the
  row clear of the header toggle cluster and stacks it onto extra lines
  below ~640px instead of overflowing left.

State machine verified in the Electron dev shell across all six
transitions (auto-close, auto-restore, manual-close-persists,
reopen-widens, browser fallback, wrap at 640/500/360).
This commit is contained in:
amosblomqvist
2026-09-17 18:57:02 +03:00
parent a20e1f1fb5
commit d46c3dae93
4 changed files with 105 additions and 6 deletions
+17
View File
@@ -0,0 +1,17 @@
/*
* Preload (2026-09-17, narrow-window wave): the ONLY bridge between the
* sandboxed renderer and the main process. contextIsolation + sandbox are
* on (electron/main.cjs), so this file is the renderer's entire access to
* Electron — keep it a minimal, explicit API surface.
*
* window.lh.expandWindow() — widen the window to the sidebar auto-close
* threshold (928px) when the sidebar is opened below it. The main
* process clamps: no-op if the window is already wide enough.
*
* Channel names are mirrored in electron/main.cjs — keep them in sync.
*/
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("lh", {
expandWindow: () => ipcRenderer.send("lh:expand-window"),
});