diff --git a/webui2/README.md b/webui2/README.md index 12ebe1b4d48430b5f88020e284a3bb575b9f337e..1dd4e4b8c485abf852e22d7947daf6dac8068486 100644 --- a/webui2/README.md +++ b/webui2/README.md @@ -26,7 +26,7 @@ Node 22 is required. If you use asdf, `.tool-versions` pins the right version au | `/` | Repo picker — auto-redirects for single repo | | `/$repo/tree/$ref/...path` | Code browser — directory listing | | `/$repo/blob/$ref/...path` | Code browser — file viewer | -| `/$repo/commits/$ref` | Commit history | +| `/$repo/commits/$ref?path=...` | Commit history (optionally scoped to a path) | | `/$repo/commit/$hash` | Commit detail with collapsible file diffs | | `/$repo/issues` | Issue list with search, filters, pagination | | `/$repo/issues/new` | New issue form | @@ -71,7 +71,7 @@ src/ Components are organized in three layers: -- **`ui/`** — Generic primitives managed by shadcn CLI (`npx shadcn add`). No domain knowledge. Examples: button, input, avatar, badge, popover, separator, skeleton, textarea. +- **`ui/`** — Generic primitives managed by shadcn CLI (`npx shadcn add`) or hand-written. No domain knowledge. Examples: button, input, avatar, badge, listbox (presentational compound components for dropdown menus), popover, separator, skeleton, textarea. Interactive dropdowns use `@floating-ui/react` hooks wired per-consumer with `Listbox.*` presentational primitives. - **`shared/`** — App-level reusable components. These know about the domain (bug status, labels, identities) but contain no data fetching. They use **composition APIs** (compound components) and are typed against **colocated GraphQL fragments**. Examples: issue-row, label-badge, status-badge, status-tabs, comment-card, pagination, query-input, write-preview, empty-state, section-heading, issue-filters. diff --git a/webui2/src/routes/$repo/_code.tsx b/webui2/src/routes/$repo/_code.tsx index 4fd9949ca52d021858af03c1dfafc3a647456990..569b6335b727ff2910f87251589b4fe488f065e2 100644 --- a/webui2/src/routes/$repo/_code.tsx +++ b/webui2/src/routes/$repo/_code.tsx @@ -54,7 +54,7 @@ function CodeLayout() { function handleRefSelect(newRef: GitRef) { const refName = newRef.shortName; if (viewMode === "commits") { - void navigate({ to: "/$repo/commits/$ref", params: { repo, ref: refName } }); + void navigate({ to: "/$repo/commits/$ref", params: { repo, ref: refName }, search: { path: currentPath || undefined } }); } else if (viewMode === "blob") { void navigate({ to: "/$repo/blob/$ref/$", @@ -92,6 +92,7 @@ function CodeLayout() { diff --git a/webui2/src/routes/$repo/_code/commits/$ref.tsx b/webui2/src/routes/$repo/_code/commits/$ref.tsx index 27ad5e818fb7acb3a249c659d4586f8a03b3b070..b0e8b865daf3d3b33b892f540cd49026b5ab161f 100644 --- a/webui2/src/routes/$repo/_code/commits/$ref.tsx +++ b/webui2/src/routes/$repo/_code/commits/$ref.tsx @@ -1,17 +1,24 @@ -// Commit history view: /$repo/commits/$ref +// Commit history view: /$repo/commits/$ref?path=... import { createFileRoute } from "@tanstack/react-router"; +import * as v from "valibot"; import { CommitList } from "@/components/code/commit-list"; +const commitsSearchSchema = v.object({ + path: v.fallback(v.optional(v.string()), undefined), +}); + export const Route = createFileRoute("/$repo/_code/commits/$ref")({ component: CommitsView, beforeLoad: () => ({ viewMode: "commits" as const }), + validateSearch: (search) => v.parse(commitsSearchSchema, search), }); function CommitsView() { const { ref: currentRef } = Route.useParams(); const { ref: repoRef } = Route.useRouteContext(); + const { path } = Route.useSearch(); - return ; + return ; }