2026-04-29 23:51:17 -07:00
|
|
|
import React from 'react';
|
|
|
|
|
import * as Popover from '@radix-ui/react-popover';
|
|
|
|
|
import { configStore, useConfigValue } from '@plannotator/ui/config';
|
|
|
|
|
import {
|
|
|
|
|
DIFF_STYLE_OPTIONS,
|
|
|
|
|
OVERFLOW_OPTIONS,
|
|
|
|
|
INDICATOR_OPTIONS,
|
|
|
|
|
LINE_DIFF_OPTIONS,
|
|
|
|
|
} from '@plannotator/ui/components/Settings';
|
|
|
|
|
|
|
|
|
|
function CompactSegmented<T extends string>({ options, value, onChange }: {
|
|
|
|
|
options: { value: T; label: string }[];
|
|
|
|
|
value: T;
|
|
|
|
|
onChange: (v: T) => void;
|
|
|
|
|
}) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex items-center gap-px bg-muted/60 rounded-md p-px">
|
|
|
|
|
{options.map((opt) => (
|
|
|
|
|
<button
|
|
|
|
|
key={opt.value}
|
|
|
|
|
onClick={() => onChange(opt.value)}
|
|
|
|
|
className={`flex-1 px-2 py-1 text-[11px] rounded-[5px] transition-colors ${
|
|
|
|
|
value === opt.value
|
|
|
|
|
? 'bg-background text-foreground shadow-sm font-medium'
|
|
|
|
|
: 'text-muted-foreground hover:text-foreground'
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
{opt.label}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function CompactToggle({ checked, onChange, label }: {
|
|
|
|
|
checked: boolean;
|
|
|
|
|
onChange: (v: boolean) => void;
|
|
|
|
|
label: string;
|
|
|
|
|
}) {
|
|
|
|
|
return (
|
|
|
|
|
<button
|
|
|
|
|
role="switch"
|
|
|
|
|
aria-checked={checked}
|
|
|
|
|
onClick={() => onChange(!checked)}
|
|
|
|
|
className="w-full flex items-center justify-between py-1 group"
|
|
|
|
|
>
|
|
|
|
|
<span className="text-[11px] text-muted-foreground group-hover:text-foreground transition-colors">{label}</span>
|
|
|
|
|
<span className={`relative inline-flex h-4 w-7 items-center rounded-full transition-colors ${
|
|
|
|
|
checked ? 'bg-primary' : 'bg-muted-foreground/25'
|
|
|
|
|
}`}>
|
|
|
|
|
<span className={`inline-block h-3 w-3 rounded-full bg-white shadow-sm transition-transform ${
|
|
|
|
|
checked ? 'translate-x-3.5' : 'translate-x-0.5'
|
|
|
|
|
}`} />
|
|
|
|
|
</span>
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const DiffOptionsPopover: React.FC = () => {
|
|
|
|
|
const diffStyle = useConfigValue('diffStyle');
|
|
|
|
|
const diffOverflow = useConfigValue('diffOverflow');
|
|
|
|
|
const diffIndicators = useConfigValue('diffIndicators');
|
|
|
|
|
const diffLineDiffType = useConfigValue('diffLineDiffType');
|
|
|
|
|
const diffShowLineNumbers = useConfigValue('diffShowLineNumbers');
|
|
|
|
|
const diffShowBackground = useConfigValue('diffShowBackground');
|
|
|
|
|
const diffHideWhitespace = useConfigValue('diffHideWhitespace');
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Popover.Root>
|
|
|
|
|
<Popover.Trigger asChild>
|
|
|
|
|
<button
|
|
|
|
|
className="text-xs text-muted-foreground hover:text-foreground rounded hover:bg-muted transition-colors flex items-center px-1.5 py-1"
|
|
|
|
|
title="Diff display options"
|
|
|
|
|
>
|
|
|
|
|
<svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
|
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
</Popover.Trigger>
|
|
|
|
|
<Popover.Portal>
|
|
|
|
|
<Popover.Content
|
|
|
|
|
align="end"
|
|
|
|
|
sideOffset={6}
|
feat(review): all-files diff view with unified scrolling (#640)
* feat(review): all-files diff view with lazy mounting
Renders all diffs in a single scrollable pane using individual FileDiff
components with sticky file headers, collapse toggles, and viewport-based
lazy mounting via IntersectionObserver.
For provenance purposes, this commit was AI assisted.
* feat(review): convert all-files view to dock panel + fixes
- Register AllFilesDiffView as a proper dock panel so it coexists
with single-file tabs, AI chat, PR panels
- Remove viewMode toggle in favor of dock panel lifecycle
- Fix annotation toolbar positioning (mouse tracking)
- Fix annotation PR/scope filtering for stacked PRs
- Fix stale patch on file switch (deferred toolbar open)
- Fix conventional comments boolean comparison
- Fix SuggestionModal props to match DiffViewer pattern
- Wire reviewBase for correct hunk expansion context
- Fix pre-existing CSS bug on .has-annotations background
- Add Shift+V/A keyboard shortcuts for viewed/stage toggle
- Add [/] keyboard shortcuts for file-to-file scrolling
- Add keyboard shortcuts to settings panel
- Restore scroll-based file tree highlight via dock panel state
For provenance purposes, this commit was AI assisted.
* feat(review): sidebar toggles, keyboard shortcuts, click-drag selection
- Move sidebar tab buttons (annotations/AI/agents) to header bar
- Generalize useSidebar hook for both plan and review editors
- Remove internal tab state from ReviewSidebar, receive from parent
- Add file tree toggle button at far-left of header
- Add click-and-drag line selection in diff content area
- Change keyboard shortcuts from Shift+V/A to bare v/a/c
v = toggle viewed (+ collapse in all-files mode)
a = toggle git add/stage
c = collapse/expand file (all-files mode)
- Widen DiffOptionsPopover to prevent word-alt line break
- Fix Shift+V/A targeting wrong file in all-files mode
- Default to all-files panel on initial load
- Hide dock headers when all-files panel is the only panel
For provenance purposes, this commit was AI assisted.
* feat(review): click-and-drag line selection in diff content area
Extract shared selection helpers to utils/diffSelection.ts and add
mouseup handlers to both DiffViewer and AllFilesDiffView so users can
click and drag across code lines to open the annotation toolbar —
not just the gutter.
For provenance purposes, this commit was AI assisted.
* fix(review): address AI review findings
- Gate all-files keyboard shortcuts on isActive to prevent double-toggle
when a single-file tab is focused
- Fix getDiffSelection to iterate all diffs-container elements so
click-drag selection works on files beyond the first
- Clear needsInitialDiffPanel after opening all-files panel to prevent
forced reactivation on diff switches
- Clear activeFilePath and collapsedFiles when files change to prevent
stale state across PR/diff switches
- Add file.patch to LazyFileDiff fetch deps so file contents refetch
when the diff context changes
- Add toggleCollapse to keyboard effect dependency array
For provenance purposes, this commit was AI assisted.
* feat(review): add z to undo collapse with scroll-back
Press z to reopen the last collapsed file and scroll back to it.
Maintains a history stack so repeated z walks back through collapses.
Skips already-expanded entries. History clears on diff/PR switch.
For provenance purposes, this commit was AI assisted.
* fix(review): review findings + sidebar toggles + folder icon
- Fix stale context memo: add isAllFilesActive + handleAddAnnotationForFile
to useMemo deps
- Fix v handler: clear activeFilePath after collapse, only collapse when
marking viewed ON (not when toggling OFF)
- Fix click-drag copy regression: only trigger annotation toolbar for
multi-line selections, preserve single-line/word selection for Cmd+C
- Fix LazyFileDiff: clear stale file contents before refetch
- Clean up App.tsx v/a handler: early return when isAllFilesActive
- Add Cmd+B (file tree) and Cmd+. (sidebar) keyboard shortcuts
- Add toggle menu items with kbd badges to Options dropdown
- Replace file tree icon with simple folder
- Add z (undo collapse) to keyboard shortcuts panel
For provenance purposes, this commit was AI assisted.
* chore: remove dead code from iterations
- Remove unused FileTreeIcon import and component file
- Remove unused AnnotationsIcon component from ReviewHeaderMenu
- Remove unused onClose prop and close button from FileTree
For provenance purposes, this commit was AI assisted.
* fix(review): gate v/a on diff panel, keep annotation selection in all-files
- Track isDiffPanelActive so v/a shortcuts only fire when viewing a
single-file diff, not PR Comments/Summary/Agent panels
- Annotation selection stays in all-files mode instead of switching to
a single-file tab — lets the scroll-to-annotation effect handle it
For provenance purposes, this commit was AI assisted.
2026-04-30 23:39:43 -07:00
|
|
|
className="z-50 w-72 bg-popover text-popover-foreground border border-border rounded-lg shadow-lg overflow-hidden origin-[var(--radix-popover-content-transform-origin)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
2026-04-29 23:51:17 -07:00
|
|
|
>
|
|
|
|
|
<div className="p-2.5 space-y-2">
|
|
|
|
|
<div className="space-y-1.5">
|
|
|
|
|
<div>
|
|
|
|
|
<div className="text-[10px] uppercase tracking-wide text-muted-foreground/70 mb-1">Layout</div>
|
feat(review): all-files diff view with unified scrolling (#640)
* feat(review): all-files diff view with lazy mounting
Renders all diffs in a single scrollable pane using individual FileDiff
components with sticky file headers, collapse toggles, and viewport-based
lazy mounting via IntersectionObserver.
For provenance purposes, this commit was AI assisted.
* feat(review): convert all-files view to dock panel + fixes
- Register AllFilesDiffView as a proper dock panel so it coexists
with single-file tabs, AI chat, PR panels
- Remove viewMode toggle in favor of dock panel lifecycle
- Fix annotation toolbar positioning (mouse tracking)
- Fix annotation PR/scope filtering for stacked PRs
- Fix stale patch on file switch (deferred toolbar open)
- Fix conventional comments boolean comparison
- Fix SuggestionModal props to match DiffViewer pattern
- Wire reviewBase for correct hunk expansion context
- Fix pre-existing CSS bug on .has-annotations background
- Add Shift+V/A keyboard shortcuts for viewed/stage toggle
- Add [/] keyboard shortcuts for file-to-file scrolling
- Add keyboard shortcuts to settings panel
- Restore scroll-based file tree highlight via dock panel state
For provenance purposes, this commit was AI assisted.
* feat(review): sidebar toggles, keyboard shortcuts, click-drag selection
- Move sidebar tab buttons (annotations/AI/agents) to header bar
- Generalize useSidebar hook for both plan and review editors
- Remove internal tab state from ReviewSidebar, receive from parent
- Add file tree toggle button at far-left of header
- Add click-and-drag line selection in diff content area
- Change keyboard shortcuts from Shift+V/A to bare v/a/c
v = toggle viewed (+ collapse in all-files mode)
a = toggle git add/stage
c = collapse/expand file (all-files mode)
- Widen DiffOptionsPopover to prevent word-alt line break
- Fix Shift+V/A targeting wrong file in all-files mode
- Default to all-files panel on initial load
- Hide dock headers when all-files panel is the only panel
For provenance purposes, this commit was AI assisted.
* feat(review): click-and-drag line selection in diff content area
Extract shared selection helpers to utils/diffSelection.ts and add
mouseup handlers to both DiffViewer and AllFilesDiffView so users can
click and drag across code lines to open the annotation toolbar —
not just the gutter.
For provenance purposes, this commit was AI assisted.
* fix(review): address AI review findings
- Gate all-files keyboard shortcuts on isActive to prevent double-toggle
when a single-file tab is focused
- Fix getDiffSelection to iterate all diffs-container elements so
click-drag selection works on files beyond the first
- Clear needsInitialDiffPanel after opening all-files panel to prevent
forced reactivation on diff switches
- Clear activeFilePath and collapsedFiles when files change to prevent
stale state across PR/diff switches
- Add file.patch to LazyFileDiff fetch deps so file contents refetch
when the diff context changes
- Add toggleCollapse to keyboard effect dependency array
For provenance purposes, this commit was AI assisted.
* feat(review): add z to undo collapse with scroll-back
Press z to reopen the last collapsed file and scroll back to it.
Maintains a history stack so repeated z walks back through collapses.
Skips already-expanded entries. History clears on diff/PR switch.
For provenance purposes, this commit was AI assisted.
* fix(review): review findings + sidebar toggles + folder icon
- Fix stale context memo: add isAllFilesActive + handleAddAnnotationForFile
to useMemo deps
- Fix v handler: clear activeFilePath after collapse, only collapse when
marking viewed ON (not when toggling OFF)
- Fix click-drag copy regression: only trigger annotation toolbar for
multi-line selections, preserve single-line/word selection for Cmd+C
- Fix LazyFileDiff: clear stale file contents before refetch
- Clean up App.tsx v/a handler: early return when isAllFilesActive
- Add Cmd+B (file tree) and Cmd+. (sidebar) keyboard shortcuts
- Add toggle menu items with kbd badges to Options dropdown
- Replace file tree icon with simple folder
- Add z (undo collapse) to keyboard shortcuts panel
For provenance purposes, this commit was AI assisted.
* chore: remove dead code from iterations
- Remove unused FileTreeIcon import and component file
- Remove unused AnnotationsIcon component from ReviewHeaderMenu
- Remove unused onClose prop and close button from FileTree
For provenance purposes, this commit was AI assisted.
* fix(review): gate v/a on diff panel, keep annotation selection in all-files
- Track isDiffPanelActive so v/a shortcuts only fire when viewing a
single-file diff, not PR Comments/Summary/Agent panels
- Annotation selection stays in all-files mode instead of switching to
a single-file tab — lets the scroll-to-annotation effect handle it
For provenance purposes, this commit was AI assisted.
2026-04-30 23:39:43 -07:00
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<div className="flex-1">
|
2026-04-29 23:51:17 -07:00
|
|
|
<CompactSegmented options={DIFF_STYLE_OPTIONS} value={diffStyle} onChange={(v) => configStore.set('diffStyle', v)} />
|
|
|
|
|
</div>
|
feat(review): all-files diff view with unified scrolling (#640)
* feat(review): all-files diff view with lazy mounting
Renders all diffs in a single scrollable pane using individual FileDiff
components with sticky file headers, collapse toggles, and viewport-based
lazy mounting via IntersectionObserver.
For provenance purposes, this commit was AI assisted.
* feat(review): convert all-files view to dock panel + fixes
- Register AllFilesDiffView as a proper dock panel so it coexists
with single-file tabs, AI chat, PR panels
- Remove viewMode toggle in favor of dock panel lifecycle
- Fix annotation toolbar positioning (mouse tracking)
- Fix annotation PR/scope filtering for stacked PRs
- Fix stale patch on file switch (deferred toolbar open)
- Fix conventional comments boolean comparison
- Fix SuggestionModal props to match DiffViewer pattern
- Wire reviewBase for correct hunk expansion context
- Fix pre-existing CSS bug on .has-annotations background
- Add Shift+V/A keyboard shortcuts for viewed/stage toggle
- Add [/] keyboard shortcuts for file-to-file scrolling
- Add keyboard shortcuts to settings panel
- Restore scroll-based file tree highlight via dock panel state
For provenance purposes, this commit was AI assisted.
* feat(review): sidebar toggles, keyboard shortcuts, click-drag selection
- Move sidebar tab buttons (annotations/AI/agents) to header bar
- Generalize useSidebar hook for both plan and review editors
- Remove internal tab state from ReviewSidebar, receive from parent
- Add file tree toggle button at far-left of header
- Add click-and-drag line selection in diff content area
- Change keyboard shortcuts from Shift+V/A to bare v/a/c
v = toggle viewed (+ collapse in all-files mode)
a = toggle git add/stage
c = collapse/expand file (all-files mode)
- Widen DiffOptionsPopover to prevent word-alt line break
- Fix Shift+V/A targeting wrong file in all-files mode
- Default to all-files panel on initial load
- Hide dock headers when all-files panel is the only panel
For provenance purposes, this commit was AI assisted.
* feat(review): click-and-drag line selection in diff content area
Extract shared selection helpers to utils/diffSelection.ts and add
mouseup handlers to both DiffViewer and AllFilesDiffView so users can
click and drag across code lines to open the annotation toolbar —
not just the gutter.
For provenance purposes, this commit was AI assisted.
* fix(review): address AI review findings
- Gate all-files keyboard shortcuts on isActive to prevent double-toggle
when a single-file tab is focused
- Fix getDiffSelection to iterate all diffs-container elements so
click-drag selection works on files beyond the first
- Clear needsInitialDiffPanel after opening all-files panel to prevent
forced reactivation on diff switches
- Clear activeFilePath and collapsedFiles when files change to prevent
stale state across PR/diff switches
- Add file.patch to LazyFileDiff fetch deps so file contents refetch
when the diff context changes
- Add toggleCollapse to keyboard effect dependency array
For provenance purposes, this commit was AI assisted.
* feat(review): add z to undo collapse with scroll-back
Press z to reopen the last collapsed file and scroll back to it.
Maintains a history stack so repeated z walks back through collapses.
Skips already-expanded entries. History clears on diff/PR switch.
For provenance purposes, this commit was AI assisted.
* fix(review): review findings + sidebar toggles + folder icon
- Fix stale context memo: add isAllFilesActive + handleAddAnnotationForFile
to useMemo deps
- Fix v handler: clear activeFilePath after collapse, only collapse when
marking viewed ON (not when toggling OFF)
- Fix click-drag copy regression: only trigger annotation toolbar for
multi-line selections, preserve single-line/word selection for Cmd+C
- Fix LazyFileDiff: clear stale file contents before refetch
- Clean up App.tsx v/a handler: early return when isAllFilesActive
- Add Cmd+B (file tree) and Cmd+. (sidebar) keyboard shortcuts
- Add toggle menu items with kbd badges to Options dropdown
- Replace file tree icon with simple folder
- Add z (undo collapse) to keyboard shortcuts panel
For provenance purposes, this commit was AI assisted.
* chore: remove dead code from iterations
- Remove unused FileTreeIcon import and component file
- Remove unused AnnotationsIcon component from ReviewHeaderMenu
- Remove unused onClose prop and close button from FileTree
For provenance purposes, this commit was AI assisted.
* fix(review): gate v/a on diff panel, keep annotation selection in all-files
- Track isDiffPanelActive so v/a shortcuts only fire when viewing a
single-file diff, not PR Comments/Summary/Agent panels
- Annotation selection stays in all-files mode instead of switching to
a single-file tab — lets the scroll-to-annotation effect handle it
For provenance purposes, this commit was AI assisted.
2026-04-30 23:39:43 -07:00
|
|
|
<div className="w-px h-5 bg-border/50 flex-shrink-0" />
|
|
|
|
|
<div className="flex-1">
|
2026-04-29 23:51:17 -07:00
|
|
|
<CompactSegmented options={OVERFLOW_OPTIONS} value={diffOverflow} onChange={(v) => configStore.set('diffOverflow', v)} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<div className="text-[10px] uppercase tracking-wide text-muted-foreground/70 mb-1">Indicators</div>
|
|
|
|
|
<CompactSegmented options={INDICATOR_OPTIONS} value={diffIndicators} onChange={(v) => configStore.set('diffIndicators', v)} />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<div className="text-[10px] uppercase tracking-wide text-muted-foreground/70 mb-1">Inline diff</div>
|
|
|
|
|
<CompactSegmented options={LINE_DIFF_OPTIONS} value={diffLineDiffType} onChange={(v) => configStore.set('diffLineDiffType', v)} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="border-t border-border/50" />
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
<CompactToggle checked={diffShowLineNumbers} onChange={(v) => configStore.set('diffShowLineNumbers', v)} label="Line numbers" />
|
|
|
|
|
<CompactToggle checked={diffShowBackground} onChange={(v) => configStore.set('diffShowBackground', v)} label="Diff background" />
|
|
|
|
|
<CompactToggle checked={diffHideWhitespace} onChange={(v) => configStore.set('diffHideWhitespace', v)} label="Hide whitespace" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Popover.Content>
|
|
|
|
|
</Popover.Portal>
|
|
|
|
|
</Popover.Root>
|
|
|
|
|
);
|
|
|
|
|
};
|