mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 10:13:32 -04:00 
			
		
		
		
	refactor(frontend): 🚧 rename recipe and meal-plan components
This commit is contained in:
		
							
								
								
									
										167
									
								
								frontend/components/Domain/Recipe/RecipeAssets.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								frontend/components/Domain/Recipe/RecipeAssets.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | |||||||
|  | <template> | ||||||
|  |   <div v-if="value.length > 0 || edit"> | ||||||
|  |     <v-card class="mt-2"> | ||||||
|  |       <v-card-title class="py-2"> | ||||||
|  |         {{ $t("asset.assets") }} | ||||||
|  |       </v-card-title> | ||||||
|  |       <v-divider class="mx-2"></v-divider> | ||||||
|  |       <v-list :flat="!edit" v-if="value.length > 0"> | ||||||
|  |         <v-list-item v-for="(item, i) in value" :key="i"> | ||||||
|  |           <v-list-item-icon class="ma-auto"> | ||||||
|  |             <v-tooltip bottom> | ||||||
|  |               <template v-slot:activator="{ on, attrs }"> | ||||||
|  |                 <v-icon v-text="getIconDefinition(item.icon).icon" v-bind="attrs" v-on="on"></v-icon> | ||||||
|  |               </template> | ||||||
|  |               <span>{{ getIconDefinition(item.icon).title }}</span> | ||||||
|  |             </v-tooltip> | ||||||
|  |           </v-list-item-icon> | ||||||
|  |           <v-list-item-content> | ||||||
|  |             <v-list-item-title class="pl-2" v-text="item.name"></v-list-item-title> | ||||||
|  |           </v-list-item-content> | ||||||
|  |           <v-list-item-action> | ||||||
|  |             <v-btn v-if="!edit" color="primary" icon :href="assetURL(item.fileName)" target="_blank" top> | ||||||
|  |               <v-icon> {{ $globals.icons.download }} </v-icon> | ||||||
|  |             </v-btn> | ||||||
|  |             <div v-else> | ||||||
|  |               <v-btn color="error" icon @click="deleteAsset(i)" top> | ||||||
|  |                 <v-icon>{{ $globals.icons.delete }}</v-icon> | ||||||
|  |               </v-btn> | ||||||
|  |               <TheCopyButton :copy-text="copyLink(item.fileName)" /> | ||||||
|  |             </div> | ||||||
|  |           </v-list-item-action> | ||||||
|  |         </v-list-item> | ||||||
|  |       </v-list> | ||||||
|  |     </v-card> | ||||||
|  |     <div class="d-flex ml-auto mt-2"> | ||||||
|  |       <v-spacer></v-spacer> | ||||||
|  |       <base-dialog @submit="addAsset" :title="$t('asset.new-asset')" :title-icon="getIconDefinition(newAsset.icon).icon"> | ||||||
|  |         <template v-slot:open="{ open }"> | ||||||
|  |           <v-btn color="secondary" dark @click="open" v-if="edit"> | ||||||
|  |             <v-icon>{{ $globals.icons.create }}</v-icon> | ||||||
|  |           </v-btn> | ||||||
|  |         </template> | ||||||
|  |         <v-card-text class="pt-2"> | ||||||
|  |           <v-text-field dense v-model="newAsset.name" :label="$t('general.name')"></v-text-field> | ||||||
|  |           <div class="d-flex justify-space-between"> | ||||||
|  |             <v-select | ||||||
|  |               dense | ||||||
|  |               :prepend-icon="getIconDefinition(newAsset.icon).icon" | ||||||
|  |               v-model="newAsset.icon" | ||||||
|  |               :items="iconOptions" | ||||||
|  |               item-text="title" | ||||||
|  |               item-value="name" | ||||||
|  |               class="mr-2" | ||||||
|  |             > | ||||||
|  |               <template v-slot:item="{ item }"> | ||||||
|  |                 <v-list-item-avatar> | ||||||
|  |                   <v-icon class="mr-auto"> | ||||||
|  |                     {{ item.icon }} | ||||||
|  |                   </v-icon> | ||||||
|  |                 </v-list-item-avatar> | ||||||
|  |                 {{ item.title }} | ||||||
|  |               </template> | ||||||
|  |             </v-select> | ||||||
|  |             <TheUploadBtn @uploaded="setFileObject" :post="false" file-name="file" :text-btn="false" /> | ||||||
|  |           </div> | ||||||
|  |           {{ fileObject.name }} | ||||||
|  |         </v-card-text> | ||||||
|  |       </base-dialog> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import TheCopyButton from "@/components/UI/Buttons/TheCopyButton"; | ||||||
|  | import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn"; | ||||||
|  | import BaseDialog from "@/components/UI/Dialogs/BaseDialog"; | ||||||
|  | import { api } from "@/api"; | ||||||
|  | export default { | ||||||
|  |   components: { | ||||||
|  |     BaseDialog, | ||||||
|  |     TheUploadBtn, | ||||||
|  |     TheCopyButton, | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     slug: String, | ||||||
|  |     value: { | ||||||
|  |       type: Array, | ||||||
|  |     }, | ||||||
|  |     edit: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       fileObject: {}, | ||||||
|  |       newAsset: { | ||||||
|  |         name: "", | ||||||
|  |         icon: "mdi-file", | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     baseURL() { | ||||||
|  |       return window.location.origin; | ||||||
|  |     }, | ||||||
|  |     iconOptions() { | ||||||
|  |       return [  | ||||||
|  |         {  | ||||||
|  |           name: "mdi-file", | ||||||
|  |           title: this.$i18n.t('asset.file'), | ||||||
|  |           icon: this.$globals.icons.file  | ||||||
|  |         }, | ||||||
|  |         {  | ||||||
|  |           name: "mdi-file-pdf-box", | ||||||
|  |           title: this.$i18n.t('asset.pdf'), | ||||||
|  |           icon: this.$globals.icons.filePDF  | ||||||
|  |         }, | ||||||
|  |         {  | ||||||
|  |           name: "mdi-file-image", | ||||||
|  |           title: this.$i18n.t('asset.image'), | ||||||
|  |           icon: this.$globals.icons.fileImage  | ||||||
|  |         }, | ||||||
|  |         {  | ||||||
|  |           name: "mdi-code-json", | ||||||
|  |           title: this.$i18n.t('asset.code'), | ||||||
|  |           icon: this.$globals.icons.codeJson  | ||||||
|  |         }, | ||||||
|  |         {  | ||||||
|  |           name: "mdi-silverware-fork-knife", | ||||||
|  |           title: this.$i18n.t('asset.recipe'), | ||||||
|  |           icon: this.$globals.icons.primary  | ||||||
|  |         }, | ||||||
|  |       ]; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getIconDefinition(val) { | ||||||
|  |       return this.iconOptions.find(({ name }) => name === val ); | ||||||
|  |     }, | ||||||
|  |     assetURL(assetName) { | ||||||
|  |       return api.recipes.recipeAssetPath(this.slug, assetName); | ||||||
|  |     }, | ||||||
|  |     setFileObject(obj) { | ||||||
|  |       this.fileObject = obj; | ||||||
|  |     }, | ||||||
|  |     async addAsset() { | ||||||
|  |       const serverAsset = await api.recipes.createAsset( | ||||||
|  |         this.slug, | ||||||
|  |         this.fileObject, | ||||||
|  |         this.newAsset.name, | ||||||
|  |         this.newAsset.icon | ||||||
|  |       ); | ||||||
|  |       this.value.push(serverAsset.data); | ||||||
|  |       this.newAsset = { name: "", icon: "mdi-file" }; | ||||||
|  |     }, | ||||||
|  |     deleteAsset(index) { | ||||||
|  |       this.value.splice(index, 1); | ||||||
|  |     }, | ||||||
|  |     copyLink(fileName) { | ||||||
|  |       const assetLink = api.recipes.recipeAssetPath(this.slug, fileName); | ||||||
|  |       return `<img src="${this.baseURL}${assetLink}" height="100%" width="100%"> </img>`; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
							
								
								
									
										57
									
								
								frontend/components/Domain/Recipe/RecipeDialogBulkAdd.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								frontend/components/Domain/Recipe/RecipeDialogBulkAdd.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="text-center"> | ||||||
|  |     <v-dialog v-model="dialog" width="600"> | ||||||
|  |       <template v-slot:activator="{ on, attrs }"> | ||||||
|  |         <v-btn color="secondary lighten-2" dark v-bind="attrs" v-on="on" @click="inputText = ''"> | ||||||
|  |           {{ $t("new-recipe.bulk-add") }} | ||||||
|  |         </v-btn> | ||||||
|  |       </template> | ||||||
|  |  | ||||||
|  |       <v-card> | ||||||
|  |         <v-card-title class="headline"> {{ $t("new-recipe.bulk-add") }} </v-card-title> | ||||||
|  |  | ||||||
|  |         <v-card-text> | ||||||
|  |           <p> | ||||||
|  |             {{ $t("new-recipe.paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list") }} | ||||||
|  |           </p> | ||||||
|  |           <v-textarea v-model="inputText"> </v-textarea> | ||||||
|  |         </v-card-text> | ||||||
|  |  | ||||||
|  |         <v-divider></v-divider> | ||||||
|  |  | ||||||
|  |         <v-card-actions> | ||||||
|  |           <v-spacer></v-spacer> | ||||||
|  |           <v-btn color="success" text @click="save"> {{ $t("general.save") }} </v-btn> | ||||||
|  |         </v-card-actions> | ||||||
|  |       </v-card> | ||||||
|  |     </v-dialog> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       dialog: false, | ||||||
|  |       inputText: "", | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     splitText() { | ||||||
|  |       let split = this.inputText.split("\n"); | ||||||
|  |  | ||||||
|  |       split.forEach((element, index) => { | ||||||
|  |         if ((element === "\n") | (element == false)) { | ||||||
|  |           split.splice(index, 1); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |  | ||||||
|  |       return split; | ||||||
|  |     }, | ||||||
|  |     save() { | ||||||
|  |       this.$emit("bulk-data", this.splitText()); | ||||||
|  |       this.dialog = false; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
| @@ -0,0 +1,85 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="text-center"> | ||||||
|  |     <v-dialog v-model="dialog" width="700"> | ||||||
|  |       <template v-slot:activator="{ on, attrs }"> | ||||||
|  |         <v-btn color="accent" dark v-bind="attrs" v-on="on"> {{ $t("recipe.api-extras") }} </v-btn> | ||||||
|  |       </template> | ||||||
|  |  | ||||||
|  |       <v-card> | ||||||
|  |         <v-card-title> {{ $t("recipe.api-extras") }} </v-card-title> | ||||||
|  |  | ||||||
|  |         <v-card-text :key="formKey"> | ||||||
|  |           <v-row align="center" v-for="(value, key, index) in extras" :key="index"> | ||||||
|  |             <v-col cols="12" sm="1"> | ||||||
|  |               <v-btn fab text x-small color="white" elevation="0" @click="removeExtra(key)"> | ||||||
|  |                 <v-icon color="error">{{ $globals.icons.delete }}</v-icon> | ||||||
|  |               </v-btn> | ||||||
|  |             </v-col> | ||||||
|  |             <v-col cols="12" md="3" sm="6"> | ||||||
|  |               <v-text-field :label="$t('recipe.object-key')" :value="key" @input="updateKey(index)"> </v-text-field> | ||||||
|  |             </v-col> | ||||||
|  |             <v-col cols="12" md="8" sm="6"> | ||||||
|  |               <v-text-field :label="$t('recipe.object-value')" v-model="extras[key]"> </v-text-field> | ||||||
|  |             </v-col> | ||||||
|  |           </v-row> | ||||||
|  |         </v-card-text> | ||||||
|  |  | ||||||
|  |         <v-divider></v-divider> | ||||||
|  |  | ||||||
|  |         <v-card-actions> | ||||||
|  |           <v-form ref="addKey"> | ||||||
|  |             <v-text-field | ||||||
|  |               :label="$t('recipe.new-key-name')" | ||||||
|  |               v-model="newKeyName" | ||||||
|  |               class="pr-4" | ||||||
|  |               :rules="[rules.required, rules.whiteSpace]" | ||||||
|  |             ></v-text-field> | ||||||
|  |           </v-form> | ||||||
|  |           <v-btn color="info" text @click="append"> {{ $t("recipe.add-key") }} </v-btn> | ||||||
|  |  | ||||||
|  |           <v-spacer></v-spacer> | ||||||
|  |  | ||||||
|  |           <v-btn color="success" text @click="save"> {{ $t("general.save") }} </v-btn> | ||||||
|  |         </v-card-actions> | ||||||
|  |       </v-card> | ||||||
|  |     </v-dialog> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   props: { | ||||||
|  |     extras: Object, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       newKeyName: null, | ||||||
|  |       dialog: false, | ||||||
|  |       formKey: 1, | ||||||
|  |       rules: { | ||||||
|  |         required: v => !!v || this.$i18n.t("recipe.key-name-required"), | ||||||
|  |         whiteSpace: v => !v || v.split(" ").length <= 1 || this.$i18n.t("recipe.no-white-space-allowed"), | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     save() { | ||||||
|  |       this.$emit("save", this.extras); | ||||||
|  |       this.dialog = false; | ||||||
|  |     }, | ||||||
|  |     append() { | ||||||
|  |       if (this.$refs.addKey.validate()) { | ||||||
|  |         this.extras[this.newKeyName] = "value"; | ||||||
|  |         this.formKey += 1; | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     removeExtra(key) { | ||||||
|  |       delete this.extras[key]; | ||||||
|  |       this.formKey += 1; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style></style> | ||||||
							
								
								
									
										76
									
								
								frontend/components/Domain/Recipe/RecipeImageUploadBtn.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								frontend/components/Domain/Recipe/RecipeImageUploadBtn.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="text-center"> | ||||||
|  |     <v-menu offset-y top nudge-top="6" :close-on-content-click="false"> | ||||||
|  |       <template v-slot:activator="{ on, attrs }"> | ||||||
|  |         <v-btn color="accent" dark v-bind="attrs" v-on="on"> | ||||||
|  |           <v-icon left> | ||||||
|  |             {{ $globals.icons.fileImage }} | ||||||
|  |           </v-icon> | ||||||
|  |           {{ $t("general.image") }} | ||||||
|  |         </v-btn> | ||||||
|  |       </template> | ||||||
|  |       <v-card width="400"> | ||||||
|  |         <v-card-title class="headline flex mb-0"> | ||||||
|  |           <div> | ||||||
|  |             {{ $t("recipe.recipe-image") }} | ||||||
|  |           </div> | ||||||
|  |           <TheUploadBtn | ||||||
|  |             class="ml-auto" | ||||||
|  |             url="none" | ||||||
|  |             file-name="image" | ||||||
|  |             :text-btn="false" | ||||||
|  |             @uploaded="uploadImage" | ||||||
|  |             :post="false" | ||||||
|  |           /> | ||||||
|  |         </v-card-title> | ||||||
|  |         <v-card-text class="mt-n5"> | ||||||
|  |           <div> | ||||||
|  |             <v-text-field :label="$t('general.url')" class="pt-5" clearable v-model="url" :messages="getMessages()"> | ||||||
|  |               <template v-slot:append-outer> | ||||||
|  |                 <v-btn class="ml-2" color="primary" @click="getImageFromURL" :loading="loading" :disabled="!slug"> | ||||||
|  |                   {{ $t("general.get") }} | ||||||
|  |                 </v-btn> | ||||||
|  |               </template> | ||||||
|  |             </v-text-field> | ||||||
|  |           </div> | ||||||
|  |         </v-card-text> | ||||||
|  |       </v-card> | ||||||
|  |     </v-menu> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | const REFRESH_EVENT = "refresh"; | ||||||
|  | const UPLOAD_EVENT = "upload"; | ||||||
|  | import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn"; | ||||||
|  | import { api } from "@/api"; | ||||||
|  | export default { | ||||||
|  |   components: { | ||||||
|  |     TheUploadBtn, | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     slug: String, | ||||||
|  |   }, | ||||||
|  |   data: () => ({ | ||||||
|  |     url: "", | ||||||
|  |     loading: false, | ||||||
|  |   }), | ||||||
|  |   methods: { | ||||||
|  |     uploadImage(fileObject) { | ||||||
|  |       this.$emit(UPLOAD_EVENT, fileObject); | ||||||
|  |     }, | ||||||
|  |     async getImageFromURL() { | ||||||
|  |       this.loading = true; | ||||||
|  |       if (await api.recipes.updateImagebyURL(this.slug, this.url)) { | ||||||
|  |         this.$emit(REFRESH_EVENT); | ||||||
|  |       } | ||||||
|  |       this.loading = false; | ||||||
|  |     }, | ||||||
|  |     getMessages() { | ||||||
|  |       return this.slug ? [""] : [this.$i18n.t("recipe.save-recipe-before-use")]; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped></style> | ||||||
							
								
								
									
										167
									
								
								frontend/components/Domain/Recipe/RecipeIngredients.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								frontend/components/Domain/Recipe/RecipeIngredients.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | |||||||
|  | <template> | ||||||
|  |   <div v-if="edit || (value && value.length > 0)"> | ||||||
|  |     <h2 class="mb-4">{{ $t("recipe.ingredients") }}</h2> | ||||||
|  |     <div v-if="edit"> | ||||||
|  |       <draggable :value="value" @input="updateIndex" @start="drag = true" @end="drag = false" handle=".handle"> | ||||||
|  |         <transition-group type="transition" :name="!drag ? 'flip-list' : null"> | ||||||
|  |           <div v-for="(ingredient, index) in value" :key="generateKey('ingredient', index)"> | ||||||
|  |             <v-row align="center"> | ||||||
|  |               <v-text-field | ||||||
|  |                 v-if="edit && showTitleEditor[index]" | ||||||
|  |                 class="mx-3 mt-3" | ||||||
|  |                 v-model="value[index].title" | ||||||
|  |                 dense | ||||||
|  |                 :label="$t('recipe.section-title')" | ||||||
|  |               > | ||||||
|  |               </v-text-field> | ||||||
|  |  | ||||||
|  |               <v-textarea | ||||||
|  |                 class="mr-2" | ||||||
|  |                 :label="$t('recipe.ingredient')" | ||||||
|  |                 v-model="value[index].note" | ||||||
|  |                 auto-grow | ||||||
|  |                 solo | ||||||
|  |                 dense | ||||||
|  |                 rows="1" | ||||||
|  |               > | ||||||
|  |                 <template slot="append"> | ||||||
|  |                   <v-tooltip right nudge-right="10"> | ||||||
|  |                     <template v-slot:activator="{ on, attrs }"> | ||||||
|  |                       <v-btn icon small class="mt-n1" v-bind="attrs" v-on="on" @click="toggleShowTitle(index)"> | ||||||
|  |                         <v-icon>{{ showTitleEditor[index] ? $globals.icons.minus : $globals.icons.createAlt }}</v-icon> | ||||||
|  |                       </v-btn> | ||||||
|  |                     </template> | ||||||
|  |                     <span>{{ | ||||||
|  |                       showTitleEditor[index] ? $t("recipe.remove-section") : $t("recipe.insert-section") | ||||||
|  |                     }}</span> | ||||||
|  |                   </v-tooltip> | ||||||
|  |                 </template> | ||||||
|  |                 <template slot="append-outer"> | ||||||
|  |                   <v-icon class="handle">{{ $globals.icons.arrowUpDown }}</v-icon> | ||||||
|  |                 </template> | ||||||
|  |                 <v-icon class="mr-n1" slot="prepend" color="error" @click="removeByIndex(value, index)"> | ||||||
|  |                   {{ $globals.icons.delete }} | ||||||
|  |                 </v-icon> | ||||||
|  |               </v-textarea> | ||||||
|  |             </v-row> | ||||||
|  |           </div> | ||||||
|  |         </transition-group> | ||||||
|  |       </draggable> | ||||||
|  |  | ||||||
|  |       <div class="d-flex row justify-end"> | ||||||
|  |         <BulkAdd @bulk-data="addIngredient" class="mr-2" /> | ||||||
|  |         <v-btn color="secondary" dark @click="addIngredient" class="mr-4"> | ||||||
|  |           <v-icon>{{ $globals.icons.create }}</v-icon> | ||||||
|  |         </v-btn> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div v-else> | ||||||
|  |       <div v-for="(ingredient, index) in value" :key="generateKey('ingredient', index)"> | ||||||
|  |         <h3 class="mt-2" v-if="showTitleEditor[index]">{{ ingredient.title }}</h3> | ||||||
|  |         <v-divider v-if="showTitleEditor[index]"></v-divider> | ||||||
|  |         <v-list-item dense @click="toggleChecked(index)"> | ||||||
|  |           <v-checkbox hide-details :value="checked[index]" class="pt-0 my-auto py-auto" color="secondary"> </v-checkbox> | ||||||
|  |           <v-list-item-content> | ||||||
|  |             <vue-markdown class="ma-0 pa-0 text-subtitle-1 dense-markdown" :source="ingredient.note"> </vue-markdown> | ||||||
|  |           </v-list-item-content> | ||||||
|  |         </v-list-item> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import BulkAdd from "@/components/Recipe/Parts/Helpers/BulkAdd"; | ||||||
|  | import VueMarkdown from "@adapttive/vue-markdown"; | ||||||
|  | import draggable from "vuedraggable"; | ||||||
|  | import { utils } from "@/utils"; | ||||||
|  | export default { | ||||||
|  |   components: { | ||||||
|  |     BulkAdd, | ||||||
|  |     draggable, | ||||||
|  |     VueMarkdown, | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     value: { | ||||||
|  |       type: Array, | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     edit: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       drag: false, | ||||||
|  |       checked: [], | ||||||
|  |       showTitleEditor: [], | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |     this.checked = this.value.map(() => false); | ||||||
|  |     this.showTitleEditor = this.value.map(x => this.validateTitle(x.title)); | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     value: { | ||||||
|  |       handler() { | ||||||
|  |         this.showTitleEditor = this.value.map(x => this.validateTitle(x.title)); | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     addIngredient(ingredients = null) { | ||||||
|  |       if (ingredients.length) { | ||||||
|  |         const newIngredients = ingredients.map(x => { | ||||||
|  |           return { | ||||||
|  |             title: null, | ||||||
|  |             note: x, | ||||||
|  |             unit: null, | ||||||
|  |             food: null, | ||||||
|  |             disableAmount: true, | ||||||
|  |             quantity: 1, | ||||||
|  |           }; | ||||||
|  |         }); | ||||||
|  |         this.value.push(...newIngredients); | ||||||
|  |       } else { | ||||||
|  |         this.value.push({ | ||||||
|  |           title: null, | ||||||
|  |           note: "", | ||||||
|  |           unit: null, | ||||||
|  |           food: null, | ||||||
|  |           disableAmount: true, | ||||||
|  |           quantity: 1, | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     generateKey(item, index) { | ||||||
|  |       return utils.generateUniqueKey(item, index); | ||||||
|  |     }, | ||||||
|  |     updateIndex(data) { | ||||||
|  |       this.$emit("input", data); | ||||||
|  |     }, | ||||||
|  |     toggleChecked(index) { | ||||||
|  |       this.$set(this.checked, index, !this.checked[index]); | ||||||
|  |     }, | ||||||
|  |     removeByIndex(list, index) { | ||||||
|  |       list.splice(index, 1); | ||||||
|  |     }, | ||||||
|  |     validateTitle(title) { | ||||||
|  |       return !(title === null || title === ""); | ||||||
|  |     }, | ||||||
|  |     toggleShowTitle(index) { | ||||||
|  |       const newVal = !this.showTitleEditor[index]; | ||||||
|  |       if (!newVal) { | ||||||
|  |         this.value[index].title = ""; | ||||||
|  |       } | ||||||
|  |       this.$set(this.showTitleEditor, index, newVal); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style> | ||||||
|  | .dense-markdown p { | ||||||
|  |   margin: auto !important; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										169
									
								
								frontend/components/Domain/Recipe/RecipeInstructions.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								frontend/components/Domain/Recipe/RecipeInstructions.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | |||||||
|  | <template> | ||||||
|  |   <div> | ||||||
|  |     <h2 class="mb-4">{{ $t("recipe.instructions") }}</h2> | ||||||
|  |     <div> | ||||||
|  |       <draggable | ||||||
|  |         :disabled="!edit" | ||||||
|  |         :value="value" | ||||||
|  |         @input="updateIndex" | ||||||
|  |         @start="drag = true" | ||||||
|  |         @end="drag = false" | ||||||
|  |         handle=".handle" | ||||||
|  |       > | ||||||
|  |         <div v-for="(step, index) in value" :key="index"> | ||||||
|  |           <v-app-bar v-if="showTitleEditor[index]" class="primary mx-1 mt-6" dark dense rounded> | ||||||
|  |             <v-toolbar-title class="headline" v-if="!edit"> | ||||||
|  |               <v-app-bar-title v-text="step.title"> </v-app-bar-title> | ||||||
|  |             </v-toolbar-title> | ||||||
|  |             <v-text-field | ||||||
|  |               v-if="edit" | ||||||
|  |               class="headline pa-0 mt-5" | ||||||
|  |               v-model="step.title" | ||||||
|  |               dense | ||||||
|  |               solo | ||||||
|  |               flat | ||||||
|  |               :placeholder="$t('recipe.section-title')" | ||||||
|  |               background-color="primary" | ||||||
|  |             > | ||||||
|  |             </v-text-field> | ||||||
|  |           </v-app-bar> | ||||||
|  |           <v-hover v-slot="{ hover }"> | ||||||
|  |             <v-card | ||||||
|  |               class="ma-1" | ||||||
|  |               :class="[{ 'on-hover': hover }, isChecked(index)]" | ||||||
|  |               :elevation="hover ? 12 : 2" | ||||||
|  |               :ripple="!edit" | ||||||
|  |               @click="toggleDisabled(index)" | ||||||
|  |             > | ||||||
|  |               <v-card-title :class="{ 'pb-0': !isChecked(index) }"> | ||||||
|  |                 <v-btn | ||||||
|  |                   v-if="edit" | ||||||
|  |                   fab | ||||||
|  |                   x-small | ||||||
|  |                   color="white" | ||||||
|  |                   class="mr-2" | ||||||
|  |                   elevation="0" | ||||||
|  |                   @click="removeByIndex(value, index)" | ||||||
|  |                 > | ||||||
|  |                   <v-icon size="24" color="error">{{ $globals.icons.delete }}</v-icon> | ||||||
|  |                 </v-btn> | ||||||
|  |  | ||||||
|  |                 {{ $t("recipe.step-index", { step: index + 1 }) }} | ||||||
|  |  | ||||||
|  |                 <v-btn v-if="edit" text color="primary" class="ml-auto" @click="toggleShowTitle(index)"> | ||||||
|  |                   {{ !showTitleEditor[index] ? $t("recipe.insert-section") : $t("recipe.remove-section") }} | ||||||
|  |                 </v-btn> | ||||||
|  |                 <v-icon v-if="edit" class="handle">{{ $globals.icons.arrowUpDown }}</v-icon> | ||||||
|  |                 <v-fade-transition> | ||||||
|  |                   <v-icon v-show="isChecked(index)" size="24" class="ml-auto" color="success"> | ||||||
|  |                     {{ $globals.icons.checkboxMarkedCircle }} | ||||||
|  |                   </v-icon> | ||||||
|  |                 </v-fade-transition> | ||||||
|  |               </v-card-title> | ||||||
|  |               <v-card-text v-if="edit"> | ||||||
|  |                 <v-textarea | ||||||
|  |                   auto-grow | ||||||
|  |                   dense | ||||||
|  |                   v-model="value[index]['text']" | ||||||
|  |                   :key="generateKey('instructions', index)" | ||||||
|  |                   rows="4" | ||||||
|  |                 > | ||||||
|  |                 </v-textarea> | ||||||
|  |               </v-card-text> | ||||||
|  |               <v-expand-transition> | ||||||
|  |                 <div class="m-0 p-0" v-show="!isChecked(index) && !edit"> | ||||||
|  |                   <v-card-text> | ||||||
|  |                     <vue-markdown :source="step.text"> </vue-markdown> | ||||||
|  |                   </v-card-text> | ||||||
|  |                 </div> | ||||||
|  |               </v-expand-transition> | ||||||
|  |             </v-card> | ||||||
|  |           </v-hover> | ||||||
|  |         </div> | ||||||
|  |       </draggable> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import draggable from "vuedraggable"; | ||||||
|  | import VueMarkdown from "@adapttive/vue-markdown"; | ||||||
|  | import { utils } from "@/utils"; | ||||||
|  | export default { | ||||||
|  |   components: { | ||||||
|  |     VueMarkdown, | ||||||
|  |     draggable, | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     value: { | ||||||
|  |       type: Array, | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     edit: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       disabledSteps: [], | ||||||
|  |       showTitleEditor: [], | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   mounted() { | ||||||
|  |     this.showTitleEditor = this.value.map(x => this.validateTitle(x.title)); | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   watch: { | ||||||
|  |     value: { | ||||||
|  |       handler() { | ||||||
|  |         this.disabledSteps = []; | ||||||
|  |         this.showTitleEditor = this.value.map(x => this.validateTitle(x.title)); | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     generateKey(item, index) { | ||||||
|  |       return utils.generateUniqueKey(item, index); | ||||||
|  |     }, | ||||||
|  |     removeByIndex(list, index) { | ||||||
|  |       list.splice(index, 1); | ||||||
|  |     }, | ||||||
|  |     validateTitle(title) { | ||||||
|  |       return !(title === null || title === ""); | ||||||
|  |     }, | ||||||
|  |     toggleDisabled(stepIndex) { | ||||||
|  |       if (this.edit) return; | ||||||
|  |       if (this.disabledSteps.includes(stepIndex)) { | ||||||
|  |         let index = this.disabledSteps.indexOf(stepIndex); | ||||||
|  |         if (index !== -1) { | ||||||
|  |           this.disabledSteps.splice(index, 1); | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         this.disabledSteps.push(stepIndex); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     isChecked(stepIndex) { | ||||||
|  |       if (this.disabledSteps.includes(stepIndex) && !this.edit) { | ||||||
|  |         return "disabled-card"; | ||||||
|  |       } else { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     toggleShowTitle(index) { | ||||||
|  |       const newVal = !this.showTitleEditor[index]; | ||||||
|  |       if (!newVal) { | ||||||
|  |         this.value[index].title = ""; | ||||||
|  |       } | ||||||
|  |       this.$set(this.showTitleEditor, index, newVal); | ||||||
|  |     }, | ||||||
|  |     updateIndex(data) { | ||||||
|  |       this.$emit("input", data); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										67
									
								
								frontend/components/Domain/Recipe/RecipeNotes.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								frontend/components/Domain/Recipe/RecipeNotes.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | <template> | ||||||
|  |   <div v-if="value.length > 0 || edit"> | ||||||
|  |     <h2 class="my-4">{{ $t("recipe.note") }}</h2> | ||||||
|  |     <v-card class="mt-1" v-for="(note, index) in value" :key="generateKey('note', index)"> | ||||||
|  |       <div v-if="edit"> | ||||||
|  |         <v-card-text> | ||||||
|  |           <v-row align="center"> | ||||||
|  |             <v-btn fab x-small color="white" class="mr-2" elevation="0" @click="removeByIndex(value, index)"> | ||||||
|  |               <v-icon color="error">{{ $globals.icons.delete }}</v-icon> | ||||||
|  |             </v-btn> | ||||||
|  |             <v-text-field :label="$t('recipe.title')" v-model="value[index]['title']"></v-text-field> | ||||||
|  |           </v-row> | ||||||
|  |  | ||||||
|  |           <v-textarea auto-grow :placeholder="$t('recipe.note')" v-model="value[index]['text']"> </v-textarea> | ||||||
|  |         </v-card-text> | ||||||
|  |       </div> | ||||||
|  |       <div v-else> | ||||||
|  |         <v-card-title class="py-2"> | ||||||
|  |           {{ note.title }} | ||||||
|  |         </v-card-title> | ||||||
|  |         <v-divider class="mx-2"></v-divider> | ||||||
|  |         <v-card-text> | ||||||
|  |           <vue-markdown :source="note.text"> </vue-markdown> | ||||||
|  |         </v-card-text> | ||||||
|  |       </div> | ||||||
|  |     </v-card> | ||||||
|  |  | ||||||
|  |     <div class="d-flex justify-end" v-if="edit"> | ||||||
|  |       <v-btn class="mt-1" color="secondary" dark @click="addNote"> | ||||||
|  |         <v-icon>{{ $globals.icons.create }}</v-icon> | ||||||
|  |       </v-btn> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import VueMarkdown from "@adapttive/vue-markdown"; | ||||||
|  | import { utils } from "@/utils"; | ||||||
|  | export default { | ||||||
|  |   components: { | ||||||
|  |     VueMarkdown, | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     value: { | ||||||
|  |       type: Array, | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     edit: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     generateKey(item, index) { | ||||||
|  |       return utils.generateUniqueKey(item, index); | ||||||
|  |     }, | ||||||
|  |     addNote() { | ||||||
|  |       this.value.push({ title: "", text: "" }); | ||||||
|  |     }, | ||||||
|  |     removeByIndex(list, index) { | ||||||
|  |       list.splice(index, 1); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style></style> | ||||||
							
								
								
									
										100
									
								
								frontend/components/Domain/Recipe/RecipeNutrition.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								frontend/components/Domain/Recipe/RecipeNutrition.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | <template> | ||||||
|  |   <div v-if="valueNotNull || edit"> | ||||||
|  |     <v-card class="mt-2"> | ||||||
|  |       <v-card-title class="py-2"> | ||||||
|  |         {{ $t("recipe.nutrition") }} | ||||||
|  |       </v-card-title> | ||||||
|  |       <v-divider class="mx-2"></v-divider> | ||||||
|  |       <v-card-text v-if="edit"> | ||||||
|  |         <div v-for="(item, key, index) in value" :key="index"> | ||||||
|  |           <v-text-field | ||||||
|  |             dense | ||||||
|  |             :value="value[key]" | ||||||
|  |             :label="labels[key].label" | ||||||
|  |             :suffix="labels[key].suffix" | ||||||
|  |             type="number" | ||||||
|  |             autocomplete="off" | ||||||
|  |             @input="updateValue(key, $event)" | ||||||
|  |           ></v-text-field> | ||||||
|  |         </div> | ||||||
|  |       </v-card-text> | ||||||
|  |       <v-list dense v-if="showViewer" class="mt-0 pt-0"> | ||||||
|  |         <v-list-item v-for="(item, key, index) in labels" :key="index"> | ||||||
|  |           <v-list-item-content> | ||||||
|  |             <v-list-item-title class="pl-4 text-subtitle-1 flex row "> | ||||||
|  |               <div>{{ item.label }}</div> | ||||||
|  |               <div class="ml-auto mr-1">{{ value[key] }}</div> | ||||||
|  |               <div>{{ item.suffix }}</div> | ||||||
|  |             </v-list-item-title> | ||||||
|  |           </v-list-item-content> | ||||||
|  |         </v-list-item> | ||||||
|  |       </v-list> | ||||||
|  |     </v-card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   props: { | ||||||
|  |     value: {}, | ||||||
|  |     edit: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       labels: { | ||||||
|  |         calories: { | ||||||
|  |           label: this.$t("recipe.calories"), | ||||||
|  |           suffix: this.$t("recipe.calories-suffix"), | ||||||
|  |         }, | ||||||
|  |         fatContent: { | ||||||
|  |           label: this.$t("recipe.fat-content"), | ||||||
|  |           suffix: this.$t("recipe.grams"), | ||||||
|  |         }, | ||||||
|  |         fiberContent: { | ||||||
|  |           label: this.$t("recipe.fiber-content"), | ||||||
|  |           suffix: this.$t("recipe.grams"), | ||||||
|  |         }, | ||||||
|  |         proteinContent: { | ||||||
|  |           label: this.$t("recipe.protein-content"), | ||||||
|  |           suffix: this.$t("recipe.grams"), | ||||||
|  |         }, | ||||||
|  |         sodiumContent: { | ||||||
|  |           label: this.$t("recipe.sodium-content"), | ||||||
|  |           suffix: this.$t("recipe.milligrams"), | ||||||
|  |         }, | ||||||
|  |         sugarContent: { | ||||||
|  |           label: this.$t("recipe.sugar-content"), | ||||||
|  |           suffix: this.$t("recipe.grams"), | ||||||
|  |         }, | ||||||
|  |         carbohydrateContent: { | ||||||
|  |           label: this.$t("recipe.carbohydrate-content"), | ||||||
|  |           suffix: this.$t("recipe.grams"), | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     showViewer() { | ||||||
|  |       return !this.edit && this.valueNotNull; | ||||||
|  |     }, | ||||||
|  |     valueNotNull() { | ||||||
|  |       for (const property in this.value) { | ||||||
|  |         const valueProperty = this.value[property]; | ||||||
|  |         if (valueProperty && valueProperty !== "") return true; | ||||||
|  |       } | ||||||
|  |       return false; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     updateValue(key, value) { | ||||||
|  |       this.$emit("input", { ...this.value, [key]: value }); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped></style> | ||||||
							
								
								
									
										62
									
								
								frontend/components/Domain/Recipe/RecipeRating.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								frontend/components/Domain/Recipe/RecipeRating.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | <template> | ||||||
|  |   <div @click.prevent> | ||||||
|  |     <v-rating | ||||||
|  |       :readonly="!loggedIn" | ||||||
|  |       color="secondary" | ||||||
|  |       background-color="secondary lighten-3" | ||||||
|  |       length="5" | ||||||
|  |       :dense="small ? true : undefined" | ||||||
|  |       :size="small ? 15 : undefined" | ||||||
|  |       hover | ||||||
|  |       v-model="rating" | ||||||
|  |       :value="value" | ||||||
|  |       @input="updateRating" | ||||||
|  |       @click="updateRating" | ||||||
|  |     ></v-rating> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import { api } from "@/api"; | ||||||
|  | export default { | ||||||
|  |   props: { | ||||||
|  |     emitOnly: { | ||||||
|  |       default: false, | ||||||
|  |     }, | ||||||
|  |     name: String, | ||||||
|  |     slug: String, | ||||||
|  |     value: Number, | ||||||
|  |     small: { | ||||||
|  |       default: false, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |     this.rating = this.value; | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       rating: 0, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     loggedIn() { | ||||||
|  |       return this.$store.getters.getIsLoggedIn; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     updateRating(val) { | ||||||
|  |       if (this.emitOnly) { | ||||||
|  |         this.$emit("input", val); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       api.recipes.patch({ | ||||||
|  |         name: this.name, | ||||||
|  |         slug: this.slug, | ||||||
|  |         rating: val, | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped></style> | ||||||
							
								
								
									
										60
									
								
								frontend/components/Domain/Recipe/RecipeSettingsMenu.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								frontend/components/Domain/Recipe/RecipeSettingsMenu.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="text-center"> | ||||||
|  |     <v-menu offset-y top nudge-top="6" :close-on-content-click="false"> | ||||||
|  |       <template v-slot:activator="{ on, attrs }"> | ||||||
|  |         <v-btn color="accent" dark v-bind="attrs" v-on="on"> | ||||||
|  |           <v-icon left> | ||||||
|  |             {{ $globals.icons.cog }} | ||||||
|  |           </v-icon> | ||||||
|  |           {{ $t("general.settings") }} | ||||||
|  |         </v-btn> | ||||||
|  |       </template> | ||||||
|  |       <v-card> | ||||||
|  |         <v-card-title class="py-2"> | ||||||
|  |           <div> | ||||||
|  |             {{ $t("recipe.recipe-settings") }} | ||||||
|  |           </div> | ||||||
|  |         </v-card-title> | ||||||
|  |         <v-divider class="mx-2"></v-divider> | ||||||
|  |         <v-card-text class="mt-n5"> | ||||||
|  |           <v-switch | ||||||
|  |             dense | ||||||
|  |             v-for="(itemValue, key) in value" | ||||||
|  |             :key="key" | ||||||
|  |             v-model="value[key]" | ||||||
|  |             flat | ||||||
|  |             inset | ||||||
|  |             :label="labels[key]" | ||||||
|  |             hide-details | ||||||
|  |           ></v-switch> | ||||||
|  |         </v-card-text> | ||||||
|  |       </v-card> | ||||||
|  |     </v-menu> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   components: {}, | ||||||
|  |   props: { | ||||||
|  |     value: Object, | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   computed: { | ||||||
|  |     labels() { | ||||||
|  |       return { | ||||||
|  |         public: this.$t("recipe.public-recipe"), | ||||||
|  |         showNutrition: this.$t("recipe.show-nutrition-values"), | ||||||
|  |         showAssets: this.$t("asset.show-assets"), | ||||||
|  |         landscapeView: this.$t("recipe.landscape-view-coming-soon"), | ||||||
|  |         disableComments: this.$t("recipe.disable-comments"), | ||||||
|  |         disableAmount: this.$t("recipe.disable-amount"), | ||||||
|  |       }; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: {}, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped></style> | ||||||
| @@ -94,7 +94,7 @@ import Rating from "@/components/Recipe/Parts/Rating"; | |||||||
| import Notes from "@/components/Recipe/Parts/Notes"; | import Notes from "@/components/Recipe/Parts/Notes"; | ||||||
| import Ingredients from "@/components/Recipe/Parts/Ingredients"; | import Ingredients from "@/components/Recipe/Parts/Ingredients"; | ||||||
| import Instructions from "@/components/Recipe/Parts/Instructions.vue"; | import Instructions from "@/components/Recipe/Parts/Instructions.vue"; | ||||||
| import Assets from "../Parts/Assets.vue"; | import Assets from "../../../../frontend.old/src/components/Recipe/Parts/Assets.vue"; | ||||||
| export default { | export default { | ||||||
|   components: { |   components: { | ||||||
|     VueMarkdown, |     VueMarkdown, | ||||||
| @@ -1,77 +1,16 @@ | |||||||
| <template> | <template> | ||||||
|   <v-row justify="center" align="center"> |   <div></div> | ||||||
|     <v-col cols="12" sm="8" md="6"> |  | ||||||
|       <v-card class="logo py-4 d-flex justify-center"> |  | ||||||
|         <NuxtLogo /> |  | ||||||
|         <VuetifyLogo /> |  | ||||||
|       </v-card> |  | ||||||
|       <v-card> |  | ||||||
|         <v-card-title class="headline"> |  | ||||||
|           Welcome to the Vuetify + Nuxt.js template |  | ||||||
|         </v-card-title> |  | ||||||
|         <v-card-text> |  | ||||||
|           <p>Vuetify is a progressive Material Design component framework for Vue.js. It was designed to empower developers to create amazing applications.</p> |  | ||||||
|           <p> |  | ||||||
|             For more information on Vuetify, check out the <a |  | ||||||
|               href="https://vuetifyjs.com" |  | ||||||
|               target="_blank" |  | ||||||
|               rel="noopener noreferrer" |  | ||||||
|             > |  | ||||||
|               documentation |  | ||||||
|             </a>. |  | ||||||
|           </p> |  | ||||||
|           <p> |  | ||||||
|             If you have questions, please join the official <a |  | ||||||
|               href="https://chat.vuetifyjs.com/" |  | ||||||
|               target="_blank" |  | ||||||
|               rel="noopener noreferrer" |  | ||||||
|               title="chat" |  | ||||||
|             > |  | ||||||
|               discord |  | ||||||
|             </a>. |  | ||||||
|           </p> |  | ||||||
|           <p> |  | ||||||
|             Find a bug? Report it on the github <a |  | ||||||
|               href="https://github.com/vuetifyjs/vuetify/issues" |  | ||||||
|               target="_blank" |  | ||||||
|               rel="noopener noreferrer" |  | ||||||
|               title="contribute" |  | ||||||
|             > |  | ||||||
|               issue board |  | ||||||
|             </a>. |  | ||||||
|           </p> |  | ||||||
|           <p>Thank you for developing with Vuetify and I look forward to bringing more exciting features in the future.</p> |  | ||||||
|           <div class="text-xs-right"> |  | ||||||
|             <em><small>— John Leider</small></em> |  | ||||||
|           </div> |  | ||||||
|           <hr class="my-3"> |  | ||||||
|           <a |  | ||||||
|             href="https://nuxtjs.org/" |  | ||||||
|             target="_blank" |  | ||||||
|             rel="noopener noreferrer" |  | ||||||
|           > |  | ||||||
|             Nuxt Documentation |  | ||||||
|           </a> |  | ||||||
|           <br> |  | ||||||
|           <a |  | ||||||
|             href="https://github.com/nuxt/nuxt.js" |  | ||||||
|             target="_blank" |  | ||||||
|             rel="noopener noreferrer" |  | ||||||
|           > |  | ||||||
|             Nuxt GitHub |  | ||||||
|           </a> |  | ||||||
|         </v-card-text> |  | ||||||
|         <v-card-actions> |  | ||||||
|           <v-spacer /> |  | ||||||
|           <v-btn |  | ||||||
|             color="primary" |  | ||||||
|             nuxt |  | ||||||
|             to="/inspire" |  | ||||||
|           > |  | ||||||
|             Continue |  | ||||||
|           </v-btn> |  | ||||||
|         </v-card-actions> |  | ||||||
|       </v-card> |  | ||||||
|     </v-col> |  | ||||||
|   </v-row> |  | ||||||
| </template> | </template> | ||||||
|  |    | ||||||
|  |   <script lang="ts"> | ||||||
|  | import { defineComponent } from "@nuxtjs/composition-api"; | ||||||
|  |  | ||||||
|  | export default defineComponent({ | ||||||
|  |   setup() { | ||||||
|  |     return {}; | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  |    | ||||||
|  |   <style scoped> | ||||||
|  | </style> | ||||||
| @@ -0,0 +1,16 @@ | |||||||
|  | <template> | ||||||
|  |   <div></div> | ||||||
|  | </template> | ||||||
|  |      | ||||||
|  |     <script lang="ts"> | ||||||
|  | import { defineComponent } from "@nuxtjs/composition-api"; | ||||||
|  |  | ||||||
|  | export default defineComponent({ | ||||||
|  |   setup() { | ||||||
|  |     return {}; | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  |      | ||||||
|  |     <style scoped> | ||||||
|  | </style> | ||||||
| @@ -3,13 +3,13 @@ | |||||||
| </template> | </template> | ||||||
|    |    | ||||||
|   <script lang="ts"> |   <script lang="ts"> | ||||||
|   import { defineComponent } from '@nuxtjs/composition-api' | import { defineComponent } from "@nuxtjs/composition-api"; | ||||||
|  |  | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
|   setup() { |   setup() { | ||||||
|       return {} |     return {}; | ||||||
|     } |   }, | ||||||
|   }) | }); | ||||||
| </script> | </script> | ||||||
|    |    | ||||||
|   <style scoped> |   <style scoped> | ||||||
|   | |||||||
| @@ -3,13 +3,13 @@ | |||||||
| </template> | </template> | ||||||
|    |    | ||||||
|   <script lang="ts"> |   <script lang="ts"> | ||||||
|   import { defineComponent } from '@nuxtjs/composition-api' | import { defineComponent } from "@nuxtjs/composition-api"; | ||||||
|  |  | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
|   setup() { |   setup() { | ||||||
|       return {} |     return {}; | ||||||
|     } |   }, | ||||||
|   }) | }); | ||||||
| </script> | </script> | ||||||
|    |    | ||||||
|   <style scoped> |   <style scoped> | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								frontend/pages/user/login.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								frontend/pages/user/login.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <template> | ||||||
|  |   <div></div> | ||||||
|  | </template> | ||||||
|  |      | ||||||
|  |     <script lang="ts"> | ||||||
|  | import { defineComponent } from "@nuxtjs/composition-api"; | ||||||
|  |  | ||||||
|  | export default defineComponent({ | ||||||
|  |   setup() { | ||||||
|  |     return {}; | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  |      | ||||||
|  |     <style scoped> | ||||||
|  | </style> | ||||||
							
								
								
									
										16
									
								
								frontend/pages/user/register.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								frontend/pages/user/register.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <template> | ||||||
|  |   <div></div> | ||||||
|  | </template> | ||||||
|  |      | ||||||
|  |     <script lang="ts"> | ||||||
|  | import { defineComponent } from "@nuxtjs/composition-api"; | ||||||
|  |  | ||||||
|  | export default defineComponent({ | ||||||
|  |   setup() { | ||||||
|  |     return {}; | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  |      | ||||||
|  |     <style scoped> | ||||||
|  | </style> | ||||||
							
								
								
									
										16
									
								
								frontend/pages/user/request-signup-link.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								frontend/pages/user/request-signup-link.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <template> | ||||||
|  |   <div></div> | ||||||
|  | </template> | ||||||
|  |      | ||||||
|  |     <script lang="ts"> | ||||||
|  | import { defineComponent } from "@nuxtjs/composition-api"; | ||||||
|  |  | ||||||
|  | export default defineComponent({ | ||||||
|  |   setup() { | ||||||
|  |     return {}; | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  |      | ||||||
|  |     <style scoped> | ||||||
|  | </style> | ||||||
		Reference in New Issue
	
	Block a user