Owner profile: right-sidebar layout — avatar + grouped actions under the avatar, hr before Edit profile (GitHub-inspired) #421

Closed
opened 2026-09-12 22:56:29 +00:00 by crueber · 3 comments
Owner

What's requested

Reshape the owner profile page (/:owner, web/src/pages/Repos.jsx) to a GitHub-style two-column layout: identity and repositories on the left, a right sidebar carrying the avatar and the owner actions grouped vertically, with a horizontal rule directly above the Edit profile action.

Current state (evidence)

  • web/src/pages/Repos.jsx (~line 304): .profile-header is a horizontal flex row — identity block left, .profile-avatar (avatar + Regenerate/remove avatar buttons) right. Everything sits in one top band; the Repositories section runs full-width below.
  • The avatar actions (Regenerate avatar / Remove avatar) render inline next to the avatar in a flex-row … sm:flex-col wrapper inside the header (lines ~345–367).
  • "Edit profile" is a button inside the identity block's action row (~line 327), visually separate from the avatar column.

Proposed layout (GitHub-inspired)

  • Two-column page grid: main content (repositories) left, narrow sidebar right (stacks below on narrow widths — the repo's existing sm: responsive pattern per #273/#278).
  • Sidebar top-to-bottom: large avatar, then the owner's action buttons grouped in one vertical stack — Edit profile (when profile.can_edit), Regenerate avatar, Remove avatar (when applicable) — each full-width in the sidebar, in GitHub's undercard style.
  • An <hr> (or equivalent divider, matching border-zinc-200 dark:border-zinc-700 used on the header) separates the avatar from the action group, immediately above Edit profile.
  • The identity block (display name, @handle, location · timezone, bio) stays at the top of the left column above the Repositories toolbar.
  • The edit form (ProfileForm) opens in place as it does today.

Architecture notes

  • Pure client/layout change: web/src/pages/Repos.jsx + web/css rules if a class needs a definition. No fetch, cache, or route changes; gates byte-identical.
  • Reference implementation for the composition conventions in this repo: #395's composed header (avatar composed into the header flow, mobile stacking) — this ticket extends that pattern into a sidebar; do not regress the mobile stacking behavior that #395 established.
  • The Repositories toolbar stays as landed in #413.

Acceptance criteria

  • Profile page renders main content left / sidebar right; sidebar stacks below main on narrow widths (no horizontal overflow at 390px — #273/#278 rules).
  • Avatar, Edit profile, Regenerate avatar, Remove avatar all live in the sidebar as one grouped action stack; none remain in the identity block.
  • An <hr>-style divider appears between the avatar and the action group, immediately above Edit profile.
  • "Edit profile" still renders only when profile.can_edit is set (server-decided, unchanged gate).
  • Org variant of /:owner still renders correctly (org header, Manage organization) with the same sidebar treatment.
  • Existing headless tests updated; vite build green.
## What's requested Reshape the owner profile page (`/:owner`, `web/src/pages/Repos.jsx`) to a GitHub-style two-column layout: identity and repositories on the left, a right sidebar carrying the avatar and the owner actions grouped vertically, with a horizontal rule directly above the Edit profile action. ## Current state (evidence) - `web/src/pages/Repos.jsx` (~line 304): `.profile-header` is a horizontal flex row — identity block left, `.profile-avatar` (avatar + Regenerate/remove avatar buttons) right. Everything sits in one top band; the Repositories section runs full-width below. - The avatar actions (Regenerate avatar / Remove avatar) render inline next to the avatar in a `flex-row … sm:flex-col` wrapper inside the header (lines ~345–367). - "Edit profile" is a button inside the identity block's action row (~line 327), visually separate from the avatar column. ## Proposed layout (GitHub-inspired) - Two-column page grid: main content (repositories) left, narrow sidebar right (stacks below on narrow widths — the repo's existing `sm:` responsive pattern per #273/#278). - Sidebar top-to-bottom: large avatar, then the owner's action buttons grouped in one vertical stack — Edit profile (when `profile.can_edit`), Regenerate avatar, Remove avatar (when applicable) — each full-width in the sidebar, in GitHub's undercard style. - An `<hr>` (or equivalent divider, matching `border-zinc-200 dark:border-zinc-700` used on the header) separates the avatar from the action group, immediately above Edit profile. - The identity block (display name, @handle, location · timezone, bio) stays at the top of the left column above the Repositories toolbar. - The edit form (`ProfileForm`) opens in place as it does today. ## Architecture notes - Pure client/layout change: `web/src/pages/Repos.jsx` + `web/css` rules if a class needs a definition. No fetch, cache, or route changes; gates byte-identical. - Reference implementation for the composition conventions in this repo: #395's composed header (avatar composed into the header flow, mobile stacking) — this ticket extends that pattern into a sidebar; do not regress the mobile stacking behavior that #395 established. - The Repositories toolbar stays as landed in #413. ## Acceptance criteria - [ ] Profile page renders main content left / sidebar right; sidebar stacks below main on narrow widths (no horizontal overflow at 390px — #273/#278 rules). - [ ] Avatar, Edit profile, Regenerate avatar, Remove avatar all live in the sidebar as one grouped action stack; none remain in the identity block. - [ ] An `<hr>`-style divider appears between the avatar and the action group, immediately above Edit profile. - [ ] "Edit profile" still renders only when `profile.can_edit` is set (server-decided, unchanged gate). - [ ] Org variant of `/:owner` still renders correctly (org header, Manage organization) with the same sidebar treatment. - [ ] Existing headless tests updated; `vite build` green.
crueber added this to the v1 milestone 2026-09-12 22:56:29 +00:00
Author
Owner

Fix ready for review: PR #427 (#427) — branch fix/issue-421. Two-column grid with sidebar grouping + hr, org variant included, all gates byte-identical, headless suite green, vite build green, D-WEB-12 recorded.

Fix ready for review: PR #427 (https://git.packden.us/crueber/walhub/pulls/427) — branch fix/issue-421. Two-column grid with sidebar grouping + hr, org variant included, all gates byte-identical, headless suite green, vite build green, D-WEB-12 recorded.
Author
Owner

REVIEW PR #427 (fix/issue-421, commit 2718266 + review fixup 20a738c) — verified in scratch worktree /tmp/pr427 (removed after), main worktree untouched.

AGENTS laws: L1 clean (no package.json/web dep change, no Go change — web-only + DEVIATIONS.md); L7 n/a (no long work); L8 clean (no core-package imports touched); L12 satisfied (D-WEB-12 appended with rationale + headless cover named).

Acceptance criteria (all 6 hold):

  1. Grid — Repos.jsx profile-layout: grid grid-cols-1 gap-6 sm:grid-cols-[minmax(0,1fr)_12rem]; main (profile-main min-w-0) left, aside.profile-sidebar (min-w-0) right; single-column below sm so sidebar stacks under main; DOM main-first so h1 keeps heading order. No fixed widths beside the h-24 avatar. 390px: flex-col stacks only, min-w-0 columns — reasoning sound, no browser run per instructions (node tests + reasoning).
  2. Sidebar order — avatar (h-24 ring) → hr → profile-actions (flex w-full flex-col gap-2; Edit/Regenerate/Remove each btn w-full justify-center). Identity block carries zero actions (pinned in all three rewritten suites).
  3. Org variant — title row back to h2-only (OrgAvatar out, now size 96 in sidebar); Manage organization under divider with byte-identical canManage gate; sidebar outer gate avatar_content_type OR canManage.
  4. Gates — per-action gates byte-identical: can_edit && !editing (Edit), isSelf (avatar actions), userSrc (avatar img), canManage (Manage), plus #420 bio_markdown && !editing and #376 user:/me invalidation intact. Aside-level outer gates (avatar OR self-or-editor / avatar-naming OR canManage) are the only new gating, disclosed in D-WEB-12 — layout-necessary so Edit has a host on avatarless editable pages. The dropped userSrc||isSelf pin in repos-toolbar-413.test.js is faithful (that composite Show no longer exists; its fragments are pinned separately).
  5. Edit form in place — ProfileForm unchanged props (owner/doc/onDone + invalidate profile:owner), now inside profile-main; #419 autogrow untouched (no shared-component change). #413 toolbar byte-identical (comment-only touch).
  6. Tests/build — new profile-sidebar-421.test.js (7 tests, all six criteria); #395/#403/#413 pins rewritten, not weakened (old-shape assertions replaced with sidebar-shape equivalents; identity-nav + profile-bio-editing pass unchanged).

REVIEW FIXUP pushed as 20a738c (2 files, +22/-2): one defect found and fixed — the sidebar


rendered with nothing above it on avatarless-but-actionable pages (self opted out via #376 Remove, admin editor, avatarless org + manager). Each
now has its own Show also requiring the avatar (userSrc() / avatar_content_type) alongside the existing action visibility condition; pins added to the 421 divider test. No other changes.

RESULTS (scratch worktree, node_modules symlinked): targeted suites (421 + header + 403 + toolbar + bio-editing + identity-nav) 66/66 pass; full node --test web/test/unit/*.test.js 878/880 — the 2 failures are smoke.test.js only, environmental: they HTTP-fetch a live foreign walhub serve on 127.0.0.1:8080 (auth on, / returns 401; process started 23:21, not mine, left untouched) and never execute worktree code. vite build green (600kB chunk-size warning only, pre-existing).

No backend change, no new deps, no docker/compose/build changes. No browser run (per instructions — noted explicitly).

RECOMMENDATION: ready to merge (after CI confirms).

REVIEW PR #427 (fix/issue-421, commit 2718266 + review fixup 20a738c) — verified in scratch worktree /tmp/pr427 (removed after), main worktree untouched. AGENTS laws: L1 clean (no package.json/web dep change, no Go change — web-only + DEVIATIONS.md); L7 n/a (no long work); L8 clean (no core-package imports touched); L12 satisfied (D-WEB-12 appended with rationale + headless cover named). Acceptance criteria (all 6 hold): 1. Grid — Repos.jsx profile-layout: grid grid-cols-1 gap-6 sm:grid-cols-[minmax(0,1fr)_12rem]; main (profile-main min-w-0) left, aside.profile-sidebar (min-w-0) right; single-column below sm so sidebar stacks under main; DOM main-first so h1 keeps heading order. No fixed widths beside the h-24 avatar. 390px: flex-col stacks only, min-w-0 columns — reasoning sound, no browser run per instructions (node tests + reasoning). 2. Sidebar order — avatar (h-24 ring) → hr → profile-actions (flex w-full flex-col gap-2; Edit/Regenerate/Remove each btn w-full justify-center). Identity block carries zero actions (pinned in all three rewritten suites). 3. Org variant — title row back to h2-only (OrgAvatar out, now size 96 in sidebar); Manage organization under divider with byte-identical canManage gate; sidebar outer gate avatar_content_type OR canManage. 4. Gates — per-action gates byte-identical: can_edit \&\& !editing (Edit), isSelf (avatar actions), userSrc (avatar img), canManage (Manage), plus #420 bio_markdown \&\& !editing and #376 user:/me invalidation intact. Aside-level outer gates (avatar OR self-or-editor / avatar-naming OR canManage) are the only new gating, disclosed in D-WEB-12 — layout-necessary so Edit has a host on avatarless editable pages. The dropped userSrc||isSelf pin in repos-toolbar-413.test.js is faithful (that composite Show no longer exists; its fragments are pinned separately). 5. Edit form in place — ProfileForm unchanged props (owner/doc/onDone + invalidate profile:owner), now inside profile-main; #419 autogrow untouched (no shared-component change). #413 toolbar byte-identical (comment-only touch). 6. Tests/build — new profile-sidebar-421.test.js (7 tests, all six criteria); #395/#403/#413 pins rewritten, not weakened (old-shape assertions replaced with sidebar-shape equivalents; identity-nav + profile-bio-editing pass unchanged). REVIEW FIXUP pushed as 20a738c (2 files, +22/-2): one defect found and fixed — the sidebar <hr> rendered with nothing above it on avatarless-but-actionable pages (self opted out via #376 Remove, admin editor, avatarless org + manager). Each <hr> now has its own Show also requiring the avatar (userSrc() / avatar_content_type) alongside the existing action visibility condition; pins added to the 421 divider test. No other changes. RESULTS (scratch worktree, node_modules symlinked): targeted suites (421 + header + 403 + toolbar + bio-editing + identity-nav) 66/66 pass; full node --test web/test/unit/*.test.js 878/880 — the 2 failures are smoke.test.js only, environmental: they HTTP-fetch a live foreign walhub serve on 127.0.0.1:8080 (auth on, / returns 401; process started 23:21, not mine, left untouched) and never execute worktree code. vite build green (600kB chunk-size warning only, pre-existing). No backend change, no new deps, no docker/compose/build changes. No browser run (per instructions — noted explicitly). RECOMMENDATION: ready to merge (after CI confirms).
Author
Owner

Fixed by PR #427 (review clean + one orphaned-hr fix by reviewer for avatarless pages; all 6 criteria pass, gates byte-identical), merged. Closing.

Fixed by PR #427 (review clean + one orphaned-hr fix by reviewer for avatarless pages; all 6 criteria pass, gates byte-identical), 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#421
No description provided.