ຕົວຢ່າງຮູບພາບ
ສະແດງ thumbnails ຂອງຮູບພາບກ່ອນອັບໂຫຼດ.
ຕົວຢ່າງພື້ນຖານ
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}
/>
)}
{/* Overlay ສຳລັບສະຖານະກຳລັງອັບໂຫຼດ */}
{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',
},
};
ຕົວຢ່າງແບບ Gallery
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>
{/* Grid ຮູບນ້ອຍ */}
<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>
{/* Lightbox */}
{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>ວາງຮູບພາບ, PDFs, ຫຼືເອກະສານ 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 ຈະ revoke Object URLs ອັດຕະໂນມັດເມື່ອໄຟລ໌ຖືກລຶບ ຫຼືເມື່ອ component ຖືກ unmount. ເຖິງຢ່າງໃດກໍຕາມ, ຖ້າທ່ານຕ້ອງການການຄວບຄຸມດ້ວຍຕົນເອງ:
import { useEffect } from 'react';
function ManualPreviewCleanup() {
const { files, actions } = useDropup();
// ຕົວຢ່າງການລ້າງດ້ວຍຕົນເອງ
useEffect(() => {
return () => {
// ລ້າງເມື່ອ unmount (Dropup ເຮັດອັນນີ້ອັດຕະໂນມັດ)
files.forEach(file => {
if (file.preview) {
URL.revokeObjectURL(file.preview);
}
});
};
}, []);
// ...
}
ຄຳແນະນຳ
Dropup ຈັດການການລ້າງ preview URL ອັດຕະໂນມັດ. ທ່ານຕ້ອງການການລ້າງດ້ວຍຕົນເອງສະເພາະສຳລັບການຈັດຕັ້ງປະຕິບັດ preview ແບບກຳນົດເອງເທົ່ານັ້ນ.