@tfw.in/structura-lib 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PRODUCTION_ARCHITECTURE.md +511 -0
- package/README.md +379 -0
- package/SAVE_FUNCTIONALITY_COMPLETE.md +448 -0
- package/dist/cjs/EditableContent.js +150 -0
- package/dist/cjs/HtmlViewer.js +587 -0
- package/dist/cjs/PdfComponents.js +16 -0
- package/dist/cjs/PdfDocumentViewer.js +281 -0
- package/dist/cjs/Structura.js +806 -0
- package/dist/cjs/Table.js +164 -0
- package/dist/cjs/TableCell.js +115 -0
- package/dist/cjs/accuracyMetrics.js +39 -0
- package/dist/cjs/helpers/preprocessData.js +143 -0
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/lib/polyfills.js +15 -0
- package/dist/cjs/lib/utils.js +10 -0
- package/dist/cjs/node_modules/react-icons/fa/index.esm.js +14 -0
- package/dist/cjs/node_modules/react-icons/lib/esm/iconBase.js +69 -0
- package/dist/cjs/node_modules/react-icons/lib/esm/iconContext.js +15 -0
- package/dist/cjs/polyfills.js +19 -0
- package/dist/cjs/route.js +102 -0
- package/dist/cjs/styles.css +7 -0
- package/dist/cjs/styles.css.map +1 -0
- package/dist/cjs/ui/badge.js +34 -0
- package/dist/cjs/ui/button.js +71 -0
- package/dist/cjs/ui/card.js +86 -0
- package/dist/cjs/ui/progress.js +45 -0
- package/dist/cjs/ui/scroll-area.js +62 -0
- package/dist/cjs/ui/tabs.js +60 -0
- package/dist/cjs/worker.js +36 -0
- package/dist/esm/EditableContent.js +161 -0
- package/dist/esm/HtmlViewer.js +640 -0
- package/dist/esm/PdfComponents.js +21 -0
- package/dist/esm/PdfDocumentViewer.js +294 -0
- package/dist/esm/Structura.js +951 -0
- package/dist/esm/Table.js +182 -0
- package/dist/esm/TableCell.js +122 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +305 -0
- package/dist/esm/accuracyMetrics.js +41 -0
- package/dist/esm/helpers/preprocessData.js +152 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/lib/polyfills.js +13 -0
- package/dist/esm/lib/utils.js +8 -0
- package/dist/esm/node_modules/react-icons/fa/index.esm.js +11 -0
- package/dist/esm/node_modules/react-icons/lib/esm/iconBase.js +66 -0
- package/dist/esm/node_modules/react-icons/lib/esm/iconContext.js +12 -0
- package/dist/esm/polyfills.js +17 -0
- package/dist/esm/route.js +154 -0
- package/dist/esm/styles.css +7 -0
- package/dist/esm/styles.css.map +1 -0
- package/dist/esm/types/EditableContent.d.ts +9 -0
- package/dist/esm/types/HtmlViewer.d.ts +10 -0
- package/dist/esm/types/PdfComponents.d.ts +35 -0
- package/dist/esm/types/PdfDocumentViewer.d.ts +22 -0
- package/dist/esm/types/Structura.d.ts +11 -0
- package/dist/esm/types/Table.d.ts +12 -0
- package/dist/esm/types/TableCell.d.ts +13 -0
- package/dist/esm/types/accuracy.d.ts +23 -0
- package/dist/esm/types/accuracyMetrics.d.ts +5 -0
- package/dist/esm/types/helpers/flattenJSON.d.ts +1 -0
- package/dist/esm/types/helpers/hardMerging.d.ts +2 -0
- package/dist/esm/types/helpers/index.d.ts +6 -0
- package/dist/esm/types/helpers/jsonToHtml.d.ts +40 -0
- package/dist/esm/types/helpers/preprocessData.d.ts +3 -0
- package/dist/esm/types/helpers/removeMetadata.d.ts +1 -0
- package/dist/esm/types/helpers/tableProcessor.d.ts +1 -0
- package/dist/esm/types/index.d.ts +3 -0
- package/dist/esm/types/lib/polyfills.d.ts +1 -0
- package/dist/esm/types/lib/utils.d.ts +2 -0
- package/dist/esm/types/polyfills.d.ts +1 -0
- package/dist/esm/types/route.d.ts +45 -0
- package/dist/esm/types/test-app/src/App.d.ts +4 -0
- package/dist/esm/types/test-app/src/main.d.ts +1 -0
- package/dist/esm/types/test-app/vite.config.d.ts +2 -0
- package/dist/esm/types/types.d.ts +23 -0
- package/dist/esm/types/ui/alert.d.ts +8 -0
- package/dist/esm/types/ui/badge.d.ts +9 -0
- package/dist/esm/types/ui/button.d.ts +11 -0
- package/dist/esm/types/ui/card.d.ts +8 -0
- package/dist/esm/types/ui/progress.d.ts +6 -0
- package/dist/esm/types/ui/scroll-area.d.ts +5 -0
- package/dist/esm/types/ui/skeleton.d.ts +2 -0
- package/dist/esm/types/ui/tabs.d.ts +7 -0
- package/dist/esm/types/worker.d.ts +1 -0
- package/dist/esm/ui/badge.js +31 -0
- package/dist/esm/ui/button.js +50 -0
- package/dist/esm/ui/card.js +67 -0
- package/dist/esm/ui/progress.js +26 -0
- package/dist/esm/ui/scroll-area.js +45 -0
- package/dist/esm/ui/tabs.js +39 -0
- package/dist/esm/worker.js +50 -0
- package/dist/index.d.ts +38 -0
- package/package.json +85 -0
- package/server/README.md +203 -0
- package/server/db.js +142 -0
- package/server/server.js +165 -0
|
@@ -0,0 +1,806 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
var button = require('./ui/button.js');
|
|
8
|
+
var card = require('./ui/card.js');
|
|
9
|
+
var tabs = require('./ui/tabs.js');
|
|
10
|
+
var LucideIcons = require('lucide-react');
|
|
11
|
+
var PdfDocumentViewer = require('./PdfDocumentViewer.js');
|
|
12
|
+
var HtmlViewer = require('./HtmlViewer.js');
|
|
13
|
+
var preprocessData = require('./helpers/preprocessData.js');
|
|
14
|
+
var reactResizablePanels = require('react-resizable-panels');
|
|
15
|
+
var badge = require('./ui/badge.js');
|
|
16
|
+
var progress = require('./ui/progress.js');
|
|
17
|
+
var scrollArea = require('./ui/scroll-area.js');
|
|
18
|
+
var route = require('./route.js');
|
|
19
|
+
|
|
20
|
+
function _interopNamespaceDefault(e) {
|
|
21
|
+
var n = Object.create(null);
|
|
22
|
+
if (e) {
|
|
23
|
+
Object.keys(e).forEach(function (k) {
|
|
24
|
+
if (k !== 'default') {
|
|
25
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
26
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () { return e[k]; }
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
n.default = e;
|
|
34
|
+
return Object.freeze(n);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var LucideIcons__namespace = /*#__PURE__*/_interopNamespaceDefault(LucideIcons);
|
|
38
|
+
|
|
39
|
+
// Remove component aliases and use direct imports
|
|
40
|
+
// This will preserve the propser types
|
|
41
|
+
function Structura({
|
|
42
|
+
initialPdfPath,
|
|
43
|
+
initialJsonData,
|
|
44
|
+
props
|
|
45
|
+
}) {
|
|
46
|
+
// Log the API key (for development only - remove in production)
|
|
47
|
+
// useEffect(() => {
|
|
48
|
+
// if (props?.APIKey) {
|
|
49
|
+
// console.log("API Key provided:", props.APIKey);
|
|
50
|
+
// }
|
|
51
|
+
// }, [props]);
|
|
52
|
+
// Log the imported SDK items to demonstrate usage
|
|
53
|
+
// console.log("Imported BlockSchema from SDK:", BlockSchema);
|
|
54
|
+
const [numPages, setNumPages] = React.useState(null);
|
|
55
|
+
const [pageNumber, setPageNumber] = React.useState(1);
|
|
56
|
+
const [selectedField, setSelectedField] = React.useState(null);
|
|
57
|
+
const [file, setFile] = React.useState(null);
|
|
58
|
+
const [fileUrl, setFileUrl] = React.useState(initialPdfPath || null);
|
|
59
|
+
const [jsonData, setJsonData] = React.useState(null);
|
|
60
|
+
const [allowedPages, setAllowedPages] = React.useState(null);
|
|
61
|
+
const pdfWrapperRef = React.useRef(null);
|
|
62
|
+
const [flattenedFields, setFlattenedFields] = React.useState([]);
|
|
63
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
64
|
+
const [loadingProgress, setLoadingProgress] = React.useState(0);
|
|
65
|
+
const [selectedBboxId, setSelectedBboxId] = React.useState(null);
|
|
66
|
+
const [error, setError] = React.useState(null);
|
|
67
|
+
const [isFileLoaded, setIsFileLoaded] = React.useState(false);
|
|
68
|
+
const [activeTab, setActiveTab] = React.useState("pdf");
|
|
69
|
+
const [backendStatus, setBackendStatus] = React.useState('checking');
|
|
70
|
+
const [isDraggingOver, setIsDraggingOver] = React.useState(false); //NOSONAR
|
|
71
|
+
// Load initial JSON data if provided (for faster iteration without API calls)
|
|
72
|
+
React.useEffect(() => {
|
|
73
|
+
var _a;
|
|
74
|
+
if (initialJsonData) {
|
|
75
|
+
console.log('[Structura] Loading initial JSON data from props');
|
|
76
|
+
setJsonData(initialJsonData);
|
|
77
|
+
const pageCount = ((_a = initialJsonData.children) === null || _a === void 0 ? void 0 : _a.length) || 0;
|
|
78
|
+
setAllowedPages(Array.from({
|
|
79
|
+
length: pageCount
|
|
80
|
+
}, (_, i) => i + 1));
|
|
81
|
+
}
|
|
82
|
+
}, [initialJsonData]);
|
|
83
|
+
React.useEffect(() => {
|
|
84
|
+
const handleDragOver = e => {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
e.stopPropagation();
|
|
87
|
+
// If PDF viewer is visible and no file is loaded, activate drag indicator
|
|
88
|
+
if (!fileUrl && !isDraggingOver && activeTab === "pdf") {
|
|
89
|
+
setIsDraggingOver(true);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const handleDragEnter = e => {
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
e.stopPropagation();
|
|
95
|
+
// If PDF viewer is visible and no file is loaded, activate drag indicator
|
|
96
|
+
if (!fileUrl && !isDraggingOver && activeTab === "pdf") {
|
|
97
|
+
setIsDraggingOver(true);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const handleDragLeave = e => {
|
|
101
|
+
e.preventDefault();
|
|
102
|
+
e.stopPropagation();
|
|
103
|
+
// Only deactivate if we're leaving the document
|
|
104
|
+
if (e.relatedTarget === null) {
|
|
105
|
+
setIsDraggingOver(false);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const handleDrop = e => {
|
|
109
|
+
e.preventDefault();
|
|
110
|
+
e.stopPropagation();
|
|
111
|
+
setIsDraggingOver(false);
|
|
112
|
+
};
|
|
113
|
+
// Prevent the browser from automatically opening dropped files
|
|
114
|
+
document.addEventListener('dragover', handleDragOver);
|
|
115
|
+
document.addEventListener('dragenter', handleDragEnter);
|
|
116
|
+
document.addEventListener('dragleave', handleDragLeave);
|
|
117
|
+
document.addEventListener('drop', handleDrop);
|
|
118
|
+
return () => {
|
|
119
|
+
document.removeEventListener('dragover', handleDragOver);
|
|
120
|
+
document.removeEventListener('dragenter', handleDragEnter);
|
|
121
|
+
document.removeEventListener('dragleave', handleDragLeave);
|
|
122
|
+
document.removeEventListener('drop', handleDrop);
|
|
123
|
+
};
|
|
124
|
+
}, [fileUrl, isDraggingOver, activeTab]);
|
|
125
|
+
// Add useEffect to handle selected PDF from localStorage
|
|
126
|
+
React.useEffect(() => {
|
|
127
|
+
const handleSelectedPdf = async () => {
|
|
128
|
+
const selectedPdfStr = localStorage.getItem('selectedPdf');
|
|
129
|
+
if (selectedPdfStr) {
|
|
130
|
+
try {
|
|
131
|
+
const selectedPdf = JSON.parse(selectedPdfStr);
|
|
132
|
+
if (selectedPdf.path === 'user-uploaded') {
|
|
133
|
+
// For user-uploaded files, retrieve from sessionStorage
|
|
134
|
+
const fileDataStr = sessionStorage.getItem('pdfFileData');
|
|
135
|
+
if (fileDataStr) {
|
|
136
|
+
try {
|
|
137
|
+
// Restore the file from sessionStorage
|
|
138
|
+
const fileData = JSON.parse(fileDataStr);
|
|
139
|
+
const byteCharacters = atob(fileData.data);
|
|
140
|
+
const byteNumbers = new Array(byteCharacters.length);
|
|
141
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
|
142
|
+
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
143
|
+
}
|
|
144
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
145
|
+
const blob = new Blob([byteArray], {
|
|
146
|
+
type: 'application/pdf'
|
|
147
|
+
});
|
|
148
|
+
const pdfFile = new File([blob], fileData.name, {
|
|
149
|
+
type: 'application/pdf'
|
|
150
|
+
});
|
|
151
|
+
const newFileUrl = URL.createObjectURL(blob);
|
|
152
|
+
setFile(pdfFile);
|
|
153
|
+
setFileUrl(newFileUrl);
|
|
154
|
+
setIsFileLoaded(true);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error('Error parsing PDF data from sessionStorage:', error);
|
|
157
|
+
setError('Failed to load the PDF file. Please try uploading again.');
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
setError('PDF data not found. Please upload the file again.');
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
// For pre-existing PDFs, fetch from the path
|
|
164
|
+
try {
|
|
165
|
+
const response = await fetch(selectedPdf.path);
|
|
166
|
+
const blob = await response.blob();
|
|
167
|
+
const pdfFile = new File([blob], selectedPdf.name, {
|
|
168
|
+
type: 'application/pdf'
|
|
169
|
+
});
|
|
170
|
+
// Set the file and URL
|
|
171
|
+
setFile(pdfFile);
|
|
172
|
+
setFileUrl(URL.createObjectURL(blob));
|
|
173
|
+
setIsFileLoaded(true);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
console.error('Error fetching PDF:', error);
|
|
176
|
+
setError('Failed to load the PDF file. Please try again.');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Clear the localStorage
|
|
180
|
+
localStorage.removeItem('selectedPdf');
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error('Error loading selected PDF:', error);
|
|
183
|
+
setError('Failed to load selected PDF');
|
|
184
|
+
localStorage.removeItem('selectedPdf');
|
|
185
|
+
}
|
|
186
|
+
} else if (initialPdfPath) {
|
|
187
|
+
// Handle the initialPdfPath if provided
|
|
188
|
+
if (initialPdfPath === 'user-uploaded') {
|
|
189
|
+
// Same logic as above for retrieving from sessionStorage
|
|
190
|
+
const fileDataStr = sessionStorage.getItem('pdfFileData');
|
|
191
|
+
if (fileDataStr) {
|
|
192
|
+
try {
|
|
193
|
+
const fileData = JSON.parse(fileDataStr);
|
|
194
|
+
const byteCharacters = atob(fileData.data);
|
|
195
|
+
const byteNumbers = new Array(byteCharacters.length);
|
|
196
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
|
197
|
+
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
198
|
+
}
|
|
199
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
200
|
+
const blob = new Blob([byteArray], {
|
|
201
|
+
type: 'application/pdf'
|
|
202
|
+
});
|
|
203
|
+
const pdfFile = new File([blob], fileData.name, {
|
|
204
|
+
type: 'application/pdf'
|
|
205
|
+
});
|
|
206
|
+
const newFileUrl = URL.createObjectURL(blob);
|
|
207
|
+
setFile(pdfFile);
|
|
208
|
+
setFileUrl(newFileUrl);
|
|
209
|
+
setIsFileLoaded(true);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error('Error parsing PDF data from sessionStorage:', error);
|
|
212
|
+
setError('Failed to load the PDF file. Please try uploading again.');
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
setError('PDF data not found. Please upload the file again.');
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
// It's a normal path
|
|
219
|
+
try {
|
|
220
|
+
const response = await fetch(initialPdfPath);
|
|
221
|
+
const blob = await response.blob();
|
|
222
|
+
const pdfFile = new File([blob], 'document.pdf', {
|
|
223
|
+
type: 'application/pdf'
|
|
224
|
+
});
|
|
225
|
+
setFile(pdfFile);
|
|
226
|
+
setFileUrl(URL.createObjectURL(blob));
|
|
227
|
+
setIsFileLoaded(true);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.error('Error fetching PDF:', error);
|
|
230
|
+
setError(`Failed to load the PDF file from ${initialPdfPath}. Please try again.`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
handleSelectedPdf();
|
|
236
|
+
}, [initialPdfPath]);
|
|
237
|
+
// Simulate loading progress
|
|
238
|
+
React.useEffect(() => {
|
|
239
|
+
if (isLoading) {
|
|
240
|
+
const interval = setInterval(() => {
|
|
241
|
+
setLoadingProgress(prev => {
|
|
242
|
+
const newProgress = prev + 10;
|
|
243
|
+
if (newProgress >= 100) {
|
|
244
|
+
clearInterval(interval);
|
|
245
|
+
return 100;
|
|
246
|
+
}
|
|
247
|
+
return newProgress;
|
|
248
|
+
});
|
|
249
|
+
}, 300);
|
|
250
|
+
return () => clearInterval(interval);
|
|
251
|
+
} else {
|
|
252
|
+
setLoadingProgress(0);
|
|
253
|
+
}
|
|
254
|
+
}, [isLoading]);
|
|
255
|
+
// Add logging to handleFileUpload
|
|
256
|
+
const handleFileUpload = uploadedFile => {
|
|
257
|
+
// console.log("!!! [Structura] handleFileUpload called with file:", uploadedFile.name);
|
|
258
|
+
// console.log("!!! [Structura] File details:", {
|
|
259
|
+
// name: uploadedFile.name,
|
|
260
|
+
// type: uploadedFile.type,
|
|
261
|
+
// size: uploadedFile.size
|
|
262
|
+
// });
|
|
263
|
+
setFile(uploadedFile);
|
|
264
|
+
setFileUrl(URL.createObjectURL(uploadedFile));
|
|
265
|
+
setJsonData(null);
|
|
266
|
+
setAllowedPages(null);
|
|
267
|
+
setSelectedBboxId(null);
|
|
268
|
+
setIsFileLoaded(false);
|
|
269
|
+
setError(null);
|
|
270
|
+
setActiveTab("pdf");
|
|
271
|
+
// console.log("!!! [Structura] File upload state updated");
|
|
272
|
+
};
|
|
273
|
+
// Add logging to the useEffect that watches isFileLoaded
|
|
274
|
+
React.useEffect(() => {
|
|
275
|
+
// console.log("!!! [Structura] isFileLoaded changed:", isFileLoaded);
|
|
276
|
+
// Skip API call if we already have initialJsonData (cached mode)
|
|
277
|
+
if (isFileLoaded && !initialJsonData) {
|
|
278
|
+
// console.log("!!! [Structura] Calling handleGenerateJSON due to isFileLoaded");
|
|
279
|
+
handleGenerateJSON();
|
|
280
|
+
} else if (isFileLoaded && initialJsonData) {
|
|
281
|
+
console.log('[Structura] Skipping API call - using cached JSON data');
|
|
282
|
+
}
|
|
283
|
+
}, [isFileLoaded, initialJsonData]);
|
|
284
|
+
// Handle removing the PDF and resetting state
|
|
285
|
+
const handleRemovePDF = () => {
|
|
286
|
+
setFile(null);
|
|
287
|
+
setFileUrl(null);
|
|
288
|
+
setJsonData(null);
|
|
289
|
+
setAllowedPages(null);
|
|
290
|
+
setSelectedBboxId(null);
|
|
291
|
+
setIsFileLoaded(false);
|
|
292
|
+
setNumPages(null);
|
|
293
|
+
setPageNumber(1);
|
|
294
|
+
setSelectedField(null);
|
|
295
|
+
setFlattenedFields([]);
|
|
296
|
+
setError(null);
|
|
297
|
+
};
|
|
298
|
+
const handleGenerateJSON = async () => {
|
|
299
|
+
if (!isFileLoaded || !file) return;
|
|
300
|
+
setIsLoading(true);
|
|
301
|
+
setLoadingProgress(0);
|
|
302
|
+
try {
|
|
303
|
+
// Send the PDF file as FormData to the API route
|
|
304
|
+
const formData = new FormData();
|
|
305
|
+
formData.append("file", file);
|
|
306
|
+
// console.log("!!! [Structura] FormData:", formData);
|
|
307
|
+
if (!(props === null || props === void 0 ? void 0 : props.APIKey)) {
|
|
308
|
+
throw new Error("API key is required but not provided");
|
|
309
|
+
}
|
|
310
|
+
const submitResponse = await route.POST(formData, {
|
|
311
|
+
apiKey: props.APIKey,
|
|
312
|
+
baseUrl: props.baseUrl
|
|
313
|
+
});
|
|
314
|
+
console.log("API response status:", submitResponse.status);
|
|
315
|
+
if (submitResponse.status !== 200) {
|
|
316
|
+
const errorData = submitResponse;
|
|
317
|
+
console.error("Submission error details:", errorData);
|
|
318
|
+
if (submitResponse.status === 503) {
|
|
319
|
+
throw new Error(`Backend connection error: ${errorData.details || "Could not connect to backend service"}`);
|
|
320
|
+
} else if (submitResponse.status === 401) {
|
|
321
|
+
throw new Error(`Authentication error: Invalid API key. Please check your API key.`);
|
|
322
|
+
} else {
|
|
323
|
+
throw new Error(`Failed to submit PDF: ${errorData.error || "Unknown error"}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
setLoadingProgress(50);
|
|
327
|
+
const requestId = submitResponse.data.request_id;
|
|
328
|
+
// Poll for result every 2 seconds
|
|
329
|
+
let pollCount = 0;
|
|
330
|
+
let resultData = null;
|
|
331
|
+
while (true) {
|
|
332
|
+
const resultResponse = await route.GET(requestId, {
|
|
333
|
+
apiKey: props.APIKey,
|
|
334
|
+
baseUrl: props.baseUrl
|
|
335
|
+
});
|
|
336
|
+
if (resultResponse.data.status === "completed") {
|
|
337
|
+
// Store the response data
|
|
338
|
+
resultData = resultResponse.data;
|
|
339
|
+
// console.log("!!! [Structura] ResultData:", resultData.result);
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
pollCount++;
|
|
343
|
+
// if (pollCount > 60) { // Timeout after 2 minutes
|
|
344
|
+
// throw new Error("Polling timed out. Please try again later.");
|
|
345
|
+
// }
|
|
346
|
+
await new Promise(res => setTimeout(res, 2000));
|
|
347
|
+
}
|
|
348
|
+
// Now validate the data format after polling is complete
|
|
349
|
+
// if (resultData) {
|
|
350
|
+
// // Zod validation
|
|
351
|
+
// const parseResult = DocumentOutputSchema.safeParse(resultData);
|
|
352
|
+
// if (!parseResult.success) {
|
|
353
|
+
// // Handle validation errors
|
|
354
|
+
// console.error("Invalid data format from server:", parseResult.error);
|
|
355
|
+
// setError("Invalid data format from server. Please check console for details.");
|
|
356
|
+
// setIsLoading(false);
|
|
357
|
+
// return;
|
|
358
|
+
// }
|
|
359
|
+
// resultData = parseResult.data;
|
|
360
|
+
// }
|
|
361
|
+
setLoadingProgress(90);
|
|
362
|
+
const processedData = preprocessData.preprocessData(resultData);
|
|
363
|
+
// console.log("!!! [Structura] ProcessedData:", processedData);
|
|
364
|
+
setJsonData(processedData.result);
|
|
365
|
+
setActiveTab("html");
|
|
366
|
+
} catch (error) {
|
|
367
|
+
console.error("Error processing PDF:", error);
|
|
368
|
+
const errorMessage = error instanceof Error ? error.message : "Failed to process PDF";
|
|
369
|
+
setError(`${errorMessage}. ${error.toString().includes("Backend connection") ? "Backend is unavailable." : "Please try again."}`);
|
|
370
|
+
setBackendStatus('offline');
|
|
371
|
+
setJsonData(null);
|
|
372
|
+
} finally {
|
|
373
|
+
setLoadingProgress(100);
|
|
374
|
+
setTimeout(() => {
|
|
375
|
+
setIsLoading(false);
|
|
376
|
+
}, 300);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
// Handle click on HTML element in the right panel
|
|
380
|
+
const handleHtmlNodeClick = nodeId => {
|
|
381
|
+
// console.log(`[PdfHighlighter] HTML Node clicked: ${nodeId}`);
|
|
382
|
+
setSelectedBboxId(nodeId);
|
|
383
|
+
// PDF scrolling will be handled by the useEffect below
|
|
384
|
+
};
|
|
385
|
+
// Handler for when a bbox is clicked in the PDF viewer
|
|
386
|
+
const handlePdfBboxClicked = blockId => {
|
|
387
|
+
// console.log(`[PdfHighlighter] PDF Bbox clicked: ${blockId}`);
|
|
388
|
+
setSelectedBboxId(blockId);
|
|
389
|
+
// HTML scrolling is handled by HtmlViewer's own useEffect
|
|
390
|
+
};
|
|
391
|
+
// Effect to scroll PDF page into view when selectedBboxId changes
|
|
392
|
+
React.useEffect(() => {
|
|
393
|
+
if (!selectedBboxId || !jsonData || !jsonData.children || !pdfWrapperRef.current) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const findPageOfBlock = (blockIdToFind, documentData) => {
|
|
397
|
+
if (!documentData || !documentData.children) return null;
|
|
398
|
+
for (let i = 0; i < documentData.children.length; i++) {
|
|
399
|
+
const pageBlock = documentData.children[i];
|
|
400
|
+
if (pageBlock.block_type === "Page") {
|
|
401
|
+
// Check if the pageBlock itself is the target
|
|
402
|
+
if (pageBlock.id === blockIdToFind) {
|
|
403
|
+
return i + 1; // Page numbers are 1-indexed
|
|
404
|
+
}
|
|
405
|
+
// Recursively search within this page's children
|
|
406
|
+
const blockExistsInPage = currentBlock => {
|
|
407
|
+
if (currentBlock.id === blockIdToFind) return true;
|
|
408
|
+
if (currentBlock.children) {
|
|
409
|
+
for (const child of currentBlock.children) {
|
|
410
|
+
if (blockExistsInPage(child)) return true;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return false;
|
|
414
|
+
};
|
|
415
|
+
if (blockExistsInPage(pageBlock)) {
|
|
416
|
+
return i + 1; // Page numbers are 1-indexed
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return null;
|
|
421
|
+
};
|
|
422
|
+
const pageNumWithSelectedBlock = findPageOfBlock(selectedBboxId, jsonData);
|
|
423
|
+
if (pageNumWithSelectedBlock !== null) {
|
|
424
|
+
// console.log(`[PdfHighlighter] Selected bbox ${selectedBboxId} found on page ${pageNumWithSelectedBlock}. Scrolling PDF page.`);
|
|
425
|
+
const pageElementId = `pdf-page-container-${pageNumWithSelectedBlock}`;
|
|
426
|
+
const pageElement = document.getElementById(pageElementId); // Check if element exists before timeout
|
|
427
|
+
if (pageElement) {
|
|
428
|
+
// console.log(`[PdfHighlighter] Scheduling scroll for PDF Page element ${pageElementId}`);
|
|
429
|
+
setTimeout(() => {
|
|
430
|
+
const el = document.getElementById(pageElementId); // Re-fetch element in timeout
|
|
431
|
+
if (el) {
|
|
432
|
+
// console.log(`[PdfHighlighter] Timeout: Scrolling to PDF Page element ${el.id} (align to top)`);
|
|
433
|
+
el.scrollIntoView(true); // Align to top, auto behavior
|
|
434
|
+
} else {
|
|
435
|
+
console.warn(`[PdfHighlighter] Timeout: PDF Page element ${pageElementId} not found at time of scroll.`);
|
|
436
|
+
}
|
|
437
|
+
}, 0); // Small delay
|
|
438
|
+
} else {
|
|
439
|
+
console.warn(`[PdfHighlighter] PDF Page element ${pageElementId} not found for scheduling scroll.`);
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
console.log(`[PdfHighlighter] Selected bbox ${selectedBboxId} not found in any page or jsonData not structured as expected.`);
|
|
443
|
+
}
|
|
444
|
+
}, [selectedBboxId, jsonData, pdfWrapperRef]);
|
|
445
|
+
// Determine which pages to render
|
|
446
|
+
let pagesToRender = [];
|
|
447
|
+
if (numPages) {
|
|
448
|
+
if (allowedPages && allowedPages.length > 0) {
|
|
449
|
+
pagesToRender = allowedPages.filter(p => p >= 1 && p <= numPages);
|
|
450
|
+
} else {
|
|
451
|
+
pagesToRender = Array.from({
|
|
452
|
+
length: numPages
|
|
453
|
+
}, (_, i) => i + 1);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return jsxRuntime.jsxs("div", {
|
|
457
|
+
className: "h-screen max-h-screen flex flex-col bg-background text-foreground",
|
|
458
|
+
children: [jsxRuntime.jsx("header", {
|
|
459
|
+
className: "border-b border-border bg-card p-4",
|
|
460
|
+
children: jsxRuntime.jsxs("div", {
|
|
461
|
+
className: "container mx-auto flex justify-between items-center",
|
|
462
|
+
children: [jsxRuntime.jsxs("div", {
|
|
463
|
+
className: "flex items-center space-x-2",
|
|
464
|
+
children: [jsxRuntime.jsx(LucideIcons__namespace.FileText, {
|
|
465
|
+
className: "h-6 w-6 text-primary"
|
|
466
|
+
}), jsxRuntime.jsx("h1", {
|
|
467
|
+
className: "text-2xl mt-2.5 font-bold",
|
|
468
|
+
children: "PLAYGROUND"
|
|
469
|
+
})]
|
|
470
|
+
}), jsxRuntime.jsx("div", {
|
|
471
|
+
className: "flex items-center gap-2",
|
|
472
|
+
children: jsxRuntime.jsx(badge.Badge, {
|
|
473
|
+
variant: "outline",
|
|
474
|
+
className: "px-3 py-1 text-xs",
|
|
475
|
+
children: isFileLoaded ? "Document Loaded" : "No Document"
|
|
476
|
+
})
|
|
477
|
+
})]
|
|
478
|
+
})
|
|
479
|
+
}), jsxRuntime.jsx("div", {
|
|
480
|
+
className: "md:hidden",
|
|
481
|
+
children: jsxRuntime.jsxs(tabs.Tabs, {
|
|
482
|
+
value: activeTab,
|
|
483
|
+
onValueChange: setActiveTab,
|
|
484
|
+
className: "w-full",
|
|
485
|
+
children: [jsxRuntime.jsxs(tabs.TabsList, {
|
|
486
|
+
className: "grid w-full grid-cols-2",
|
|
487
|
+
children: [jsxRuntime.jsxs(tabs.TabsTrigger, {
|
|
488
|
+
value: "pdf",
|
|
489
|
+
className: "flex items-center gap-2",
|
|
490
|
+
children: [jsxRuntime.jsx(LucideIcons__namespace.FileText, {
|
|
491
|
+
className: "h-4 w-4"
|
|
492
|
+
}), "PDF View"]
|
|
493
|
+
}), jsxRuntime.jsxs(tabs.TabsTrigger, {
|
|
494
|
+
value: "html",
|
|
495
|
+
className: "flex items-center gap-2",
|
|
496
|
+
children: [jsxRuntime.jsx(LucideIcons__namespace.FileText, {
|
|
497
|
+
className: "h-4 w-4"
|
|
498
|
+
}), "HTML View"]
|
|
499
|
+
})]
|
|
500
|
+
}), jsxRuntime.jsx(tabs.TabsContent, {
|
|
501
|
+
value: "pdf",
|
|
502
|
+
className: "p-0 border-0",
|
|
503
|
+
children: jsxRuntime.jsx("div", {
|
|
504
|
+
ref: pdfWrapperRef,
|
|
505
|
+
className: "h-[calc(100vh-220px)] overflow-auto",
|
|
506
|
+
children: jsxRuntime.jsx(scrollArea.ScrollArea, {
|
|
507
|
+
className: "w-full h-[calc(100vh-220px)]",
|
|
508
|
+
children: fileUrl ? jsxRuntime.jsx(PdfDocumentViewer.default, {
|
|
509
|
+
fileUrl: fileUrl,
|
|
510
|
+
allowedPages: pagesToRender,
|
|
511
|
+
onLoadSuccess: num => {
|
|
512
|
+
// console.log("!!! PDF loaded successfully, numPages:", num);
|
|
513
|
+
setNumPages(num);
|
|
514
|
+
// console.log("!!! Setting isFileLoaded to true");
|
|
515
|
+
setIsFileLoaded(true);
|
|
516
|
+
},
|
|
517
|
+
onFileUpload: handleFileUpload,
|
|
518
|
+
onRemovePDF: handleRemovePDF,
|
|
519
|
+
jsonData: jsonData,
|
|
520
|
+
selectedBboxId: selectedBboxId,
|
|
521
|
+
onPdfBboxClick: handlePdfBboxClicked
|
|
522
|
+
}) : jsxRuntime.jsx("div", {
|
|
523
|
+
className: `min-h-full w-full flex flex-col items-center justify-center p-8 text-center transition-all duration-200 ${isDraggingOver ? 'bg-primary/10 border-2 border-dashed border-primary' : 'bg-muted/50'}`,
|
|
524
|
+
onDragOver: e => {
|
|
525
|
+
e.preventDefault();
|
|
526
|
+
e.stopPropagation();
|
|
527
|
+
setIsDraggingOver(true);
|
|
528
|
+
},
|
|
529
|
+
onDragLeave: e => {
|
|
530
|
+
e.preventDefault();
|
|
531
|
+
e.stopPropagation();
|
|
532
|
+
setIsDraggingOver(false);
|
|
533
|
+
},
|
|
534
|
+
onDrop: e => {
|
|
535
|
+
e.preventDefault();
|
|
536
|
+
e.stopPropagation();
|
|
537
|
+
setIsDraggingOver(false);
|
|
538
|
+
// console.log("!!! File drop event triggered");
|
|
539
|
+
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
|
540
|
+
// If multiple files were dropped, show an error
|
|
541
|
+
if (e.dataTransfer.files.length > 1) {
|
|
542
|
+
// console.log("!!! Multiple files dropped - showing error");
|
|
543
|
+
setError('Please upload only one PDF file at a time');
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
const file = e.dataTransfer.files[0];
|
|
547
|
+
// console.log("!!! Dropped file type:", file.type);
|
|
548
|
+
if (file.type === 'application/pdf') {
|
|
549
|
+
// console.log("!!! Valid PDF file dropped:", file.name);
|
|
550
|
+
handleFileUpload(file);
|
|
551
|
+
} else {
|
|
552
|
+
// console.log("!!! Invalid file type dropped");
|
|
553
|
+
setError(`Invalid file type: ${file.name}. Please upload a PDF file only.`);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
children: jsxRuntime.jsxs("div", {
|
|
558
|
+
className: "max-w-md mx-auto flex flex-col items-center",
|
|
559
|
+
children: [jsxRuntime.jsx("div", {
|
|
560
|
+
className: `w-24 h-24 border-2 border-dashed rounded-full flex items-center justify-center mb-6 transition-all duration-200 ${isDraggingOver ? 'border-primary bg-primary/5 scale-110' : 'border-muted-foreground/50'}`,
|
|
561
|
+
children: jsxRuntime.jsx(LucideIcons__namespace.Upload, {
|
|
562
|
+
className: `h-12 w-12 transition-colors duration-200 ${isDraggingOver ? 'text-primary' : 'text-muted-foreground'}`
|
|
563
|
+
})
|
|
564
|
+
}), jsxRuntime.jsx("h3", {
|
|
565
|
+
className: "text-xl font-medium mb-4",
|
|
566
|
+
children: isDraggingOver ? 'Release to Upload PDF' : 'Drop PDF Here or Click to Upload'
|
|
567
|
+
}), jsxRuntime.jsx("p", {
|
|
568
|
+
className: "text-muted-foreground mb-6",
|
|
569
|
+
children: isDraggingOver ? 'Let go to start processing your document' : 'Drag and drop your PDF document here, or click the button below to browse files'
|
|
570
|
+
}), jsxRuntime.jsxs(button.Button, {
|
|
571
|
+
onClick: () => {
|
|
572
|
+
var _a;
|
|
573
|
+
return (_a = document.getElementById('pdf-upload')) === null || _a === void 0 ? void 0 : _a.click();
|
|
574
|
+
},
|
|
575
|
+
className: "flex items-center gap-2",
|
|
576
|
+
size: "lg",
|
|
577
|
+
children: ["Upload Document ", jsxRuntime.jsx(LucideIcons__namespace.Upload, {
|
|
578
|
+
className: "h-4 w-4 ml-1"
|
|
579
|
+
})]
|
|
580
|
+
}), jsxRuntime.jsx("input", {
|
|
581
|
+
type: "file",
|
|
582
|
+
id: "pdf-upload",
|
|
583
|
+
accept: ".pdf",
|
|
584
|
+
className: "hidden",
|
|
585
|
+
onChange: e => {
|
|
586
|
+
var _a;
|
|
587
|
+
// console.log("!!! File input onChange triggered");
|
|
588
|
+
if ((_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0]) {
|
|
589
|
+
// console.log("!!! File selected from input:", e.target.files[0].name);
|
|
590
|
+
handleFileUpload(e.target.files[0]);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}), jsxRuntime.jsx("p", {
|
|
594
|
+
className: "text-xs text-muted-foreground mt-4",
|
|
595
|
+
children: "Supported format: PDF only"
|
|
596
|
+
})]
|
|
597
|
+
})
|
|
598
|
+
})
|
|
599
|
+
})
|
|
600
|
+
})
|
|
601
|
+
}), jsxRuntime.jsx(tabs.TabsContent, {
|
|
602
|
+
value: "html",
|
|
603
|
+
className: "p-0 border-0",
|
|
604
|
+
children: jsxRuntime.jsx("div", {
|
|
605
|
+
className: "h-[calc(100vh-220px)]",
|
|
606
|
+
children: jsxRuntime.jsx(HtmlViewer.default, {
|
|
607
|
+
jsonData: jsonData,
|
|
608
|
+
selectedBboxId: selectedBboxId,
|
|
609
|
+
isLoading: isLoading,
|
|
610
|
+
onNodeClick: handleHtmlNodeClick,
|
|
611
|
+
onSave: props.onSave
|
|
612
|
+
})
|
|
613
|
+
})
|
|
614
|
+
})]
|
|
615
|
+
})
|
|
616
|
+
}), jsxRuntime.jsx("div", {
|
|
617
|
+
className: "hidden md:block flex-1 overflow-hidden",
|
|
618
|
+
children: jsxRuntime.jsxs(reactResizablePanels.PanelGroup, {
|
|
619
|
+
direction: "horizontal",
|
|
620
|
+
className: "h-full",
|
|
621
|
+
children: [jsxRuntime.jsx(reactResizablePanels.Panel, {
|
|
622
|
+
minSize: 20,
|
|
623
|
+
defaultSize: 50,
|
|
624
|
+
children: jsxRuntime.jsxs(card.Card, {
|
|
625
|
+
className: "h-full border-0 rounded-none",
|
|
626
|
+
children: [jsxRuntime.jsx(card.CardHeader, {
|
|
627
|
+
className: "py-3 px-4 border-b bg-muted/30",
|
|
628
|
+
children: jsxRuntime.jsxs(card.CardTitle, {
|
|
629
|
+
className: "text-base flex items-center gap-2",
|
|
630
|
+
children: [jsxRuntime.jsx(LucideIcons__namespace.FileText, {
|
|
631
|
+
className: "h-4 w-4"
|
|
632
|
+
}), "PDF Document", file && jsxRuntime.jsx(badge.Badge, {
|
|
633
|
+
variant: "secondary",
|
|
634
|
+
className: "ml-2",
|
|
635
|
+
children: file.name
|
|
636
|
+
})]
|
|
637
|
+
})
|
|
638
|
+
}), jsxRuntime.jsx(card.CardContent, {
|
|
639
|
+
className: "p-0 flex-1 flex flex-col overflow-hidden",
|
|
640
|
+
children: jsxRuntime.jsx(scrollArea.ScrollArea, {
|
|
641
|
+
className: "w-full h-[calc(100vh-220px)]",
|
|
642
|
+
children: fileUrl ? jsxRuntime.jsx(PdfDocumentViewer.default, {
|
|
643
|
+
fileUrl: fileUrl,
|
|
644
|
+
allowedPages: pagesToRender,
|
|
645
|
+
onLoadSuccess: num => {
|
|
646
|
+
// console.log("!!! PDF loaded successfully, numPages:", num);
|
|
647
|
+
setNumPages(num);
|
|
648
|
+
// console.log("!!! Setting isFileLoaded to true");
|
|
649
|
+
setIsFileLoaded(true);
|
|
650
|
+
},
|
|
651
|
+
onFileUpload: handleFileUpload,
|
|
652
|
+
onRemovePDF: handleRemovePDF,
|
|
653
|
+
jsonData: jsonData,
|
|
654
|
+
selectedBboxId: selectedBboxId,
|
|
655
|
+
onPdfBboxClick: handlePdfBboxClicked
|
|
656
|
+
}) : jsxRuntime.jsx("div", {
|
|
657
|
+
className: `min-h-full w-full flex flex-col items-center justify-center p-8 text-center transition-all duration-200 ${isDraggingOver ? 'bg-primary/10 border-2 border-dashed border-primary' : 'bg-muted/50'}`,
|
|
658
|
+
onDragOver: e => {
|
|
659
|
+
e.preventDefault();
|
|
660
|
+
e.stopPropagation();
|
|
661
|
+
setIsDraggingOver(true);
|
|
662
|
+
},
|
|
663
|
+
onDragLeave: e => {
|
|
664
|
+
e.preventDefault();
|
|
665
|
+
e.stopPropagation();
|
|
666
|
+
setIsDraggingOver(false);
|
|
667
|
+
},
|
|
668
|
+
onDrop: e => {
|
|
669
|
+
e.preventDefault();
|
|
670
|
+
e.stopPropagation();
|
|
671
|
+
setIsDraggingOver(false);
|
|
672
|
+
// console.log("!!! File drop event triggered");
|
|
673
|
+
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
|
674
|
+
// If multiple files were dropped, show an error
|
|
675
|
+
if (e.dataTransfer.files.length > 1) {
|
|
676
|
+
// console.log("!!! Multiple files dropped - showing error");
|
|
677
|
+
setError('Please upload only one PDF file at a time');
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
const file = e.dataTransfer.files[0];
|
|
681
|
+
// console.log("!!! Dropped file type:", file.type);
|
|
682
|
+
if (file.type === 'application/pdf') {
|
|
683
|
+
// console.log("!!! Valid PDF file dropped:", file.name);
|
|
684
|
+
handleFileUpload(file);
|
|
685
|
+
} else {
|
|
686
|
+
// console.log("!!! Invalid file type dropped");
|
|
687
|
+
setError(`Invalid file type: ${file.name}. Please upload a PDF file only.`);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
children: jsxRuntime.jsxs("div", {
|
|
692
|
+
className: "max-w-md mx-auto flex flex-col items-center",
|
|
693
|
+
children: [jsxRuntime.jsx("div", {
|
|
694
|
+
className: `w-24 h-24 border-2 border-dashed rounded-full flex items-center justify-center mb-6 transition-all duration-200 ${isDraggingOver ? 'border-primary bg-primary/5 scale-110' : 'border-muted-foreground/50'}`,
|
|
695
|
+
children: jsxRuntime.jsx(LucideIcons__namespace.Upload, {
|
|
696
|
+
className: `h-12 w-12 transition-colors duration-200 ${isDraggingOver ? 'text-primary' : 'text-muted-foreground'}`
|
|
697
|
+
})
|
|
698
|
+
}), jsxRuntime.jsx("h3", {
|
|
699
|
+
className: "text-xl font-medium mb-4",
|
|
700
|
+
children: isDraggingOver ? 'Release to Upload PDF' : 'Drop PDF Here or Click to Upload'
|
|
701
|
+
}), jsxRuntime.jsx("p", {
|
|
702
|
+
className: "text-muted-foreground mb-6",
|
|
703
|
+
children: isDraggingOver ? 'Let go to start processing your document' : 'Drag and drop your PDF document here, or click the button below to browse files'
|
|
704
|
+
}), jsxRuntime.jsxs(button.Button, {
|
|
705
|
+
onClick: () => {
|
|
706
|
+
var _a;
|
|
707
|
+
return (_a = document.getElementById('pdf-upload')) === null || _a === void 0 ? void 0 : _a.click();
|
|
708
|
+
},
|
|
709
|
+
className: "flex items-center gap-2",
|
|
710
|
+
size: "lg",
|
|
711
|
+
children: ["Upload Document ", jsxRuntime.jsx(LucideIcons__namespace.Upload, {
|
|
712
|
+
className: "h-4 w-4 ml-1"
|
|
713
|
+
})]
|
|
714
|
+
}), jsxRuntime.jsx("input", {
|
|
715
|
+
type: "file",
|
|
716
|
+
id: "pdf-upload",
|
|
717
|
+
accept: ".pdf",
|
|
718
|
+
className: "hidden",
|
|
719
|
+
onChange: e => {
|
|
720
|
+
var _a;
|
|
721
|
+
// console.log("!!! File input onChange triggered");
|
|
722
|
+
if ((_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0]) {
|
|
723
|
+
// console.log("!!! File selected from input:", e.target.files[0].name);
|
|
724
|
+
handleFileUpload(e.target.files[0]);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}), jsxRuntime.jsx("p", {
|
|
728
|
+
className: "text-xs text-muted-foreground mt-4",
|
|
729
|
+
children: "Supported format: PDF only"
|
|
730
|
+
})]
|
|
731
|
+
})
|
|
732
|
+
})
|
|
733
|
+
})
|
|
734
|
+
})]
|
|
735
|
+
})
|
|
736
|
+
}), jsxRuntime.jsx(reactResizablePanels.PanelResizeHandle, {
|
|
737
|
+
className: "w-1.5 bg-black hover:bg-primary/20 transition-colors cursor-col-resize"
|
|
738
|
+
}), jsxRuntime.jsx(reactResizablePanels.Panel, {
|
|
739
|
+
minSize: 20,
|
|
740
|
+
defaultSize: 50,
|
|
741
|
+
children: jsxRuntime.jsxs(card.Card, {
|
|
742
|
+
className: "h-full border-0 rounded-none",
|
|
743
|
+
children: [jsxRuntime.jsx(card.CardHeader, {
|
|
744
|
+
className: "py-3 px-4 border-b bg-muted/30",
|
|
745
|
+
children: jsxRuntime.jsxs(card.CardTitle, {
|
|
746
|
+
className: "text-base flex items-center gap-2",
|
|
747
|
+
children: [jsxRuntime.jsx(LucideIcons__namespace.FileText, {
|
|
748
|
+
className: "h-4 w-4"
|
|
749
|
+
}), "HTML Structure"]
|
|
750
|
+
})
|
|
751
|
+
}), jsxRuntime.jsx(card.CardContent, {
|
|
752
|
+
className: "p-0 h-[calc(100%-56px)] relative overflow-hidden",
|
|
753
|
+
children: jsxRuntime.jsx("div", {
|
|
754
|
+
className: "absolute inset-0",
|
|
755
|
+
children: jsonData ? jsxRuntime.jsx(HtmlViewer.default, {
|
|
756
|
+
jsonData: jsonData,
|
|
757
|
+
selectedBboxId: selectedBboxId,
|
|
758
|
+
isLoading: isLoading,
|
|
759
|
+
onNodeClick: handleHtmlNodeClick,
|
|
760
|
+
onSave: props.onSave
|
|
761
|
+
}) : jsxRuntime.jsx("div", {
|
|
762
|
+
className: "flex flex-col items-center justify-center h-full p-8 text-center",
|
|
763
|
+
children: jsxRuntime.jsxs("div", {
|
|
764
|
+
className: "bg-muted/50 p-8 rounded-lg flex flex-col items-center",
|
|
765
|
+
children: [jsxRuntime.jsx(LucideIcons__namespace.Upload, {
|
|
766
|
+
className: "h-12 w-12 text-muted-foreground mb-4"
|
|
767
|
+
}), jsxRuntime.jsx("h3", {
|
|
768
|
+
className: "text-lg font-medium mb-2",
|
|
769
|
+
children: "No Data Available"
|
|
770
|
+
}), jsxRuntime.jsx("p", {
|
|
771
|
+
className: "text-muted-foreground mb-4",
|
|
772
|
+
children: "First upload a PDF document, then generate the HTML structure"
|
|
773
|
+
})]
|
|
774
|
+
})
|
|
775
|
+
})
|
|
776
|
+
})
|
|
777
|
+
})]
|
|
778
|
+
})
|
|
779
|
+
})]
|
|
780
|
+
})
|
|
781
|
+
}), isLoading && jsxRuntime.jsx("div", {
|
|
782
|
+
className: "fixed bottom-0 left-0 right-0 bg-background border-t border-border p-4 z-50",
|
|
783
|
+
children: jsxRuntime.jsx("div", {
|
|
784
|
+
className: "container mx-auto",
|
|
785
|
+
children: jsxRuntime.jsxs("div", {
|
|
786
|
+
className: "flex flex-col gap-2",
|
|
787
|
+
children: [jsxRuntime.jsxs("div", {
|
|
788
|
+
className: "flex items-center justify-between",
|
|
789
|
+
children: [jsxRuntime.jsx("span", {
|
|
790
|
+
className: "text-sm font-medium",
|
|
791
|
+
children: "Processing document..."
|
|
792
|
+
}), jsxRuntime.jsxs("span", {
|
|
793
|
+
className: "text-sm text-muted-foreground",
|
|
794
|
+
children: [loadingProgress, "%"]
|
|
795
|
+
})]
|
|
796
|
+
}), jsxRuntime.jsx(progress.Progress, {
|
|
797
|
+
value: loadingProgress,
|
|
798
|
+
className: "h-2"
|
|
799
|
+
})]
|
|
800
|
+
})
|
|
801
|
+
})
|
|
802
|
+
})]
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
exports.default = Structura;
|