feat: flatten reviews file tree and refine pierre tree styling (#1541)

* feat(ui): flatten reviews file tree and refine pierre tree styling

Switch the reviews-page file tree off forced full expansion so it renders
as a compact, flattened directory tree (single-child chains merged into one
row) like the pierre "flattened directories" preset. Expand only the
selected file's ancestors so the active diff stays revealed. Refine the
shared tree theme: subtle accent-tinted hover/selection and a complete
git-status palette (renamed/untracked/ignored) plus search input fg.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

* fix(ui): neutralize pierre tree filenames and selection styling

Use neutral grey/white filename colors instead of git-status accents,
apply unsafe CSS overrides for selected-row contrast, and switch to
complete icons in both agent and review file trees.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
Johannes du Plessis 2026-06-16 10:54:30 -07:00 • committed by GitHub
parent 3021bbe4b5
commit 272ffc78a6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 50 additions and 12 deletions

View file

@ -165,22 +165,50 @@ function PanelResizeHandle({
)
}
// Neutral filename foreground from the pierre Shiki themes (pierre-light /
// pierre-dark sidebar foreground). The tree tints filename text by git status,
// so feeding this keeps names neutral grey/white instead of accent-blue.
const TREE_FILE_FG = "light-dark(#525252, #a3a3a3)"
// Selected rows must read as high-contrast (white in dark, near-black in light)
// while the rest stay neutral. The built-in git-status content color outranks
// the selection color by specificity, so override it from the `unsafe` layer.
export const TREE_UNSAFE_CSS = `
[data-item-selected="true"] [data-item-section="content"] {
color: var(--trees-selected-fg);
}
/* On click a row is focus-ringed a frame before it's marked selected, which
* flashes the accent outline. Pointer focus doesn't match :focus-visible, so
* drop the ring there; keyboard navigation keeps it. */
[data-item-focused="true"]:not(:focus-visible)::before {
outline-color: transparent;
}
`
export function treeThemeStyle(): React.CSSProperties {
return {
"--trees-theme-sidebar-bg": "var(--ui-surface)",
"--trees-theme-sidebar-fg": "var(--ui-text)",
"--trees-theme-sidebar-border": "var(--ui-border)",
"--trees-theme-sidebar-header-fg": "var(--ui-text-dim)",
"--trees-theme-list-hover-bg": "var(--ui-panel-2)",
"--trees-theme-list-active-selection-bg": "var(--ui-accent-bubble)",
"--trees-theme-list-hover-bg":
"color-mix(in oklab, var(--ui-accent) 10%, transparent)",
"--trees-theme-list-active-selection-bg":
"color-mix(in oklab, var(--ui-accent) 22%, transparent)",
"--trees-theme-list-active-selection-fg": "var(--ui-text)",
"--trees-selected-focused-border-color-override": "transparent",
"--trees-theme-input-bg": "var(--ui-panel)",
"--trees-theme-input-fg": "var(--ui-text)",
"--trees-theme-input-border": "var(--ui-border)",
"--trees-theme-focus-ring": "var(--ui-accent)",
"--trees-theme-scrollbar-thumb": "var(--ui-border)",
"--trees-theme-git-added-fg": "var(--ui-success)",
"--trees-theme-git-deleted-fg": "var(--ui-danger)",
"--trees-theme-git-modified-fg": "var(--ui-accent)",
"--trees-theme-git-added-fg": TREE_FILE_FG,
"--trees-theme-git-modified-fg": TREE_FILE_FG,
"--trees-theme-git-deleted-fg": TREE_FILE_FG,
"--trees-theme-git-renamed-fg": TREE_FILE_FG,
"--trees-theme-git-untracked-fg": TREE_FILE_FG,
"--trees-theme-git-ignored-fg": "var(--ui-text-dim)",
} as React.CSSProperties
}
@ -557,7 +585,8 @@ function FileTreeExplorer({
initialExpansion: "open",
flattenEmptyDirectories: true,
search: true,
icons: "standard",
icons: "complete",
unsafeCSS: TREE_UNSAFE_CSS,
})
useEffect(() => {

View file

@ -5,10 +5,14 @@ import {
useFileTreeSelection,
} from "@pierre/trees/react"
import type { GitStatus, GitStatusEntry } from "@pierre/trees"
import type {
FileTreeDirectoryHandle,
GitStatus,
GitStatusEntry,
} from "@pierre/trees"
import type { ReviewDiffFile } from "@/lib/api"
import { Skeleton } from "@/components/ui/skeleton"
import { treeThemeStyle } from "@/components/agents/AgentGitPanel"
import { TREE_UNSAFE_CSS, treeThemeStyle } from "@/components/agents/AgentGitPanel"
function reviewFileGitStatus(status: ReviewDiffFile["status"]): GitStatus {
if (status === "removed") return "deleted"
@ -100,9 +104,10 @@ function ReviewFileTreeExplorer({
const { model } = useFileTree({
paths,
gitStatus,
initialExpansion: "open",
flattenEmptyDirectories: true,
icons: "standard",
density: "default",
icons: "complete",
unsafeCSS: TREE_UNSAFE_CSS,
})
useEffect(() => {
@ -120,9 +125,13 @@ function ReviewFileTreeExplorer({
}, [selection, onSelect])
useEffect(() => {
if (selected) {
model.scrollToPath(selected, { focus: false })
if (!selected) return
const segments = selected.split("/")
for (let depth = 1; depth < segments.length; depth += 1) {
const item = model.getItem(segments.slice(0, depth).join("/"))
if (item?.isDirectory()) (item as FileTreeDirectoryHandle).expand()
}
model.scrollToPath(selected, { focus: false })
}, [model, selected])
return (