Unify capture/edit form, thicker active document border, layer-hide toggles

Three UX iterations rolled into one:

1. Unified evidence form
   - New EvidenceFormBody is the single source for "citation +
     commentary" editing. Both InlineCaptureForm (creating fresh
     evidence from a selection) and the EvidenceCard edit mode render
     this body with their own save/cancel labels + badge/helper text.
   - The capture form now exposes the citation as an editable
     textarea — pre-filled with the selection text — so the user can
     refine a partial capture before saving without re-selecting.
   - Old testid prefixes are unchanged for the inline-capture flow
     (`inline-capture-quote/commentary/save/cancel`); edit-mode
     testids are now `evidence-edit-<id>-{quote,commentary,save,cancel}`.

2. Active document card
   - The blue background alone was the only "this is open" cue. Added
     a 3px #0050b3 border (matching the evidence-card thick-border
     pattern, but in the documents-are-blue palette) plus a
     `data-active` attribute.

3. PDF layer-hide diagnostics
   - New debug flags `hideCanvas`, `hideTextLayer`, `hideAnnotationLayer`,
     `hideXfaLayer` — applied as `.ce-hide-<layer>` classes on the viewer
     wrapper, each `display: none`-ing the matching PDF.js layer.
   - SessionMenu groups the toggles under a "PDF diagnostics" header
     with a new shared DebugCheckbox helper. The existing "Debug text
     layer" highlight toggle now lives in the same group.
   - Lets the user isolate stacking issues by elimination — e.g.
     "hide text layer, can I now see the canvas content underneath?".

Tests
   - citation-card-export-e2e + session-export-reimport switched from
     placeholder/role-name lookups to the inline-capture testids so
     they survive form-copy changes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-05-26 23:27:08 +02:00
parent f42b4ec87c
commit bef2725fdd
11 changed files with 309 additions and 148 deletions

View file

@ -36,6 +36,10 @@ export function SessionMenu({ onExportZip, onImportZip, onOpenSamples }: Session
const tick = useSessionListTick();
const active = useActiveSession();
const [debugTextLayer, setDebugTextLayer] = useDebugFlag("textLayer");
const [hideCanvas, setHideCanvas] = useDebugFlag("hideCanvas");
const [hideTextLayer, setHideTextLayer] = useDebugFlag("hideTextLayer");
const [hideAnnotationLayer, setHideAnnotationLayer] = useDebugFlag("hideAnnotationLayer");
const [hideXfaLayer, setHideXfaLayer] = useDebugFlag("hideXfaLayer");
const [open, setOpen] = useState(false);
const [newName, setNewName] = useState("");
@ -407,25 +411,52 @@ export function SessionMenu({ onExportZip, onImportZip, onOpenSamples }: Session
)}
<hr style={dividerStyle} />
<label
data-testid="session-menu-debug-textlayer"
<div
style={{
...menuItemStyle,
display: "flex",
alignItems: "center",
gap: 6,
cursor: "pointer",
padding: "4px 8px",
color: "#666",
fontSize: 11,
textTransform: "uppercase",
letterSpacing: 0.5,
}}
title="Paint the PDF text-layer spans in yellow so you can see what's selectable. Also logs every selection event to the browser console."
>
<input
type="checkbox"
checked={debugTextLayer}
onChange={(e) => setDebugTextLayer(e.target.checked)}
style={{ margin: 0 }}
/>
Debug text layer
</label>
PDF diagnostics
</div>
<DebugCheckbox
label="Highlight text layer"
testid="session-menu-debug-textlayer"
title="Paint the PDF text-layer spans in light grey so you can see what's selectable. Logs every selection event to the browser console."
checked={debugTextLayer}
onChange={setDebugTextLayer}
/>
<DebugCheckbox
label="Hide canvas layer"
testid="session-menu-hide-canvas"
title="Hide the rendered glyphs so only the text/annotation overlay layers remain. Use to see if the textLayer covers regions where the canvas has no content."
checked={hideCanvas}
onChange={setHideCanvas}
/>
<DebugCheckbox
label="Hide text layer"
testid="session-menu-hide-textlayer"
title="Hide the invisible selection text layer entirely. Use to see if it's covering the canvas content underneath."
checked={hideTextLayer}
onChange={setHideTextLayer}
/>
<DebugCheckbox
label="Hide annotation layer"
testid="session-menu-hide-annotation"
title="Hide PDF annotations (stamps, form widgets, links). Use to see if a stamp is obscuring content or capturing your clicks."
checked={hideAnnotationLayer}
onChange={setHideAnnotationLayer}
/>
<DebugCheckbox
label="Hide XFA layer"
testid="session-menu-hide-xfa"
title="Hide the XFA form layer (rare; only present on Adobe XFA forms)."
checked={hideXfaLayer}
onChange={setHideXfaLayer}
/>
<button
type="button"
role="menuitem"
@ -459,6 +490,38 @@ export function SessionMenu({ onExportZip, onImportZip, onOpenSamples }: Session
);
}
interface DebugCheckboxProps {
readonly label: string;
readonly testid: string;
readonly title: string;
readonly checked: boolean;
onChange(next: boolean): void;
}
function DebugCheckbox(p: DebugCheckboxProps) {
return (
<label
data-testid={p.testid}
title={p.title}
style={{
...menuItemStyle,
display: "flex",
alignItems: "center",
gap: 6,
cursor: "pointer",
}}
>
<input
type="checkbox"
checked={p.checked}
onChange={(e) => p.onChange(e.target.checked)}
style={{ margin: 0 }}
/>
{p.label}
</label>
);
}
const menuItemStyle: CSSProperties = {
display: "block",
width: "100%",