mealie/frontend/components/global/AppButtonUpload.vue
Hoa (Kyle) Trinh c24d532608
Some checks are pending
CodeQL / Analyze (push) Waiting to run
Docker Nightly Production / Backend Server Tests (push) Waiting to run
Docker Nightly Production / Frontend Tests (push) Waiting to run
Docker Nightly Production / Build Package (push) Waiting to run
Docker Nightly Production / Build Tagged Release (push) Blocked by required conditions
Docker Nightly Production / Notify Discord (push) Blocked by required conditions
Release Drafter / ✏️ Draft release (push) Waiting to run
feat: Migrate to Nuxt 3 framework (#5184)
Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
2025-06-19 17:09:12 +00:00

147 lines
3 KiB
Vue

<template>
<v-form ref="file">
<input
ref="uploader"
class="d-none"
type="file"
:accept="accept"
@change="onFileChanged"
>
<slot v-bind="{ isSelecting, onButtonClick }">
<v-btn
:loading="isSelecting"
:small="small"
:color="color"
:variant="textBtn ? 'text' : 'elevated'"
:disabled="disabled"
@click="onButtonClick"
>
<v-icon start>
{{ effIcon }}
</v-icon>
{{ text ? text : defaultText }}
</v-btn>
</slot>
</v-form>
</template>
<script lang="ts">
import { useUserApi } from "~/composables/api";
const UPLOAD_EVENT = "uploaded";
export default defineNuxtComponent({
props: {
small: {
type: Boolean,
default: false,
},
post: {
type: Boolean,
default: true,
},
url: {
type: String,
default: "",
},
text: {
type: String,
default: "",
},
icon: {
type: String,
default: null,
},
fileName: {
type: String,
default: "archive",
},
textBtn: {
type: Boolean,
default: true,
},
accept: {
type: String,
default: "",
},
color: {
type: String,
default: "info",
},
disabled: {
type: Boolean,
default: false,
},
},
setup(props, context) {
const file = ref<File | null>(null);
const uploader = ref<HTMLInputElement | null>(null);
const isSelecting = ref(false);
const i18n = useI18n();
const { $globals } = useNuxtApp();
const effIcon = props.icon ? props.icon : $globals.icons.upload;
const defaultText = i18n.t("general.upload");
const api = useUserApi();
async function upload() {
if (file.value != null) {
isSelecting.value = true;
if (!props.post) {
context.emit(UPLOAD_EVENT, file.value);
isSelecting.value = false;
return;
}
const formData = new FormData();
formData.append(props.fileName, file.value);
try {
const response = await api.upload.file(props.url, formData);
if (response) {
context.emit(UPLOAD_EVENT, response);
}
}
catch (e) {
console.error(e);
context.emit(UPLOAD_EVENT, null);
}
isSelecting.value = false;
}
}
function onFileChanged(e: Event) {
const target = e.target as HTMLInputElement;
if (target.files !== null && target.files.length > 0 && file.value !== null) {
file.value = target.files[0];
upload();
}
}
function onButtonClick() {
isSelecting.value = true;
window.addEventListener(
"focus",
() => {
isSelecting.value = false;
},
{ once: true },
);
uploader.value?.click();
}
return {
file,
uploader,
isSelecting,
effIcon,
defaultText,
onFileChanged,
onButtonClick,
};
},
});
</script>
<style></style>