Alleinzellgaenger commited on
Commit
4a6c290
·
1 Parent(s): f1b7f9a

Implement navigation via chunks

Browse files
frontend/src/components/DocumentProcessor.jsx CHANGED
@@ -1,4 +1,5 @@
1
  import 'katex/dist/katex.min.css';
 
2
 
3
  // Import custom hooks
4
  import { useDocumentProcessor } from '../hooks/useDocumentProcessor';
@@ -12,6 +13,9 @@ import ChunkNavigation from './ChunkNavigation';
12
  import ChunkPanel from './ChunkPanel';
13
 
14
  function DocumentProcessor() {
 
 
 
15
  // Custom hooks
16
  const {
17
  fileInputRef,
@@ -48,6 +52,16 @@ function DocumentProcessor() {
48
  handleMouseDown
49
  } = usePanelResize(50);
50
 
 
 
 
 
 
 
 
 
 
 
51
  // Simplified startInteractiveLesson
52
  const handleStartInteractiveLesson = () => {
53
  startInteractiveLesson();
@@ -111,6 +125,7 @@ function DocumentProcessor() {
111
  <DocumentViewer
112
  selectedFile={selectedFile}
113
  documentData={documentData}
 
114
  />
115
  </div>
116
 
 
1
  import 'katex/dist/katex.min.css';
2
+ import { useState, useEffect } from 'react';
3
 
4
  // Import custom hooks
5
  import { useDocumentProcessor } from '../hooks/useDocumentProcessor';
 
13
  import ChunkPanel from './ChunkPanel';
14
 
15
  function DocumentProcessor() {
16
+ // State for PDF navigation
17
+ const [pdfNavigation, setPdfNavigation] = useState(null);
18
+
19
  // Custom hooks
20
  const {
21
  fileInputRef,
 
52
  handleMouseDown
53
  } = usePanelResize(50);
54
 
55
+ // Sync PDF page navigation with chunk switching
56
+ useEffect(() => {
57
+ if (pdfNavigation && documentData && documentData.chunks[currentChunkIndex]) {
58
+ const currentChunk = documentData.chunks[currentChunkIndex];
59
+ if (currentChunk.page && pdfNavigation.goToPage) {
60
+ pdfNavigation.goToPage(currentChunk.page);
61
+ }
62
+ }
63
+ }, [currentChunkIndex, pdfNavigation, documentData]);
64
+
65
  // Simplified startInteractiveLesson
66
  const handleStartInteractiveLesson = () => {
67
  startInteractiveLesson();
 
125
  <DocumentViewer
126
  selectedFile={selectedFile}
127
  documentData={documentData}
128
+ onPageChange={setPdfNavigation}
129
  />
130
  </div>
131
 
frontend/src/components/DocumentViewer.jsx CHANGED
@@ -5,7 +5,7 @@ import 'react-pdf/dist/Page/TextLayer.css';
5
 
6
  pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js';
7
 
8
- const DocumentViewer = ({ selectedFile, documentData }) => {
9
  const pdfContainerRef = useRef(null);
10
  const [numPages, setNumPages] = useState(null);
11
  const [currentPage, setCurrentPage] = useState(1);
@@ -29,6 +29,13 @@ const DocumentViewer = ({ selectedFile, documentData }) => {
29
  return () => window.removeEventListener('resize', updateContainerWidth);
30
  }, []);
31
 
 
 
 
 
 
 
 
32
  // Calculate optimal page width
33
  const getPageWidth = () => {
34
  if (!containerWidth) return 600; // Fallback
@@ -70,7 +77,7 @@ const DocumentViewer = ({ selectedFile, documentData }) => {
70
 
71
  // Jump to specific page
72
  const goToPage = (pageNumber) => {
73
- if (!pdfContainerRef.current || !numPages) return;
74
 
75
  // Update visible pages immediately for target page
76
  const newVisiblePages = new Set();
@@ -80,17 +87,55 @@ const DocumentViewer = ({ selectedFile, documentData }) => {
80
  }
81
  setVisiblePages(newVisiblePages);
82
 
83
- const container = pdfContainerRef.current;
84
- const totalScrollHeight = container.scrollHeight - container.clientHeight;
85
-
86
- // Calculate scroll position for the target page
87
- const targetScrollPercent = (pageNumber - 1) / numPages;
88
- const targetScrollTop = targetScrollPercent * totalScrollHeight;
89
-
90
- container.scrollTo({
91
- top: targetScrollTop,
92
- behavior: 'smooth'
93
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  };
95
 
96
  // Zoom controls
@@ -131,10 +176,9 @@ const DocumentViewer = ({ selectedFile, documentData }) => {
131
  {numPages && Array.from(new Array(numPages), (_, index) => {
132
  const pageNum = index + 1;
133
  const isVisible = visiblePages.has(pageNum);
134
- const currentZoom = isVisible ? zoomLevel : 1;
135
 
136
  return (
137
- <div key={pageNum} className="mb-4 flex justify-center">
138
  <Page
139
  pageNumber={pageNum}
140
  width={isVisible ? getPageWidth() : getPageWidth() / zoomLevel}
 
5
 
6
  pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js';
7
 
8
+ const DocumentViewer = ({ selectedFile, documentData, onPageChange }) => {
9
  const pdfContainerRef = useRef(null);
10
  const [numPages, setNumPages] = useState(null);
11
  const [currentPage, setCurrentPage] = useState(1);
 
29
  return () => window.removeEventListener('resize', updateContainerWidth);
30
  }, []);
31
 
32
+ // Expose goToPage function to parent component (only once when component mounts)
33
+ useEffect(() => {
34
+ if (onPageChange) {
35
+ onPageChange({ goToPage });
36
+ }
37
+ }, [onPageChange]);
38
+
39
  // Calculate optimal page width
40
  const getPageWidth = () => {
41
  if (!containerWidth) return 600; // Fallback
 
77
 
78
  // Jump to specific page
79
  const goToPage = (pageNumber) => {
80
+ if (!pdfContainerRef.current || !numPages || pageNumber < 1 || pageNumber > numPages) return;
81
 
82
  // Update visible pages immediately for target page
83
  const newVisiblePages = new Set();
 
87
  }
88
  setVisiblePages(newVisiblePages);
89
 
90
+ // Use setTimeout to ensure pages are rendered before scrolling
91
+ setTimeout(() => {
92
+ const container = pdfContainerRef.current;
93
+ if (!container) return;
94
+
95
+ // Find the target page element by its data attribute or position
96
+ const pageElements = container.querySelectorAll('[data-page-number]');
97
+ let targetElement = null;
98
+
99
+ // If we can't find elements by data attribute, calculate position manually
100
+ if (pageElements.length === 0) {
101
+ // Calculate approximate position based on page height
102
+ // Each page has some margin (mb-4 = 16px) plus the actual page height
103
+ const containerHeight = container.clientHeight;
104
+ const totalContent = container.scrollHeight;
105
+ const avgPageHeight = totalContent / numPages;
106
+ const targetPosition = (pageNumber - 1) * avgPageHeight;
107
+
108
+ // Center the page in viewport
109
+ const scrollPosition = Math.max(0, targetPosition - containerHeight / 4);
110
+
111
+ container.scrollTo({
112
+ top: scrollPosition,
113
+ behavior: 'smooth'
114
+ });
115
+ } else {
116
+ // Find the specific page element
117
+ for (const element of pageElements) {
118
+ if (parseInt(element.getAttribute('data-page-number')) === pageNumber) {
119
+ targetElement = element;
120
+ break;
121
+ }
122
+ }
123
+
124
+ if (targetElement) {
125
+ // Scroll to center the page in viewport
126
+ const elementRect = targetElement.getBoundingClientRect();
127
+ const containerRect = container.getBoundingClientRect();
128
+ const scrollOffset = container.scrollTop;
129
+
130
+ const targetPosition = scrollOffset + elementRect.top - containerRect.top - (container.clientHeight - elementRect.height) / 4;
131
+
132
+ container.scrollTo({
133
+ top: Math.max(0, targetPosition),
134
+ behavior: 'smooth'
135
+ });
136
+ }
137
+ }
138
+ }, 100); // Small delay to ensure rendering
139
  };
140
 
141
  // Zoom controls
 
176
  {numPages && Array.from(new Array(numPages), (_, index) => {
177
  const pageNum = index + 1;
178
  const isVisible = visiblePages.has(pageNum);
 
179
 
180
  return (
181
+ <div key={pageNum} className="mb-4 flex justify-center" data-page-number={pageNum}>
182
  <Page
183
  pageNumber={pageNum}
184
  width={isVisible ? getPageWidth() : getPageWidth() / zoomLevel}