feat(transcription): show block numbers on PDF annotation overlays
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Failing after 1m26s
CI / Backend Unit Tests (pull_request) Failing after 2m29s
CI / E2E Tests (pull_request) Failing after 1h28m33s

Add blockNumbers prop through AnnotationLayer → PdfViewer → DocumentViewer.
Each turquoise annotation rectangle now shows a numbered badge (top-left,
matching the block card number in the right panel).

Block numbers are derived from sorted transcriptionBlocks, mapped by
annotationId, creating a visual link between PDF regions and block cards.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-05 21:39:11 +02:00
parent 7ad852dd52
commit 569a13e1b1
4 changed files with 43 additions and 1 deletions

View File

@@ -12,12 +12,14 @@ let {
annotations = [], annotations = [],
canDraw, canDraw,
color, color,
blockNumbers = {},
onDraw, onDraw,
onAnnotationClick onAnnotationClick
}: { }: {
annotations: Annotation[]; annotations: Annotation[];
canDraw: boolean; canDraw: boolean;
color: string; color: string;
blockNumbers?: Record<string, number>;
onDraw: (rect: DrawRect) => void; onDraw: (rect: DrawRect) => void;
onAnnotationClick?: (id: string) => void; onAnnotationClick?: (id: string) => void;
} = $props(); } = $props();
@@ -125,7 +127,32 @@ const containerStyle = $derived(
cursor: pointer; cursor: pointer;
transition: background-color 0.15s ease, box-shadow 0.15s ease; transition: background-color 0.15s ease, box-shadow 0.15s ease;
" "
></div> >
{#if blockNumbers[annotation.id]}
<div
style="
position: absolute;
top: -8px;
left: -8px;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: {annotation.color};
color: white;
font-size: 11px;
font-family: sans-serif;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
"
>
{blockNumbers[annotation.id]}
</div>
{/if}
</div>
{/each} {/each}
{#if drawRect && drawRect.width > 0} {#if drawRect && drawRect.width > 0}

View File

@@ -17,6 +17,7 @@ type Props = {
isLoading: boolean; isLoading: boolean;
error: string; error: string;
transcribeMode?: boolean; transcribeMode?: boolean;
blockNumbers?: Record<string, number>;
activeAnnotationId: string | null; activeAnnotationId: string | null;
onAnnotationClick: (id: string) => void; onAnnotationClick: (id: string) => void;
onTranscriptionDraw?: (rect: DrawRect) => void; onTranscriptionDraw?: (rect: DrawRect) => void;
@@ -28,6 +29,7 @@ let {
isLoading, isLoading,
error, error,
transcribeMode = false, transcribeMode = false,
blockNumbers = {},
activeAnnotationId = $bindable(), activeAnnotationId = $bindable(),
onAnnotationClick, onAnnotationClick,
onTranscriptionDraw onTranscriptionDraw
@@ -83,6 +85,7 @@ let {
url={fileUrl} url={fileUrl}
documentId={doc.id} documentId={doc.id}
transcribeMode={transcribeMode} transcribeMode={transcribeMode}
blockNumbers={blockNumbers}
bind:activeAnnotationId={activeAnnotationId} bind:activeAnnotationId={activeAnnotationId}
onAnnotationClick={onAnnotationClick} onAnnotationClick={onAnnotationClick}
onTranscriptionDraw={onTranscriptionDraw} onTranscriptionDraw={onTranscriptionDraw}

View File

@@ -11,6 +11,7 @@ let {
url, url,
documentId = '', documentId = '',
transcribeMode = false, transcribeMode = false,
blockNumbers = {},
activeAnnotationId = $bindable<string | null>(null), activeAnnotationId = $bindable<string | null>(null),
onAnnotationClick, onAnnotationClick,
onTranscriptionDraw, onTranscriptionDraw,
@@ -19,6 +20,7 @@ let {
url: string; url: string;
documentId?: string; documentId?: string;
transcribeMode?: boolean; transcribeMode?: boolean;
blockNumbers?: Record<string, number>;
activeAnnotationId?: string | null; activeAnnotationId?: string | null;
onAnnotationClick?: (id: string) => void; onAnnotationClick?: (id: string) => void;
onTranscriptionDraw?: (rect: DrawRect) => void; onTranscriptionDraw?: (rect: DrawRect) => void;
@@ -424,6 +426,7 @@ function zoomOut() {
annotations={visibleAnnotations.filter((a) => a.pageNumber === currentPage)} annotations={visibleAnnotations.filter((a) => a.pageNumber === currentPage)}
canDraw={transcribeMode} canDraw={transcribeMode}
color={TRANSCRIPTION_COLOR} color={TRANSCRIPTION_COLOR}
blockNumbers={blockNumbers}
onDraw={handleDraw} onDraw={handleDraw}
onAnnotationClick={handleAnnotationClick} onAnnotationClick={handleAnnotationClick}
/> />

View File

@@ -55,6 +55,14 @@ let activeAnnotationId = $state<string | null>(null);
let transcriptionBlocks = $state<TranscriptionBlockData[]>([]); let transcriptionBlocks = $state<TranscriptionBlockData[]>([]);
const blockNumbers = $derived(
Object.fromEntries(
[...transcriptionBlocks]
.sort((a, b) => a.sortOrder - b.sortOrder)
.map((b, i) => [b.annotationId, i + 1])
)
);
async function loadTranscriptionBlocks() { async function loadTranscriptionBlocks() {
if (!doc?.id) return; if (!doc?.id) return;
try { try {
@@ -197,6 +205,7 @@ onMount(() => {
isLoading={isLoading} isLoading={isLoading}
error={fileError} error={fileError}
transcribeMode={transcribeMode} transcribeMode={transcribeMode}
blockNumbers={blockNumbers}
bind:activeAnnotationId={activeAnnotationId} bind:activeAnnotationId={activeAnnotationId}
onAnnotationClick={handleAnnotationClick} onAnnotationClick={handleAnnotationClick}
onTranscriptionDraw={createBlockFromDraw} onTranscriptionDraw={createBlockFromDraw}