1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-07-24 07:39:41 +02:00

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>
This commit is contained in:
Hoa (Kyle) Trinh 2025-06-20 00:09:12 +07:00 committed by GitHub
parent 89ab7fac25
commit c24d532608
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
403 changed files with 23959 additions and 19557 deletions

View file

@ -1,59 +1,77 @@
<template>
<div>
<slot name="activator" v-bind="{ open }" />
<slot
name="activator"
v-bind="{ open }"
/>
<v-dialog
v-model="dialog"
absolute
:width="width"
:max-width="maxWidth"
:max-width="maxWidth ?? undefined"
:content-class="top ? 'top-dialog' : undefined"
:fullscreen="$vuetify.breakpoint.xsOnly"
@keydown.enter="
$emit('submit');
dialog = false;
"
@click:outside="$emit('cancel')"
@keydown.esc="$emit('cancel')"
:fullscreen="$vuetify.display.xs"
@keydown.enter="() => {
emit('submit'); dialog = false;
}"
@click:outside="emit('cancel')"
@keydown.esc="emit('cancel')"
>
<v-card height="100%">
<v-app-bar dark dense :color="color" class="">
<v-icon large left>
<v-toolbar
dark
density="comfortable"
:color="color"
class="px-3 position-relative top-0 left-0 w-100"
>
<v-icon size="large">
{{ icon }}
</v-icon>
<v-toolbar-title class="headline"> {{ title }} </v-toolbar-title>
<v-spacer></v-spacer>
</v-app-bar>
<v-progress-linear v-if="loading" class="mt-1" indeterminate color="primary"></v-progress-linear>
<v-toolbar-title class="headline">
{{ title }}
</v-toolbar-title>
<v-spacer />
</v-toolbar>
<v-progress-linear
v-if="loading"
class="mt-1"
indeterminate
color="primary"
/>
<div>
<slot v-bind="{ submitEvent }" />
</div>
<v-divider class="mx-2"></v-divider>
<v-divider class="mx-2" />
<v-card-actions>
<slot name="card-actions">
<v-btn
text
variant="text"
color="grey"
@click="
dialog = false;
$emit('cancel');
emit('cancel');
"
>
{{ $t("general.cancel") }}
</v-btn>
<v-spacer></v-spacer>
<v-spacer />
<slot name="custom-card-action"></slot>
<BaseButton v-if="$listeners.delete" delete secondary @click="deleteEvent" />
<slot name="custom-card-action" />
<BaseButton
v-if="$listeners.confirm"
v-if="canDelete"
delete
secondary
@click="deleteEvent"
/>
<BaseButton
v-if="canConfirm"
:color="color"
type="submit"
:disabled="submitDisabled"
@click="
$emit('confirm');
emit('confirm');
dialog = false;
"
>
@ -63,141 +81,127 @@
{{ $t("general.confirm") }}
</BaseButton>
<BaseButton
v-if="$listeners.submit"
v-if="canSubmit"
type="submit"
:disabled="submitDisabled"
@click="submitEvent"
>
{{ submitText }}
<template v-if="submitIcon" #icon>
<template
v-if="submitIcon"
#icon
>
{{ submitIcon }}
</template>
</BaseButton>
</slot>
</v-card-actions>
<div v-if="$slots['below-actions']" class="pb-4">
<slot name="below-actions"> </slot>
<div
v-if="$slots['below-actions']"
class="pb-4"
>
<slot name="below-actions" />
</div>
</v-card>
</v-dialog>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from "@nuxtjs/composition-api";
export default defineComponent({
name: "BaseDialog",
props: {
value: {
type: Boolean,
default: false,
},
color: {
type: String,
default: "primary",
},
title: {
type: String,
default: "Modal Title",
},
icon: {
type: String,
default: null,
},
width: {
type: [Number, String],
default: "500",
},
maxWidth: {
type: [Number, String],
default: null,
},
loading: {
type: Boolean,
default: false,
},
top: {
default: null,
type: Boolean,
},
submitIcon: {
type: String,
default: null,
},
submitText: {
type: String,
default: function () {
return this.$t("general.create");
},
},
submitDisabled: {
type: Boolean,
default: false,
},
keepOpen: {
default: false,
type: Boolean,
},
},
setup(props, context) {
const dialog = computed<boolean>({
get() {
return props.value;
},
set(val) {
context.emit("input", val);
},
});
<script setup lang="ts">
import { useNuxtApp } from "#app";
return {
dialog,
};
},
data() {
return {
submitted: false,
};
},
computed: {
determineClose(): boolean {
return this.submitted && !this.loading && !this.keepOpen;
},
},
watch: {
determineClose() {
this.submitted = false;
this.dialog = false;
},
dialog(val) {
if (val) this.submitted = false;
if (!val) this.$emit("close");
},
},
methods: {
submitEvent() {
this.$emit("submit");
this.submitted = true;
},
deleteEvent() {
this.$emit("delete");
this.submitted = true;
},
open() {
this.dialog = true;
this.logDeprecatedProp("open");
},
close() {
this.dialog = false;
this.logDeprecatedProp("close");
},
logDeprecatedProp(val: string) {
console.warn(
`[BaseDialog] The method '${val}' is deprecated. Please use v-model="value" to manage state instead.`
);
},
},
interface DialogProps {
modelValue: boolean;
color?: string;
title?: string;
icon?: string | null;
width?: number | string;
maxWidth?: number | string | null;
loading?: boolean;
top?: boolean | null;
submitIcon?: string | null;
submitText?: string;
submitDisabled?: boolean;
keepOpen?: boolean;
// actions
canDelete?: boolean;
canConfirm?: boolean;
canSubmit?: boolean;
}
interface DialogEmits {
(e: "update:modelValue", value: boolean): void;
(e: "submit" | "cancel" | "confirm" | "delete" | "close"): void;
}
// Using TypeScript interface with withDefaults for props
const props = withDefaults(defineProps<DialogProps>(), {
color: "primary",
title: "Modal Title",
icon: null,
width: "500",
maxWidth: null,
loading: false,
top: null,
submitIcon: null,
submitText: () => useNuxtApp().$i18n.t("general.create"),
submitDisabled: false,
keepOpen: false,
canDelete: false,
canConfirm: false,
canSubmit: false,
});
const emit = defineEmits<DialogEmits>();
const dialog = computed({
get: () => props.modelValue,
set: val => emit("update:modelValue", val),
});
const submitted = ref(false);
const determineClose = computed(() => {
return submitted.value && !props.loading && !props.keepOpen;
});
watch(determineClose, (shouldClose) => {
if (shouldClose) {
submitted.value = false;
dialog.value = false;
}
});
watch(dialog, (val) => {
if (val) submitted.value = false;
if (!val) emit("close");
});
function submitEvent() {
emit("submit");
submitted.value = true;
}
function deleteEvent() {
emit("delete");
submitted.value = true;
}
function open() {
dialog.value = true;
logDeprecatedProp("open");
}
/* function close() {
dialog.value = false;
logDeprecatedProp("close");
} */
function logDeprecatedProp(val: string) {
console.warn(
`[BaseDialog] The method '${val}' is deprecated. Please use v-model="value" to manage state instead.`,
);
}
</script>
<style>