From 5ed029a2b89247fd7cd9100d3120a692fe0dc230 Mon Sep 17 00:00:00 2001 From: Jokin Date: Sun, 16 Aug 2026 21:04:09 +0200 Subject: [PATCH] Flatten the selection and the menu highlight; kill the Aero afterglow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things looked wrong, three different causes. The selected row carried a border. 7.css outlines tr.highlighted (#aaddfa) on top of its fill, and we had been restating that outline in the new blue — so the band had an edge, and on the cursor row the dotted focus rect made three concentric outlines around a single row. The reserved 1px border stays (it is what stops selection from shifting rows) but is transparent in every state; the fill paints under it, since background-clip is border-box. --w7-sel-bd and --w7-sel-bd-idle are gone with it. The context menu highlighted items with 7.css's translucent gradient wash — the same gradient the ListView selection just dropped. It now uses --w7-sel-bg, so selection reads identically wherever it appears. The hover-off animation was button.css bleeding into menu items, which ARE buttons: button::before is a glow overlay that fades out over a full second, and menu.css suppresses it with content:none on the :hover arm ONLY — so leaving an item brought the pseudo back with opacity animating 1 -> 0, a ghost trailing the pointer. Killing content in every state removes it. Same family, also fixed: button:focus runs pulse-anim infinitely, and this menu moves real focus between items for keyboard nav. menu-probe.ts now checks the highlight too, using hover-probe's :hover -> .simhover rewrite: it measures colour spread down a text-free strip of a force-hovered item, so "is it flat?" is a measurement. Verified the check can fail by injecting the old wash into the built stylesheet — spread 9, exit 2; the flat fill reads spread 0 at exactly #cbe8f6. The harness lost its selection outlines and nothing else, in both themes. Co-Authored-By: Claude --- docs/architecture.md | 27 ++++++---- docs/gotchas.md | 14 +++++ scripts/menu-probe.ts | 90 ++++++++++++++++++++++++++++++-- ui/dev/harness.html | 5 +- ui/src/app/skins/7like/7like.css | 62 ++++++++++++++++------ 5 files changed, 167 insertions(+), 31 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index ce37b9a..309ad4f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -429,12 +429,17 @@ zeroed); the frame reads the state off its own child with 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/-bd` = `#cbe8f6`/`#26a0da`), not 7.css's `--w7-el-grad-h` — that -var is its Aero element-hover ramp and stays reserved for buttons and tabs, -which still want the gloss. The unfocused pane gets `--w7-sel-bg-idle/-bd-idle`, -Explorer's grey inactive selection; the band never disappears with focus, only -weakens (the commander convention above). All four are dark-overridden in BOTH -dark blocks. +(`--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, @@ -446,9 +451,13 @@ 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 -one structural override: `.w7-ctx` restores `position: fixed`, which 7.css's own -`position: relative` on `ul[role=menu]` had been silently winning (see -gotchas.md; `scripts/menu-probe.ts` is the regression test). +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 diff --git a/docs/gotchas.md b/docs/gotchas.md index d7c1c44..0dd9958 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -176,6 +176,20 @@ touching the adjacent code. 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 diff --git a/scripts/menu-probe.ts b/scripts/menu-probe.ts index 1b533c7..8ac9571 100644 --- a/scripts/menu-probe.ts +++ b/scripts/menu-probe.ts @@ -1,4 +1,4 @@ -// Programmatic POSITIONING test for the win7 context menu. +// Programmatic POSITIONING + HIGHLIGHT test for the win7 context menu. // // bun scripts/menu-probe.ts // @@ -16,6 +16,16 @@ // i.e. the bug verbatim. That one must stay invisible — if it ever shows up, // 7.css stopped forcing `relative` and this probe's premise is stale. // +// It also checks the item HIGHLIGHT, using hover-probe.ts's trick (`:hover` +// rewritten to a `.simhover` class, since headless Firefox has no pointer): +// 7.css paints hovered items with a translucent gradient wash, and this app +// wants one flat colour. A gradient is detectable as vertical colour spread +// down a text-free strip of the item, so "is it flat?" is a measurement, not +// an opinion. What canNOT be measured here is the 1s afterglow fade — a +// temporal effect — but its cause is structural (`button::before` still has +// `content`), and this probe would show the glow's colour if the pseudo ever +// came back. +// // Inherits shot.ts's constraints: dedicated Firefox profile (a running Firefox // holds the default profile's lock), and the page must be written INTO the // dist folder or strict_origin_policy silently unstyles it. @@ -35,6 +45,12 @@ if (!existsSync(DIST)) fail(`no build output at ${DIST} — run: bun run build:u const styles = readdirSync(DIST).find((f) => f.startsWith("styles-") && f.endsWith(".css")); if (!styles) fail(`no styles-*.css in ${DIST} — run: bun run build:ui`); +// Hover as a CLASS: same rewrite hover-probe.ts uses, for the same reason — +// `--screenshot` has no pointer. `:hover` has no partial-token hazard. +const css = await Bun.file(path.join(DIST, styles)).text(); +const PROBE_CSS = "_menu-probe.css"; +await Bun.write(path.join(DIST, PROBE_CSS), css.replaceAll(":hover", ".simhover")); + // ---- the probe page ---- // Geometry (CSS px = image px; headless Firefox applies no DPR scaling). @@ -51,7 +67,7 @@ const menu = (x: number, marker: boolean) => `