mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 02:03:35 -04:00 
			
		
		
		
	Upload recipe step images from mobile devices (#2025)
* Upload recipe step images from mobile devices This adds a button in the recipe step dropdown, as not all mobile devices can drag and drop a file into the web page See #885 * Add progress bar
This commit is contained in:
		| @@ -146,6 +146,10 @@ | |||||||
|                               text: 'Merge Above', |                               text: 'Merge Above', | ||||||
|                               event: 'merge-above', |                               event: 'merge-above', | ||||||
|                             }, |                             }, | ||||||
|  |                             { | ||||||
|  |                               text: 'Upload image', | ||||||
|  |                               event: 'upload-image' | ||||||
|  |                             }, | ||||||
|                             { |                             { | ||||||
|                               icon: previewStates[index] ? $globals.icons.edit : $globals.icons.eye, |                               icon: previewStates[index] ? $globals.icons.edit : $globals.icons.eye, | ||||||
|                               text: previewStates[index] ? 'Edit Markdown' : 'Preview Markdown', |                               text: previewStates[index] ? 'Edit Markdown' : 'Preview Markdown', | ||||||
| @@ -158,6 +162,7 @@ | |||||||
|                       @toggle-section="toggleShowTitle(step.id)" |                       @toggle-section="toggleShowTitle(step.id)" | ||||||
|                       @link-ingredients="openDialog(index, step.text, step.ingredientReferences)" |                       @link-ingredients="openDialog(index, step.text, step.ingredientReferences)" | ||||||
|                       @preview-step="togglePreviewState(index)" |                       @preview-step="togglePreviewState(index)" | ||||||
|  |                       @upload-image="openImageUpload(index)" | ||||||
|                       @delete="value.splice(index, 1)" |                       @delete="value.splice(index, 1)" | ||||||
|                     /> |                     /> | ||||||
|                   </div> |                   </div> | ||||||
| @@ -169,6 +174,8 @@ | |||||||
|                 </v-fade-transition> |                 </v-fade-transition> | ||||||
|               </v-card-title> |               </v-card-title> | ||||||
|  |  | ||||||
|  |               <v-progress-linear v-if="isEditForm && loadingStates[index]" :active="true" :indeterminate="true" /> | ||||||
|  |  | ||||||
|               <!-- Content --> |               <!-- Content --> | ||||||
|               <DropZone @drop="(f) => handleImageDrop(index, f)"> |               <DropZone @drop="(f) => handleImageDrop(index, f)"> | ||||||
|                 <v-card-text |                 <v-card-text | ||||||
| @@ -548,6 +555,8 @@ export default defineComponent({ | |||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |     const loadingStates = ref<{ [key: number]: boolean }>({}); | ||||||
|  |  | ||||||
|     async function handleImageDrop(index: number, files: File[]) { |     async function handleImageDrop(index: number, files: File[]) { | ||||||
|       if (!files) { |       if (!files) { | ||||||
|         return; |         return; | ||||||
| @@ -559,6 +568,8 @@ export default defineComponent({ | |||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       loadingStates.value[index] = true; | ||||||
|  |  | ||||||
|       const { data } = await api.recipes.createAsset(props.recipe.slug, { |       const { data } = await api.recipes.createAsset(props.recipe.slug, { | ||||||
|         name: file.name, |         name: file.name, | ||||||
|         icon: "mdi-file-image", |         icon: "mdi-file-image", | ||||||
| @@ -566,6 +577,8 @@ export default defineComponent({ | |||||||
|         extension: file.name.split(".").pop() || "", |         extension: file.name.split(".").pop() || "", | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|  |       loadingStates.value[index] = false; | ||||||
|  |  | ||||||
|       if (!data) { |       if (!data) { | ||||||
|         return; // TODO: Handle error |         return; // TODO: Handle error | ||||||
|       } |       } | ||||||
| @@ -576,11 +589,26 @@ export default defineComponent({ | |||||||
|       props.value[index].text += text; |       props.value[index].text += text; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     function openImageUpload(index: number) { | ||||||
|  |       const input = document.createElement("input"); | ||||||
|  |       input.type = "file"; | ||||||
|  |       input.accept = "image/*"; | ||||||
|  |       input.onchange = async () => { | ||||||
|  |         if (input.files) { | ||||||
|  |           await handleImageDrop(index, Array.from(input.files)); | ||||||
|  |           input.remove(); | ||||||
|  |         } | ||||||
|  |       }; | ||||||
|  |       input.click(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return { |     return { | ||||||
|       // Image Uploader |       // Image Uploader | ||||||
|       toggleDragMode, |       toggleDragMode, | ||||||
|       handleImageDrop, |       handleImageDrop, | ||||||
|       imageUploadMode, |       imageUploadMode, | ||||||
|  |       openImageUpload, | ||||||
|  |       loadingStates, | ||||||
|  |  | ||||||
|       // Rest |       // Rest | ||||||
|       drag, |       drag, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user