mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
0fd9826c2c
* 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.
172 lines
5.8 KiB
TypeScript
172 lines
5.8 KiB
TypeScript
import React from 'react';
|
|
import { isMac, modKey, altKey } from '../utils/platform';
|
|
|
|
/* ─── Key cap component ─── */
|
|
|
|
const Kbd: React.FC<{ children: React.ReactNode; wide?: boolean }> = ({ children, wide }) => (
|
|
<kbd
|
|
className={`inline-flex items-center justify-center h-[22px] ${
|
|
wide ? 'min-w-[22px] px-1.5' : 'min-w-[22px]'
|
|
} rounded bg-muted border border-border/60 border-b-[2px] text-[11px] font-mono leading-none text-foreground/80 shadow-sm`}
|
|
>
|
|
{children}
|
|
</kbd>
|
|
);
|
|
|
|
/* ─── Key combo renderer ─── */
|
|
|
|
const Keys: React.FC<{ keys: string[] }> = ({ keys }) => (
|
|
<span className="inline-flex items-center gap-0.5">
|
|
{keys.map((k, i) => (
|
|
<Kbd key={i} wide={k.length > 1}>{k}</Kbd>
|
|
))}
|
|
</span>
|
|
);
|
|
|
|
/* ─── Shortcut row ─── */
|
|
|
|
const ShortcutRow: React.FC<{ keys: string[]; desc: string; hint?: string }> = ({ keys, desc, hint }) => (
|
|
<div className="flex items-center justify-between py-1">
|
|
<span className="text-xs text-muted-foreground">
|
|
{desc}
|
|
{hint && (
|
|
<span className="relative group ml-1 inline-flex">
|
|
<span className="inline-flex items-center justify-center w-3.5 h-3.5 rounded-full text-[9px] font-medium bg-muted-foreground/15 text-muted-foreground/60 cursor-default">?</span>
|
|
<span className="absolute bottom-full left-0 mb-1.5 px-2.5 py-1.5 rounded bg-foreground text-background text-[11px] leading-snug w-[320px] opacity-0 pointer-events-none group-hover:opacity-100 transition-opacity shadow-lg z-50">
|
|
{hint}
|
|
</span>
|
|
</span>
|
|
)}
|
|
</span>
|
|
<Keys keys={keys} />
|
|
</div>
|
|
);
|
|
|
|
/* ─── Section ─── */
|
|
|
|
const Section: React.FC<{ title: string; children: React.ReactNode }> = ({ title, children }) => (
|
|
<div className="space-y-0.5">
|
|
<div className="text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 mb-1.5">
|
|
{title}
|
|
</div>
|
|
{children}
|
|
</div>
|
|
);
|
|
|
|
/* ─── Platform-aware key names ─── */
|
|
|
|
const enter = isMac ? '⏎' : '↵';
|
|
|
|
/* ─── Shortcut data ─── */
|
|
|
|
interface Shortcut {
|
|
keys: string[];
|
|
desc: string;
|
|
hint?: string;
|
|
}
|
|
|
|
interface ShortcutSection {
|
|
title: string;
|
|
shortcuts: Shortcut[];
|
|
}
|
|
|
|
const planShortcuts: ShortcutSection[] = [
|
|
{
|
|
title: 'Actions',
|
|
shortcuts: [
|
|
{ keys: [modKey, enter], desc: 'Submit / Approve' },
|
|
{ keys: [modKey, 'S'], desc: 'Save to notes app' },
|
|
{ keys: [modKey, 'P'], desc: 'Print plan' },
|
|
{ keys: ['Esc'], desc: 'Close dialog' },
|
|
],
|
|
},
|
|
{
|
|
title: 'Input Method',
|
|
shortcuts: [
|
|
{ keys: [altKey, 'hold'], desc: 'Temporarily switch mode', hint: 'Hold to switch between Select and Pinpoint, release to revert' },
|
|
{ keys: [altKey, altKey], desc: 'Toggle mode', hint: 'Double-tap to permanently switch between Select and Pinpoint' },
|
|
],
|
|
},
|
|
{
|
|
title: 'Annotations',
|
|
shortcuts: [
|
|
{ keys: ['a-z'], desc: 'Start typing comment', hint: 'When the annotation toolbar is open, any letter key opens the comment editor with that character' },
|
|
{ keys: [altKey, '1-0'], desc: 'Apply quick label', hint: 'Instantly applies the Nth preset label (0 = 10th). When the label picker is open, bare digits also work.' },
|
|
{ keys: [modKey, enter], desc: 'Submit comment' },
|
|
{ keys: [modKey, 'C'], desc: 'Copy selected text' },
|
|
{ keys: ['Esc'], desc: 'Close toolbar / Cancel' },
|
|
],
|
|
},
|
|
{
|
|
title: 'Image Annotator',
|
|
shortcuts: [
|
|
{ keys: ['1'], desc: 'Pen tool' },
|
|
{ keys: ['2'], desc: 'Arrow tool' },
|
|
{ keys: ['3'], desc: 'Circle tool' },
|
|
{ keys: [modKey, 'Z'], desc: 'Undo' },
|
|
{ keys: [enter], desc: 'Finish' },
|
|
{ keys: ['Esc'], desc: 'Cancel' },
|
|
],
|
|
},
|
|
];
|
|
|
|
const reviewShortcuts: ShortcutSection[] = [
|
|
{
|
|
title: 'Actions',
|
|
shortcuts: [
|
|
{ keys: [modKey, enter], desc: 'Approve / Send feedback' },
|
|
{ keys: [altKey, altKey], desc: 'Toggle destination', hint: 'Double-tap to switch between GitHub and Agent in PR review mode' },
|
|
{ keys: [modKey, '⇧', 'C'], desc: 'Toggle comment mode' },
|
|
{ keys: [modKey, 'B'], desc: 'Toggle file tree' },
|
|
{ keys: [modKey, '.'], desc: 'Toggle sidebar' },
|
|
{ keys: ['Esc'], desc: 'Collapse sidebar' },
|
|
],
|
|
},
|
|
{
|
|
title: 'File Navigation',
|
|
shortcuts: [
|
|
{ keys: ['J'], desc: 'Next file' },
|
|
{ keys: ['K'], desc: 'Previous file' },
|
|
{ keys: ['['], desc: 'Scroll to previous file', hint: 'In all-files view, scrolls the viewport to the previous file' },
|
|
{ keys: [']'], desc: 'Scroll to next file', hint: 'In all-files view, scrolls the viewport to the next file' },
|
|
{ keys: ['Home'], desc: 'First file' },
|
|
{ keys: ['End'], desc: 'Last file' },
|
|
],
|
|
},
|
|
{
|
|
title: 'File Actions',
|
|
shortcuts: [
|
|
{ keys: ['V'], desc: 'Toggle viewed', hint: 'In all-files view, also collapses the file' },
|
|
{ keys: ['A'], desc: 'Toggle git add / stage' },
|
|
{ keys: ['C'], desc: 'Collapse / expand file', hint: 'In all-files view, toggles the focused file' },
|
|
{ keys: ['Z'], desc: 'Undo collapse', hint: 'Reopens the last collapsed file and scrolls to it' },
|
|
],
|
|
},
|
|
{
|
|
title: 'Annotations',
|
|
shortcuts: [
|
|
{ keys: [modKey, enter], desc: 'Submit comment' },
|
|
{ keys: ['Tab'], desc: 'Indent in editor' },
|
|
{ keys: ['Esc'], desc: 'Close toolbar / Cancel' },
|
|
],
|
|
},
|
|
];
|
|
|
|
/* ─── Exported panel ─── */
|
|
|
|
export const KeyboardShortcuts: React.FC<{ mode: 'plan' | 'review' }> = ({ mode }) => {
|
|
const sections = mode === 'review' ? reviewShortcuts : planShortcuts;
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{sections.map((section) => (
|
|
<Section key={section.title} title={section.title}>
|
|
{section.shortcuts.map((s, i) => (
|
|
<ShortcutRow key={i} keys={s.keys} desc={s.desc} hint={s.hint} />
|
|
))}
|
|
</Section>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|