feat(transcription): mobile stacked layout + cross-page scroll-sync
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
Mobile layout (< 768px): - Split view stacks vertically: PDF top (min 40vh), blocks below - Blocks panel gets border-top instead of border-left - PDF remains interactive for drawing in stacked mode Scroll-sync (block → PDF): - Clicking a block sets activeAnnotationId - PdfViewer effect watches activeAnnotationId, navigates to the annotation's page if different from current, then scrolls the annotation element into view (double-rAF for async render timing) - Works across pages: block on page 3 navigates PDF to page 3 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -217,6 +217,26 @@ $effect(() => {
|
|||||||
if (transcribeMode) showAnnotations = true;
|
if (transcribeMode) showAnnotations = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Scroll-sync: when activeAnnotationId changes, navigate to its page
|
||||||
|
$effect(() => {
|
||||||
|
if (!activeAnnotationId || !pdfDoc) return;
|
||||||
|
const ann = annotations.find((a) => a.id === activeAnnotationId);
|
||||||
|
if (!ann) return;
|
||||||
|
|
||||||
|
if (ann.pageNumber !== currentPage) {
|
||||||
|
currentPage = ann.pageNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
// After page renders, scroll the annotation into view (double-rAF for async render)
|
||||||
|
const targetId = activeAnnotationId;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
const el = document.querySelector(`[data-testid="annotation-${targetId}"]`);
|
||||||
|
el?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function prevPage() {
|
function prevPage() {
|
||||||
if (currentPage > 1) currentPage -= 1;
|
if (currentPage > 1) currentPage -= 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,8 +197,10 @@ onMount(() => {
|
|||||||
bind:transcribeMode={transcribeMode}
|
bind:transcribeMode={transcribeMode}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="relative flex-1 overflow-hidden {transcribeMode ? 'flex' : ''}">
|
<div class="relative flex-1 overflow-hidden {transcribeMode ? 'flex flex-col md:flex-row' : ''}">
|
||||||
<div class={transcribeMode ? 'relative flex-1 overflow-hidden' : 'absolute inset-0'}>
|
<div
|
||||||
|
class={transcribeMode ? 'relative min-h-[40vh] flex-1 overflow-hidden md:min-h-0' : 'absolute inset-0'}
|
||||||
|
>
|
||||||
<DocumentViewer
|
<DocumentViewer
|
||||||
doc={doc}
|
doc={doc}
|
||||||
fileUrl={fileUrl}
|
fileUrl={fileUrl}
|
||||||
@@ -213,7 +215,9 @@ onMount(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if transcribeMode}
|
{#if transcribeMode}
|
||||||
<div class="w-[400px] shrink-0 border-l border-line lg:w-[480px]">
|
<div
|
||||||
|
class="shrink-0 border-t border-line md:w-[400px] md:border-t-0 md:border-l lg:w-[480px]"
|
||||||
|
>
|
||||||
<TranscriptionEditView
|
<TranscriptionEditView
|
||||||
documentId={doc.id}
|
documentId={doc.id}
|
||||||
blocks={transcriptionBlocks}
|
blocks={transcriptionBlocks}
|
||||||
|
|||||||
Reference in New Issue
Block a user