feat: PDF upload response forks to picker callback or direct placement

This commit is contained in:
Hiren Kangad
2026-03-14 11:28:29 +05:30
parent 3bd6270990
commit bbf9b9484a
+64 -2
View File
@@ -8,6 +8,14 @@ import { wasRecentInternalPaste } from './shortcut-definitions';
type OnChange = () => void; type OnChange = () => void;
export interface PdfUploadedData {
imageId: string;
fileName: string;
pageCount: number;
dimensions: Array<{ w: number; h: number }>;
singlePage: boolean;
}
/** Client-side file size limit (matches backend MAX_FILE_SIZE_MB default) */ /** Client-side file size limit (matches backend MAX_FILE_SIZE_MB default) */
const MAX_FILE_SIZE_MB = 200; const MAX_FILE_SIZE_MB = 200;
const MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024; const MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024;
@@ -155,6 +163,7 @@ export function setupDragDrop(
onChange: OnChange, onChange: OnChange,
selection?: SelectionManager | null, selection?: SelectionManager | null,
uploads?: UploadManager | null, uploads?: UploadManager | null,
onPdfUploaded?: (data: PdfUploadedData) => void,
): () => void { ): () => void {
function onDragOver(e: DragEvent) { function onDragOver(e: DragEvent) {
e.preventDefault(); e.preventDefault();
@@ -279,6 +288,33 @@ export function setupDragDrop(
if (jobId) uploads?.setProgress(jobId, p); if (jobId) uploads?.setProgress(jobId, p);
}); });
removePlaceholder(viewport, placeholder); removePlaceholder(viewport, placeholder);
// PDF fork — single-page goes directly on canvas, multi-page opens picker
const resData = res.data.image || res.data;
if (resData.media_type === 'pdf') {
if (jobId) uploads?.uploadComplete(jobId, resData.id);
if (resData.single_page) {
const item = sceneManager.addPdfPageFromUpload(
null, null, resData.width, resData.height,
cursorX, cursorY,
resData.id, file.name, 1, 1,
);
newItemIds.push(item.id);
onChange();
} else if (onPdfUploaded) {
onPdfUploaded({
imageId: resData.id,
fileName: file.name,
pageCount: resData.page_count,
dimensions: resData.dimensions,
singlePage: false,
});
}
col++;
if (col >= cols) { col = 0; row++; cursorY += rowMaxH + GAP; rowMaxH = 0; }
continue;
}
const { w: placedW, h: placedH, id } = handleUploadResult(res, viewport, sceneManager, cursorX, cursorY, onChange); const { w: placedW, h: placedH, id } = handleUploadResult(res, viewport, sceneManager, cursorX, cursorY, onChange);
newItemIds.push(id); newItemIds.push(id);
if (placedW > (colWidths[col] || 0)) colWidths[col] = placedW; if (placedW > (colWidths[col] || 0)) colWidths[col] = placedW;
@@ -346,6 +382,7 @@ export function setupPaste(
opts?: { opts?: {
onTextPaste?: (data: { text: string; html: string; hasImage: boolean }) => void; onTextPaste?: (data: { text: string; html: string; hasImage: boolean }) => void;
onShortTextPaste?: (text: string) => void; onShortTextPaste?: (text: string) => void;
onPdfUploaded?: (data: PdfUploadedData) => void;
}, },
): () => void { ): () => void {
// Track last known cursor position in world coordinates for paste-at-cursor // Track last known cursor position in world coordinates for paste-at-cursor
@@ -377,7 +414,7 @@ export function setupPaste(
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
const item = items[i]; const item = items[i];
if (item.type.startsWith('image/') || item.type.startsWith('video/')) hasMedia = true; if (item.type.startsWith('image/') || item.type.startsWith('video/') || item.type === 'application/pdf') hasMedia = true;
if (item.type === 'text/plain') textContent = e.clipboardData?.getData('text/plain') || ''; if (item.type === 'text/plain') textContent = e.clipboardData?.getData('text/plain') || '';
if (item.type === 'text/html') htmlContent = e.clipboardData?.getData('text/html') || ''; if (item.type === 'text/html') htmlContent = e.clipboardData?.getData('text/html') || '';
} }
@@ -402,7 +439,7 @@ export function setupPaste(
const item = items[i]; const item = items[i];
// Skip non-media clipboard items (text, html, etc.) // Skip non-media clipboard items (text, html, etc.)
if (!item.type.startsWith('image/') && !item.type.startsWith('video/')) continue; if (!item.type.startsWith('image/') && !item.type.startsWith('video/') && item.type !== 'application/pdf') continue;
e.preventDefault(); e.preventDefault();
@@ -438,6 +475,31 @@ export function setupPaste(
if (jobId) uploads?.setProgress(jobId, p); if (jobId) uploads?.setProgress(jobId, p);
}); });
removePlaceholder(viewport, placeholder); removePlaceholder(viewport, placeholder);
// PDF fork — single-page goes directly on canvas, multi-page opens picker
const resData = res.data.image || res.data;
if (resData.media_type === 'pdf') {
if (jobId) uploads?.uploadComplete(jobId, resData.id);
if (resData.single_page) {
const pdfItem = sceneManager.addPdfPageFromUpload(
null, null, resData.width, resData.height,
cx - 100, cy - 75,
resData.id, file.name, 1, 1,
);
newItemIds.push(pdfItem.id);
onChange();
} else if (opts?.onPdfUploaded) {
opts.onPdfUploaded({
imageId: resData.id,
fileName: file.name,
pageCount: resData.page_count,
dimensions: resData.dimensions,
singlePage: false,
});
}
continue;
}
const { id } = handleUploadResult(res, viewport, sceneManager, cx - 100, cy - 75, onChange); const { id } = handleUploadResult(res, viewport, sceneManager, cx - 100, cy - 75, onChange);
newItemIds.push(id); newItemIds.push(id);
const imgData = res.data.image || res.data; const imgData = res.data.image || res.data;