mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-02-17 13:52:14 +01:00
Page editor fixes and improvements and restructuring
This commit is contained in:
@@ -21,7 +21,6 @@ interface FilePickerModalProps {
|
||||
onClose: () => void;
|
||||
storedFiles: any[]; // Files from storage (FileWithUrl format)
|
||||
onSelectFiles: (selectedFiles: File[]) => void;
|
||||
allowMultiple?: boolean;
|
||||
}
|
||||
|
||||
const FilePickerModal = ({
|
||||
@@ -29,7 +28,6 @@ const FilePickerModal = ({
|
||||
onClose,
|
||||
storedFiles,
|
||||
onSelectFiles,
|
||||
allowMultiple = true,
|
||||
}: FilePickerModalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [selectedFileIds, setSelectedFileIds] = useState<string[]>([]);
|
||||
@@ -43,21 +41,14 @@ const FilePickerModal = ({
|
||||
|
||||
const toggleFileSelection = (fileId: string) => {
|
||||
setSelectedFileIds(prev => {
|
||||
if (allowMultiple) {
|
||||
return prev.includes(fileId)
|
||||
? prev.filter(id => id !== fileId)
|
||||
: [...prev, fileId];
|
||||
} else {
|
||||
// Single selection mode
|
||||
return prev.includes(fileId) ? [] : [fileId];
|
||||
}
|
||||
return prev.includes(fileId)
|
||||
? prev.filter(id => id !== fileId)
|
||||
: [...prev, fileId];
|
||||
});
|
||||
};
|
||||
|
||||
const selectAll = () => {
|
||||
if (allowMultiple) {
|
||||
setSelectedFileIds(storedFiles.map(f => f.id || f.name));
|
||||
}
|
||||
setSelectedFileIds(storedFiles.map(f => f.id || f.name));
|
||||
};
|
||||
|
||||
const selectNone = () => {
|
||||
@@ -145,20 +136,18 @@ const FilePickerModal = ({
|
||||
<Group justify="space-between">
|
||||
<Text size="sm" c="dimmed">
|
||||
{storedFiles.length} {t("fileUpload.filesAvailable", "files available")}
|
||||
{allowMultiple && selectedFileIds.length > 0 && (
|
||||
{selectedFileIds.length > 0 && (
|
||||
<> • {selectedFileIds.length} selected</>
|
||||
)}
|
||||
</Text>
|
||||
{allowMultiple && (
|
||||
<Group gap="xs">
|
||||
<Button size="xs" variant="light" onClick={selectAll}>
|
||||
{t("pageEdit.selectAll", "Select All")}
|
||||
</Button>
|
||||
<Button size="xs" variant="light" onClick={selectNone}>
|
||||
{t("pageEdit.deselectAll", "Select None")}
|
||||
</Button>
|
||||
</Group>
|
||||
)}
|
||||
<Group gap="xs">
|
||||
<Button size="xs" variant="light" onClick={selectAll}>
|
||||
{t("pageEdit.selectAll", "Select All")}
|
||||
</Button>
|
||||
<Button size="xs" variant="light" onClick={selectNone}>
|
||||
{t("pageEdit.deselectAll", "Select None")}
|
||||
</Button>
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
{/* File grid */}
|
||||
@@ -186,21 +175,11 @@ const FilePickerModal = ({
|
||||
onClick={() => toggleFileSelection(fileId)}
|
||||
>
|
||||
<Group gap="sm" align="flex-start">
|
||||
{allowMultiple ? (
|
||||
<Checkbox
|
||||
checked={isSelected}
|
||||
onChange={() => toggleFileSelection(fileId)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
type="radio"
|
||||
checked={isSelected}
|
||||
onChange={() => toggleFileSelection(fileId)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{ margin: '4px' }}
|
||||
/>
|
||||
)}
|
||||
<Checkbox
|
||||
checked={isSelected}
|
||||
onChange={() => toggleFileSelection(fileId)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
|
||||
{/* Thumbnail */}
|
||||
<Box
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import React, { useState, useCallback, useRef } from 'react';
|
||||
import { Stack, Button, Text, Center } from '@mantine/core';
|
||||
import { Dropzone } from '@mantine/dropzone';
|
||||
import UploadFileIcon from '@mui/icons-material/UploadFile';
|
||||
@@ -13,9 +13,8 @@ interface FileUploadSelectorProps {
|
||||
|
||||
// File handling
|
||||
sharedFiles?: any[];
|
||||
onFileSelect: (file: File) => void;
|
||||
onFilesSelect?: (files: File[]) => void;
|
||||
allowMultiple?: boolean;
|
||||
onFileSelect?: (file: File) => void;
|
||||
onFilesSelect: (files: File[]) => void;
|
||||
accept?: string[];
|
||||
|
||||
// Loading state
|
||||
@@ -30,39 +29,54 @@ const FileUploadSelector = ({
|
||||
sharedFiles = [],
|
||||
onFileSelect,
|
||||
onFilesSelect,
|
||||
allowMultiple = false,
|
||||
accept = ["application/pdf"],
|
||||
loading = false,
|
||||
disabled = false,
|
||||
}: FileUploadSelectorProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [showFilePickerModal, setShowFilePickerModal] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleFileUpload = useCallback((uploadedFiles: File[]) => {
|
||||
if (uploadedFiles.length === 0) return;
|
||||
|
||||
if (allowMultiple && onFilesSelect) {
|
||||
if (onFilesSelect) {
|
||||
onFilesSelect(uploadedFiles);
|
||||
} else {
|
||||
} else if (onFileSelect) {
|
||||
onFileSelect(uploadedFiles[0]);
|
||||
}
|
||||
}, [allowMultiple, onFileSelect, onFilesSelect]);
|
||||
}, [onFileSelect, onFilesSelect]);
|
||||
|
||||
const handleFileInputChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = event.target.files;
|
||||
if (files && files.length > 0) {
|
||||
const fileArray = Array.from(files);
|
||||
console.log('File input change:', fileArray.length, 'files');
|
||||
handleFileUpload(fileArray);
|
||||
}
|
||||
// Reset input
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = '';
|
||||
}
|
||||
}, [handleFileUpload]);
|
||||
|
||||
const openFileDialog = useCallback(() => {
|
||||
fileInputRef.current?.click();
|
||||
}, []);
|
||||
|
||||
const handleStorageSelection = useCallback((selectedFiles: File[]) => {
|
||||
if (selectedFiles.length === 0) return;
|
||||
|
||||
if (allowMultiple && onFilesSelect) {
|
||||
if (onFilesSelect) {
|
||||
onFilesSelect(selectedFiles);
|
||||
} else {
|
||||
} else if (onFileSelect) {
|
||||
onFileSelect(selectedFiles[0]);
|
||||
}
|
||||
}, [allowMultiple, onFileSelect, onFilesSelect]);
|
||||
}, [onFileSelect, onFilesSelect]);
|
||||
|
||||
// Get default title and subtitle from translations if not provided
|
||||
const displayTitle = title || t(allowMultiple ? "fileUpload.selectFiles" : "fileUpload.selectFile",
|
||||
allowMultiple ? "Select files" : "Select a file");
|
||||
const displaySubtitle = subtitle || t(allowMultiple ? "fileUpload.chooseFromStorageMultiple" : "fileUpload.chooseFromStorage",
|
||||
allowMultiple ? "Choose files from storage or upload new PDFs" : "Choose a file from storage or upload a new PDF");
|
||||
const displayTitle = title || t("fileUpload.selectFiles", "Select files");
|
||||
const displaySubtitle = subtitle || t("fileUpload.chooseFromStorageMultiple", "Choose files from storage or upload new PDFs");
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -98,15 +112,15 @@ const FileUploadSelector = ({
|
||||
<Dropzone
|
||||
onDrop={handleFileUpload}
|
||||
accept={accept}
|
||||
multiple={allowMultiple}
|
||||
multiple={true}
|
||||
disabled={disabled || loading}
|
||||
style={{ width: '100%', minHeight: 120 }}
|
||||
activateOnClick={true}
|
||||
>
|
||||
<Center>
|
||||
<Stack align="center" gap="sm">
|
||||
<Text size="md" fw={500}>
|
||||
{t(allowMultiple ? "fileUpload.dropFilesHere" : "fileUpload.dropFileHere",
|
||||
allowMultiple ? "Drop files here or click to upload" : "Drop file here or click to upload")}
|
||||
{t("fileUpload.dropFilesHere", "Drop files here or click to upload")}
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed">
|
||||
{accept.includes('application/pdf')
|
||||
@@ -118,23 +132,27 @@ const FileUploadSelector = ({
|
||||
</Center>
|
||||
</Dropzone>
|
||||
) : (
|
||||
<Dropzone
|
||||
onDrop={handleFileUpload}
|
||||
accept={accept}
|
||||
multiple={allowMultiple}
|
||||
disabled={disabled || loading}
|
||||
style={{ display: 'contents' }}
|
||||
>
|
||||
<Stack align="center" gap="sm">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
disabled={disabled}
|
||||
loading={loading}
|
||||
onClick={openFileDialog}
|
||||
>
|
||||
{t(allowMultiple ? "fileUpload.uploadFiles" : "fileUpload.uploadFile",
|
||||
allowMultiple ? "Upload Files" : "Upload File")}
|
||||
{t("fileUpload.uploadFiles", "Upload Files")}
|
||||
</Button>
|
||||
</Dropzone>
|
||||
|
||||
{/* Manual file input as backup */}
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
multiple={true}
|
||||
accept={accept.join(',')}
|
||||
onChange={handleFileInputChange}
|
||||
style={{ display: 'none' }}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
@@ -145,7 +163,6 @@ const FileUploadSelector = ({
|
||||
onClose={() => setShowFilePickerModal(false)}
|
||||
storedFiles={sharedFiles}
|
||||
onSelectFiles={handleStorageSelection}
|
||||
allowMultiple={allowMultiple}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user