Skip to content

feat(web): tidy workspace menus, dock and sidebar controls - #256

Merged
kinqsradio merged 5 commits into
orbyn-dev:feat/web-rebuildfrom
luannn010:fix/web-workspace-popups
Nov 3, 2026
Merged

kinqsradio merged 5 commits into
orbyn-dev:feat/web-rebuildfrom
luannn010:fix/web-workspace-popups

Conversation

@luannn010

@luannn010 luannn010 commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

See CONTRIBUTING before starting engineering work.

Change

Makes the web rebuild's pop-ups consistent and keeps side panels on the right.

Stacked on #254 (99818e49). This branch contains #254's commits; merge #254 first.

  • Workspace menu (··· Workspace): left-aligned rows with icons, grouped under Layout and Dock, end-aligned to the button. "Reopen closed tab" is a normal row, disabled when nothing is closed. Previously the items were <Button> pills, whose .btn styles overrode .menu rows.
  • Tab options (··· on a tab): now uses the shared Menu (closes on pick, Escape or outside click; arrow keys move), grouped as Pin/Duplicate · Move · Close, with icons. The Done button and the old .workspace-tab-actions styles are removed.
  • Shared Menu (ui/kit.tsx): new side, align and fitTrigger options; focuses the first enabled item; adds .menu-label, separators and disabled/checked row styles.
  • Dock header: one row; tabs scroll on the left, "Open in originating pane" and "Hide dock" are icon buttons with tooltips.
  • Dock under 760px: a full-height right-hand sheet (z-index 30, under menus and the nav drawer) instead of a 45% strip under the page.
  • Account menu: icons on every item, divider before Sign out; opens above the sidebar trigger at sidebar width. At ≤800px (sidebar is a drawer) the avatar moves to the right of the top bar and the menu opens below it.
  • Sidebar controls: "Arrange navigation" moves into the account menu; the "Icon rail" text button becomes a side-panel icon beside the logo (hidden on phones). Arrange navigation rows show each destination's icon.

Checks and limits

  • tsc --noEmit in web/ and Prettier on the changed files: pass.
  • Checked by hand in a local browser, signed in as a local demo member, at 1440, 1200, 700 and 375px widths: workspace menu, tab menu, dock header, narrow dock sheet and Hide dock, account menu in sidebar and top bar, Arrange dialog and the collapse/expand toggle. No console errors.
  • Not covered by automated tests (none exist for these menus). The collapsed-sidebar account menu (280px fallback) was only checked visually in collapsed mode, not exhaustively. No keyboard-only or screen-reader pass beyond the shared Menu's existing arrow/Escape handling.

Follow-up e8e6562a (3 Nov 2026): rebased onto #254 (99818e49) and resolved the kit.tsx conflict. The merge keeps event-based anchoring and scroll/resize placement plus side/align/fitTrigger, reapplying trigger width on resize; arrow navigation and initial focus skip disabled items; the rail account trigger keeps its accessible name and adds aria-haspopup="menu". Prettier and vite build pass; tsc --noEmit passes with the ES2023 array lib. The stock npm run build still stops at the pre-existing Array.findLast/ES2022 error in library/page/Source.tsx. No browser pass was run after the follow-up.

Workspace

  • Used the outer Orbyn Engineering workspace with this target nested under repo/, and read the relevant project guides.

This contributor confirmation is not an automated claim that a host loaded policies.

Agent disclosure

  • Tools: Claude Code (desktop app) with its built-in browser for local checks.
  • Model: Claude Opus 5.5 (claude-opus-5-5), default effort.
  • Human role: Luan Nguyen chose the arrangement option and scope from mocked alternatives and reviewed each step in the browser.
  • External sources: none.

🤖 Generated with Claude Code

Follow-up fixes (3 Nov 2026)

  • Tools: Freebuff Desktop coding agent, terminal, git, gh, npm, tsc, Prettier, Vite.
  • Model: selected by the host and not exposed to the session; exact identifier unavailable.
  • Effort: host default; not separately set.
  • Human role: maintainer requested the review fixes and the feat(web): tidy workspace menus, dock and sidebar controls #256 rebase; no human code edits.
  • External sources: none.

luannn010 and others added 2 commits November 3, 2026 14:20
WebKit does not focus a button on mouse click, so Menu read <body> from
document.activeElement and opened the popup at the top-left corner. Anchor
to the click's currentTarget, keeping focus as the fallback for bare open(),
and re-place the open menu on resize and scroll.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Absolutely positioned descendants such as .sr-only labels escaped the
scrolling frame and extended the document, so the shell could scroll up
and expose the page background below it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kinqsradio
kinqsradio self-requested a review November 3, 2026 04:43

@kinqsradio kinqsradio left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed #256 against feat/web-rebuild (cadf0db6). The consolidation is good: one account menu, a labelled collapse control, consistent menu rows and a cleaner dock header. The manual checks at 1440/1200/700/375 are useful.

This cannot merge as-is: it conflicts with #254 in web/src/ui/kit.tsx. I verified with git merge-tree; each branch merges cleanly into the base alone, but #254 + #256 produce a content conflict. Rebase #256 after #254 and keep both sides:

  • #254's event-based open(event) and its place() + resize/scroll listeners;
  • #256's side, align, fitTrigger and button:not(:disabled) initial focus.

In the merged place(), re-apply the fitTrigger width on resize too, not just left/top, and include side/align/fitTrigger in the layout-effect dependencies. Merge order matters beyond the text conflict: the new account/tab menus here (and #255's new menus) pass open directly to onClick, so on WebKit they rely on #254 to avoid anchoring at the top-left.

After the rebase, the inline comments cover the menu arrow-key handling and the rail account button's accessible name. tsc --noEmit -p web/tsconfig.json, Prettier on the changed files and npm run build -w web pass locally. No CI checks are reported, and I did not run a keyboard/screen-reader pass.

Comment thread web/src/ui/kit.tsx
menu.style.top = `${below ? at.bottom + 4 : Math.max(8, at.top - size.height - 4)}px`;
menu.querySelector("button")?.focus();
}, [opener]);
menu.querySelector<HTMLElement>("button:not(:disabled)")?.focus();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial focus now skips disabled buttons, but the arrow handler at line 341 still builds its item list with querySelectorAll("button"). With the new disabled rows, focus() on a disabled button no-ops and the next Arrow press tries the same row again, so navigation can get stuck. Filter to button:not(:disabled) in the arrow handler too.

Comment thread web/src/ui/kit.tsx Outdated
const size = menu.getBoundingClientRect();
const left = Math.max(8, Math.min(at.left, innerWidth - size.width - 8));
const below = at.bottom + 4 + size.height <= innerHeight - 8;
const wanted = align === "end" ? at.right - size.width : at.left;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This layout effect overlaps #254's changes to the same Menu function. After rebasing, keep #254's place() plus its resize/scroll listeners and call the combined function here. Also re-apply the fitTrigger width inside place(), not just left/top, so resizing the sidebar does not leave the account menu at its old width.

Comment thread web/src/app/Shell.tsx
fitTrigger={where === "sidebar" && !size.rail}
trigger={(open, expanded) => (
<button
className={`account account-${where}`}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the rail, .shell-nav-text is display: none and the avatar is aria-hidden, so the sidebar account button has no accessible name — aria-label is only set for the topbar variant. Set the label for the sidebar/rail case too. Consider adding aria-haspopup="menu" to this trigger for consistency with the other menu buttons.

kinqsradio and others added 3 commits November 3, 2026 16:15
- Workspace, tab and account menus use grouped menu rows with icons
  instead of pill buttons; tab actions use the shared Menu (Escape,
  outside click, arrow keys) and drop the Done button.
- The shared Menu can open above, align to the trigger's end edge and
  match the trigger's width.
- The dock header is one row with icon actions; under 760px the dock is
  a right-hand sheet instead of a half-height strip.
- The account menu opens above the sidebar trigger at sidebar width and
  moves to the top bar when the sidebar becomes a drawer (<=800px).
- Arrange navigation moves into the account menu, the Icon rail button
  becomes a side-panel toggle beside the logo, and Arrange rows show
  each destination's icon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kinqsradio
kinqsradio force-pushed the fix/web-workspace-popups branch from ef40807 to e8e6562 Compare November 3, 2026 05:26
@kinqsradio

Copy link
Copy Markdown
Member

Rebased onto #254 (99818e49) and resolved the kit.tsx conflict. This branch now contains #254's commits, so merge #254 first. The merged menu keeps event-based anchoring and scroll/resize placement, plus side / align / fitTrigger (including reapplying trigger width on resize).

Also fixed: arrow navigation and initial focus skip disabled buttons; the rail account button keeps its accessible name and reports aria-haspopup="menu".

Checks: Prettier and vite build pass; tsc --noEmit passes with the pre-existing Array.findLast lib workaround. No browser pass was run.

@kinqsradio kinqsradio left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@kinqsradio
kinqsradio merged commit f2a60f9 into orbyn-dev:feat/web-rebuild Nov 3, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants