Avatar restyle: bare-circle navbar trigger (far right, light ring, still a dropdown) + large floating avatar on the profile page #390

Closed
opened 2026-09-12 16:13:44 +00:00 by crueber · 3 comments
Owner

What's requested

Restyle the navbar identity control (IdentityMenu, upper right) and the profile-page avatar:

Navbar:

  1. No container — the avatar should not sit inside the btn box it's in today; it should be a bare circle as the far-right icon in the header.
  2. Bigger than the current 20px inline image.
  3. A light highlight on the outside — a subtle ring/halo around the circle (not a filled button background) so it reads as interactive.
  4. Still clearly a dropdown — the affordance must survive the container removal: a small chevron/caret attached to the circle (outside or bottom-right of it), plus the existing hover highlight and aria-expanded. The screenshot's current state (avatar inside a button box) is what to move away from.

Profile page:
5. The avatar should be much bigger and very visible — floating right, positioned above the "New repository" button on the owner profile page, so it gets more space than the navbar can give.

Current implementation (code evidence)

  • web/src/components/IdentityMenu.jsx:75 — the trigger is class="btn max-w-32 truncate px-2 py-1" (a boxed button), avatar rendered inline at h-5 w-5 (:86), username fallback when no avatar. Dropdown popover at :94 (card absolute right-0 z-50 mt-1 w-52) with outside-click/Esc handling — that behavior stays untouched.
  • The control sits in the header's right cluster (web/src/App.jsx:101-105, #371) among the notification tray and theme toggle — it should become the far-right element.
  • Profile page: web/src/pages/Repos.jsx (/:owner, the #234 owner profile) — the "New repository" button and repo list; the avatar has no presence there today beyond possibly the #234 profile header (verify what /:owner renders now — the avatar floats right above the New-repo button per the request).
  • The avatar URL source is me().avatar_url (#376 dicebear, stable per-user).

Design details

  • Navbar trigger: drop the btn container entirely; render the avatar as a standalone circle (e.g. h-8 w-8 rounded-full) with a subtle ring — ring-1 ring-zinc-300 dark:ring-zinc-600 plus a hover ring emphasis (hover:ring-2 hover:ring-emerald-500/50 or similar, "lightly" per the request). When no avatar exists, the username-initials chip or username text stands in, same shape.
  • Dropdown affordance without a box: a small caret (▾) positioned at the circle's bottom-right or immediately beside it, sharing the hover state, + aria-expanded/aria-haspopup on the trigger (already present). The hover ring IS the primary "this is interactive" signal; the caret disambiguates "menu".
  • Far right: reorder the right cluster so the identity control is the last element (after the theme toggle and notification tray) — verify against #273's mobile-width constraints (the cluster still fits at 390px with the box removed, which frees width).
  • Profile page: avatar at a prominent size (e.g. h-24 w-24 / 96px class range), floated/aligned right above the New-repository button row, ring treatment matching the navbar. Confirm it doesn't collide with the #345 visibility badge or the description text at mobile widths (stacks below on narrow screens).
  • Behavior unchanged: menu items, keyboard support (Esc, focus return), outside-click close, busy/loading states — restyle only.

Acceptance criteria

  • Navbar avatar is a bare circle (no button container), far-right in the header, larger than today's 20px, with a light outer ring that emphasizes on hover.
  • The control still reads as a dropdown (caret/chevron affordance + hover state + aria-expanded); menu behavior unchanged (items, Esc, outside-click, focus return).
  • Username fallback (no avatar) renders in the same bare-circle/affordance style.
  • Profile page shows a large avatar (≥ 72px), floated right above the New-repository button, clearly visible, ring treatment consistent with the navbar.
  • No collision with the visibility badge, description, or New-repository button at desktop or 390px mobile widths (stacks cleanly on narrow screens).
  • Light/dark themes verified; the ring/hover treatment works in both.
  • Headless test updates for the IdentityMenu structure (trigger classes/affordance), per the existing test conventions.
## What's requested Restyle the navbar identity control (`IdentityMenu`, upper right) and the profile-page avatar: **Navbar:** 1. **No container** — the avatar should not sit inside the `btn` box it's in today; it should be a bare **circle** as the far-right icon in the header. 2. **Bigger** than the current 20px inline image. 3. **A light highlight on the outside** — a subtle ring/halo around the circle (not a filled button background) so it reads as interactive. 4. **Still clearly a dropdown** — the affordance must survive the container removal: a small chevron/caret attached to the circle (outside or bottom-right of it), plus the existing hover highlight and `aria-expanded`. The screenshot's current state (avatar inside a button box) is what to move away from. **Profile page:** 5. The avatar should be **much bigger and very visible** — floating right, positioned **above the "New repository" button** on the owner profile page, so it gets more space than the navbar can give. ## Current implementation (code evidence) - `web/src/components/IdentityMenu.jsx:75` — the trigger is `class="btn max-w-32 truncate px-2 py-1"` (a boxed button), avatar rendered inline at `h-5 w-5` (:86), username fallback when no avatar. Dropdown popover at :94 (`card absolute right-0 z-50 mt-1 w-52`) with outside-click/Esc handling — **that behavior stays untouched**. - The control sits in the header's right cluster (`web/src/App.jsx:101-105`, #371) among the notification tray and theme toggle — it should become the **far-right** element. - Profile page: `web/src/pages/Repos.jsx` (`/:owner`, the #234 owner profile) — the "New repository" button and repo list; the avatar has no presence there today beyond possibly the #234 profile header (verify what `/:owner` renders now — the avatar floats right above the New-repo button per the request). - The avatar URL source is `me().avatar_url` (#376 dicebear, stable per-user). ## Design details - **Navbar trigger:** drop the `btn` container entirely; render the avatar as a standalone circle (e.g. `h-8 w-8 rounded-full`) with a subtle ring — `ring-1 ring-zinc-300 dark:ring-zinc-600` plus a hover ring emphasis (`hover:ring-2 hover:ring-emerald-500/50` or similar, "lightly" per the request). When no avatar exists, the username-initials chip or username text stands in, same shape. - **Dropdown affordance without a box:** a small caret (`▾`) positioned at the circle's bottom-right or immediately beside it, sharing the hover state, + `aria-expanded`/`aria-haspopup` on the trigger (already present). The hover ring IS the primary "this is interactive" signal; the caret disambiguates "menu". - **Far right:** reorder the right cluster so the identity control is the last element (after the theme toggle and notification tray) — verify against #273's mobile-width constraints (the cluster still fits at 390px with the box removed, which frees width). - **Profile page:** avatar at a prominent size (e.g. `h-24 w-24` / 96px class range), floated/aligned right above the New-repository button row, ring treatment matching the navbar. Confirm it doesn't collide with the #345 visibility badge or the description text at mobile widths (stacks below on narrow screens). - **Behavior unchanged:** menu items, keyboard support (Esc, focus return), outside-click close, busy/loading states — restyle only. ## Acceptance criteria - [ ] Navbar avatar is a bare circle (no button container), far-right in the header, larger than today's 20px, with a light outer ring that emphasizes on hover. - [ ] The control still reads as a dropdown (caret/chevron affordance + hover state + `aria-expanded`); menu behavior unchanged (items, Esc, outside-click, focus return). - [ ] Username fallback (no avatar) renders in the same bare-circle/affordance style. - [ ] Profile page shows a large avatar (≥ 72px), floated right above the New-repository button, clearly visible, ring treatment consistent with the navbar. - [ ] No collision with the visibility badge, description, or New-repository button at desktop or 390px mobile widths (stacks cleanly on narrow screens). - [ ] Light/dark themes verified; the ring/hover treatment works in both. - [ ] Headless test updates for the IdentityMenu structure (trigger classes/affordance), per the existing test conventions.
crueber added this to the v1 milestone 2026-09-12 16:13:44 +00:00
Author
Owner

Fixed by PR #393 (#393) — bare-circle navbar trigger far-right + large profile avatar, restyle only.

Fixed by PR #393 (https://git.packden.us/crueber/walhub/pulls/393) — bare-circle navbar trigger far-right + large profile avatar, restyle only.
Author
Owner

Review of PR #393 (fix/issue-390 @ 6bda256), verified in scratch worktree + reasoning (no browser, per instructions).

ACCEPTANCE CRITERIA (issue #390, 7 items) — all met:

  1. Bare circle, far-right, bigger, light ring + hover: trigger drops the btn box for class='group flex ... rounded-full p-0.5' (IdentityMenu.jsx:83); avatar h-8 w-8 (32px, was h-5 w-5 20px) with ring-1 ring-zinc-300 dark:ring-zinc-600 + group-hover:ring-2 group-hover:ring-emerald-500/50. No 'btn' or 'h-5 w-5' leftovers (grepped). PASS
  2. Far-right order: App.jsx moves the showIdentity Show after NotificationTray + theme toggle (was before). Freed btn-box width supports the #273/390px-fit claim by reasoning. PASS
  3. Dropdown affordance, behavior identical: caret span (U+25BE) beside circle shares group-hover state; aria-haspopup='menu' (:86) + aria-expanded (:87) kept; popover div, Esc/outside-click/focus-return/arrow handlers untouched (diff is trigger-button-only). PASS
  4. Fallback: username-initials chip (username?.slice(0,1)) in h-8 w-8 rounded-full ring-1, same shape/size/ring, dark variants included. PASS
  5. Profile avatar: Repos.jsx own-row 'mb-3 flex justify-end' block above the title + New-repository row, h-24 w-24 (96px >= 72px) with matching ring-1 ring-zinc-300 dark:ring-zinc-600. Own block => no collision with title/#345 badges/description/button at desktop or 390px (stacks, reasoning). Orgs gated by !isOrg() — OrgAvatar size=36 title-row path untouched. PASS
  6. Small-inline removal clean: old width={36} inline img gone (grepped, absent); userSrc() still consumed by new block + pre-existing avatar manage row (:398 Regenerate/Remove, unrelated); OrgAvatar import/prop intact. Removal is genuinely in-scope (criterion 4 requires replacing it) and follows the pre-1.0 no-shim rule. PASS
  7. Tests: identity-nav.test.js 30/30 green incl. 5 new #390 tests (bare-circle, ring/hover, affordance, fallback, Repos large) + updated far-right + fallback-width tests. PASS

LAWS: L1 no new deps (5-file diff, no package.json/manifest touch; Tailwind utilities only); L7 n/a (no long work); L8 clean (view-only restyle inside web/, no seam/registry change); L12 D-WEB-8 entry warranted and accurate (dated, refs #390, restyle-only/no-deps rationale, matches code: h-8/h-24/ring/caret/far-right/orgs).

VERIFICATION: full node suite in scratch worktree — 769 pass, 2 fail, both smoke.test.js dist/server-dependent and byte-identical on pristine origin/main (764 pass + same 2 fails there; delta +5 = the new tests). identity-nav.test.js 30/30 exit 0. vite build exit 0 (589.99 kB / 170.29 kB gzip; chunk-size warning only, pre-existing shape). NOTE: something already listens on 127.0.0.1:8080 returning 401 to the smoke probes — left untouched per instructions; that is the smoke-failure source in this environment, unrelated to the PR. No browser run (reasoning + node tests, as instructed).

No fixes pushed — nothing broken. RECOMMENDATION: ready to merge.

Review of PR #393 (fix/issue-390 @ 6bda256), verified in scratch worktree + reasoning (no browser, per instructions). ACCEPTANCE CRITERIA (issue #390, 7 items) — all met: 1. Bare circle, far-right, bigger, light ring + hover: trigger drops the btn box for class='group flex ... rounded-full p-0.5' (IdentityMenu.jsx:83); avatar h-8 w-8 (32px, was h-5 w-5 20px) with ring-1 ring-zinc-300 dark:ring-zinc-600 + group-hover:ring-2 group-hover:ring-emerald-500/50. No 'btn' or 'h-5 w-5' leftovers (grepped). PASS 2. Far-right order: App.jsx moves the showIdentity Show after NotificationTray + theme toggle (was before). Freed btn-box width supports the #273/390px-fit claim by reasoning. PASS 3. Dropdown affordance, behavior identical: caret span (U+25BE) beside circle shares group-hover state; aria-haspopup='menu' (:86) + aria-expanded (:87) kept; popover div, Esc/outside-click/focus-return/arrow handlers untouched (diff is trigger-button-only). PASS 4. Fallback: username-initials chip (username?.slice(0,1)) in h-8 w-8 rounded-full ring-1, same shape/size/ring, dark variants included. PASS 5. Profile avatar: Repos.jsx own-row 'mb-3 flex justify-end' block above the title + New-repository row, h-24 w-24 (96px >= 72px) with matching ring-1 ring-zinc-300 dark:ring-zinc-600. Own block => no collision with title/#345 badges/description/button at desktop or 390px (stacks, reasoning). Orgs gated by !isOrg() — OrgAvatar size=36 title-row path untouched. PASS 6. Small-inline removal clean: old width={36} inline img gone (grepped, absent); userSrc() still consumed by new block + pre-existing avatar manage row (:398 Regenerate/Remove, unrelated); OrgAvatar import/prop intact. Removal is genuinely in-scope (criterion 4 requires replacing it) and follows the pre-1.0 no-shim rule. PASS 7. Tests: identity-nav.test.js 30/30 green incl. 5 new #390 tests (bare-circle, ring/hover, affordance, fallback, Repos large) + updated far-right + fallback-width tests. PASS LAWS: L1 no new deps (5-file diff, no package.json/manifest touch; Tailwind utilities only); L7 n/a (no long work); L8 clean (view-only restyle inside web/, no seam/registry change); L12 D-WEB-8 entry warranted and accurate (dated, refs #390, restyle-only/no-deps rationale, matches code: h-8/h-24/ring/caret/far-right/orgs). VERIFICATION: full node suite in scratch worktree — 769 pass, 2 fail, both smoke.test.js dist/server-dependent and byte-identical on pristine origin/main (764 pass + same 2 fails there; delta +5 = the new tests). identity-nav.test.js 30/30 exit 0. vite build exit 0 (589.99 kB / 170.29 kB gzip; chunk-size warning only, pre-existing shape). NOTE: something already listens on 127.0.0.1:8080 returning 401 to the smoke probes — left untouched per instructions; that is the smoke-failure source in this environment, unrelated to the PR. No browser run (reasoning + node tests, as instructed). No fixes pushed — nothing broken. RECOMMENDATION: ready to merge.
Author
Owner

Fixed by PR #393 (review clean — all 7 criteria pass, behavior untouched, D-WEB-8 recorded), merged. Closing.

Fixed by PR #393 (review clean — all 7 criteria pass, behavior untouched, D-WEB-8 recorded), merged. Closing.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
crueber/walhub#390
No description provided.