From d389dc2023809d28c62919588d41a43fd514945d Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 5 Apr 2026 23:26:02 +0200 Subject: [PATCH] feat(annotations): dim non-active annotations when a block is focused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When activeAnnotationId is set, the active annotation stays at full opacity with a highlight box-shadow, while all other annotations fade to 30% opacity (300ms ease transition). When no block is focused, all annotations show at full opacity. Prop chain: activeAnnotationId flows from PdfViewer → AnnotationLayer. 2 new tests (RED/GREEN): - dims non-active annotations when activeAnnotationId is set - shows all at full opacity when no activeAnnotationId Co-Authored-By: Claude Sonnet 4.6 --- .../src/lib/components/AnnotationLayer.svelte | 9 ++++-- .../components/AnnotationLayer.svelte.spec.ts | 29 +++++++++++++++++++ frontend/src/lib/components/PdfViewer.svelte | 1 + 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/components/AnnotationLayer.svelte b/frontend/src/lib/components/AnnotationLayer.svelte index ed8ce6d7..2afe3b47 100644 --- a/frontend/src/lib/components/AnnotationLayer.svelte +++ b/frontend/src/lib/components/AnnotationLayer.svelte @@ -13,6 +13,7 @@ let { canDraw, color, blockNumbers = {}, + activeAnnotationId = null, onDraw, onAnnotationClick }: { @@ -20,6 +21,7 @@ let { canDraw: boolean; color: string; blockNumbers?: Record; + activeAnnotationId?: string | null; onDraw: (rect: DrawRect) => void; onAnnotationClick?: (id: string) => void; } = $props(); @@ -121,11 +123,12 @@ const containerStyle = $derived( top: {annotation.y * 100}%; width: {annotation.width * 100}%; height: {annotation.height * 100}%; - background-color: {hexToRgba(annotation.color, hoveredId === annotation.id ? 0.5 : 0.3)}; - box-shadow: {hoveredId === annotation.id ? `inset 0 0 0 2px ${hexToRgba(annotation.color, 0.8)}` : 'none'}; + background-color: {hexToRgba(annotation.color, hoveredId === annotation.id || annotation.id === activeAnnotationId ? 0.5 : 0.3)}; + box-shadow: {annotation.id === activeAnnotationId ? `inset 0 0 0 2px ${hexToRgba(annotation.color, 0.8)}` : hoveredId === annotation.id ? `inset 0 0 0 2px ${hexToRgba(annotation.color, 0.8)}` : 'none'}; + opacity: {activeAnnotationId && annotation.id !== activeAnnotationId ? 0.3 : 1}; pointer-events: auto; cursor: pointer; - transition: background-color 0.15s ease, box-shadow 0.15s ease; + transition: background-color 0.15s ease, box-shadow 0.15s ease, opacity 0.3s ease; " > {#if blockNumbers[annotation.id]} diff --git a/frontend/src/lib/components/AnnotationLayer.svelte.spec.ts b/frontend/src/lib/components/AnnotationLayer.svelte.spec.ts index 78befeca..7a4b4e07 100644 --- a/frontend/src/lib/components/AnnotationLayer.svelte.spec.ts +++ b/frontend/src/lib/components/AnnotationLayer.svelte.spec.ts @@ -69,6 +69,35 @@ describe('AnnotationLayer', () => { expect(container.getAttribute('style')).not.toContain('cursor: crosshair'); }); + it('dims non-active annotations when activeAnnotationId is set', async () => { + render(AnnotationLayer, { + annotations: [makeAnnotation('ann-1'), makeAnnotation('ann-2')], + canDraw: false, + color: '#00C7B1', + activeAnnotationId: 'ann-1', + onDraw: () => {} + }); + + const active = page.getByTestId('annotation-ann-1').element(); + const dimmed = page.getByTestId('annotation-ann-2').element(); + expect(active.style.opacity).toBe('1'); + expect(dimmed.style.opacity).toBe('0.3'); + }); + + it('shows all annotations at full opacity when no activeAnnotationId', async () => { + render(AnnotationLayer, { + annotations: [makeAnnotation('ann-1'), makeAnnotation('ann-2')], + canDraw: false, + color: '#00C7B1', + onDraw: () => {} + }); + + const el1 = page.getByTestId('annotation-ann-1').element(); + const el2 = page.getByTestId('annotation-ann-2').element(); + expect(el1.style.opacity).toBe('1'); + expect(el2.style.opacity).toBe('1'); + }); + it('does not show delete buttons (annotations owned by blocks)', async () => { render(AnnotationLayer, { annotations: [makeAnnotation('ann-1')], diff --git a/frontend/src/lib/components/PdfViewer.svelte b/frontend/src/lib/components/PdfViewer.svelte index a061b939..f2b45011 100644 --- a/frontend/src/lib/components/PdfViewer.svelte +++ b/frontend/src/lib/components/PdfViewer.svelte @@ -447,6 +447,7 @@ function zoomOut() { canDraw={transcribeMode} color={TRANSCRIPTION_COLOR} blockNumbers={blockNumbers} + activeAnnotationId={activeAnnotationId} onDraw={handleDraw} onAnnotationClick={handleAnnotationClick} />