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:
+60
-228
@@ -28,17 +28,6 @@ touching the adjacent code.
|
||||
- Tailwind v4 canonical class names: `wrap-break-word` not `break-words`,
|
||||
`accent-primary` not `accent-[var(--primary)]`, `z-60` not `z-[60]`.
|
||||
Every color used in a template must resolve through `@theme inline`.
|
||||
- **The win7 skin layer outranks Tailwind utilities.** 7.css is imported
|
||||
`layer(skin)`, ordered above `utilities`, so any utility you add to a
|
||||
`button`/`input`/`select`/`textarea`/`table` is silently dead under that
|
||||
skin. If it matters, neutralize in the `@layer skin` block in
|
||||
`app/skins/7like/7like.css` — and note `revert-layer` only reaches
|
||||
`utilities` from **inside `skin`**; used from `skinfix` it falls back onto
|
||||
7.css and is a no-op. This bit once already.
|
||||
- `@import … layer(name)` works through `@tailwindcss/postcss` (it wraps the
|
||||
imported AST), but the **deep path is mandatory**: 7.css ships no `exports`
|
||||
map and Tailwind's resolver reads only `style`/`mainFields`, so a bare
|
||||
`@import "7.css"` resolves to nothing. Use `7.css/dist/7.scoped.css`.
|
||||
- Stylesheet `url()` must resolve at BUILD time: assets referenced from
|
||||
`styles.css` live under `ui/src/` (esbuild emits them hashed into `media/`
|
||||
and rewrites the url), NOT `ui/public/` — a public path fails the build with
|
||||
@@ -53,6 +42,18 @@ touching the adjacent code.
|
||||
- **A component `template:` is a TS template literal, so no backticks inside
|
||||
it** — not even in an HTML comment. A backtick in a comment terminates the
|
||||
literal and the errors point at the prose, not at the quoting.
|
||||
- **Reach `core/` through the `@core/*` alias, never a relative path.**
|
||||
Components sit at varying depths and get moved; the alias is what let 67
|
||||
imports survive two relocations untouched. A `../../core/...` path is a
|
||||
future merge conflict.
|
||||
- **The build DOES type-check components nothing imports.** ngtsc compiles the
|
||||
whole program, so an unreferenced component still fails `bun run build:ui` on
|
||||
a type or template error (verified by injecting an error into an
|
||||
unreferenced file).
|
||||
- **`overflow-x: auto` also clips vertically.** CSS refuses to pair `visible`
|
||||
with a non-visible axis, so the computed `overflow-y` becomes `auto` too:
|
||||
anything poking out of a horizontally scrolling strip (a raised tab, an
|
||||
underline at `-bottom-px`) is silently clipped. Reserve padding instead.
|
||||
|
||||
## The interface scale (root font-size lever)
|
||||
|
||||
@@ -66,137 +67,16 @@ touching the adjacent code.
|
||||
JSDoc's "(WebKit only)" means macOS WKWebView. This is why the scale is CSS.
|
||||
- **Everything the UI sizes with must be rem.** The scale works by setting the
|
||||
root font-size, so a px value freezes while everything around it grows. The
|
||||
three px reservoirs were: the panel-chrome tokens (`--row-h` etc.), 93
|
||||
`text-[11px]` arbitraries, and 7.css itself — 370 px values, zero rem, with
|
||||
`--w7-font` reaching only 15 rules' typography. 7like.css's `skinfix` carries
|
||||
a scale bridge re-expressing 7.css's vars and hardcoded box metrics in rem.
|
||||
1px hairlines and focus rects stay px deliberately (crisp at any scale; the
|
||||
`tr` border exists to stop selection shifting rows).
|
||||
- **Restating a 7.css rule in `skinfix` also outranks 7.css's VARIANTS of that
|
||||
rule — by layer, regardless of specificity.** The title-bar-controls
|
||||
restatement silently shrank the close button from 48px to 29px (7.css widens
|
||||
it via `button[aria-label=Close]`), and the tablist padding flattened the
|
||||
active tab's 4px raise. Caught only by the harness pixel diff. When bridging
|
||||
a rule, grep 7.scoped.css for every variant that overrides the same
|
||||
properties and restate those too.
|
||||
px reservoirs were the panel-chrome tokens (`--row-h` etc.) and 93
|
||||
`text-[11px]` arbitraries. 1px hairlines and focus rects stay px deliberately
|
||||
(crisp at any scale).
|
||||
- **px constants in TS that mirror rem-sized CSS are latent scale bugs.** The
|
||||
shadlike context menu's `MENU_W = 224` was a hardcoded mirror of `w-56`
|
||||
context menu's `MENU_W = 224` was a hardcoded mirror of `w-56`
|
||||
(14rem): box grew, math didn't, flip fired at the wrong edge. Convert through
|
||||
`@core/metrics` `remPx()` at use time — it reads the LIVE root font-size,
|
||||
and per call, since the scale changes mid-session. The editor's canvas-based
|
||||
`charWidth` is cached keyed on the computed font string for the same reason.
|
||||
|
||||
## Hover states and the frame edge
|
||||
|
||||
- **A child's box-shadow is NOT clipped by its parent's border or radius.** The
|
||||
close button's hover glow (7.css: `0 0 7px 3px #e68e75` on a `::before`)
|
||||
painted across the window's top border and onto the desktop beyond it — the
|
||||
caption buttons sit flush against the top edge (`border-top: 0`), and the
|
||||
frame's rounded transparent corners clip nothing. Fixed with
|
||||
`clip-path: inset(0 0 -1rem 0)` on `.w7-frame > .title-bar`: glow stops at
|
||||
the frame like the real DWM, bottom bleed (authentic) stays open. Note
|
||||
clip-path also clips hit-testing — safe here because the drag region is the
|
||||
title-bar's own box, entirely inside the clip.
|
||||
- **Hover states CAN be tested headlessly**: `scripts/hover-probe.ts` copies
|
||||
the built stylesheet with `:hover` rewritten to `.simhover`, renders the
|
||||
frame markup with the state forced, and pixel-scans artifact regions,
|
||||
exiting non-zero on hover-introduced red outside the frame. Firefox
|
||||
`--screenshot` has no pointer and `import -window` captures the real
|
||||
pointer's state, so the class rewrite is the only programmatic hover on this
|
||||
machine. Re-run it after touching title-bar or hover styling.
|
||||
|
||||
## The two skin trees (`ui/src/app/skins/`)
|
||||
|
||||
- **`.win7` is not a name we may change.** `7.scoped.css` is precompiled with
|
||||
every selector prefixed by that literal class, so the skin id in
|
||||
`AppSettings` stays `"win7"` even though its folder is `7like/`. The folder
|
||||
names are cosmetic; the class and the persisted setting value are not.
|
||||
- **Reach `core/` through the `@core/*` alias, never a relative path.** Skin
|
||||
components sit at varying depths and get moved; the alias is what let 67
|
||||
imports survive two relocations untouched. A `../../core/...` path is a
|
||||
future merge conflict.
|
||||
- **`@font-face` `url()` resolves relative to the file that declares it.** When
|
||||
the win7 rules moved three directories deeper, `./fonts/...` would silently
|
||||
have 404'd — build still green, app just renders a fallback font. The fonts
|
||||
therefore live inside the skin that uses them.
|
||||
- **The `@layer` statement must stay the first statement in `ui/src/styles.css`.**
|
||||
It is one of only two rule types allowed above `@import`, and it is what sorts
|
||||
`skin` above `utilities`. Every `@import` (Tailwind and both skin sheets) must
|
||||
also precede all other rules.
|
||||
- **Duplicate selectors across skins are safe.** `app-file-panel` exists in both
|
||||
trees; standalone components resolve through their importer's `imports:`
|
||||
array, never a global registry, and the trees are never mounted together.
|
||||
- **The build DOES type-check components nothing imports.** ngtsc compiles the
|
||||
whole program, so a skin that is currently unreachable still fails
|
||||
`bun run build:ui` on a type or template error. Verified deliberately by
|
||||
injecting an error into an unreferenced file — worth knowing before assuming
|
||||
a green build proves nothing about the inactive skin.
|
||||
|
||||
## The win7 skin (7.css)
|
||||
|
||||
- **Unlayered declarations beat every `@layer`, regardless of specificity.**
|
||||
`html, body { background: … }` in styles.css is unlayered, so no `skinfix`
|
||||
rule can override it — the win7 transparent-corner reset has to be unlayered
|
||||
too. The frame's rounded corners only read as rounded because nothing paints
|
||||
an opaque full-bleed ground behind them; anything that does fills the corners
|
||||
and the window becomes a rectangle with a curve drawn on it.
|
||||
- **7.css restates `border-color` at (0,3,1)** via
|
||||
`.win7 button:not(:disabled):not(:hover)` and its `:hover` twin. A two-class
|
||||
selector like `.win7 .w7-flat` (0,2,0) loses to it, so paint suppression for
|
||||
flat buttons lives in `skinfix` where layer order settles it. The
|
||||
`.w7-toolbar` arm only ever won by tying on specificity and landing later in
|
||||
the same layer — an accident `w7-flat` did not share, which is why it
|
||||
rendered a bordered slab while its neighbours went flat.
|
||||
- **`overflow-x: auto` also clips vertically.** CSS refuses to pair `visible`
|
||||
with a non-visible axis, so the computed `overflow-y` becomes `auto` too.
|
||||
7.css raises the active tab with `margin-top: -2px`; inside the horizontally
|
||||
scrolling tab strip that put its top border outside the scroll box and
|
||||
deleted it silently. The strip reserves `padding-top: 2px` to compensate —
|
||||
mirroring the `padding-left: 3px` 7.css already reserves for the same tab's
|
||||
`-3px` left margin.
|
||||
- **7.css hardcodes light-mode literals outside its own var system** —
|
||||
`color: #222` on tablist buttons, black/white bevels in the ListView and
|
||||
menu. Each one has to be routed through a `--w7-*` token declared in
|
||||
`:root.win7` and overridden in **both** dark blocks (the `[data-theme]`
|
||||
attribute one *and* the `prefers-color-scheme` one; system dark sets no
|
||||
attribute).
|
||||
- **The skin layer can also override `position`, and that breaks LAYOUT, not
|
||||
just paint.** `ul[role=menu]` carries `position: relative` in 7.css (for the
|
||||
gutter stripe's `::before` and submenu anchoring), which outranked Tailwind's
|
||||
`.fixed` on the app's own context menu. `[style.left/top.px]` then became
|
||||
*flow* offsets from the menu's static position — the last child of the
|
||||
`h-screen` frame — so every right-click menu rendered below the viewport,
|
||||
unreachable behind `overflow: hidden`. The backdrop is a plain `<div>`, which
|
||||
7.css does not match, so it stayed genuinely fixed and ate the next click:
|
||||
the symptom was "right-click does nothing, then the app ignores me once".
|
||||
Fixed with a `position: fixed` restatement in `skinfix`, scoped to a `w7-ctx`
|
||||
marker class so 7.css's own menus keep theirs. Regressed in `0ae2a62`, when
|
||||
the menu root became a real `ul[role=menu]` — i.e. adopting the framework's
|
||||
markup is what exposed it. **A resting pixel diff cannot catch this class of
|
||||
bug**: nothing about the idle window changes. `scripts/menu-probe.ts` renders
|
||||
the menu at declared coordinates and scans whether it landed there, with a
|
||||
marker-less control menu as its own discriminator.
|
||||
- **7.css's button effects reach anything that IS a button — including menu
|
||||
items — and one of them fades out over a FULL SECOND.** `button::before` is
|
||||
an Aero glow overlay with `opacity: 0`, raised to 1 on hover, and
|
||||
`button:not(:hover):before` carries `transition: opacity 1s linear`.
|
||||
menu.css suppresses it with `content: none` on the **`:hover` arm only**, so
|
||||
while an item is hovered nothing paints, but the moment the pointer leaves,
|
||||
the pseudo returns with opacity animating 1 → 0: a blue ghost trailing the
|
||||
cursor down the menu. Killing `content` in *every* state is the fix —
|
||||
suppressing the transition alone leaves a glow that simply snaps. Two more
|
||||
from the same family: `button:focus` runs `pulse-anim` *infinitely*
|
||||
(`1s ease infinite alternate`), which matters because the context menu moves
|
||||
REAL focus between items for keyboard nav, and the hover paint is 7.css's
|
||||
translucent gradient wash — the same one the ListView selection dropped.
|
||||
All three are overridden together, scoped to `w7-ctx`.
|
||||
- **Its selectors are exact, and a near-miss looks exactly like "7.css doesn't
|
||||
support this".** `menu[role=tablist] button` is a DESCENDANT selector, so
|
||||
every button inside the strip becomes a tab — the `+` and the right-hand
|
||||
tools must live outside it. `.window.glass > .title-bar` is direct-child, so
|
||||
an inner wrapper breaks the glass coupling. A wrong guess here already
|
||||
produced one hand-written lookalike that was deleted.
|
||||
|
||||
## Electrobun
|
||||
|
||||
- **Window `close` is not cancellable** (response type `{}`; only the
|
||||
@@ -221,9 +101,48 @@ touching the adjacent code.
|
||||
`dist/api/bun/proc/linux.md` says so; the app also prints "Application menus are
|
||||
not supported on Linux" at boot). Because the UI suppresses the webview's own
|
||||
right-click menu, that left EVERY panel context menu dead on Linux — no error,
|
||||
nothing happens. The menu is plain HTML now (`ui/src/app/skins/*/context-menu.ts`) on
|
||||
nothing happens. The menu is plain HTML now (`ui/src/app/skins/shadlike/context-menu.ts`) on
|
||||
every platform; don't reintroduce the native one for "nativeness" on mac/win
|
||||
without keeping a Linux path.
|
||||
- **Window-open flash prevention is three-layer** — remove any one and the
|
||||
white/inverted blink returns: (1) windows are created `hidden: true` and
|
||||
revealed by `showWhenReady` on the webview's first `dom-ready` (800 ms
|
||||
fallback), (2) the bun preload bakes the persisted `data-theme`/tone/accent
|
||||
attributes and the interface scale before first paint (`buildPreload`),
|
||||
(3) `ui/src/index.html` carries an inline `<style>` with the html background
|
||||
per theme — its oklch values MUST stay in sync with the `--background` tokens
|
||||
in styles.css. (The win7 branch once replaced (3) with a transparent rule and
|
||||
the modern skin silently lost it — the other two layers do not cover it.)
|
||||
- Dev vs prod URL: `getMainViewUrl()` resolves the ng-serve dev server only
|
||||
when `DEV_SERVER_URL` is set AND the updater channel is `dev` AND the
|
||||
server answers a HEAD request; secondary windows must reuse the resolved
|
||||
URL, never hardcode `views://`.
|
||||
- Upstream Bun panic (`FFI_Callback_threadsafe_call` → `web_worker.spin`):
|
||||
rare segfault under long sessions; upstream electrobun×Bun issue, restart
|
||||
recovers, nothing app-side to fix.
|
||||
- **Preloads and frames are construction-time only.** The preload is a
|
||||
persistent `WebKitUserScript` at DOCUMENT_START, frozen at webview
|
||||
construction — `webview.loadURL()` re-runs the OLD one
|
||||
(`updatePreloadScriptToWebView` is only reachable from electrobun's internal
|
||||
`<electrobun-webview>` handler). `titleBarStyle`/`transparent` have no
|
||||
setters. Anything `buildPreload` bakes is a first-paint snapshot the UI must
|
||||
correct live over RPC. Recreating the main window is not an escape hatch:
|
||||
`exitOnLastWindowClosed`, push closures and the tray capture it, and there
|
||||
is no `off()`.
|
||||
- **Drag regions ignore `preventDefault`.** The preload starts a window move
|
||||
from a bubble-phase `mousedown` on `document` and never reads
|
||||
`defaultPrevented`; a `pointerdown` handler doesn't stop it either (the
|
||||
compat `mousedown` still fires). `isAppRegionDrag` checks
|
||||
`.electrobun-webkit-app-region-no-drag` first — that class on the element is
|
||||
the only reliable suppressor (`dist/api/bun/preload/dragRegions.ts`).
|
||||
- **No resize, maximize-event or double-click-maximize primitives (1.18.1).**
|
||||
`titleBarStyle: "hidden"` drops the whole frame (Cocoa `Titled` — the only
|
||||
way to remove the traffic lights; `gtk_window_set_decorated(false)` on
|
||||
Linux) and with it the WM resize borders; nothing restores them (no
|
||||
`startWindowResize`, no `gtk_window_begin_resize_drag`, no
|
||||
`setResizable`/min-size options — only `setFrame`/`getFrame`). No maximize
|
||||
event exists (derive it from `resize` + `isMaximized()`), and drag regions
|
||||
don't double-click-maximize. A custom-chrome window has to build all three.
|
||||
|
||||
## Linux
|
||||
|
||||
@@ -266,100 +185,13 @@ touching the adjacent code.
|
||||
pattern appears in the killing command's OWN argv. Break the literal with a
|
||||
character class — `pkill -f 'dev-linux-x[6]4'` — the way `ps | grep [x]yz`
|
||||
has always worked.
|
||||
- **A frameless window cannot be resized, and `preventDefault` will not save
|
||||
you from the drag region.** Undecorating the GTK window (what
|
||||
`titleBarStyle: "hidden"` does) takes the WM's resize borders with it, and
|
||||
electrobun exposes no resize gesture — hence the synthesized grip in
|
||||
`ui/src/app/skins/7like/window-resize/` (a STOPGAP; that file carries the
|
||||
removal checklist, and `scripts/check-electrobun-resize.ts` fires from
|
||||
`postinstall` when upstream makes it deletable).
|
||||
**An invisible resize handle over a control steals that control's hover.** A
|
||||
full eight-handle set shipped briefly and was reverted: the north strip ran
|
||||
the whole width across the caption buttons and the north-east square sat on
|
||||
the close button's corner, so crossing one dropped the button's `:hover`
|
||||
mid-glow and looked like a rendering artifact in 7.css — nothing in the CSS
|
||||
was wrong. Only the bottom-right corner overlaps nothing (it lands in the 6px
|
||||
gutter `.window-body { margin: 0 6px 6px }` leaves). Any new handle must be
|
||||
checked against what sits under it; south/east/west are innocent, north and
|
||||
both top corners are not.
|
||||
Three more traps live in that code, all verified against
|
||||
`dist/api/bun/preload/dragRegions.ts`:
|
||||
- It starts a window **move** from a `mousedown` listener on `document`, in
|
||||
the **bubble** phase. It never reads `defaultPrevented`, so
|
||||
`event.preventDefault()` does **nothing** to stop it.
|
||||
- A `pointerdown` handler does not stop it either: the compatibility
|
||||
`mousedown` still fires afterwards, and stopping propagation on a *pointer*
|
||||
event has no effect on a *mouse* event. This is the trap that looks fixed
|
||||
in every test until the window jumps.
|
||||
- `isAppRegionDrag` checks `.electrobun-webkit-app-region-no-drag` **first**
|
||||
and short-circuits, so that class — on the handle itself — is the only
|
||||
reliable suppressor. Without it, every resize drag also drags the window.
|
||||
Also: deltas must come from `screenX/screenY`. North/west resizes move the
|
||||
window's origin, which moves the webview's client origin under a stationary
|
||||
pointer, so `clientX` feeds that movement back into the next delta and the
|
||||
window runs away. And the minimum-size clamp must re-anchor the opposite
|
||||
edge — clamping the width alone lets `x` keep tracking the pointer, walking
|
||||
the window off-screen while it looks frozen (`scripts/resize-math-probe.ts`
|
||||
asserts exactly that, and was verified to catch it).
|
||||
- **Prefer the headless probes over launching the app.** `bun run start` opens a
|
||||
real window that takes focus, which interrupts whatever the user is doing;
|
||||
there is no Xvfb/xvfb-run on this machine and Wayland offers no
|
||||
launch-without-focus. `scripts/shot.ts` (+ `--dark`), `hover-probe.ts` and
|
||||
`menu-probe.ts` all render through headless Firefox and open nothing. Launch
|
||||
the real app only for what Gecko genuinely cannot answer — WebKitGTK
|
||||
behaviour, the native frame, transparency, live RPC — ask first, and batch
|
||||
every live check into a single launch.
|
||||
- **X11 capture cannot answer "is this pixel transparent?"** for the frameless
|
||||
window. `import -window` grabs the window's own pixels with no compositing,
|
||||
so a transparent corner and an opaque black one both come out black;
|
||||
`png32:` just fills alpha with 1 and proves nothing. XWayland's root window
|
||||
is not the composited desktop, so `import -window root` fails too. Frame
|
||||
transparency and the maximized corners need a human looking at the screen —
|
||||
say so rather than reporting a screenshot as confirmation.
|
||||
- **Launching the app steals focus — ask first.** `bun run start` opens a real
|
||||
window that takes focus, which interrupts whatever the user is doing; there
|
||||
is no Xvfb/xvfb-run on this machine and Wayland offers no
|
||||
launch-without-focus. Batch every live check into a single launch.
|
||||
- Benign startup noise on Linux — non-fatal, the app runs normally:
|
||||
`libayatana-appindicator is deprecated. Please use libayatana-appindicator-glib`
|
||||
(upstream electrobun's choice, not ours).
|
||||
- **Window-open flash prevention is three-layer** — remove any one and the
|
||||
white/inverted blink returns: (1) windows are created `hidden: true` and
|
||||
revealed by `showWhenReady` on the webview's first `dom-ready` (800 ms
|
||||
fallback), (2) the bun preload bakes the persisted `data-theme`/tone/accent
|
||||
attributes before first paint (`buildPreload`), (3) `ui/src/index.html`
|
||||
carries an inline `<style>` with the html background per theme — its oklch
|
||||
values MUST stay in sync with the `--background` tokens in styles.css.
|
||||
The win7 skin adds a **fourth value to keep in sync**: `buildPreload` also
|
||||
bakes the `.win7` class, and index.html carries a matching `html.win7` arm
|
||||
for all four theme states. Miss it and every win7 window flashes white.
|
||||
- **The skin is a LAUNCH-TIME choice. Never apply one to a running window.**
|
||||
This shipped broken once: `SettingsService.applySkin` toggled the `.win7`
|
||||
class the moment the setting changed, which was harmless when there was one
|
||||
component tree and became a broken window as soon as there were two — 7.css
|
||||
painted onto shadlike markup that has no `.window.glass`, no `.title-bar`, no
|
||||
`menu[role=tablist]` and no `<table>` ListView. Each skin's CSS is written
|
||||
against its OWN tree's markup; the class must only ever be written by
|
||||
`buildPreload`, for the tree that window actually booted.
|
||||
- **A reload does not rescue it.** The preload is a persistent
|
||||
`WebKitUserScript` injected at DOCUMENT_START, so its string is frozen at
|
||||
webview construction — `webview.loadURL()` re-runs it with the OLD
|
||||
`__APP_SKIN`. (`updatePreloadScriptToWebView` exists in the FFI but is
|
||||
reachable only from electrobun's internal `<electrobun-webview>` handler.)
|
||||
- **`titleBarStyle`/`transparent` are construction-time only** — no setters
|
||||
exist, so a live window can never be re-framed. win7 → modern is the
|
||||
dangerous direction: the modern tree draws no title bar, so it would land
|
||||
in a frameless transparent window with no way to move, minimize or close.
|
||||
- Don't "fix" this by recreating the main window either: `exitOnLastWindowClosed`
|
||||
is true, the main `rpc` is captured by six push closures, the tray captures
|
||||
`win`, listeners cannot be removed (no `off()`) — and it would drop every
|
||||
session and tab.
|
||||
- Bun pins it: `initSessionSkin` freezes the skin before any window exists,
|
||||
and `buildPreload`/`chromeOptions` read that, never the live settings. Skip
|
||||
the pin and a window opened after a pending change boots the other skin.
|
||||
- Dev vs prod URL: `getMainViewUrl()` resolves the ng-serve dev server only
|
||||
when `DEV_SERVER_URL` is set AND the updater channel is `dev` AND the
|
||||
server answers a HEAD request; secondary windows must reuse the resolved
|
||||
URL, never hardcode `views://`.
|
||||
- Upstream Bun panic (`FFI_Callback_threadsafe_call` → `web_worker.spin`):
|
||||
rare segfault under long sessions; upstream electrobun×Bun issue, restart
|
||||
recovers, nothing app-side to fix.
|
||||
|
||||
## Domain logic
|
||||
|
||||
|
||||
Reference in New Issue
Block a user