mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 10:13:32 -04: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:
		| @@ -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> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user