This commit is contained in:
seb
2026-09-15 16:10:42 +02:00
parent 0217156d19
commit 7135cdb5fe
2 changed files with 143 additions and 8 deletions

View File

@@ -0,0 +1,108 @@
import { useState, useRef } from 'react';
import Box from '@mui/material/Box';
/**
* An otherwise invisible dropzone wrapper.
* Renders seamlessly around children without altering layout or style,
* and highlights with an outline only while a file is dragged over it.
*/
export function FileDropzone({
accept = 'application/pdf,.pdf',
disabled = false,
onFileDrop,
children,
sx,
...props
}) {
const [isDragging, setIsDragging] = useState(false);
const dragCounter = useRef(0);
const handleDragEnter = (e) => {
e.preventDefault();
e.stopPropagation();
if (disabled) return;
dragCounter.current += 1;
if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
setIsDragging(true);
}
};
const handleDragLeave = (e) => {
e.preventDefault();
e.stopPropagation();
dragCounter.current -= 1;
if (dragCounter.current <= 0) {
dragCounter.current = 0;
setIsDragging(false);
}
};
const handleDragOver = (e) => {
e.preventDefault();
e.stopPropagation();
if (disabled) {
e.dataTransfer.dropEffect = 'none';
return;
}
e.dataTransfer.dropEffect = 'copy';
};
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
dragCounter.current = 0;
setIsDragging(false);
if (disabled) return;
const file = e.dataTransfer.files?.[0];
if (!file) return;
if (accept) {
const allowed = accept
.split(',')
.map((s) => s.trim().toLowerCase())
.filter(Boolean);
const name = (file.name || '').toLowerCase();
const dotIndex = name.lastIndexOf('.');
const ext = dotIndex !== -1 ? name.slice(dotIndex) : '';
const mimeType = (file.type || '').toLowerCase();
const matches = allowed.some((item) => {
if (item.startsWith('.')) {
return ext === item;
}
return mimeType === item;
});
if (!matches) return;
}
onFileDrop?.(file);
};
return (
<Box
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
onDragOver={handleDragOver}
onDrop={handleDrop}
sx={{
display: 'inline-flex',
position: 'relative',
borderRadius: 1,
flexShrink: 0,
// Keep outline inset so it never affects external geometry or causes scrollbars:
outline: isDragging ? '2px dashed' : 'none',
outlineColor: 'primary.main',
outlineOffset: -2,
transition: 'outline 0.15s ease-in-out',
...sx,
}}
{...props}
>
{typeof children === 'function' ? children({ isDragging }) : children}
</Box>
);
}
export default FileDropzone;

View File

@@ -7,6 +7,7 @@ import TextField from '@mui/material/TextField';
import UploadFileIcon from '@mui/icons-material/UploadFile';
import SingleLineTextEdit from 'dashgui/SingleLineTextEdit';
import { PanelTile } from 'dashgui/panels';
import FileDropzone from '../FileDropzone';
import { manifestConfig, partyDisplayName } from './manifestConfig';
class ManifestHeader extends PureComponent {
@@ -122,16 +123,42 @@ class ManifestHeader extends PureComponent {
/>
) : null}
{onPdfUpload ? (
<Button
variant="outlined"
size="small"
startIcon={pdfUploading ? <CircularProgress size={16} color="inherit" /> : <UploadFileIcon />}
<FileDropzone
accept="application/pdf,.pdf"
disabled={saving || pdfUploading}
onClick={this.handleUploadClick}
sx={{ whiteSpace: 'nowrap', height: 40, alignSelf: { xs: 'stretch', sm: 'center' }, px: 2 }}
onFileDrop={onPdfUpload}
sx={{
alignSelf: { xs: 'stretch', sm: 'center' },
flexShrink: 0,
width: { xs: '100%', sm: 175 },
}}
>
{pdfUploading ? 'Wird analysiert…' : 'PDF hochladen'}
</Button>
{({ isDragging }) => (
<Button
variant="outlined"
size="small"
startIcon={pdfUploading ? <CircularProgress size={16} color="inherit" /> : <UploadFileIcon />}
disabled={saving || pdfUploading}
onClick={this.handleUploadClick}
sx={{
whiteSpace: 'nowrap',
height: 40,
width: '100%',
px: 2,
boxSizing: 'border-box',
bgcolor: isDragging ? 'action.hover' : 'transparent',
borderColor: isDragging ? 'primary.main' : undefined,
transition: 'background-color 0.15s, border-color 0.15s',
}}
>
{pdfUploading
? 'Wird analysiert…'
: isDragging
? 'PDF hier ablegen'
: 'PDF hochladen'}
</Button>
)}
</FileDropzone>
) : null}
</Stack>
{onPdfUpload ? (