feat(transcription): clicking annotation focuses corresponding block
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) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled

Pass activeAnnotationId to TranscriptionEditView. An $effect watches
it and sets activeBlockId to the block matching the annotation,
activating its turquoise focus border.

2 new tests (RED/GREEN):
- activates block matching activeAnnotationId (turquoise border)
- no block activated when activeAnnotationId is null

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-05 23:36:06 +02:00
parent 676d3cb6a7
commit ef11cbee4e
3 changed files with 27 additions and 0 deletions

View File

@@ -11,6 +11,7 @@ type Props = {
blocks: TranscriptionBlockData[];
canComment: boolean;
currentUserId: string | null;
activeAnnotationId?: string | null;
onBlockFocus: (blockId: string) => void;
onSaveBlock: (blockId: string, text: string) => Promise<void>;
onDeleteBlock: (blockId: string) => Promise<void>;
@@ -21,12 +22,20 @@ let {
blocks,
canComment,
currentUserId,
activeAnnotationId = null,
onBlockFocus,
onSaveBlock,
onDeleteBlock
}: Props = $props();
let activeBlockId: string | null = $state(null);
// Sync: when an annotation is clicked on the PDF, activate the corresponding block
$effect(() => {
if (!activeAnnotationId) return;
const block = blocks.find((b) => b.annotationId === activeAnnotationId);
if (block) activeBlockId = block.id;
});
let saveStates = new SvelteMap<string, SaveState>();
let debounceTimers = new SvelteMap<string, ReturnType<typeof setTimeout>>();
let pendingTexts = new SvelteMap<string, string>();

View File

@@ -55,6 +55,23 @@ describe('TranscriptionEditView — rendering', () => {
});
});
describe('TranscriptionEditView — annotation sync', () => {
it('activates block matching activeAnnotationId', async () => {
renderView({ activeAnnotationId: 'a2' });
// Block 2 (annotation a2) should have turquoise border
const block = document.querySelector('[data-block-id="b2"]')!;
expect(block.className).toContain('border-turquoise');
});
it('does not activate any block when activeAnnotationId is null', async () => {
renderView({ activeAnnotationId: null });
const block1 = document.querySelector('[data-block-id="b1"]')!;
const block2 = document.querySelector('[data-block-id="b2"]')!;
expect(block1.className).not.toContain('border-turquoise');
expect(block2.className).not.toContain('border-turquoise');
});
});
describe('TranscriptionEditView — reorder', () => {
it('renders move-up button disabled on first block', async () => {
renderView();

View File

@@ -223,6 +223,7 @@ onMount(() => {
blocks={transcriptionBlocks}
canComment={canWrite}
currentUserId={currentUserId}
activeAnnotationId={activeAnnotationId}
onBlockFocus={handleBlockFocus}
onSaveBlock={saveBlock}
onDeleteBlock={deleteBlock}