feat: edit in the Changes panel, git graph history, plan quota (v2.3.0)

- Changes panel: a working file opens in a CodeMirror editor with its diff
  inline (DiffEditor.tsx, @codemirror/merge, lazy-loaded); Changes folds the
  unchanged lines, Whole file shows them; side by side at 50/50 and full
  width; a Revert per block; original from HEAD or the branch's merge base
  (`mergeBase` on GET /git/changes?range=branch)
- Every diff: green = line added whole, red = removed whole, blue = edited
  in place (--diff-mod)
- History drawn as a commit graph (#58: `parents` on GET /git/log,
  --date-order; lib/commitGraph.ts)
- Per-workspace never-stage list, drawn orange in the Files tree (--kept);
  closed Terminal rows past three deleted
- Status bar plan quota for Claude (per account) and Codex
  (GET /api/pricing/quota, server/lib/quota.js); compact hover panel that
  stays open, Refresh button with a spinner
- Settings → Appearance holds language, theme and pet; Ctrl+Shift+C copies;
  compact sidebar navigation and short session times
This commit is contained in:
2026-10-06 15:38:25 +07:00
parent f0500dc592
commit daf5b7be92
65 changed files with 2414 additions and 587 deletions
+10 -8
View File
@@ -396,13 +396,15 @@ export function Sidebar({
onUpdateAvailableChange?.(updateAvailable);
}, [updateAvailable, onUpdateAvailableChange]);
// Same density and selection as a workspace row, so the whole sidebar
// reads as one list: no border, the active item tinted with an accent icon.
const navClass = ({ isActive }: { isActive: boolean }) =>
`flex items-center gap-3 rounded-lg text-sm font-medium transition-colors duration-150 ${
collapsed ? "justify-center px-2 py-2.5" : "px-3 py-2.5"
`flex items-center gap-2.5 rounded-md text-[13px] transition-colors duration-150 ${
collapsed ? "justify-center px-2 py-2" : "px-2.5 py-1.5"
} ${
isActive
? "bg-accent/10 text-accent border border-accent/20"
: "text-fg-secondary hover:text-fg-primary hover:bg-surface-3 border border-transparent"
? "bg-accent/10 font-medium text-fg-primary [&>svg]:text-accent"
: "text-fg-secondary hover:bg-surface-3 hover:text-fg-primary"
}`;
return (
@@ -451,7 +453,7 @@ export function Sidebar({
Chevron buttons appear at the edges when content is clipped, so the
user knows there's more to reach without inspecting the scrollbar. */}
<div className="flex-1 min-h-0 relative flex">
<nav ref={navRef} className="flex-1 overflow-y-auto overflow-x-hidden px-2 py-3 space-y-1">
<nav ref={navRef} className="flex-1 overflow-y-auto overflow-x-hidden px-2 py-2 space-y-px">
{NAV_KEYS.map(({ to, icon: Icon, key }) => {
const label = t(key);
return (
@@ -475,7 +477,7 @@ export function Sidebar({
onClick={onToggle}
title={t("lanes:tree.title")}
aria-label={t("lanes:tree.title")}
className="flex w-full items-center justify-center rounded-lg border border-transparent px-2 py-2.5 text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg-primary"
className="flex w-full items-center justify-center rounded-md px-2 py-2 text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg-primary"
>
<FolderTree className="w-4 h-4" />
</button>
@@ -528,8 +530,8 @@ export function Sidebar({
data-testid="sidebar-toggle"
title={drawer ? t("nav:closeMenu") : collapsed ? t("nav:expand") : t("nav:collapse")}
aria-label={drawer ? t("nav:closeMenu") : collapsed ? t("nav:expand") : t("nav:collapse")}
className={`inline-flex items-center justify-center rounded-lg text-fg-muted transition-colors hover:bg-surface-3 hover:text-fg-primary ${
collapsed ? "py-2.5" : "h-9 w-9 flex-shrink-0"
className={`inline-flex items-center justify-center rounded-md text-fg-muted transition-colors hover:bg-surface-3 hover:text-fg-primary ${
collapsed ? "py-2" : "h-8 w-8 flex-shrink-0"
}`}
>
{collapsed ? (