Skip to content

UX review pass — Wave 5: clarity, honesty, componentization - #43

Merged
dPeluChe merged 14 commits into
mainfrom
ux-review-improvements
Aug 14, 2026
Merged

dPeluChe merged 14 commits into
mainfrom
ux-review-improvements

Conversation

@dPeluChe

@dPeluChe dPeluChe commented Jun 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

Wave 5 UX review pass — 9 UX improvements + 1 refactor commit. All items from the systematic review are now complete.

UX improvements

  • Topbar grouping — split overloaded .meta into .topbar-status (sync + refresh + summary + rate-low) and .topbar-actions (help + logout); rate-limit only renders inline when low, otherwise lives in the sync-indicator tooltip
  • Phase-2 row actions wired — Approve (✓) and Request changes (✗) on review-requested rows now open the detail modal with a pendingAction that fires once the PR loads (approve submits; request-changes jumps to composer). "Mark read" on mentioned rows is now an honest snooze with a clear tooltip — no more dead stubs
  • Snooze undo toast — snoozing a row shows an inline "Snoozed 18h · Undo" toast for 5s; pointer-events: auto overrides the faded row so the button stays clickable
  • Sidebar icons → react-icons — replaced ambiguous unicode glyphs (● ◔ ↻ ◈ ∿ ★ ▴ ⊞) with react-icons/md (MdInbox, MdNotificationsActive, MdRefresh, MdReport, MdDashboard, MdStar, MdTrendingUp, MdFolder)
  • Digest tiered stat cards — 8 flat cards split into 4 primary (active, open PRs, failing CI, stale PRs) at full size + 4 secondary (total, merged, avg time, pinned) compact and borderless. Responsive 4→2 columns under 720px
  • RepoCard signal fix — pinned no longer adds +20 to the signal score; it only lifts a quiet repo to active (not attention), so critical/attention stay reserved for real signals
  • Composer Write/Preview toggle — PR comment composer has a Write/Preview tab; preview renders through a minimal inline markdown→HTML converter (no new dep) piped through SanitizedMarkdown
  • Empty states with CTA — shared EmptyState component (icon + title + description + optional CTA button) replaces 14 plain hs-empty divs across all scopes. Needs me gets "Browse open PRs →", Pinned gets "Browse repos →", error states use tone="danger"
  • Mobile focus trap + responsive pass — useFocusTrap hook traps Tab/Shift+Tab in the mobile sidebar drawer, focuses first element on open, restores focus on close, Escape closes. Responsive 860px + 480px breakpoints: topbar wraps, rows stack, modal tabs scroll horizontally, relationships table scrolls, sparklines/branch badges/kbd hints hide at 480px

Refactor — componentization

Extracted 7 reusable modules to keep files under 300 LOC:

New module LOC Reusable by
utils/miniMarkdown.ts 30 any markdown preview
utils/topbar.ts 35 Dashboard + future topbars
hooks/useFocusTrap.ts 52 any drawer/modal
home/EmptyState.tsx 28 all scopes
home/detail/Composer.tsx 114 any modal with comments
home/scopes/digestMath.ts 96 Digest + future tests
home/scopes/DigestParts.tsx 37 Digest + other scopes
home/rowParts.tsx 75 AttentionRow + other scopes

LOC reductions in existing files:

  • DetailModalBody.tsx: 275 → 140
  • DigestScope.tsx: 307 → 168
  • AttentionRow.tsx: 182 → 112
  • Dashboard.tsx: 285 → 251

Test plan

  • npm run lint — clean
  • npm run build — green (tsc -b && vite build)
  • Manual: topbar clusters render correctly at narrow widths
  • Manual: approve from Needs row opens modal and submits
  • Manual: snooze undo toast appears and Undo restores the row
  • Manual: sidebar icons render with correct semantics
  • Manual: digest primary/secondary tiers render responsively
  • Manual: composer Write/Preview toggle works
  • Manual: empty states show icon + CTA where expected
  • Manual: mobile sidebar focus trap (Tab cycles, Escape closes, focus restores)
  • Manual: responsive layout at 860px and 480px breakpoints

Generated with Devin

dPeluChe and others added 9 commits June 23, 2026 19:07
Splits the overloaded .meta block into two visually separated clusters:
.topbar-status (sync + refresh + summary + rate-low) and .topbar-actions
(help + logout). The rate-limit now only renders inline when low; when
healthy it lives in the sync-indicator tooltip so the bar stays calm.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ark-read

The review-requested row had ✓/✗ stubs that silently opened the modal
instead of approving. Now they open the modal with a pendingAction that
DetailModal fires once the PR detail loads (approve submits immediately;
request-changes jumps to the composer for the required body). The
mentioned "Mark read" stub is now an honest snooze with a clear tooltip.

Plumbing: ScopeProps.onOpenItemWithAction → NeedsScope → AttentionRow
→ HomeShell.selectItemWithAction → DetailModal.pendingAction.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Snoozing a row now shows an inline "Snoozed 18h · Undo" toast for 5s.
The toast sits above the faded row (pointer-events: auto overrides the
snoozed none) and calls unsnoozePr + refresh on click. Plumbing adds
onUnsnoozeItem through ScopeProps → NeedsScope → AttentionRow.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replaces the ambiguous unicode icons (● ◔ ↻ ◈ ∿ ★ ▴ ⊞ ◉ ◆ ◇) with
react-icons/md (MdInbox, MdNotificationsActive, MdRefresh, MdReport,
MdDashboard, MdStar, MdTrendingUp, MdFolder, MdPerson, MdGroup,
MdGroupWork). Same weight, conventional meanings. ItemDef.icon is now
ReactNode instead of string.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Splits the 8 flat stat cards into two tiers: 4 primary (active, open
PRs, failing CI, stale PRs) at full size, and 4 secondary (total repos,
merged, avg time, pinned) compact and borderless. Failing/stale keep
the warn border. Responsive: 4→2 columns under 720px.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…only

Pinned used to add +20 to the signal score, pushing a quiet pinned repo
to 'attention' alongside repos with failing CI. Now pinned only adds a
reason tag and lifts a quiet repo to 'active' (not 'attention'), so the
critical/attention levels stay reserved for real signals.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Adds a Write/Preview tab toggle to the PR comment composer. Preview
renders the draft through a minimal inline markdown→HTML converter
(headers, bold, italic, code, links, lists, blockquote) piped through
SanitizedMarkdown — no new dependency. Preview is disabled when the
body is empty.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Splits the files touched in this branch into focused, reusable units:

- miniMarkdown → src/utils/miniMarkdown.ts (shared util)
- Composer → src/components/home/detail/Composer.tsx (self-contained)
- computeDigest + types → src/components/home/scopes/digestMath.ts
- DigestStat/DigestAttn/Sparkline → src/components/home/scopes/DigestParts.tsx
- ReasonChips/actionsFor/ActionDef → src/components/home/rowParts.tsx
- syncTitle/timeAgoShort → src/utils/topbar.ts

LOC reductions:
  DetailModalBody: 275 → 140
  DigestScope:     307 → 168
  AttentionRow:    182 → 112
  Dashboard:       285 → 251

All extracted modules are reusable (RowProps shared by AttentionRow +
other scopes; miniMarkdown usable anywhere; DigestParts presentational).
Lint clean, build green.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@vercel

vercel Bot commented Jun 24, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
devcompass Ready Ready Preview, Comment Jun 24, 2026 2:59am

dPeluChe and others added 3 commits June 23, 2026 19:24
Replaces 14 plain <div className="hs-empty"> blocks with a shared
EmptyState component that supports an icon, title, description, and
optional CTA button. Key improvements:

- Needs me: icon + "Browse open PRs" CTA when empty
- Pinned: icon + "Browse repos" CTA when empty
- Issues/Notifications/Since: icon + contextual description
- Error states use tone="danger" for red title
- All filter-no-match states get "Try clearing the filter" hint

EmptyState is reusable (presentational, no domain logic). CSS updated
with flex column layout, icon opacity, and CTA hover styles.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
P2.10 — Focus trap for the mobile sidebar drawer:
- New useFocusTrap hook (src/hooks/useFocusTrap.ts) traps Tab/Shift+Tab
  inside the sidebar while open, focuses the first element on open,
  restores focus to the toggle button on close, and closes on Escape.
- Removed the redundant keydown handler on the backdrop (the hook
  handles Escape on the container).

Responsive pass (860px + 480px breakpoints):
- Topbar: wraps status/actions, hides verbose summary + QS trigger text,
  pads left for the floating ≡ button
- Rows: stack title/meta + actions vertically on narrow
- Issue/notification groups: tighter padding
- Digest: less horizontal padding, smaller headings
- Modal: horizontal-scroll tabs, tighter header/footer padding
- Composer: smaller textarea, wrapping actions
- Relationships table: wrapped in scrollable .rel-table-wrap
- 480px: hide sparklines, branch badges, kbd hints; 2-col stat cards

Also migrated remaining empty states (Repos, Relationships, Digest
sections) to the shared EmptyState component.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ests

Four refactors in one pass, all preserving existing imports via barrels:

**demo-data.ts (727 → 4 LOC barrel)**
  → src/api/demo/helpers.ts (215) — shared builders: ago, ghAvatar, pr, makeRepo, fullPR, issue, notif, mergedPR, deploy
  → src/api/demo/github.ts (421) — all GitHub demo data
  → src/api/demo/sentry.ts (34) — Sentry demo data
  → src/api/demo/vercel.ts (63) — Vercel demo data

**ui.tsx (323 → 5 LOC barrel)**
  → src/components/ui/Skeletons.tsx (84) — Skeleton, CardSkeleton, ListSkeleton, Spinner, Pulse
  → src/components/ui/Motion.tsx (120) — FadeIn, SlideIn, Stagger, StaggerItem, PageTransition, TabTransition
  → src/components/ui/Primitives.tsx (122) — Avatar, Badge, Button, Input, Flex, Divider

**SentryConnector.tsx (350 → 198 LOC)**
  → src/components/connectors/sentry/SetupForm.tsx (114) — credentials form + describeError helper
  → src/components/connectors/sentry/ProjectMappingList.tsx (50) — presentational mapping list
  → src/components/connectors/sentry/IssueTestPanel.tsx (26) — test-issues result panel
  → src/components/connectors/sentry/types.ts (2) — shared Async<T> type

**useViewerData.ts (254 → 145 LOC)**
  → src/hooks/loadRepos.ts (156) — pure sortRepos, mergeOrgs, syncRepos (testable)
  → src/hooks/loadRepos.test.ts (96) — 7 new tests for sortRepos + mergeOrgs

All gates: tsc ✓, eslint ✓, vitest 71/71 ✓, vite build ✓

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- SettingsTab.tsx (282→96 LOC): extract AppearanceSection, PinnedPanel,
  StoragePanel into src/components/settings/
- QuickSwitcher.tsx (251→124 LOC): extract buildItems, matchScore,
  kindLabel, VIEWS/SCOPES into quickSwitcherData.ts (+13 tests)
- CSS audit: remove 244 dead rules across styles.css (-841),
  home.css (-182), ui.css (-210). CSS bundle 106.47→104.12 kB.
  Dynamic class constructions protected via manual verification.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@dPeluChe
dPeluChe merged commit 85ce299 into main Aug 14, 2026
3 checks passed

This branch was successfully deployed

1 active deployment
Preview — 667eba8c Deployed Jun 24, 2026 by vercel[bot]
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