feat(ui): add bidirectional scroll-sync with flash animations
Paragraph click flashes the PDF annotation outline (1.5s fade). Annotation click highlights the paragraph with a background flash. Both directions scroll the target into view. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ let {
|
||||
blockNumbers = {},
|
||||
activeAnnotationId = null,
|
||||
dimmed = false,
|
||||
flashAnnotationId = null,
|
||||
onDraw,
|
||||
onAnnotationClick
|
||||
}: {
|
||||
@@ -24,6 +25,7 @@ let {
|
||||
blockNumbers?: Record<string, number>;
|
||||
activeAnnotationId?: string | null;
|
||||
dimmed?: boolean;
|
||||
flashAnnotationId?: string | null;
|
||||
onDraw: (rect: DrawRect) => void;
|
||||
onAnnotationClick?: (id: string) => void;
|
||||
} = $props();
|
||||
@@ -110,6 +112,7 @@ const containerStyle = $derived(
|
||||
<div
|
||||
data-testid="annotation-{annotation.id}"
|
||||
data-annotation
|
||||
class:annotation-flash={flashAnnotationId === annotation.id}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="Block anzeigen"
|
||||
@@ -175,3 +178,20 @@ const containerStyle = $derived(
|
||||
></div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@keyframes annotation-flash-anim {
|
||||
0% {
|
||||
outline: 3px solid rgba(0, 199, 177, 0.8);
|
||||
outline-offset: 0px;
|
||||
}
|
||||
100% {
|
||||
outline: 3px solid rgba(0, 199, 177, 0);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.annotation-flash {
|
||||
animation: annotation-flash-anim 1.5s ease-out;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -21,6 +21,7 @@ type Props = {
|
||||
annotationReloadKey?: number;
|
||||
activeAnnotationId: string | null;
|
||||
annotationsDimmed?: boolean;
|
||||
flashAnnotationId?: string | null;
|
||||
onAnnotationClick: (id: string) => void;
|
||||
onTranscriptionDraw?: (rect: DrawRect) => void;
|
||||
};
|
||||
@@ -35,6 +36,7 @@ let {
|
||||
annotationReloadKey = 0,
|
||||
activeAnnotationId = $bindable(),
|
||||
annotationsDimmed = false,
|
||||
flashAnnotationId = null,
|
||||
onAnnotationClick,
|
||||
onTranscriptionDraw
|
||||
}: Props = $props();
|
||||
@@ -93,6 +95,7 @@ let {
|
||||
annotationReloadKey={annotationReloadKey}
|
||||
bind:activeAnnotationId={activeAnnotationId}
|
||||
annotationsDimmed={annotationsDimmed}
|
||||
flashAnnotationId={flashAnnotationId}
|
||||
onAnnotationClick={onAnnotationClick}
|
||||
onTranscriptionDraw={onTranscriptionDraw}
|
||||
documentFileHash={doc.fileHash ?? null}
|
||||
|
||||
@@ -17,7 +17,8 @@ let {
|
||||
onAnnotationClick,
|
||||
onTranscriptionDraw,
|
||||
documentFileHash,
|
||||
annotationsDimmed = false
|
||||
annotationsDimmed = false,
|
||||
flashAnnotationId = null
|
||||
}: {
|
||||
url: string;
|
||||
documentId?: string;
|
||||
@@ -29,6 +30,7 @@ let {
|
||||
onTranscriptionDraw?: (rect: DrawRect) => void;
|
||||
documentFileHash?: string | null;
|
||||
annotationsDimmed?: boolean;
|
||||
flashAnnotationId?: string | null;
|
||||
} = $props();
|
||||
|
||||
let pdfDoc = $state<PDFDocumentProxy | null>(null);
|
||||
@@ -459,6 +461,7 @@ function zoomOut() {
|
||||
blockNumbers={blockNumbers}
|
||||
activeAnnotationId={activeAnnotationId}
|
||||
dimmed={annotationsDimmed}
|
||||
flashAnnotationId={flashAnnotationId}
|
||||
onDraw={handleDraw}
|
||||
onAnnotationClick={handleAnnotationClick}
|
||||
/>
|
||||
|
||||
@@ -54,6 +54,7 @@ let transcribeMode = $state(false);
|
||||
let panelMode = $state<'read' | 'edit'>('read');
|
||||
let activeAnnotationId = $state<string | null>(null);
|
||||
let highlightBlockId = $state<string | null>(null);
|
||||
let flashAnnotationId = $state<string | null>(null);
|
||||
|
||||
// ── Transcription blocks ─────────────────────────────────────────────────────
|
||||
|
||||
@@ -177,6 +178,10 @@ async function handleAnnotationClick(annotationId: string) {
|
||||
|
||||
function handleParagraphClick(annotationId: string) {
|
||||
activeAnnotationId = annotationId;
|
||||
flashAnnotationId = annotationId;
|
||||
setTimeout(() => {
|
||||
flashAnnotationId = null;
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
// Load blocks when transcribe mode is entered and set default panel mode
|
||||
@@ -241,6 +246,7 @@ onMount(() => {
|
||||
blockNumbers={blockNumbers}
|
||||
annotationReloadKey={annotationReloadKey}
|
||||
annotationsDimmed={transcribeMode && panelMode === 'read'}
|
||||
flashAnnotationId={flashAnnotationId}
|
||||
bind:activeAnnotationId={activeAnnotationId}
|
||||
onAnnotationClick={handleAnnotationClick}
|
||||
onTranscriptionDraw={createBlockFromDraw}
|
||||
|
||||
Reference in New Issue
Block a user