Skip to content

feat(ux): dedupe page links and collapse tree row actions behind an overflow menu - #42

Merged
alexk-dev merged 1 commit into
mainfrom
feat/mobile-first-ux-hardening
Jul 26, 2026
Merged

feat(ux): dedupe page links and collapse tree row actions behind an overflow menu#42
alexk-dev merged 1 commit into
mainfrom
feat/mobile-first-ux-hardening

Conversation

@alexk-dev

@alexk-dev alexk-dev commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes two reported defects and the mobile-first issues a UX audit surfaced around them.

Duplicated links at the bottom of a document. The cause was data, not a double render: extractResolvedLinks emitted one entry per link occurrence, so a body referencing the same page twice produced two identical rows under Outgoing links, and two identical Backlinks rows on the target page. The React keys collided as well. Deduped by resolved target path in WikiApplicationService, plus a defensive pass in LinkInfo so the pane stays correct against an older backend.

Tree navigation on desktop. Every row rendered up to seven icon buttons on hover. Moving the pointer onto a row materialised ~214px of controls, re-truncating the title under the cursor, with Delete adjacent to Convert. Replaced with a single overflow menu (Radix DropdownMenu) at all breakpoints; the trigger keeps its slot reserved so revealing it causes no reflow.

Worth calling out: the old max-md:hidden guard on that cluster never won the cascade(0,1,0) against group-hover:flex at (0,2,0), and media queries add no specificity. Tapping a row on mobile focused the title button, matched :focus-within, and revealed all seven desktop icons plus the mobile overflow button — eight controls in a ≤320px sidebar, collapsing the title to zero width.

Also fixed

Area Change
Sidebar Search tab opened the embedded panel and the modal dialog on top of it; now swaps the panel in place
Editor Unsaved-changes and conflict prompts were bare overlay divs with no focus trap, Escape or dialog role; now use ModalCard. Hotkeys no longer fire from behind an open prompt
iOS zoom Form fields (14px) and the code editor (13px) triggered Safari auto-zoom on focus; both render at 16px on phones
Editor Autofocus gated behind (pointer: fine) so the on-screen keyboard no longer covers the fixed save bar
Markdown Wide tables dragged the whole article sideways; each table now scrolls in its own container
Touch targets 44px minimum across tree rows, editor toolbar, links pane, history actions and modal dismiss
Assets Rows overflowed the dialog on a phone and the rename field was a fixed 160px in a ~263px box; rows wrap and rename gets its own line plus a cancel action
Layout sidebarVisible was seeded once at module load and went stale on rotation; now follows breakpoint crossings while preserving manual toggles
Chat Sends on Enter, Shift+Enter for a newline, transcript exposed as a live region
Users Deletion used window.confirm; now uses the same in-app dialog as every other destructive action
a11y aria-expanded/aria-controls on the sidebar toggle, tab/tabpanel semantics, aria-current on the active tree row

…verflow menu

Links pane

extractResolvedLinks emitted one entry per link occurrence, so a body that
referenced the same page twice produced duplicate Outgoing links rows, and
duplicate Backlinks rows on the target page, with colliding React keys.
Dedupe by resolved target path on the server, and defensively in LinkInfo so
the pane stays correct against an older backend.

Tree navigation

Replace the seven hover-only icon buttons on every tree row with a single
overflow menu at all breakpoints. The trigger keeps its slot reserved, so
revealing it no longer reflows the row or re-truncates the title, and the
destructive action no longer sits next to the label. The previous
max-md:hidden guard never won the cascade against group-hover:flex, so
tapping a row on mobile exposed all eight controls at once.

Mobile-first and accessibility

- Sidebar search tab swaps the panel in place instead of also raising the
  modal search dialog on top of it.
- Editor unsaved-changes and conflict prompts render through ModalCard, so
  they get a focus trap, Escape and dialog semantics; editor hotkeys no
  longer fire from behind an open prompt.
- Form fields and the code editor render at 16px on phones to stop iOS
  Safari auto-zoom, and editor autofocus is gated behind a fine pointer so
  the keyboard cannot cover the save bar.
- Markdown tables scroll inside their own container instead of dragging the
  article sideways.
- 44px touch targets across tree rows, editor toolbar, links pane, history
  actions and modal dismiss.
- Asset manager rows wrap instead of overflowing the dialog; rename moves to
  its own line and gains a cancel action.
- sidebarVisible follows breakpoint changes instead of going stale on
  rotation.
- Chat sends on Enter, keeps Shift+Enter for a newline, and exposes the
  transcript as a live region.
- User deletion uses the in-app confirm dialog instead of window.confirm.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@alexk-dev
alexk-dev merged commit 9c704f2 into main Jul 26, 2026
13 checks passed
@alexk-dev
alexk-dev deleted the feat/mobile-first-ux-hardening branch July 26, 2026 22:24
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.

1 participant