From 7eb80d18d2547a02958fafa6e0f7d7e06e8891ac Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sun, 5 Jun 2022 11:28:38 -0800 Subject: [PATCH] feat: attached images by drag and drop for recipe steps (#1341) * add drag and drop support for recipe steps * fix recipe assets dialog state * add attr support for markdown editor * add persistent hint for recipe text editor --- .../components/Domain/Recipe/RecipeAssets.vue | 2 +- .../Domain/Recipe/RecipeInstructions.vue | 111 +++++++++++++++++- frontend/components/global/MarkdownEditor.vue | 13 +- frontend/pages/recipe/_slug/index.vue | 3 + 4 files changed, 118 insertions(+), 11 deletions(-) diff --git a/frontend/components/Domain/Recipe/RecipeAssets.vue b/frontend/components/Domain/Recipe/RecipeAssets.vue index 63159229..f6c0e40f 100644 --- a/frontend/components/Domain/Recipe/RecipeAssets.vue +++ b/frontend/components/Domain/Recipe/RecipeAssets.vue @@ -45,7 +45,7 @@ @submit="addAsset" > diff --git a/frontend/components/Domain/Recipe/RecipeInstructions.vue b/frontend/components/Domain/Recipe/RecipeInstructions.vue index d66c6874..25fcb12a 100644 --- a/frontend/components/Domain/Recipe/RecipeInstructions.vue +++ b/frontend/components/Domain/Recipe/RecipeInstructions.vue @@ -168,12 +168,26 @@ - + + + +
RecipeAsset[], + required: true, + }, }, setup(props, context) { + const { req } = useContext(); + const BASE_URL = detectServerBaseUrl(req); + + console.log("Base URL", BASE_URL); + const state = reactive({ dialog: false, disabledSteps: [] as number[], @@ -368,7 +400,7 @@ export default defineComponent({ } function autoSetReferences() { - // Ingore matching blacklisted words when auto-linking - This is kind of a cludgey implementation. We're blacklisting common words but + // Ignore matching blacklisted words when auto-linking - This is kind of a cludgey implementation. We're blacklisting common words but // other common phrases trigger false positives and I'm not sure how else to approach this. In the future I maybe look at looking directly // at the food variable and seeing if the food is in the instructions, but I still need to support those who don't want to provide the value // and only use the "notes" feature. @@ -493,7 +525,59 @@ export default defineComponent({ const drag = ref(false); + // =============================================================== + // Image Uploader + const api = useUserApi(); + const { recipeAssetPath } = useStaticRoutes(); + + const imageUploadMode = ref(false); + + function toggleDragMode() { + console.log("Toggling Drag Mode"); + imageUploadMode.value = !imageUploadMode.value; + } + + onMounted(() => { + if (props.assets === undefined) { + context.emit("update:assets", []); + } + }); + + async function handleImageDrop(index: number, e: DragEvent) { + if (!e.dataTransfer) { + return; + } + + // Check if the file is an image + const file = e.dataTransfer.files[0]; + if (!file || !file.type.startsWith("image/")) { + return; + } + + const { data } = await api.recipes.createAsset(props.recipeSlug, { + name: file.name, + icon: "mdi-file-image", + file, + extension: file.name.split(".").pop() || "", + }); + + if (!data) { + return; // TODO: Handle error + } + + context.emit("update:assets", [...props.assets, data]); + const assetUrl = BASE_URL + recipeAssetPath(props.recipeId, data.fileName as string); + const text = ``; + props.value[index].text += text; + } + return { + // Image Uploader + toggleDragMode, + handleImageDrop, + imageUploadMode, + + // Rest drag, togglePreviewState, toggleCollapseSection, @@ -553,4 +637,21 @@ export default defineComponent({ .list-group-item i { cursor: pointer; } + +.blur { + filter: blur(2px); +} + +.upload-overlay { + display: flex; + justify-content: center; + align-items: center; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + z-index: 1; +} diff --git a/frontend/components/global/MarkdownEditor.vue b/frontend/components/global/MarkdownEditor.vue index ff455c42..2ed14520 100644 --- a/frontend/components/global/MarkdownEditor.vue +++ b/frontend/components/global/MarkdownEditor.vue @@ -5,7 +5,7 @@ :buttons="[ { icon: previewState ? $globals.icons.edit : $globals.icons.eye, - text: previewState ? $t('general.edit') : 'Preview Markdown', + text: previewState ? $tc('general.edit') : 'Preview Markdown', event: 'toggle', }, ]" @@ -14,14 +14,15 @@
- + /> + @@ -53,6 +54,10 @@ export default defineComponent({ type: Boolean, default: true, }, + textarea: { + type: Object, + default: () => ({}), + }, }, setup(props, context) { const fallbackPreview = ref(false); @@ -84,5 +89,3 @@ export default defineComponent({ }, }); - - diff --git a/frontend/pages/recipe/_slug/index.vue b/frontend/pages/recipe/_slug/index.vue index 37dde85c..1004ba85 100644 --- a/frontend/pages/recipe/_slug/index.vue +++ b/frontend/pages/recipe/_slug/index.vue @@ -319,6 +319,9 @@ :ingredients="recipe.recipeIngredient" :disable-amount="recipe.settings.disableAmount" :edit="form" + :recipe-id="recipe.id" + :recipe-slug="recipe.slug" + :assets.sync="recipe.assets" />