feat(lanes,ui): per-lane git surface — Changes panel, VS Code-style diff, branch-aware Add lane, redesigned tooltips (#34, #35)

- Changes card beside lane detail with five modes: Files tree, overview,
  Review (whole diff, per-file collapse), single file, commit history.
- LaneDiffView: unified / side-by-side with independent scroll on both axes
  and mirrored scrollLeft, expand/collapse context, intra-line emphasis.
- Staged-only commit box; git actions (fetch/pull/push/stage/unstage/
  discard/commit/switch/branch-create/branch-delete) guarded in git-ops.js.
- Server: git-diff.js + git-ops.js behind GET /api/lanes/:id/git/* and
  POST /api/lanes/:id/git/:action; gitFacts gains upstream/ahead/behind.
- Add lane: new/existing branch, current branch, worktree list, prefill
  from the git bar's "New lane here"; /api/run/cwds gains a repo kind.
- GlobalTooltip upgrades every native title into a themed anchored bubble;
  chart/info popovers use theme tokens.
This commit is contained in:
2026-09-23 09:18:17 +07:00
parent 32a8887419
commit 1b561c22d9
47 changed files with 7354 additions and 895 deletions
+19
View File
@@ -726,6 +726,25 @@ flowchart LR
Renders the hook payload for a single event inline below its row. Scalars appear as `key: value` pairs; objects and arrays render in a terminal-styled code block with a copy button.
#### Tooltips (`components/Tooltip.tsx`)
`GlobalTooltip` is mounted once in `App.tsx` and gives **every** control in the
app the same designed tooltip — there is no wrapper to add at the call site.
It listens at the document, and on hover (after a 350 ms rest) or on keyboard
focus (immediately) it takes the element's native `title`, shows it as an
anchored bubble with an arrow, and puts the attribute back when the bubble
closes. Consequences worth knowing:
- **Write `title="…"` exactly as before.** That is the whole API. A control
keeps its native tooltip, and its accessible name, when JS has not run.
- **Opt out with `data-tip-off`** where the browser's own tooltip is wanted.
- The bubble is built from theme tokens (`TOOLTIP_SURFACE`), so it is legible
in light mode; it flips above/below, clamps to the viewport, and closes on
scroll, resize, pointer-down or `Escape`.
- `Tip` (`components/Tip.tsx`) stays separate and cursor-following for
expanding a truncated **number** inside a line of text, but draws the same
surface so the two read as one thing.
---
## Utilities