Navbar identity dropdown renders translucent in dark mode (IdentityMenu) - needs fix + systemic popover guard #405
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub#405
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Navbar identity dropdown renders translucent in dark mode (IdentityMenu)
What's requested
The navbar account dropdown (
IdentityMenu) opens a panel that is translucent in dark mode — page text scrolls visibly through it. Fix IdentityMenu AND add a systemic guard so no popover/dropdown can ever ship with a translucent panel background again.Evidence (root cause)
web/src/components/IdentityMenu.jsx:119— the menu panel isclass="card absolute right-0 z-50 mt-1 grid max-h-96 w-52 …".web/src/ui.css:26— the shared.cardutility resolves tobg-white dark:bg-zinc-900/70— the dark-mode background is 70% alpha, translucent by design.web/src/ui.css:165-171— the repo already solved this for every other popover: a "Floating popovers" rule (from issues #37/#115, extended by #278) forcesbg-white dark:bg-zinc-900on an enumerated class list:.clone-body, .ref-drop, .tasks-drop, .notif-drop, .reaction-drop, .label-drop, .milestone-drop, .close-drop, .tag-drop.IdentityMenu's dropdown carries none of those classes (the component predates none — it simply was never added to the sweep, consistent with the #390 restyle touching only the trigger). So the only background it gets is
.card'szinc-900/70, and page content bleeds through in dark mode. Every other absolute.cardpanel in the tree (RefPicker, TasksOverlay, NotificationTray, ReactionMenu, LabelPicker, MilestonePicker, close menu, tag menu, clone box) carries one of the enumerated classes; IdentityMenu is the sole offender.Architecture notes
absolute/fixed-positioned.card(or a single.popover/.dropclass applied in the shared panel recipe) and delete the enumeration.web/test/unit/, same harness asweb/test/unit/identity-nav.test.js) that readsweb/src/components/*.jsx+web/src/pages/*.jsxand fails when acardclass string containsabsoluteorfixedwithout one of the opaque classes present — the same static-assert style the repo already uses in unit tests.Acceptance criteria
.cardpanel ships translucent.makeweb test target used by CI).Fix PR: #408 (branch fix/issue-405). Chose guard option 1 (structural default
.card.absolute/.card.fixedopaque) PLUS a static test pinning it (safest combination). IdentityMenu fixed with zero JSX churn; all 9 legacy popovers subsumed (still present, still floating .cards). Tests: targeted 39/39 green; full suite delta is exactly +4 new passing (13 pre-existing failures on main unchanged); vite build green with the opaque rule in compiled CSS. No new deps; doc decision appended (law 12). Not merging per instructions — ready for review.REVIEW PR #408 (fix/issue-405) — verified in scratch worktrees, main worktree untouched. No browser (node tests + compiled-CSS reasoning, per instructions).
(1) IdentityMenu fixed, zero JSX churn — PASS. web/src/components/IdentityMenu.jsx:119 panel is
card absolute right-0 z-50 ...; file untouched by the diff.card absolutematches the new.card.absoluteselector, so it now renders opaque dark zinc-900 instead of .card's zinc-900/70.(2) Structural rule correct — PASS. web/src/ui.css:178
.card.absolute, .card.fixed { @apply bg-white dark:bg-zinc-900; }is (0,2,0) vs .card's (0,1,0): wins regardless of order. Compiled CSS (vite build in scratch) confirms:.card.absolute,.card.fixed{background-color:var(--color-white)}and:is(.card.absolute,.card.fixed):where(.dark,.dark *){background-color:var(--color-zinc-900)}(fully opaque, no alpha) vs .card's darkcolor-mix(...70%...). Utilities-layer caveat is real (a bg-*/70 utility on the element would beat the components-layer rule) and guard test 3 (TRANSLUCENT_BG scan) covers exactly that.(3) All 9 legacy popovers subsumed — PASS. Exhaustive grep finds 13 literal floating .card class strings (all absolute, zero fixed): clone-body, ref-drop x3, tasks-drop, tag-drop, reaction-drop, notif-drop, milestone-drop, label-drop x2, close-drop, + IdentityMenu. The deleted enumeration carried ONLY the opacity @apply (viewport max-width rule below still enumerates the hooks incl. .tray, untouched), so nothing else relied on the deleted block. Test 4 pins each hook still on a floating .card.
(4) Guard tests — PASS. popover-opaque.test.js: proven the structural-rule regex FAILS against origin/main's old enumeration CSS (guard catches regression); translucent-utility test, IdentityMenu pin, and legacy-presence test all pass (targeted popover-opaque + popover-viewport + identity-nav = 39/39). Milestone pin update in popover-viewport.test.js is faithful (same intent, asserts structural coverage + floating .card).
(5) No missed absolute/fixed .card — PASS. Only dynamic card class in the tree is pages/Notifications.jsx:137 (non-floating list row, no absolute/fixed) — correctly out of scope.
(6) Compiled CSS contains the rule — PASS (see (2)).
(7) No new deps; docs accurate — PASS. Diff touches only ui.css + 2 test files + docs/go/12_web_ui.md decision entry (law 12). Test imports are node stdlib only. Law 1/7/8 clean.
(8) Full suite — PASS with one stale-description note. Branch: 809 tests / 807 pass / 2 fail; pristine origin/main: 805 / 803 / 2 fail — identical failing files (smoke.test.js x2, need a live server; unrelated paths), delta is exactly the +4 new passing tests. The PR description's '13 failures' is stale (main has moved on since; HEAD
b2dbf8d) — actual state is strictly better, no action needed.No fixes required; nothing pushed. MERGE RECOMMENDATION: ready to merge.
Fixed by PR #408 (review clean — structural rule + guard proven, all popovers subsumed, compiled CSS verified), merged. Closing.