diff --git a/docs/architecture.md b/docs/architecture.md index 8c71cfc..5aa8775 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -307,8 +307,37 @@ still scales and 7.css's `pt` shorthand stops resetting weight/line-height. **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 the three header rows (their buttons go -flat — Explorer's command bar was flat, unlike dialog push buttons), `w7-btn` -on the 10 dialog action buttons. +flat — Explorer's command bar was flat, unlike dialog push buttons), `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 ``. +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. **Context menu**: pure 7.css via its real menu contract — `ul[role=menu] > li[role=menuitem] > button` for actions, diff --git a/docs/gotchas.md b/docs/gotchas.md index 3214c51..1ebac3e 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -43,6 +43,51 @@ touching the adjacent code. `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 "Could not resolve". +- **Two `class` attributes on one element: the second is silently dropped.** + No warning, no build error — the layout classes simply never apply. This + collapsed the tab strip and two window headers at once (`fe028a9`), because + a scripted edit appended `class="…"` to elements that already had one. + When removing a conditional binding, check what the branch *contained*: the + bindings there were genuinely dead, but the layout classes inside them were + not, and nothing replaced them. +- **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. + +## 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). +- **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 @@ -100,6 +145,22 @@ touching the adjacent code. an explicit `WEBKIT_DISABLE_DMABUF_RENDERER` from the user always wins. - A "does it boot?" log check does NOT catch this — grep for the GBM line, or look at the window. +- **`bun run start` leaves the old instance running, and + `import -window miniSCP` grabs the OLDEST match.** Instances pile up across + rebuilds, so every screenshot silently comes from a stale build and the fix + you just made looks like it did nothing. Cost three wrong readings in one + session, including a "the CSS is in the bundle but does not apply" dead end. + Kill first (`pkill -f dev-linux-x64`), confirm with + `pgrep -cf 'dev-linux-x64/miniSCP-dev/bin/launcher'`, then launch and capture. + Note `pkill -f 'electrobun dev'` also matches the shell running it and kills + your own command (exit 144) — match on the build path instead. +- **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. - 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). diff --git a/ui/src/app/status-bar/status-bar.ts b/ui/src/app/status-bar/status-bar.ts index b7ca324..868bf19 100644 --- a/ui/src/app/status-bar/status-bar.ts +++ b/ui/src/app/status-bar/status-bar.ts @@ -15,9 +15,12 @@ import { TransfersService } from '../transfers.service'; class="flex h-6 items-center justify-between gap-4 border-t border-border bg-chrome px-3 text-[11px] text-muted-foreground select-none" > +