छवि पूर्वावलोकन
अपलोड करने से पहले छवियों के थंबनेल प्रदर्शित करें।
बुनियादी पूर्वावलोकन
import { useDropup } from '@samithahansaka/dropup';
function PreviewUploader() {
const { files, actions, getDropProps, getInputProps } = useDropup({
accept: 'image/*',
generatePreviews: true, // डिफ़ॉल्ट रूप से सक्षम
});
return (
<div>
<div {...getDropProps()} style={styles.dropzone}>
<input {...getInputProps()} />
<p>यहाँ छवियाँ छोड़ें</p>
</div>
<div style={styles.previewGrid}>
{files.map(file => (
<div key={file.id} style={styles.previewCard}>
{file.preview && (
<img
src={file.preview}
alt={file.name}
style={styles.previewImage}
/>
)}
<p style={styles.fileName}>{file.name}</p>
<button onClick={() => actions.remove(file.id)}>हटाएं</button>
</div>
))}
</div>
</div>
);
}
const styles = {
dropzone: {
border: '2px dashed #ccc',
borderRadius: 8,
padding: 40,
textAlign: 'center' as const,
marginBottom: 20,
},
previewGrid: {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))',
gap: 16,
},
previewCard: {
border: '1px solid #eee',
borderRadius: 8,
padding: 8,
textAlign: 'center' as const,
},
previewImage: {
width: '100%',
height: 120,
objectFit: 'cover' as const,
borderRadius: 4,
},
fileName: {
fontSize: 12,
margin: '8px 0',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap' as const,
},
};
अपलोड प्रगति के साथ पूर्वावलोकन
import { useDropup } from '@samithahansaka/dropup';
function PreviewWithProgress() {
const { files, actions, state, getDropProps, getInputProps } = useDropup({
accept: 'image/*',
upload: { url: '/api/upload' },
});
return (
<div>
<div {...getDropProps()} style={styles.dropzone}>
<input {...getInputProps()} />
<p>यहाँ छवियाँ छोड़ें</p>
</div>
<div style={styles.previewGrid}>
{files.map(file => (
<div key={file.id} style={styles.previewCard}>
<div style={styles.imageWrapper}>
{file.preview && (
<img
src={file.preview}
alt={file.name}
style={styles.previewImage}
/>
)}
{/* अपलोड स्थिति के लिए ओवरले */}
{file.status === 'uploading' && (
<div style={styles.overlay}>
<div style={styles.progressRing}>
{file.progress}%
</div>
</div>
)}
{/* पूर्ण के लिए चेकमार्क */}
{file.status === 'complete' && (
<div style={styles.checkmark}>✓</div>
)}
{/* त्रुटि आइकन */}
{file.status === 'error' && (
<div style={styles.errorIcon}>✕</div>
)}
</div>
<p style={styles.fileName}>{file.name}</p>
<div>
{file.status === 'error' && (
<button onClick={() => actions.retry([file.id])}>
पुनः प्रयास
</button>
)}
<button onClick={() => actions.remove(file.id)}>
हटाएं
</button>
</div>
</div>
))}
</div>
{files.length > 0 && (
<button
onClick={() => actions.upload()}
disabled={state.isUploading}
style={styles.uploadButton}
>
{state.isUploading
? `अपलोड हो रहा है... ${state.progress}%`
: 'सभी अपलोड करें'
}
</button>
)}
</div>
);
}
const styles = {
dropzone: {
border: '2px dashed #ccc',
borderRadius: 8,
padding: 40,
textAlign: 'center' as const,
marginBottom: 20,
},
previewGrid: {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))',
gap: 16,
},
previewCard: {
border: '1px solid #eee',
borderRadius: 8,
padding: 8,
textAlign: 'center' as const,
},
imageWrapper: {
position: 'relative' as const,
width: '100%',
height: 120,
},
previewImage: {
width: '100%',
height: '100%',
objectFit: 'cover' as const,
borderRadius: 4,
},
overlay: {
position: 'absolute' as const,
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0,0,0,0.5)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 4,
},
progressRing: {
color: 'white',
fontSize: 18,
fontWeight: 'bold' as const,
},
checkmark: {
position: 'absolute' as const,
top: 8,
right: 8,
width: 24,
height: 24,
backgroundColor: '#4caf50',
color: 'white',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
errorIcon: {
position: 'absolute' as const,
top: 8,
right: 8,
width: 24,
height: 24,
backgroundColor: '#f44336',
color: 'white',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
fileName: {
fontSize: 12,
margin: '8px 0',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap' as const,
},
uploadButton: {
marginTop: 20,
padding: '12px 24px',
fontSize: 16,
cursor: 'pointer',
},
};
गैलरी स्टाइल पूर्वावलोकन
import { useDropup, type DropupFile } from '@samithahansaka/dropup';
import { useState } from 'react';
function GalleryUploader() {
const { files, actions, getDropProps, getInputProps } = useDropup({
accept: 'image/*',
maxFiles: 10,
});
const [selectedFile, setSelectedFile] = useState<DropupFile | null>(null);
return (
<div>
<div {...getDropProps()} style={styles.dropzone}>
<input {...getInputProps()} />
<p>10 छवियाँ तक छोड़ें</p>
</div>
{/* थंबनेल ग्रिड */}
<div style={styles.gallery}>
{files.map(file => (
<div
key={file.id}
style={styles.thumbnail}
onClick={() => setSelectedFile(file)}
>
{file.preview && (
<img
src={file.preview}
alt={file.name}
style={styles.thumbImage}
/>
)}
<button
style={styles.removeBtn}
onClick={(e) => {
e.stopPropagation();
actions.remove(file.id);
}}
>
×
</button>
</div>
))}
</div>
{/* लाइटबॉक्स */}
{selectedFile && (
<div
style={styles.lightbox}
onClick={() => setSelectedFile(null)}
>
<img
src={selectedFile.preview}
alt={selectedFile.name}
style={styles.lightboxImage}
/>
<p style={styles.lightboxCaption}>{selectedFile.name}</p>
</div>
)}
</div>
);
}
const styles = {
dropzone: {
border: '2px dashed #ccc',
borderRadius: 8,
padding: 40,
textAlign: 'center' as const,
marginBottom: 20,
},
gallery: {
display: 'flex',
flexWrap: 'wrap' as const,
gap: 8,
},
thumbnail: {
position: 'relative' as const,
width: 100,
height: 100,
cursor: 'pointer',
},
thumbImage: {
width: '100%',
height: '100%',
objectFit: 'cover' as const,
borderRadius: 4,
},
removeBtn: {
position: 'absolute' as const,
top: 4,
right: 4,
width: 20,
height: 20,
border: 'none',
backgroundColor: 'rgba(0,0,0,0.5)',
color: 'white',
borderRadius: '50%',
cursor: 'pointer',
fontSize: 14,
lineHeight: 1,
},
lightbox: {
position: 'fixed' as const,
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0,0,0,0.9)',
display: 'flex',
flexDirection: 'column' as const,
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
zIndex: 1000,
},
lightboxImage: {
maxWidth: '90%',
maxHeight: '80%',
objectFit: 'contain' as const,
},
lightboxCaption: {
color: 'white',
marginTop: 16,
},
};
गैर-छवि फ़ाइल पूर्वावलोकन
import { useDropup } from '@samithahansaka/dropup';
function FileTypePreview() {
const { files, actions, getDropProps, getInputProps } = useDropup({
accept: ['image/*', 'application/pdf', '.doc', '.docx'],
});
const getFileIcon = (type: string, name: string) => {
if (type.startsWith('image/')) return '🖼️';
if (type === 'application/pdf') return '📄';
if (name.endsWith('.doc') || name.endsWith('.docx')) return '📝';
return '📁';
};
return (
<div>
<div {...getDropProps()} style={styles.dropzone}>
<input {...getInputProps()} />
<p>छवियाँ, PDF, या Word दस्तावेज़ छोड़ें</p>
</div>
<div style={styles.fileList}>
{files.map(file => (
<div key={file.id} style={styles.fileItem}>
<div style={styles.filePreview}>
{file.preview ? (
<img
src={file.preview}
alt=""
style={styles.imagePreview}
/>
) : (
<span style={styles.fileIcon}>
{getFileIcon(file.type, file.name)}
</span>
)}
</div>
<div style={styles.fileInfo}>
<p style={styles.fileName}>{file.name}</p>
<p style={styles.fileSize}>
{(file.size / 1024).toFixed(1)} KB
</p>
</div>
<button onClick={() => actions.remove(file.id)}>
हटाएं
</button>
</div>
))}
</div>
</div>
);
}
const styles = {
dropzone: {
border: '2px dashed #ccc',
borderRadius: 8,
padding: 40,
textAlign: 'center' as const,
marginBottom: 20,
},
fileList: {
display: 'flex',
flexDirection: 'column' as const,
gap: 8,
},
fileItem: {
display: 'flex',
alignItems: 'center',
padding: 12,
border: '1px solid #eee',
borderRadius: 8,
gap: 12,
},
filePreview: {
width: 50,
height: 50,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#f5f5f5',
borderRadius: 4,
},
imagePreview: {
width: '100%',
height: '100%',
objectFit: 'cover' as const,
borderRadius: 4,
},
fileIcon: {
fontSize: 28,
},
fileInfo: {
flex: 1,
},
fileName: {
margin: 0,
fontWeight: 500,
},
fileSize: {
margin: 0,
fontSize: 12,
color: '#666',
},
};
मेमोरी प्रबंधन
Dropup फ़ाइलें हटाए जाने या कंपोनेंट अनमाउंट होने पर स्वचालित रूप से Object URL को रद्द कर देता है। हालाँकि, यदि आपको मैनुअल नियंत्रण की आवश्यकता है:
import { useEffect } from 'react';
function ManualPreviewCleanup() {
const { files, actions } = useDropup();
// मैनुअल सफाई उदाहरण
useEffect(() => {
return () => {
// अनमाउंट पर सफाई (Dropup यह स्वचालित रूप से करता है)
files.forEach(file => {
if (file.preview) {
URL.revokeObjectURL(file.preview);
}
});
};
}, []);
// ...
}
सुझाव
Dropup पूर्वावलोकन URL सफाई स्वचालित रूप से संभालता है। आपको केवल कस्टम पूर्वावलोकन कार्यान्वयन के लिए मैनुअल सफाई की आवश्यकता है।