From bef2725fdd997e8596e8115f0af3c5ba64ba1da1 Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 26 May 2026 23:27:08 +0200 Subject: [PATCH] Unify capture/edit form, thicker active document border, layer-hide toggles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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--{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-` 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 --- src/anchor/debug-textlayer.css | 24 ++++ src/anchor/pdf-viewer-adapter-spike.tsx | 24 +++- src/app/sessions/SessionMenu.tsx | 95 +++++++++++++--- src/work/CollectionList.tsx | 3 +- src/work/EvidenceFormBody.tsx | 104 ++++++++++++++++++ src/work/EvidenceSidebar.tsx | 86 +++------------ src/work/InlineCaptureForm.tsx | 81 ++++++-------- src/work/ViewerShell.tsx | 25 ++++- src/work/useDebugFlags.ts | 7 +- .../citation-card-export-e2e.dom.test.tsx | 4 +- .../session-export-reimport.dom.test.tsx | 4 +- 11 files changed, 309 insertions(+), 148 deletions(-) create mode 100644 src/work/EvidenceFormBody.tsx diff --git a/src/anchor/debug-textlayer.css b/src/anchor/debug-textlayer.css index 9c251e7..6c029f0 100644 --- a/src/anchor/debug-textlayer.css +++ b/src/anchor/debug-textlayer.css @@ -33,3 +33,27 @@ .ce-debug-textlayer canvas { opacity: 0.4; } + +/* + * Layer-visibility toggles. Each `.ce-hide-` class is applied + * to the same viewer-wrapper element so a single parent can hide any + * combination of layers. Useful for diagnosing layer stacking issues + * (e.g. "is the textLayer covering the canvas?") by elimination. + */ + +.ce-hide-canvas canvas { + display: none !important; +} + +.ce-hide-text-layer .textLayer { + display: none !important; +} + +.ce-hide-annotation-layer .annotationLayer, +.ce-hide-annotation-layer .annotationEditorLayer { + display: none !important; +} + +.ce-hide-xfa-layer .xfaLayer { + display: none !important; +} diff --git a/src/anchor/pdf-viewer-adapter-spike.tsx b/src/anchor/pdf-viewer-adapter-spike.tsx index b2c501d..2b4f5df 100644 --- a/src/anchor/pdf-viewer-adapter-spike.tsx +++ b/src/anchor/pdf-viewer-adapter-spike.tsx @@ -199,6 +199,15 @@ export interface PdfSpikeViewerProps { * image-only. Also logs every onSelection event to the console. */ readonly debugTextLayer?: boolean; + /** + * Hide specific PDF.js layers so you can see what sits underneath. + * Helps diagnose layer-stacking issues (e.g. "is the text layer + * covering the canvas content?"). + */ + readonly hideCanvas?: boolean; + readonly hideTextLayer?: boolean; + readonly hideAnnotationLayer?: boolean; + readonly hideXfaLayer?: boolean; } export interface StoredAnnotation { @@ -222,11 +231,24 @@ export function PdfSpikeViewer(props: PdfSpikeViewerProps) { activeAnnotationId, onHighlightClicked, debugTextLayer, + hideCanvas, + hideTextLayer, + hideAnnotationLayer, + hideXfaLayer, } = props; const HighlightContainer = useMemo( () => makeSpikeHighlightContainer({ activeAnnotationId, onHighlightClicked }), [activeAnnotationId, onHighlightClicked], ); + const wrapperClasses = [ + debugTextLayer ? "ce-debug-textlayer" : null, + hideCanvas ? "ce-hide-canvas" : null, + hideTextLayer ? "ce-hide-text-layer" : null, + hideAnnotationLayer ? "ce-hide-annotation-layer" : null, + hideXfaLayer ? "ce-hide-xfa-layer" : null, + ] + .filter((c): c is string => c !== null) + .join(" "); const utilsRef = useRef(null); const [didScroll, setDidScroll] = useState(null); @@ -273,7 +295,7 @@ export function PdfSpikeViewer(props: PdfSpikeViewerProps) { return (
0 ? wrapperClasses : undefined} style={{ height: "100%" }} > diff --git a/src/app/sessions/SessionMenu.tsx b/src/app/sessions/SessionMenu.tsx index e7ee672..c4ffb55 100644 --- a/src/app/sessions/SessionMenu.tsx +++ b/src/app/sessions/SessionMenu.tsx @@ -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 )}
- + PDF diagnostics +
+ + + + +