various improvements

This commit is contained in:
vabene1111
2025-03-31 16:06:20 +02:00
parent 235c5d6b4a
commit c03e82f094
11 changed files with 81 additions and 84 deletions

View File

@@ -1,6 +1,6 @@
<template>
<component :is="compiled_instructions" :ingredient_factor="ingredient_factor" :instructions_html="instructions_html"></component>
<!-- <div v-html="instructions_html"></div>-->
<!-- <div v-html="instructions_html"></div>-->
</template>
<script>
@@ -31,7 +31,8 @@ export default defineComponent({
ingredient_factor: {type: Number, required: true},
},
components: {ScalableNumber,},
template: `<div>${this.instructions_html}</div>`
template: `
<div>${this.instructions_html}</div>`
}))
}
},
@@ -41,3 +42,14 @@ export default defineComponent({
})
</script>
<style>
/**
vuetify removes all margins and paddings which break layout, re-add them by reverting vuetify change
*/
p, ol, ul, li {
padding: revert;
margin: revert;
}
</style>

View File

@@ -26,7 +26,7 @@
<v-col cols="12" md="6" v-if="step.ingredients.length > 0">
<ingredients-table v-model="step.ingredients" :ingredient-factor="ingredientFactor"></ingredients-table>
</v-col>
<v-col cols="12" md="6">
<v-col cols="12" md="6" class="markdown-body">
<instructions :instructions_html="step.instructionsMarkdown" :ingredient_factor="ingredientFactor" v-if="step.instructionsMarkdown != undefined"></instructions>
<!-- sub recipes dont have a correct schema, thus they use different variable naming -->
<instructions :instructions_html="step.instructions_markdown" :ingredient_factor="ingredientFactor" v-else></instructions>

View File

@@ -55,15 +55,15 @@
<v-row v-for="(ingredient, index) in step.ingredients" dense>
<v-col cols="2" v-if="!ingredient.isHeader">
<v-text-field :id="`id_input_amount_${step.id}_${index}`" :label="$t('Amount')" type="number" v-model="ingredient.amount" density="compact"
hide-details>
hide-details v-if="!ingredient.noAmount">
<template #prepend>
<v-icon icon="$dragHandle" class="drag-handle cursor-grab"></v-icon>
</template>
</v-text-field>
</v-col>
<v-col cols="3" v-if="!ingredient.isHeader">
<model-select model="Unit" v-model="ingredient.unit" density="compact" allow-create hide-details></model-select>
<v-col cols="3" v-if="!ingredient.isHeader ">
<model-select model="Unit" v-model="ingredient.unit" density="compact" allow-create hide-details v-if="!ingredient.noAmount"></model-select>
</v-col>
<v-col cols="3" v-if="!ingredient.isHeader">
<model-select model="Food" v-model="ingredient.food" density="compact" allow-create hide-details></model-select>
@@ -84,6 +84,9 @@
<v-list-item link>
<v-switch v-model="step.ingredients[index].isHeader" :label="$t('Headline')" hide-details></v-switch>
</v-list-item>
<v-list-item link>
<v-switch v-model="step.ingredients[index].noAmount" :label="$t('Disable_Amount')" hide-details></v-switch>
</v-list-item>
<v-list-item @click="editingIngredientIndex = index; dialogIngredientSorter = true" prepend-icon="fa-solid fa-sort">{{
$t('Move')
}}
@@ -120,7 +123,7 @@
</v-col>
<v-col cols="12">
<v-label>{{ $t('Instructions') }}</v-label>
<v-alert @click="dialogMarkdownEditor = true" class="mt-2 cursor-pointer" min-height="52px">
<v-alert @click="dialogMarkdownEditor = true" class="mt-2 cursor-pointer" min-height="52px" v-if="mobile">
<template v-if="step.instruction != '' && step.instruction != null">
{{ step.instruction }}
</template>
@@ -128,6 +131,11 @@
<i> {{ $t('InstructionsEditHelp') }} </i>
</template>
</v-alert>
<template v-else>
<p>
<step-markdown-editor class="h-100" v-model="step"></step-markdown-editor>
</p>
</template>
</v-col>
</v-row>
@@ -352,7 +360,11 @@ function handleIngredientNoteTab(event: KeyboardEvent, index: number) {
* insert a new ingredient and focus its first input
*/
function insertAndFocusIngredient() {
let ingredient = {} as Ingredient
let ingredient = {
amount: 0,
unit: null,
food: null,
} as Ingredient
if (defaultUnit.value != null) {
ingredient.unit = defaultUnit.value

View File

@@ -2,23 +2,23 @@
<mavon-editor v-model="step.instruction" :autofocus="false"
style="z-index: auto" :id="'id_instruction_' + step.id"
:language="'en'"
:toolbars="md_editor_toolbars" :defaultOpen="'edit'">
:toolbars="md_editor_toolbars" :defaultOpen="'edit'" ref="markdownEditor">
<template #left-toolbar-after>
<span class="op-icon-divider"></span>
<button
type="button"
@click="step.instruction+= ' {{ scale(100) }}'"
@click="insertTextAtPosition('{{ scale(100) }} ')"
class="op-icon fas fa-calculator"
aria-hidden="true"
:title="$t('ScalableNumber')"
></button>
<button class="op-icon fa-solid fa-code">
<button class="op-icon fa-solid fa-code" v-if="templates.length > 0" type="button">
<v-menu activator="parent">
<v-list density="compact">
<v-list-subheader>{{$t('Ingredients')}}</v-list-subheader>
<v-list-item
v-for="template in templates"
@click="step.instruction+= template.template"
@click="insertTextAtPosition(template.template + ' ')"
>
<ingredient-string :ingredient="template.ingredient"></ingredient-string>
</v-list-item>
@@ -34,9 +34,11 @@
import {Ingredient, Step} from "@/openapi";
import 'mavon-editor/dist/css/index.css'
import IngredientString from "@/components/display/IngredientString.vue";
import {computed} from "vue";
import {computed, nextTick, useTemplateRef} from "vue";
import editor from "mavon-editor";
const step = defineModel<Step>({required: true})
const markdownEditor = useTemplateRef('markdownEditor')
type IngredientTemplate = {
name: string,
@@ -58,6 +60,24 @@ const templates = computed(() => {
return templateList
})
/**
* insert the given text at the caret position into the text
* @param text
*/
function insertTextAtPosition(text: string){
let textarea = markdownEditor.value.getTextareaDom()
let position = textarea.selectionStart
if (step.value.instruction){
step.value.instruction = step.value.instruction.slice(0, position) + text + step.value.instruction.slice(position)
nextTick(() => {
textarea.focus()
textarea.selectionStart = position + text.length
textarea.selectionEnd = position + text.length
})
}
}
const md_editor_toolbars = {
bold: true,
italic: true,

View File

@@ -17,8 +17,8 @@
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate && !modelClass.model.disableDelete" :disabled="loading">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" :model-name="$t(modelClass.model.localizationKey)" @delete="emit('delete')"></delete-confirm-dialog>
</v-btn>
<v-btn color="save" prepend-icon="$create" @click="emit('save')" v-if="!isUpdate && !modelClass.model.disableCreate" :disabled="loading">{{ $t('Create') }}</v-btn>
<v-btn color="save" prepend-icon="$save" @click="emit('save')" v-if="isUpdate && !modelClass.model.disableUpdate" :disabled="loading">{{ $t('Save') }}</v-btn>
<v-btn color="save" prepend-icon="$create" @click="emit('save')" v-if="!isUpdate && !modelClass.model.disableCreate" :loading="loading">{{ $t('Create') }}</v-btn>
<v-btn color="save" prepend-icon="$save" @click="emit('save')" v-if="isUpdate && !modelClass.model.disableUpdate" :loading="loading"> {{ $t('Save') }}</v-btn>
</v-card-actions>
</v-card>

View File

@@ -28,7 +28,7 @@
<v-row>
<v-col cols="12" md="6">
<v-file-upload v-model="file" @update:modelValue="updateUserFileName"
<v-file-upload v-model="file"
:title="(mobile) ? $t('Select_File') : $t('DragToUpload')"
:browse-text="$t('Select_File')"
:divider-text="$t('or')"

View File

@@ -5,6 +5,7 @@
<v-card>
<v-card-text class="pt-2 pb-2">
<v-btn variant="flat" @click="router.go(-1)" prepend-icon="fa-solid fa-arrow-left">{{ $t('Back') }}</v-btn>
<v-btn variant="flat" @click="router.push({name : 'RecipeViewPage', params: {id: props.id}})" class="float-right" prepend-icon="fa-solid fa-eye" v-if="props.id && model.toLowerCase() == 'recipe'">{{$t('View')}}</v-btn>
</v-card-text>
</v-card>
</v-col>
@@ -21,7 +22,7 @@
import {useRouter} from "vue-router";
import {EditorSupportedModels, getGenericModelFromString} from "@/types/Models";
import {defineAsyncComponent, onMounted, PropType, shallowRef} from "vue";
import {defineAsyncComponent, onMounted, PropType, shallowRef, watch} from "vue";
import {useI18n} from "vue-i18n";
const {t} = useI18n()
@@ -35,6 +36,13 @@ const editorComponent = shallowRef(defineAsyncComponent(() => import(`@/componen
const router = useRouter()
//TODO quick hack for some edge cases, move to proper reinitialization of all model editors should this case occur (currently only recipe editor create new via navigation btn)
watch(() => props.id, (newValue, oldValue) => {
if(newValue != oldValue){
location.reload()
}
})
/**
* after creation open object with correct URL in edit mode
* @param obj obj that was created

View File

@@ -1,27 +1,16 @@
<template>
<v-container>
<v-row>
<v-col>
<v-text-field v-model="dateTest1" label="Test 1 - text field type date" type="date"></v-text-field>
<p>Test P1</p>
<p>Test 2P</p>
<ol>
<li>Test 1</li>
<li>Test 2</li>
<li>Test 3</li>
</ol>
<p>Text Bla Bla3</p>
</v-col>
<v-col>
{{ dateTest1 }}
</v-col>
</v-row>
<v-row>
<v-col>
<v-date-input v-model="dateTest2" label="Test 2 - date input"></v-date-input>
</v-col>
<v-col> {{ dateTest2 }}</v-col>
</v-row>
<v-row>
<v-col>
<v-date-input v-model="dateTest3" label="Test 3 - date input with routeQueryModel"></v-date-input>
</v-col>
<v-col> {{ dateTest3 }}</v-col>
</v-row>
@@ -36,50 +25,6 @@ import {useRouteQuery} from "@vueuse/router";
import {DateTime} from "luxon";
const dateTest1 = ref(null)
const dateTest2 = ref(null)
const dateTest3 = useRouteQuery('cookedonGte', null, {
transform: {
get: (value: string | null | Date) => {
if (value == null) {
console.log('get null')
return null
} else {
console.log('get', new Date(value), (new Date(value)).getMonth())
return new Date(value)
}
},
set: value => {
if (value == null) {
console.log('-- set null')
return null
} else {
console.log('-- set', DateTime.fromJSDate(new Date(value)).toISODate())
return DateTime.fromJSDate(new Date(value)).toISODate()
}
}
}
})
const typeOfDateTest1 = computed(() => {
return dateTest1 instanceof Date
})
const typeOfDateTest2 = computed(() => {
return dateTest2 instanceof Date
})
watch(dateTest1, () => {
console.log(dateTest1.value, dateTest1.value.getMonth())
})
watch(dateTest2, () => {
console.log(dateTest2.value, dateTest2.value.getMonth())
})
</script>