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 @@