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
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:
@@ -11,6 +11,7 @@ type Props = {
|
|||||||
blocks: TranscriptionBlockData[];
|
blocks: TranscriptionBlockData[];
|
||||||
canComment: boolean;
|
canComment: boolean;
|
||||||
currentUserId: string | null;
|
currentUserId: string | null;
|
||||||
|
activeAnnotationId?: string | null;
|
||||||
onBlockFocus: (blockId: string) => void;
|
onBlockFocus: (blockId: string) => void;
|
||||||
onSaveBlock: (blockId: string, text: string) => Promise<void>;
|
onSaveBlock: (blockId: string, text: string) => Promise<void>;
|
||||||
onDeleteBlock: (blockId: string) => Promise<void>;
|
onDeleteBlock: (blockId: string) => Promise<void>;
|
||||||
@@ -21,12 +22,20 @@ let {
|
|||||||
blocks,
|
blocks,
|
||||||
canComment,
|
canComment,
|
||||||
currentUserId,
|
currentUserId,
|
||||||
|
activeAnnotationId = null,
|
||||||
onBlockFocus,
|
onBlockFocus,
|
||||||
onSaveBlock,
|
onSaveBlock,
|
||||||
onDeleteBlock
|
onDeleteBlock
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
let activeBlockId: string | null = $state(null);
|
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 saveStates = new SvelteMap<string, SaveState>();
|
||||||
let debounceTimers = new SvelteMap<string, ReturnType<typeof setTimeout>>();
|
let debounceTimers = new SvelteMap<string, ReturnType<typeof setTimeout>>();
|
||||||
let pendingTexts = new SvelteMap<string, string>();
|
let pendingTexts = new SvelteMap<string, string>();
|
||||||
|
|||||||
@@ -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', () => {
|
describe('TranscriptionEditView — reorder', () => {
|
||||||
it('renders move-up button disabled on first block', async () => {
|
it('renders move-up button disabled on first block', async () => {
|
||||||
renderView();
|
renderView();
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ onMount(() => {
|
|||||||
blocks={transcriptionBlocks}
|
blocks={transcriptionBlocks}
|
||||||
canComment={canWrite}
|
canComment={canWrite}
|
||||||
currentUserId={currentUserId}
|
currentUserId={currentUserId}
|
||||||
|
activeAnnotationId={activeAnnotationId}
|
||||||
onBlockFocus={handleBlockFocus}
|
onBlockFocus={handleBlockFocus}
|
||||||
onSaveBlock={saveBlock}
|
onSaveBlock={saveBlock}
|
||||||
onDeleteBlock={deleteBlock}
|
onDeleteBlock={deleteBlock}
|
||||||
|
|||||||
Reference in New Issue
Block a user