feat: Primer decluttered#6
Conversation
Apply the decluttered GitHub Primer layout from the design handoff to the renderer chrome (tokens and the file-card diff surface were already in place): - TitleBar becomes the 56px topbar and hosts the Tweaks popover + user menu (moved from TopBar), beside the brand and repo selector. - TopBar becomes the 48px context bar: branch, commit, changes summary, centered file search, refresh; Tweaks/user removed. - StatusBar slimmed to essentials: synced dot, active path, J/K and V hints, viewed count. App.vue rewires the relocated props/events.
Close the remaining gaps between the Primer-light design mockup and the app: - Consolidate the top chrome to the mockup's two-bar shape: merge the separate RepoToolbar (History/Pull requests/Generate walkthrough/Copy review) into TopBar as a Primer-styled right cluster; remove RepoToolbar. - Restyle the diff/review surface as white, rounded, bordered cards with 16px gaps on a subtle grey canvas, 44px card heads, and accent-subtle (blue) hunk headers. - Add "Wrap long lines" tweak (diff.wrap pref) wired via a .gd-wrap-lines container class that overrides the inline white-space on code cells. - Add "Hide viewed files" tweak (diff.hideViewed pref): drops viewed files from the sidebar list and diff column (and J/K + jump-nav) while keeping the "X/N viewed" counts on the full set. - Add visual-only "Comment" + "Request" secondary buttons to the sidebar footer to match the mockup.
The Primer-light card-surface work pointed the hunk header at var(--accent-subtle), a token the app never defines, so the header rendered with no background in both themes. Point it at the existing --gd-accent-soft, which already resolves to the design's exact --accent-subtle values per theme (#ddf4ff light, #388bfd26 dark). The app's :root.dark block already mirrors the GitHub Primer dark design (canvas #0d1117, borders #30363d, text #e6edf3, accent #2f81f7, translucent diff fills), so the dark variant needed only this fix.
Map the @pierre/trees file tree to the app's Primer light/dark tokens using the library's real override hooks (the previous overrides used variable names the library never reads, so hover/selection/indent/icon colors fell back to the library's blue-tinted defaults). Replace the custom data-changed accent dot with the library's native git-status coloring via setGitStatus(), driven by ChangedFile.status, mapped to the Primer diff tokens (added/untracked green, modified orange, deleted red, renamed accent).
Phase 1 of swapping the hand-rolled diff renderer to the @pierre/diffs (diffs.com) FileDiff engine. Registers the existing Licht/Dunkel theme JSONs with the library via registerCustomTheme, and adds a .pierre-diff CSS scope that bridges the library's --diffs-* shadow-DOM custom properties onto the app's Primer --gd-*/--diff-* tokens. Inert until the renderer lands in Phase 3.
Phase 2. Pure toPierreDisplayOptions() maps the app's Tweaks/props (viewMode, diffStyle soft/punchy/bar, wordHighlight, wrapLongLines, hideWhitespace, themeType) onto the declarative slice of FileDiffOptions, and pierreSurfaceClasses() drives the CSS bridge (density + punchy). Covered by 11 unit tests. Adds the .pierre-diff--punchy fill rule.
…mode) Phase 3. New PierreDiffBody.vue drives one FileDiff instance per diff section, replacing the hand-rolled DiffBody in the LazyDiffBody chain. usePierreFileDiff.ts resolves each section to a FileDiffMetadata: it fetches whole old+new file contents at the right git refs (per section kind / commit / PR base) via readRepositoryFileBytes and feeds parseDiffFromFile (non-partial → native context expansion + ignore- whitespace), falling back to processFile(patch) when a blob is missing or over the 2 MB cap. Threads wrapLongLines + PR baseRef through App→DiffList→LazyDiffBody. Themes registered at point-of-use so the renderer works under unit tests too. Comments come in Phase 4. Verified: type-check, 149 UI tests (incl. full-app mount), prod build.
Phase 4. Adds the add-comment affordance via the library's gutter utility (single click or drag-select a range) -> emits add-comment with a translated PatchLine/LineSelectionRange, preserving the open-comment-for-line contract (useReviewSession untouched). Comment threads render in light DOM beneath each section (FileDiff is Shadow DOM, where Tailwind-based CommentThread can't be styled), labelled by line, with reply/resolve/delete intact. Outdated comments are detected via FileDiff.getLineIndex on every render. New usePierreComments.ts holds the pure side-translation + selection->target helpers (8 tests). Verified: type-check, 157 UI tests, prod build.
Phase 5. @pierre/diffs owns its split layout + synced scrolling with no resizable-divider API, so the per-file splitRatio state and its plumbing are dead. Removes splitRatios/setSplitRatio from useDiffLayout, the App→DiffList→LazyDiffBody splitRatio props/emit, and the bindings. Also refreshes the PierreDiffBody comment-affordance doc comment. Visual/behaviour parity (split/unified, soft/punchy/bar, word highlight, density, light/dark, wrap, hide-whitespace) to be confirmed live. Verified: type-check, 157 UI tests.
Phase 6. The ref-aware whole-file read already exists end-to-end (readRepositoryFileBytes → ReadRepositoryBlob), so no new endpoint is needed. But PR diffs are computed against the merge-base while only the base branch name is surfaced; recomputing full-file from its current tip can drift. PRs therefore use the accurate pre-computed patch. Working- tree and plain-commit diffs keep exact-ref full-file mode + native expansion. Surfacing the exact base SHA for PR native expansion is a future enhancement.
Phase 7. @pierre/diffs now owns rendering, so delete the superseded implementation: DiffBody + DiffSplitRow/DiffCodeCell/DiffGutter/ DiffHunkHeader/SplitHandle, useDiffStyles/useDiffHighlighting/useHunkInfo/ useSplitCellRender/useContextExpansion(+Controls)/useLineComments, the custom Shiki stack (lib/highlight, lib/highlightPool, the highlight worker + protocol), the App.vue language prewarm, and the four tests covering deleted code. Refreshes packages/ui/AGENTS.md to document the @pierre/diffs architecture. 21 files removed. Verified: type-check, check:imports, 131 UI tests, prod build (the licht/dunkel dynamic-import warning is now resolved).
There was a problem hiding this comment.
Code Review
This pull request replaces the custom legacy diff rendering implementation with the @pierre/diffs engine. It removes several legacy components and composables (such as DiffBody.vue, useContextExpansion, and useDiffHighlighting) and introduces PierreDiffBody.vue along with new composables to handle options, comments, and file resolution. Additionally, it integrates new user tweaks for wrapping long lines and hiding viewed files, updates the repository file tree to use Git status entries, and updates the test suite. The review feedback highlights two key improvements for PierreDiffBody.vue: resolving a potential race condition in the asynchronous renderAll method by tracking render IDs, and adding a deep watcher on props.comments to ensure the outdated status of comments is correctly recomputed when comments are updated.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
…ted on comment change Address PR #6 review: - Stamp each renderAll pass with a monotonic id and discard stale passes, preventing overlapping async render passes from racing into the same container (duplicate FileDiff instances, leaked listeners). - Watch props.comments (deep) and recompute each section's outdated map so asynchronously loaded/updated comments keep accurate anchors.
No description provided.