initiation librodrome
This commit is contained in:
107
app/components/admin/AdminMediaUpload.vue
Normal file
107
app/components/admin/AdminMediaUpload.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div
|
||||
class="upload-zone"
|
||||
:class="{ 'upload-zone--active': isDragging }"
|
||||
@dragenter.prevent="isDragging = true"
|
||||
@dragleave.prevent="isDragging = false"
|
||||
@dragover.prevent
|
||||
@drop.prevent="handleDrop"
|
||||
>
|
||||
<input
|
||||
ref="fileInput"
|
||||
type="file"
|
||||
multiple
|
||||
accept="image/*,audio/*,.pdf"
|
||||
class="hidden"
|
||||
@change="handleFiles"
|
||||
/>
|
||||
|
||||
<div v-if="uploading" class="upload-progress">
|
||||
<div class="i-lucide-loader-2 h-6 w-6 animate-spin text-primary" />
|
||||
<span>Upload en cours...</span>
|
||||
</div>
|
||||
|
||||
<div v-else class="upload-content" @click="fileInput?.click()">
|
||||
<div class="i-lucide-upload h-8 w-8 text-white/30 mb-2" />
|
||||
<p class="text-sm text-white/50">Glissez des fichiers ici ou cliquez pour sélectionner</p>
|
||||
<p class="text-xs text-white/30 mt-1">Images, audio, PDF</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const emit = defineEmits<{
|
||||
uploaded: [files: string[]]
|
||||
}>()
|
||||
|
||||
const fileInput = ref<HTMLInputElement>()
|
||||
const isDragging = ref(false)
|
||||
const uploading = ref(false)
|
||||
|
||||
function handleDrop(e: DragEvent) {
|
||||
isDragging.value = false
|
||||
const files = e.dataTransfer?.files
|
||||
if (files) upload(files)
|
||||
}
|
||||
|
||||
function handleFiles(e: Event) {
|
||||
const target = e.target as HTMLInputElement
|
||||
if (target.files) upload(target.files)
|
||||
}
|
||||
|
||||
async function upload(files: FileList) {
|
||||
uploading.value = true
|
||||
try {
|
||||
const formData = new FormData()
|
||||
for (const file of files) {
|
||||
formData.append('file', file)
|
||||
}
|
||||
|
||||
const result = await $fetch<{ files: string[] }>('/api/admin/media/upload', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
})
|
||||
|
||||
emit('uploaded', result.files)
|
||||
}
|
||||
finally {
|
||||
uploading.value = false
|
||||
if (fileInput.value) fileInput.value.value = ''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.upload-zone {
|
||||
border: 2px dashed hsl(20 8% 22%);
|
||||
border-radius: 0.75rem;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.upload-zone:hover {
|
||||
border-color: hsl(12 76% 48% / 0.4);
|
||||
}
|
||||
|
||||
.upload-zone--active {
|
||||
border-color: hsl(12 76% 48%);
|
||||
background: hsl(12 76% 48% / 0.05);
|
||||
}
|
||||
|
||||
.upload-progress {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: hsl(20 8% 55%);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.upload-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user