Remove the Windows 7 (7.css) skin
The win7 skin is dropped. Everything else the branch built stays: Linux support and the HTML context menus, the workspace-tab menu, the continuous interface scale (rem everywhere, stepper, Ctrl/Cmd +/-/0) and the core/ service layer. The modern tree already carried all of them, and nothing outside skins/7like/ imported the win7 tree except main.ts and styles.css. Removed: the skins/7like/ tree (5.1k lines, fonts), the 7.css dependency, the skin setting and its options row + strings in all 7 locales, the frameless-window plumbing (window-control RPCs, windowState push, trackMaximizeState, the synthesized resize grip and its postinstall watchdog), the session-skin pinning in buildPreload/chromeOptions, the skin/skinfix cascade layers, and the win7-only probes and screenshot harness (the harness cannot render the modern tree: plain Firefox has no RPC bridge). chromeOptions() stays as the one shared frame decision. Fixed on the way out: - index.html's per-theme pre-paint background is restored. The branch had replaced it with a win7-only transparent rule, so modern dark windows had silently lost one of the three flash guards. - editor-windows.ts wrote its window-key separator as a literal NUL byte, which made git and grep treat the file as binary; it is `\0` now (same string at runtime). No settings migration: a stale "skin" key is carried harmlessly by the store's spread-merge and dropped on the next save. UI bundle: 616.7 kB -> 405.4 kB, back under the 500 kB budget. Docs: architecture, gotchas and platform-notes lose the win7 material but keep what stays true (construction-time preloads/frames, drag regions ignoring preventDefault, electrobun's missing resize/maximize primitives); flash-prevention, dev-URL and Bun-panic notes move back under Electrobun; stale context-menu/tab-bar links fixed; README documents the scale keys. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+30
-234
@@ -44,17 +44,15 @@ no-op functions, reassigned in `src/bun/index.ts` after everything exists:
|
||||
## Window kinds
|
||||
|
||||
`src/bun/windows.ts` — `buildPreload(mode, settings, ctx?)` injects
|
||||
`__APP_PLATFORM`, `__APP_MODE` (`main|editor|manager`), `__APP_SKIN`
|
||||
(`modern|win7`), `__APP_CTX` before any page script. `ui/src/main.ts` selects on
|
||||
BOTH axes: the skin picks a component tree, `APP_MODE` picks a root within it
|
||||
(see "UI layout" below). All roots use selector `app-root` (index.html hosts
|
||||
only that tag). Both globals are preload-baked because both are needed before
|
||||
first paint — settings arrive over an async RPC, far too late to choose a tree
|
||||
without flashing the wrong UI. `chromeOptions(skin)` is the ONLY place the
|
||||
native frame is decided: win7 is frameless + transparent everywhere, modern
|
||||
keeps the native titlebar (macOS `hiddenInset` + `trafficLightOffset
|
||||
{x:12,y:13}`, where the shadlike tree renders an `h-10 pl-24` drag-region header
|
||||
via `IS_MAC_CHROME`).
|
||||
`__APP_PLATFORM`, `__APP_MODE` (`main|editor|manager`), `__APP_CTX` before any
|
||||
page script, plus the persisted theme attributes and interface scale so the
|
||||
first paint is already right. `ui/src/main.ts` picks the root component from
|
||||
`APP_MODE`; all three roots use selector `app-root` (index.html hosts only that
|
||||
tag). `chromeOptions()` is the ONLY place the native frame is decided, spread by
|
||||
the main window and `openSecondaryWindow`: macOS `hiddenInset` +
|
||||
`trafficLightOffset {x:12,y:13}` (the UI renders an `h-10 pl-24` drag-region
|
||||
header via `IS_MAC_CHROME`); other platforms keep the native titlebar and a
|
||||
compact `h-9` non-drag header.
|
||||
|
||||
`WindowRegistry<Rec>` (same file): keyed window map with dedupe/activate,
|
||||
cascade placement off an anchor frame, focus tracking. electrobun's emitter
|
||||
@@ -62,7 +60,7 @@ has **no `off()`** — `track()` closures capture only `(this, key)` so closed
|
||||
records can be garbage collected. A future "window follows window" grouping
|
||||
belongs here (`anchor.on('move')` + `setPosition`).
|
||||
|
||||
### Editor windows (`src/bun/editor-windows.ts` + `ui/src/app/skins/*/editor-window/`)
|
||||
### Editor windows (`src/bun/editor-windows.ts` + `ui/src/app/skins/shadlike/editor-window/`)
|
||||
|
||||
One window per file, key `sessionId+path` (sessionId, not fsKey: saves route
|
||||
through a concrete session, and `local` is one shared session anyway).
|
||||
@@ -171,39 +169,23 @@ would float over editor windows).
|
||||
rpc; manager/editors constructed after win; quit guard; focus tracking for
|
||||
notification suppression across all windows).
|
||||
|
||||
## UI layout: one core, two skin trees
|
||||
## UI layout
|
||||
|
||||
```
|
||||
ui/src/app/
|
||||
core/ app.config.ts, icons.ts, platform.ts, format.ts, file-icons.ts,
|
||||
and all 12 *.service.ts — everything skin-agnostic
|
||||
skins/
|
||||
shadlike/ the modern (shadcn-style) tree + shadlike.css
|
||||
7like/ the Windows 7 tree + 7like.css + fonts/ + title-bar/
|
||||
core/ app.config.ts, icons.ts, platform.ts, format.ts, file-icons.ts,
|
||||
metrics.ts and every *.service.ts — the non-visual layer
|
||||
skins/shadlike/ the component tree: three window roots (SHAD_ROOTS barrel,
|
||||
picked by main.ts), dialogs, context menu
|
||||
```
|
||||
|
||||
Each skin owns a **complete** component tree, including its own three window
|
||||
roots, and exports a barrel (`SHAD_ROOTS` / `SEVEN_ROOTS`) with the same
|
||||
`{ main, manager, editor }` shape. `main.ts` therefore knows nothing about
|
||||
either tree's internals: `APP_SKIN` picks the barrel, `APP_MODE` picks the root.
|
||||
Both trees are imported statically into one bundle — the inactive skin costs
|
||||
bundle size but no runtime work, which keeps bootstrap synchronous.
|
||||
Components reach `core/` through the **`@core/*`** tsconfig alias (alongside
|
||||
`@shared/*` → `src/shared`), which is deliberate: components sit at varying
|
||||
depths and an alias keeps their imports identical wherever a file moves. Do not
|
||||
replace it with relative paths.
|
||||
|
||||
Duplicate selectors across trees (`app-file-panel` exists in both) are safe:
|
||||
standalone components resolve through their importer's `imports:` array, never
|
||||
a global registry, and the two trees are never mounted together.
|
||||
|
||||
Only `7like` has a `title-bar/`. The modern skin defers to the native frame,
|
||||
which is exactly what `IS_MAC_CHROME` accounts for.
|
||||
|
||||
**Why this split was cheap**: the service layer was already skin-agnostic —
|
||||
`git diff main...feat/7css-skin` touched none of it. Components reach it through
|
||||
the **`@core/*`** tsconfig alias (alongside `@shared/*` → `src/shared`), which
|
||||
is deliberate: skin components sit at varying depths and an alias keeps their
|
||||
imports identical wherever a file moves. Do not replace it with relative paths.
|
||||
|
||||
**Where a new rule goes**: shared behaviour → `core/`; markup and appearance for
|
||||
one look → that skin's folder; tokens both skins consume → `ui/src/styles.css`.
|
||||
**Where a new rule goes**: behaviour → `core/`; markup and appearance → the
|
||||
component; tokens → `ui/src/styles.css`.
|
||||
|
||||
## UI services (`ui/src/app/core/`)
|
||||
|
||||
@@ -235,8 +217,8 @@ one look → that skin's folder; tokens both skins consume → `ui/src/styles.cs
|
||||
enqueue and runs the collision flow (same-path auto-skip, type-mismatch
|
||||
skip, overwrite dialog with all/none batch modes).
|
||||
- `settings.service.ts` — one signal per setting; **imperative apply pattern**
|
||||
(`applyTheme/DarkTone/Accent/TextSize` set `data-*` attributes on
|
||||
`<html>`); `applyAll` also serves the `settingsChanged` broadcast so editor
|
||||
(`applyTheme/DarkTone/Accent` set `data-*` attributes on `<html>`;
|
||||
`applyUiScale` sets its inline `font-size`); `applyAll` also serves the `settingsChanged` broadcast so editor
|
||||
and manager windows restyle live (they render no settings UI, so no
|
||||
persist echo). New setting = five touches here + types.ts (backend merges
|
||||
automatically).
|
||||
@@ -256,7 +238,7 @@ one look → that skin's folder; tokens both skins consume → `ui/src/styles.cs
|
||||
boot and on the `settingsChanged` broadcast (so editor/manager windows follow).
|
||||
- `file-actions.service.ts` — toolbar/keyboard/context-menu file ops, always
|
||||
against an explicit panel; `menuTarget` remembers the right-clicked row.
|
||||
- `context-menu.service.ts` + `context-menu.ts` — the panel and tab right-click
|
||||
- `context-menu.service.ts` + `skins/shadlike/context-menu.ts` — the panel and tab right-click
|
||||
menus, in HTML. Electrobun's native `showContextMenu` is a no-op on Linux, so it was
|
||||
retired on ALL platforms rather than kept as a second code path (see
|
||||
platform-notes.md). The service builds the item list (row / empty-space menu,
|
||||
@@ -274,11 +256,10 @@ one look → that skin's folder; tokens both skins consume → `ui/src/styles.cs
|
||||
`disconnectWorkspace`. **The target id travels inside the action string**: the
|
||||
right-clicked tab is not necessarily the active one, so nothing on that path
|
||||
may fall back to `activeWorkspaceId`. Illegal entries are `disabled`, not
|
||||
omitted — Win7 greys out, and a menu whose items move between right-clicks is
|
||||
worse than one with a dead row. 7.css hangs that state on
|
||||
`li[role=menuitem][aria-disabled]` (opacity + `pointer-events: none`), which
|
||||
the keyboard path never consults — so `pick()` and the arrow-key walker check
|
||||
the flag themselves, in both skins.
|
||||
omitted — a menu whose items move between right-clicks is worse than one with
|
||||
a dead row. The disabled styling (`pointer-events: none`) only stops the
|
||||
pointer; the keyboard path never consults it — so `pick()` and the arrow-key
|
||||
walker check the flag themselves.
|
||||
- `file-icons.ts` — extension → category map driving glyphs, colors
|
||||
(fixed `--icon-*` tokens, never accent-tinted) and the Kind column.
|
||||
- `platform.ts` — preload-global readers (`PLATFORM`, `APP_MODE`,
|
||||
@@ -319,194 +300,9 @@ toolbars deliberately stay on `--background`. Accent tones: one
|
||||
pixel-identical to the old neutral hover. **Interface scale** (`settings.uiScale`,
|
||||
0.5–4 in 0.1 steps): one root font-size lever — `applyUiScale` sets
|
||||
`html { font-size: 16px * scale }`, and since EVERY size in the app is rem
|
||||
(panel tokens like `--row-h`, all Tailwind utilities, ng-icon sizes, `--w7-fs`
|
||||
and the 7.css bridge in 7like.css), both skins scale whole, chrome included.
|
||||
(panel tokens like `--row-h`, all Tailwind utilities, ng-icon sizes), the
|
||||
whole UI scales, chrome included.
|
||||
Driven by the tab-bar stepper, Ctrl/Cmd +/−/0, and preload-baked for a
|
||||
flash-free first paint. It replaced the 3-tier `data-text` axis; the store
|
||||
migrates old `textSize` values. TS that measures rem-sized CSS converts through
|
||||
`@core/metrics` `remPx()` — never an assumed 16.
|
||||
|
||||
### Skins (`settings.skin`: `modern | win7`)
|
||||
|
||||
A fifth theming axis, and the only one that is a **class** (`.win7` on
|
||||
`<html>`) rather than a `data-*` attribute — `7.css/dist/7.scoped.css` is
|
||||
precompiled against a literal `.win7`, so the name is not ours to pick.
|
||||
Default `modern` = class absent, matching the delete-when-default rule.
|
||||
`buildPreload` is the **only** writer of that class, ever — there is
|
||||
deliberately no `SettingsService.applySkin`.
|
||||
|
||||
**Unlike the other four axes, this one is launch-time only.** It selects a
|
||||
whole component tree (see "UI layout") as well as CSS, and neither half can
|
||||
change on a live window: the tree is bootstrapped once from the preload-baked
|
||||
`__APP_SKIN`, and `titleBarStyle`/`transparent` are `BrowserWindow` constructor
|
||||
options with no setters. Clicking a skin therefore only persists it; the
|
||||
options row shows the saved value as pending (`skinPending()` compares
|
||||
`settings.skin()` against `APP_SKIN`) and the running UI is untouched until the
|
||||
next app start.
|
||||
|
||||
The bun side pins this: `initSessionSkin` freezes the skin at startup, before
|
||||
any window exists, and both `buildPreload` and `chromeOptions` read that pinned
|
||||
value rather than the live settings snapshot. Otherwise an editor or manager
|
||||
opened after a pending change would boot the *new* tree and frame while the
|
||||
main window still ran the old one.
|
||||
|
||||
**Stylesheet split.** `ui/src/styles.css` holds only what BOTH skins consume —
|
||||
the `@layer` statement, the Tailwind import, OKLCH tokens, `@theme inline`,
|
||||
panel-chrome tokens, animations, the accent axis, and the `html, body` base. Each
|
||||
skin's own rules live in its folder (`skins/7like/7like.css`,
|
||||
`skins/shadlike/shadlike.css`) and are `@import`ed from there. `shadlike.css` is
|
||||
near-empty by nature: that skin IS the shared token system plus inline Tailwind.
|
||||
Two constraints: the `@layer` statement must stay the FIRST statement in
|
||||
`styles.css` (it is one of only two rule types allowed above `@import`), and
|
||||
`@font-face` `url()`s resolve relative to the file that declares them — which is
|
||||
why 7like's Noto Sans lives at `skins/7like/fonts/`, inside the skin.
|
||||
|
||||
**Cascade** (`ui/src/styles.css` first lines + `skins/7like/7like.css`): the
|
||||
explicit `@layer theme, base, components, utilities, skin, skinfix;` statement
|
||||
precedes every import. 7.css is imported with `layer(skin)`, i.e. **above
|
||||
`utilities`**,
|
||||
so a bare `button` rule in 7.css outranks `rounded-md` on that same button —
|
||||
that inversion is what reskins ~1900 inline utility classes with no template
|
||||
edits. Consequences: (1) any utility later added to a `button`/`input`/
|
||||
`select`/`textarea`/`table` silently loses under the skin; (2) neutralizers
|
||||
that want the Tailwind value back must sit **inside `@layer skin`**, not
|
||||
`skinfix` — `revert-layer` rolls back one layer, so from `skin` it lands on
|
||||
`utilities`, but from `skinfix` it lands back on 7.css and does nothing.
|
||||
`skinfix` is for rules that state an explicit value (`.w7-btn`).
|
||||
|
||||
**Token bridge** (`skins/7like/7like.css`): `:root.win7` re-points the existing
|
||||
semantic tokens at Win7 values, so utilities Tailwind still controls come out
|
||||
right too. It adds NO new tokens on purpose — a new colour would need another
|
||||
`@theme inline` line. The Win7 surface ramp **inverts** the modern one:
|
||||
`--background` (content panes) is Explorer white and `--chrome` is the darker
|
||||
`#f0f0f0` window surface. `--radius: 5px` so `rounded-md`
|
||||
(`calc(--radius - 2px)`, 74 uses) lands exactly on 7.css's 3px `--w7-el-bdr`.
|
||||
`--primary`/`--ring` are deliberately left alone so the accent axis stays live;
|
||||
`:root.win7[data-accent]` feeds it to `--w7-w-bg`, which is authentic (Win7
|
||||
shipped "Window Color"). Dark Win7 is hand-authored (Microsoft never shipped
|
||||
one) as ~20 `--w7-*` overrides, duplicated forced + system like every other
|
||||
dark block. `--w7-font` is restated as a rem `font` shorthand so the interface
|
||||
scale reaches it and 7.css's `pt` shorthand stops resetting weight/line-height;
|
||||
the rest of 7.css's px metrics are re-expressed in rem by the scale bridge in
|
||||
7like.css's `skinfix`.
|
||||
|
||||
**Markup hooks**: `role="progressbar"` (+aria) on the transfer bars,
|
||||
`has-scrollbar` on scroll containers (7.css only styles `::-webkit-scrollbar`
|
||||
under that class), `w7-toolbar` on every command row — the three window header
|
||||
rows plus each file panel's session strip and path bar (their buttons go flat
|
||||
with a hover glow — Explorer's command bar was flat, unlike dialog push
|
||||
buttons; it only targets `button`, so the path `<input>` keeps its 7.css
|
||||
textbox treatment), `w7-flat`
|
||||
as the per-button escape hatch for the same treatment outside a toolbar (the
|
||||
status-bar transfers summary is a text toggle, not a push button), `w7-btn`
|
||||
on the 10 dialog action buttons. The flat treatment is split across two
|
||||
layers on purpose: `background: revert-layer` must sit in `skin` to reach
|
||||
`utilities`, while `border-color`/`box-shadow` sit in `skinfix` because 7.css
|
||||
restates `border-color` at (0,3,1) and no sane `.w7-flat` selector outranks
|
||||
that.
|
||||
|
||||
**Tabs**: the workspace strip is 7.css's real tab component —
|
||||
`menu[role=tablist]` + one `button[role=tab][aria-selected]` per workspace, so
|
||||
the framework draws the joined inactive tabs and the raised active one. The
|
||||
selector is a DESCENDANT (`menu[role=tablist] button`), so the `+` button, the
|
||||
update pill and the right-hand tools deliberately sit outside the `<menu>`.
|
||||
Tabs are exempted from the `w7-toolbar` flattening via `:not([role='tab'])` —
|
||||
they want the full Aero slab their neighbours are stripped of. There is no
|
||||
per-tab ✕ (Win7 tab controls had none, and a nested button is invalid HTML):
|
||||
closing is `Ctrl/Cmd+W` or middle-click. `role="tabpanel"` on the panel area
|
||||
was considered and rejected — its `padding: 14px`, `margin-bottom: 9px` and
|
||||
border fight the split-pane layout for a join that cannot read anyway with the
|
||||
panel toolbar row in between.
|
||||
|
||||
**Frame transparency**: the rounded frame only reads as rounded because
|
||||
nothing paints an opaque full-bleed ground behind it. That is not free —
|
||||
`html, body` paint `var(--background)` **unlayered**, which beats every
|
||||
`@layer`, so `.win7` resets them to transparent in an equally unlayered rule
|
||||
next to the `font-family` one. A maximized window drops the radius (7.css
|
||||
declares it three times: `.window`, `::before`, `::after` — all three must be
|
||||
zeroed); the frame reads the state off its own child with
|
||||
`:has(> .title-bar.is-maximized)`, which `title-bar.ts` publishes from its
|
||||
existing `maximized` signal rather than subscribing to `windowState` twice.
|
||||
|
||||
**Selection band**: the file list's selected row is a FLAT Win7-Explorer blue
|
||||
(`--w7-sel-bg`, `#cbe8f6`) with **no border** — not 7.css's `--w7-el-grad-h`,
|
||||
which is its Aero element-hover ramp and stays reserved for buttons and tabs
|
||||
that still want the gloss, and not its `#aaddfa` row outline, which stacked a
|
||||
second edge inside the fill and, with the cursor row's dotted rect, drew three
|
||||
concentric outlines on one row. Every row still reserves `border: 1px solid
|
||||
transparent` for geometry; the fill paints under it (`background-clip`
|
||||
defaults to `border-box`). The unfocused pane gets `--w7-sel-bg-idle`,
|
||||
Explorer's grey inactive selection — the band never disappears with focus,
|
||||
only weakens (the commander convention above). Both are dark-overridden in
|
||||
BOTH dark blocks. The context menu's item highlight uses the same
|
||||
`--w7-sel-bg`, so selection reads identically wherever it appears.
|
||||
|
||||
**Context menu**: pure 7.css via its real menu contract —
|
||||
`ul[role=menu] > li[role=menuitem] > button` for actions,
|
||||
`input[type=checkbox] + label` for the checkable column toggles, dividers as
|
||||
`.has-divider` on the PRECEDING item (an `::after` bevel, not a node). The
|
||||
contract is exact: an earlier iteration rendered `div > button`, matched
|
||||
nothing, and wrongly concluded "7.css has no menu component" — it has a full
|
||||
one (`dist/gui/menu.css`), including the gutter stripe, disabled state and
|
||||
submenu arrows. Keyboard moves REAL focus between items (7.css styles
|
||||
`:focus-visible` like `:hover`); Enter/Space activate buttons natively. Only
|
||||
menu.css's hardcoded light literals are restated for dark, in `skinfix` — plus
|
||||
three overrides keyed on the app's own `w7-ctx` marker: `position: fixed`
|
||||
(7.css's `position: relative` on `ul[role=menu]` had been silently winning),
|
||||
the flat `--w7-sel-bg` highlight in place of its gradient wash, and
|
||||
`content: none` on the item buttons' pseudo-elements, which kills both the
|
||||
1s Aero afterglow and the infinite `pulse-anim` on a focused item (see
|
||||
gotchas.md). `scripts/menu-probe.ts` regression-tests placement AND highlight
|
||||
flatness, each with a control that proves the check can fail.
|
||||
|
||||
**Font**: Segoe UI is absent off Windows and not redistributable. Noto Sans —
|
||||
the substitute 7.css itself names — is vendored (OFL-1.1, from
|
||||
`@fontsource/noto-sans`) into `ui/src/fonts/`; under `src/` and not `public/`
|
||||
so esbuild emits it hashed into `media/` and rewrites the `url()`.
|
||||
|
||||
**Window chrome**: `chromeOptions(skin)` in `src/bun/windows.ts` is the single
|
||||
place either skin's frame is decided, spread by both the main window and
|
||||
`openSecondaryWindow`. `win7` uses `titleBarStyle: "hidden"` on **every**
|
||||
platform — that clears `Titled` from the Cocoa style mask, which is also the
|
||||
only way to remove the macOS traffic lights. **Linux honours it too**: the GTK
|
||||
wrapper calls `gtk_window_set_decorated(false)` and logs "GTK: Created window
|
||||
without decorations (custom titlebar)" (verified on GNOME/Wayland), so the
|
||||
frameless Aero chrome is not a mac/win-only feature. The webview then draws the whole
|
||||
frame via `ui/src/app/skins/7like/title-bar/title-bar.ts` (7.css's `.title-bar` >
|
||||
`.title-bar-text` + `.title-bar-controls`, buttons keyed by `aria-label`),
|
||||
mounted by all three of that skin's window roots. Because `titleBarStyle` is
|
||||
fixed at construction, **a skin change only reaches the frame on the next app
|
||||
start** — and nothing about the skin flips live, deliberately. `IS_WIN7_CHROME` in
|
||||
`platform.ts` reads the preload-baked `__APP_SKIN` (settings resolve too late
|
||||
for layout) and forces `IS_MAC_CHROME` false, since there are no traffic
|
||||
lights to reserve `pl-24` for.
|
||||
|
||||
**Window resize (STOPGAP)**: undecorating the window also removes the WM's
|
||||
resize borders, and electrobun 1.18.1 has no native resize gesture — so
|
||||
`skins/7like/window-resize/` synthesizes one: a bottom-right grip drags the
|
||||
frame through `windowGetFrame`/`windowSetFrame` → `BrowserWindow.setFrame`.
|
||||
Mounted by all three win7 roots, hidden while maximized by a CSS `:has()` rule
|
||||
(no second `windowState` subscription), and the grip carries
|
||||
`electrobun-webkit-app-region-no-drag` or the drag region would move the window
|
||||
instead. **One corner, not eight handles**: the handles are invisible and paint
|
||||
above the frame, so a north strip or top corner overlays the caption buttons and
|
||||
steals their `:hover`, which reads as the Aero glow flickering on those buttons.
|
||||
The bottom-right corner is the only one that overlaps nothing (it sits in the
|
||||
6px gutter `.window-body`'s margin leaves). The frame math is a dependency-free module so
|
||||
`scripts/resize-math-probe.ts` can assert all eight edges without a window.
|
||||
**This is meant to be deleted**: the component header carries the removal
|
||||
checklist and `scripts/check-electrobun-resize.ts` (wired into `postinstall`)
|
||||
prints it when upstream ships the primitive. See platform-notes.md.
|
||||
|
||||
**Window controls**: new `windowMinimize` / `windowToggleMaximize` /
|
||||
`windowClose` / `windowIsMaximized` requests, built by
|
||||
`windowControlHandlers(getWindow, onClose?)` in `rpc-handlers.ts` and served by
|
||||
all three window kinds (each passing a late-bound getter for its own window —
|
||||
the window takes the rpc in its constructor, same reason `events` is
|
||||
late-bound). `onClose` is overridden per window kind so the X reuses the
|
||||
existing close path: editors run their dirty prompt, the manager runs
|
||||
`managerClose`, main falls through to the cancellable `before-quit` guard.
|
||||
electrobun emits **no maximize event**, so `trackMaximizeState` derives it from
|
||||
`resize` + the synchronous `isMaximized()` and pushes `windowState` — which
|
||||
also covers Aero Snap and Win+Up. Double-click-to-maximize is likewise absent
|
||||
from electrobun's drag regions and is implemented in the title-bar component.
|
||||
|
||||
Reference in New Issue
Block a user