Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ plannotator/
│ │ │ ├── plan-diff/ # PlanDiffBadge, PlanDiffViewer, clean/raw diff views
│ │ │ └── sidebar/ # SidebarContainer, SidebarTabs, VersionBrowser
│ │ ├── utils/ # parser.ts, sharing.ts, storage.ts, planSave.ts, agentSwitch.ts, planDiffEngine.ts
│ │ ├── hooks/ # useSharing.ts, usePlanDiff.ts, useSidebar.ts, useLinkedDoc.ts, useAnnotationDraft.ts, useCodeAnnotationDraft.ts
│ │ ├── hooks/ # useAnnotationHighlighter.ts, useSharing.ts, usePlanDiff.ts, useSidebar.ts, useLinkedDoc.ts, useAnnotationDraft.ts, useCodeAnnotationDraft.ts
│ │ └── types.ts
│ ├── shared/ # Cross-package types (EditorAnnotation)
│ ├── editor/ # Plan review App.tsx
Expand Down Expand Up @@ -227,6 +227,10 @@ When a user denies a plan and Claude resubmits, the UI shows what changed betwee

**State** (`packages/ui/hooks/usePlanDiff.ts`): Manages base version selection, diff computation, and version fetching. The server sends `previousPlan` with the initial `/api/plan` response; the hook auto-diffs against it. Users can select any prior version from the sidebar Version Browser.

**Diff annotations:** The clean diff view supports block-level annotation — hover over added/removed/modified sections to annotate entire blocks. Annotations carry a `diffContext` field (`added`/`removed`/`modified`). Exported feedback includes `[In diff content]` labels.

**Annotation hook** (`packages/ui/hooks/useAnnotationHighlighter.ts`): Annotation infrastructure used by `Viewer.tsx`. Manages web-highlighter lifecycle, toolbar/popover state, annotation creation, text-based restoration, and scroll-to-selected. The diff view uses its own block-level hover system instead.

**Sidebar** (`packages/ui/hooks/useSidebar.ts`): Shared left sidebar with two tabs — Table of Contents and Version Browser. The "Auto-open Sidebar" setting controls whether it opens on load (TOC tab only).

## Data Types
Expand Down Expand Up @@ -258,6 +262,7 @@ interface Annotation {
createdA: number; // Timestamp
author?: string; // Tater identity
images?: ImageAttachment[]; // Attached images with names
diffContext?: 'added' | 'removed' | 'modified'; // Set when annotation created in plan diff view
startMeta?: { parentTagName; parentIndex; textOffset };
endMeta?: { parentTagName; parentIndex; textOffset };
}
Expand Down Expand Up @@ -286,7 +291,7 @@ interface Block {
- Horizontal rules (`---`)
- Paragraphs (default)

`exportAnnotations(blocks, annotations, globalAttachments)` generates human-readable feedback for Claude. Images are referenced by name: `[image-name] /tmp/path...`.
`exportAnnotations(blocks, annotations, globalAttachments)` generates human-readable feedback for Claude. Images are referenced by name: `[image-name] /tmp/path...`. Annotations with `diffContext` include `[In diff content]` labels.

## Annotation System

Expand All @@ -311,6 +316,7 @@ interface SharePayload {
p: string; // Plan markdown
a: ShareableAnnotation[]; // Compact annotations
g?: ShareableImage[]; // Global attachments
d?: (string | null)[]; // diffContext per annotation, parallel to `a`
}

type ShareableAnnotation =
Expand Down
32 changes: 17 additions & 15 deletions packages/editor/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ const App: React.FC = () => {
if (restoredGlobal.length > 0) setGlobalAttachments(restoredGlobal);
// Apply highlights to DOM after a tick
setTimeout(() => {
viewerRef.current?.applySharedAnnotations(restored);
viewerRef.current?.applySharedAnnotations(restored.filter(a => !a.diffContext));
}, 100);
}
}, [restoreDraft]);
Expand All @@ -279,7 +279,7 @@ const App: React.FC = () => {
const timer = setTimeout(() => {
// Clear existing highlights first (important when loading new share URL)
viewerRef.current?.clearAllHighlights();
viewerRef.current?.applySharedAnnotations(pendingSharedAnnotations);
viewerRef.current?.applySharedAnnotations(pendingSharedAnnotations.filter(a => !a.diffContext));
clearPendingSharedAnnotations();
}, 100);
return () => clearTimeout(timer);
Expand Down Expand Up @@ -1152,18 +1152,16 @@ const App: React.FC = () => {
showCancel
/>
<div className="min-h-full flex flex-col items-center px-2 py-3 md:px-10 md:py-8 xl:px-16">
{/* Annotation Toolstrip (hidden during plan diff) */}
{!isPlanDiffActive && (
<div className="w-full mb-3 md:mb-4 flex items-center justify-start" style={{ maxWidth: planMaxWidth }}>
<AnnotationToolstrip
inputMethod={inputMethod}
onInputMethodChange={handleInputMethodChange}
mode={editorMode}
onModeChange={handleEditorModeChange}
taterMode={taterMode}
/>
</div>
)}
{/* Annotation Toolstrip */}
<div className="w-full mb-3 md:mb-4 flex items-center justify-start" style={{ maxWidth: planMaxWidth }}>
<AnnotationToolstrip
inputMethod={inputMethod}
onInputMethodChange={handleInputMethodChange}
mode={editorMode}
onModeChange={handleEditorModeChange}
taterMode={taterMode}
/>
</div>

{/* Plan Diff View or Normal Plan View */}
{isPlanDiffActive && planDiff.diffBlocks && planDiff.diffStats ? (
Expand All @@ -1177,6 +1175,10 @@ const App: React.FC = () => {
baseVersionLabel={planDiff.diffBaseVersion != null ? `v${planDiff.diffBaseVersion}` : undefined}
baseVersion={planDiff.diffBaseVersion ?? undefined}
maxWidth={planMaxWidth}
onAddAnnotation={handleAddAnnotation}
onSelectAnnotation={handleSelectAnnotation}
selectedAnnotationId={selectedAnnotationId}
mode={editorMode}
/>
) : (
<Viewer
Expand All @@ -1185,7 +1187,7 @@ const App: React.FC = () => {
blocks={blocks}
markdown={markdown}
frontmatter={frontmatter}
annotations={annotations}
annotations={annotations.filter(a => !a.diffContext)}
onAddAnnotation={handleAddAnnotation}
onSelectAnnotation={handleSelectAnnotation}
selectedAnnotationId={selectedAnnotationId}
Expand Down
5 changes: 5 additions & 0 deletions packages/ui/components/AnnotationPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ const AnnotationCard: React.FC<{
{config.label}
</span>
</div>
{annotation.diffContext && (
<span className="text-[9px] px-1.5 py-0.5 rounded font-medium bg-muted text-muted-foreground">
diff
</span>
)}
<span className="text-[10px] text-muted-foreground/50">
{formatTimestamp(annotation.createdA)}
</span>
Expand Down
Loading