61 lines
2.2 KiB
TypeScript
61 lines
2.2 KiB
TypeScript
// PreviewTester.tsx
|
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
import { Box, Button, Card, CardMedia, CardContent, Typography } from '@mui/material';
|
|
import { useDropzone } from 'react-dropzone';
|
|
|
|
type Item = { id: string; file: File; previewUrl: string };
|
|
|
|
export default function PreviewTester() {
|
|
const [items, setItems] = useState<Item[]>([]);
|
|
|
|
const onDrop = useCallback((acceptedFiles: File[]) => {
|
|
console.log('onDrop called, acceptedFiles:', acceptedFiles);
|
|
const now = Date.now();
|
|
const newItems = acceptedFiles.map((f, i) => ({
|
|
id: `${now}-${i}-${f.name}`,
|
|
file: f,
|
|
previewUrl: URL.createObjectURL(f),
|
|
}));
|
|
setItems((prev) => [...newItems, ...prev]);
|
|
}, []);
|
|
|
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, multiple: true, accept: { 'image/*': [] } });
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
items.forEach((it) => {
|
|
try {
|
|
URL.revokeObjectURL(it.previewUrl);
|
|
} catch {
|
|
// ignore
|
|
}
|
|
});
|
|
};
|
|
}, [items]);
|
|
|
|
|
|
return (
|
|
<Box sx={{ p: 3 }}>
|
|
<Box {...getRootProps()} sx={{ border: '2px dashed', p: 2, textAlign: 'center', mb: 2 }}>
|
|
<input {...getInputProps()} />
|
|
<Typography>{isDragActive ? 'Drop images here' : 'Drag & drop images (PreviewTester)'}</Typography>
|
|
</Box>
|
|
|
|
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
|
|
{items.map((it) => (
|
|
<Card key={it.id} sx={{ width: 160 }}>
|
|
<CardMedia component="img" height="100" image={it.previewUrl} alt={it.file.name} />
|
|
<CardContent>
|
|
<Typography variant="caption" noWrap>{it.file.name}</Typography>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</Box>
|
|
|
|
<Box sx={{ mt: 2 }}>
|
|
<Button onClick={() => { console.log('items state:', items); alert(`Items: ${items.length}`); }}>Console.log items</Button>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
}
|