π Live Demo
A comprehensive Vue 3 file uploader component library with advanced features including automatic video thumbnail generation, multiple upload styles, and extensive file type support.
- Automatic thumbnail extraction from video files using Canvas API
- Support for MP4, AVI, MOV, WMV, FLV, WebM formats
- Real-time thumbnail display with play button overlay
- No external dependencies required
- Images: JPG, JPEG, PNG, GIF, BMP, SVG, WebP, TIFF
- Videos: MP4, AVI, MOV, WMV, FLV, WebM
- Documents: PDF, DOC, DOCX, TXT, RTF, ODT
- Spreadsheets: XLS, XLSX, CSV, ODS
- Presentations: PPT, PPTX, ODP
- Archives: ZIP, RAR, 7Z, TAR, GZ
- Audio: MP3, WAV, FLAC, AAC, OGG
- ThumbnailUploader: Grid-based layout with file previews
- TableUploader: Table-based layout for detailed file information
- SimpleUploader: Minimalist drag-and-drop interface
- 8 languages: English, Chinese, Spanish, French, German, Japanese, Korean, Arabic
- RTL support for Arabic
- Easy language switching
npm install handy-uploaderyarn add handy-uploaderpnpm add handy-uploaderMake sure you have the required peer dependencies:
npm install vue@^3.0.0 vuetify@^3.0.0<template>
<div>
<!-- Thumbnail Uploader with Video Support -->
<ThumbnailUploader
:max-file-size="10485760"
:max-file-count="5"
:accepted-file-types="['image/*', 'video/*']"
:language="'en'"
@files-selected="handleFilesSelected"
/>
</div>
</template>
<script setup lang="ts">
import { ThumbnailUploader } from 'handy-uploader'
import type { FileData } from 'handy-uploader'
const handleFilesSelected = (files: FileData[]) => {
console.log('Selected files:', files)
// Each file includes base64 data and video thumbnails are auto-generated
}
</script>// main.ts
import { createApp } from 'vue'
import { createVuetify } from 'vuetify'
import 'vuetify/styles'
import '@mdi/font/css/materialdesignicons.css'
const vuetify = createVuetify()
const app = createApp(App)
app.use(vuetify)
app.mount('#app')Perfect for media files with automatic video thumbnail generation:
<template>
<ThumbnailUploader
:max-file-size="52428800"
:max-file-count="10"
:accepted-file-types="['image/*', 'video/*', 'application/pdf']"
:language="'en'"
:theme="'light'"
@files-selected="onFilesSelected"
@file-removed="onFileRemoved"
@error="onError"
/>
</template>
<script setup>
import { ThumbnailUploader } from 'handy-uploader'
const onFilesSelected = (files) => {
// Video files will have thumbnails automatically generated
files.forEach(file => {
if (file.type === 'video') {
console.log('Video thumbnail:', file.thumbnail) // Base64 thumbnail
}
})
}
</script>Great for document management with detailed file information:
<template>
<TableUploader
:max-file-size="104857600"
:max-file-count="20"
:language="'en'"
@files-selected="handleFiles"
/>
</template>Minimal drag-and-drop interface:
<template>
<SimpleUploader
:max-file-size="5242880"
:accepted-file-types="['image/*']"
@files-selected="handleImages"
/>
</template>| Prop | Type | Default | Description |
|---|---|---|---|
maxFileSize |
number |
10485760 |
Maximum file size in bytes (10MB) |
maxFileCount |
number |
5 |
Maximum number of files |
acceptedFileTypes |
string[] |
['*'] |
Accepted MIME types |
language |
string |
'en' |
Language code |
theme |
string |
'light' |
Theme variant |
| Event | Payload | Description |
|---|---|---|
files-selected |
FileData[] |
Emitted when files are selected |
file-removed |
FileData |
Emitted when a file is removed |
error |
Error |
Emitted on errors |
interface FileData {
id: string
name: string
size: number
type: string
format: string
base64?: string
thumbnail?: string // Auto-generated for videos
lastModified: number
}The library automatically generates thumbnails for video files:
// Thumbnails are generated automatically
const videoFile = {
name: 'video.mp4',
type: 'video',
thumbnail: 'data:image/jpeg;base64,/9j/4AAQ...' // Auto-generated
}Automatic file type detection and icon assignment:
// Automatic type detection
const file = {
name: 'document.pdf',
type: 'document', // Auto-detected
icon: 'mdi-file-pdf-box', // Auto-assigned
color: 'red' // Auto-assigned
}Built-in image compression for large files:
<ThumbnailUploader
:compress-images="true"
:compression-quality="0.8"
:max-width="1920"
:max-height="1080"
/>Supported languages:
const languages = [
'en', // English
'zh', // Chinese
'es', // Spanish
'fr', // French
'de', // German
'ja', // Japanese
'ko', // Korean
'ar' // Arabic (RTL)
]- Vue: ^3.0.0
- Vuetify: ^3.0.0
- Chrome 88+
- Firefox 85+
- Safari 14+
- Edge 88+
- Gzipped: ~45KB
- Minified: ~120KB
Works with Vuetify's theming system:
// vuetify.config.js
export default createVuetify({
theme: {
themes: {
light: {
primary: '#1976D2',
secondary: '#424242',
// Custom theme colors
}
}
}
})<style scoped>
.handy-uploader {
--uploader-border-radius: 12px;
--uploader-primary-color: #1976D2;
--uploader-background: #f5f5f5;
}
</style><template>
<div class="uploader-container">
<h2>File Upload with Video Thumbnails</h2>
<ThumbnailUploader
:max-file-size="52428800"
:max-file-count="10"
:accepted-file-types="['image/*', 'video/*', 'application/pdf']"
:language="currentLanguage"
:theme="isDark ? 'dark' : 'light'"
:compress-images="true"
:compression-quality="0.8"
@files-selected="handleFilesSelected"
@file-removed="handleFileRemoved"
@error="handleError"
/>
<!-- Display selected files -->
<div v-if="selectedFiles.length" class="mt-4">
<h3>Selected Files:</h3>
<div v-for="file in selectedFiles" :key="file.id" class="file-item">
<img v-if="file.thumbnail" :src="file.thumbnail" alt="Thumbnail" width="100" />
<span>{{ file.name }} ({{ formatFileSize(file.size) }})</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ThumbnailUploader, type FileData } from 'handy-uploader'
const selectedFiles = ref<FileData[]>([])
const currentLanguage = ref('en')
const isDark = ref(false)
const handleFilesSelected = (files: FileData[]) => {
selectedFiles.value = files
console.log('Files with thumbnails:', files)
}
const handleFileRemoved = (file: FileData) => {
console.log('File removed:', file.name)
}
const handleError = (error: Error) => {
console.error('Upload error:', error)
}
const formatFileSize = (bytes: number) => {
return bytes > 1024 * 1024
? `${(bytes / 1024 / 1024).toFixed(2)} MB`
: `${(bytes / 1024).toFixed(2)} KB`
}
</script>We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ for the Vue.js community