Make w7-flat actually flatten; document this round
The status bar's transfers summary is a text toggle, but 7.css painted it as a full Aero push button — a stray bordered slab sitting in the status line. Marked it w7-flat, the per-button escape hatch that existed for exactly this and had never been used. It did not work, for a reason worth keeping: 7.css restates border-color at `.win7 button:not(:disabled):not(:hover)` = (0,3,1), which outranks `.win7 .w7-flat` = (0,2,0). The .w7-toolbar arm of the same rule only ever won that fight by tying on specificity and landing later in the same layer — an accident w7-flat did not share. Split the rule: `background: revert-layer` stays in `skin` (it must land on `utilities`), and the paint-suppression literals move to `skinfix`, where layer order settles it instead of a specificity arms race. Docs updated in the same change per the working agreement — architecture.md gains the tabs contract, the w7-flat/w7-toolbar split and the frame transparency invariant; gotchas.md gains a win7-skin section (unlayered beats every layer, the (0,3,1) border-color restatement, overflow-x clipping the y-axis, 7.css's hardcoded light literals, exact selectors) plus the two Angular traps this round hit: a duplicate `class` attribute is silently dropped, and a backtick inside a component template's HTML comment terminates the TS template literal. Also recorded the verification trap that cost three wrong readings today: `bun run start` leaves the old instance running and `import -window` grabs the OLDEST match, so screenshots silently come from a stale build — this is what made the w7-flat fix above look like a no-op when it was already correct. Kill and count instances before capturing. And `pkill -f 'electrobun dev'` matches the shell running it and kills your own command. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+31
-2
@@ -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 `<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.
|
||||
|
||||
**Context menu**: pure 7.css via its real menu contract —
|
||||
`ul[role=menu] > li[role=menuitem] > button` for actions,
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
<!-- transfers summary; click toggles the detailed list -->
|
||||
<!-- w7-flat: this is a text toggle, not a push button. Without it 7.css
|
||||
paints the full Aero slab and the status line reads as a stray
|
||||
bordered button sitting in the status bar. -->
|
||||
<button
|
||||
(click)="transfers.expanded.set(!transfers.expanded())"
|
||||
class="flex min-w-0 items-center gap-1.5 hover:text-foreground"
|
||||
class="w7-flat flex min-w-0 items-center gap-1.5 hover:text-foreground"
|
||||
[title]="i18n.t('transfer.showDetails')"
|
||||
>
|
||||
@if (transfers.currentJob(); as job) {
|
||||
|
||||
+20
-3
@@ -678,12 +678,17 @@ html.win7 body {
|
||||
so without the exemption this rule would strip the border, gradient and
|
||||
both pseudo-elements off every tab and leave 7.css's tab component drawing
|
||||
nothing. Tabs want the full Aero slab; the +/Connections/options buttons
|
||||
beside them want the flat treatment. */
|
||||
beside them want the flat treatment.
|
||||
Only `background` stays here — it is the one property that needs to land
|
||||
on `utilities` via revert-layer. The literals that suppress the Aero slab
|
||||
moved to `skinfix`, because 7.css restates border-color at
|
||||
`.win7 button:not(:disabled):not(:hover)` = (0,3,1), which outranks
|
||||
`.win7 .w7-flat` = (0,2,0). The toolbar arm only ever won that fight by
|
||||
tying on specificity and landing later in the same layer — an accident,
|
||||
and one w7-flat did not share: it rendered a bordered slab regardless. */
|
||||
.win7 .w7-toolbar button:not([role='tab']),
|
||||
.win7 .w7-flat {
|
||||
background: revert-layer;
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
.win7 .w7-toolbar button:not([role='tab'])::before,
|
||||
.win7 .w7-toolbar button:not([role='tab'])::after,
|
||||
@@ -853,6 +858,18 @@ html.win7 body {
|
||||
color: var(--w7-mn-check-c);
|
||||
}
|
||||
|
||||
/* ---- Flat buttons (toolbars + the w7-flat escape hatch) ----
|
||||
The paint-suppression half of the rule in `skin` (see there for the split).
|
||||
It lives in `skinfix` because 7.css restates border-color at (0,3,1) via
|
||||
`.win7 button:not(:disabled):not(:hover)` and again on :hover, which no
|
||||
reasonable `.w7-flat` selector outranks — layer order settles it instead
|
||||
of a specificity arms race. */
|
||||
.win7 .w7-toolbar button:not([role='tab']),
|
||||
.win7 .w7-flat {
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* ---- Tabs (workspace strip) ----
|
||||
7.css owns the tab CHROME; these restore the tab CONTENT layout it breaks.
|
||||
`menu[role=tablist] button` sets `display: block` at (0,2,1), which
|
||||
|
||||
Reference in New Issue
Block a user