laravel-nuxt/nuxt/app/components/input/UploadAvatar.vue

132 lines
2.9 KiB
Vue

<script lang="ts" setup>
import type { IUploadResponse } from '~/types/account'
interface Props {
modelValue: string
entity: string
accept: string
maxSize: number
}
const props = defineProps<Props>()
const emit = defineEmits<{
'update:modelValue': [value: string]
}>()
const { $storage } = useNuxtApp()
const value = computed({
get(): string {
return props.modelValue
},
set(value: string) {
emit('update:modelValue', value)
},
})
const inputRef = ref<HTMLInputElement>()
const loading = ref<boolean>(false)
const onSelect = async (e: Event) => {
const target = e.target as HTMLInputElement
const file = target.files?.[0]
if (!file) return
target.value = ''
if (file.size > props.maxSize * 1024 * 1024) {
return useToast().add({
title: 'File is too large.',
color: 'error',
icon: 'i-heroicons-exclamation-circle-solid',
})
}
loading.value = true
const formData = new FormData()
formData.append('image', file)
await $fetch<IUploadResponse>('upload', {
method: 'POST',
body: formData,
params: {
entity: props.entity,
width: 300,
height: 300,
},
ignoreResponseError: true,
onResponse({ response }) {
if (response.status !== 200) {
useToast().add({
icon: 'i-heroicons-exclamation-circle-solid',
color: 'error',
title: response._data?.message ?? response.statusText ?? 'Something went wrong',
})
}
else if (response._data?.ok) {
value.value = response._data?.path
}
loading.value = false
},
})
}
</script>
<template>
<div class="flex gap-6">
<div class="relative flex">
<UAvatar
:src="$storage(value)"
size="3xl"
img-class="object-cover"
/>
<UTooltip
text="Upload avatar"
class="absolute top-0 end-0 -m-2"
:popper="{ placement: 'right' }"
>
<UButton
type="button"
color="neutral"
variant="link"
icon="i-heroicons-cloud-arrow-up"
size="xs"
:ui="{ base: 'rounded-full' }"
:loading="loading"
@click="inputRef.click()"
/>
</UTooltip>
<UTooltip
text="Delete avatar"
class="absolute bottom-0 end-0 -m-2"
:popper="{ placement: 'right' }"
>
<UButton
type="button"
color="neutral"
variant="link"
icon="i-heroicons-x-mark-20-solid"
size="xs"
:ui="{ base: 'rounded-full' }"
:disabled="loading"
@click="value = ''"
/>
</UTooltip>
<input
ref="inputRef"
type="file"
class="hidden"
:accept="accept"
@change="onSelect"
>
</div>
<div class="text-sm opacity-80">
<div>Max upload size: {{ maxSize }}Mb</div>
<div>Accepted formats: {{ accept }}</div>
</div>
</div>
</template>