mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-09 03:04:54 -04:00
ux: unify UI based on user-feedback (#1216)
* unify UI based on user-feedback * fix layout shify error * implement drag and drop animation
This commit is contained in:
parent
8f1c082d79
commit
4fe19b88ca
@ -24,19 +24,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</v-expand-transition>
|
</v-expand-transition>
|
||||||
</RecipeCardImage>
|
</RecipeCardImage>
|
||||||
<v-card-title class="my-n3 mb-n6">
|
<v-card-title class="my-n3 px-2 mb-n6">
|
||||||
<div class="headerClass">
|
<div class="headerClass">
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</div>
|
</div>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<slot name="actions">
|
<slot name="actions">
|
||||||
<v-card-actions>
|
<v-card-actions class="px-1">
|
||||||
<RecipeFavoriteBadge v-if="loggedIn" :slug="slug" show-always />
|
<RecipeFavoriteBadge v-if="loggedIn" class="absolute" :slug="slug" show-always />
|
||||||
<RecipeRating :value="rating" :name="name" :slug="slug" :small="true" />
|
|
||||||
|
<RecipeRating class="pb-1" :value="rating" :name="name" :slug="slug" :small="true" />
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<RecipeChips :truncate="true" :items="tags" :title="false" :limit="2" :small="true" url-prefix="tags" />
|
<RecipeChips :truncate="true" :items="tags" :title="false" :limit="2" :small="true" url-prefix="tags" />
|
||||||
<RecipeContextMenu
|
<RecipeContextMenu
|
||||||
|
color="grey darken-2"
|
||||||
:slug="slug"
|
:slug="slug"
|
||||||
:name="name"
|
:name="name"
|
||||||
:recipe-id="recipeId"
|
:recipe-id="recipeId"
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, reactive, toRefs, useContext } from "@nuxtjs/composition-api";
|
import { defineComponent, reactive, toRefs, useContext } from "@nuxtjs/composition-api";
|
||||||
|
import colors from "vuetify/lib/util/colors";
|
||||||
import { useUserApi } from "~/composables/api";
|
import { useUserApi } from "~/composables/api";
|
||||||
|
|
||||||
export interface ContextMenuIncludes {
|
export interface ContextMenuIncludes {
|
||||||
@ -91,7 +92,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "primary",
|
default: colors.grey.darken2,
|
||||||
},
|
},
|
||||||
slug: {
|
slug: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-app-bar dark color="primary" class="mt-n1 mb-3">
|
<v-app-bar dense dark color="primary" class="mb-2">
|
||||||
<v-icon large left>
|
<v-icon large left>
|
||||||
{{ $globals.icons.createAlt }}
|
{{ $globals.icons.createAlt }}
|
||||||
</v-icon>
|
</v-icon>
|
||||||
@ -21,34 +21,26 @@
|
|||||||
v-model="inputText"
|
v-model="inputText"
|
||||||
outlined
|
outlined
|
||||||
rows="12"
|
rows="12"
|
||||||
|
hide-details
|
||||||
:placeholder="$t('new-recipe.paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list')"
|
:placeholder="$t('new-recipe.paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list')"
|
||||||
>
|
>
|
||||||
</v-textarea>
|
</v-textarea>
|
||||||
<v-tooltip top>
|
|
||||||
<template #activator="{ on, attrs }">
|
|
||||||
<v-btn outlined color="info" small v-bind="attrs" @click="trimAllLines" v-on="on">
|
|
||||||
Trim Whitespace
|
|
||||||
</v-btn>
|
|
||||||
</template>
|
|
||||||
<span> Trim leading and trailing whitespace as well as blank lines </span>
|
|
||||||
</v-tooltip>
|
|
||||||
|
|
||||||
<v-tooltip top>
|
<v-divider></v-divider>
|
||||||
<template #activator="{ on, attrs }">
|
<template v-for="(util, idx) in utilities">
|
||||||
<v-btn class="ml-1" outlined color="info" small v-bind="attrs" @click="removeFirstCharacter" v-on="on">
|
<v-list-item :key="util.id" dense class="py-1">
|
||||||
Trim Prefix
|
<v-list-item-title>
|
||||||
</v-btn>
|
<v-list-item-subtitle class="wrap-word">
|
||||||
</template>
|
{{ util.description }}
|
||||||
<span> Trim first character from each line </span>
|
</v-list-item-subtitle>
|
||||||
</v-tooltip>
|
</v-list-item-title>
|
||||||
<v-tooltip top>
|
<BaseButton small color="info" @click="util.action">
|
||||||
<template #activator="{ on, attrs }">
|
<template #icon> {{ $globals.icons.robot }}</template>
|
||||||
<v-btn class="ml-1" outlined color="info" small v-bind="attrs" @click="splitByNumberedLine" v-on="on">
|
Run
|
||||||
Split By Numbered Line
|
</BaseButton>
|
||||||
</v-btn>
|
</v-list-item>
|
||||||
</template>
|
<v-divider :key="`divider-${idx}`" class="mx-2"></v-divider>
|
||||||
<span> Attempts to split a paragraph by matching 1) or 1. patterns </span>
|
</template>
|
||||||
</v-tooltip>
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
@ -64,7 +56,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { reactive, toRefs, defineComponent } from "@nuxtjs/composition-api";
|
import { reactive, toRefs, defineComponent, useContext } from "@nuxtjs/composition-api";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup(_, context) {
|
setup(_, context) {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@ -78,7 +70,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
function removeFirstCharacter() {
|
function removeFirstCharacter() {
|
||||||
state.inputText = splitText()
|
state.inputText = splitText()
|
||||||
.map((line) => line.substr(1))
|
.map((line) => line.substring(1))
|
||||||
.join("\n");
|
.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +101,28 @@ export default defineComponent({
|
|||||||
state.dialog = false;
|
state.dialog = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { i18n } = useContext();
|
||||||
|
|
||||||
|
const utilities = [
|
||||||
|
{
|
||||||
|
id: "trim-whitespace",
|
||||||
|
description: i18n.tc("new-recipe.trim-whitespace-description"),
|
||||||
|
action: trimAllLines,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "trim-prefix",
|
||||||
|
description: i18n.tc("new-recipe.trim-prefix-description"),
|
||||||
|
action: removeFirstCharacter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "split-by-numbered-line",
|
||||||
|
description: i18n.tc("new-recipe.split-by-numbered-line-description"),
|
||||||
|
action: splitByNumberedLine,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
utilities,
|
||||||
splitText,
|
splitText,
|
||||||
trimAllLines,
|
trimAllLines,
|
||||||
removeFirstCharacter,
|
removeFirstCharacter,
|
||||||
|
@ -21,18 +21,12 @@
|
|||||||
type="number"
|
type="number"
|
||||||
placeholder="Quantity"
|
placeholder="Quantity"
|
||||||
>
|
>
|
||||||
<v-icon
|
<v-icon v-if="$listeners && $listeners.delete" slot="prepend" class="mr-n1 handle">
|
||||||
v-if="$listeners && $listeners.delete"
|
{{ $globals.icons.arrowUpDown }}
|
||||||
slot="prepend"
|
|
||||||
class="mr-n1"
|
|
||||||
color="error"
|
|
||||||
@click="$emit('delete')"
|
|
||||||
>
|
|
||||||
{{ $globals.icons.delete }}
|
|
||||||
</v-icon>
|
</v-icon>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col v-if="!disableAmount && units" sm="12" md="3" cols="12">
|
<v-col v-if="!disableAmount" sm="12" md="3" cols="12">
|
||||||
<v-autocomplete
|
<v-autocomplete
|
||||||
v-model="value.unit"
|
v-model="value.unit"
|
||||||
:search-input.sync="unitSearch"
|
:search-input.sync="unitSearch"
|
||||||
@ -40,7 +34,7 @@
|
|||||||
dense
|
dense
|
||||||
solo
|
solo
|
||||||
return-object
|
return-object
|
||||||
:items="units"
|
:items="units || []"
|
||||||
item-text="name"
|
item-text="name"
|
||||||
class="mx-1"
|
class="mx-1"
|
||||||
placeholder="Choose Unit"
|
placeholder="Choose Unit"
|
||||||
@ -59,7 +53,7 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- Foods Input -->
|
<!-- Foods Input -->
|
||||||
<v-col v-if="!disableAmount && foods" m="12" md="3" cols="12" class="">
|
<v-col v-if="!disableAmount" m="12" md="3" cols="12" class="">
|
||||||
<v-autocomplete
|
<v-autocomplete
|
||||||
v-model="value.food"
|
v-model="value.food"
|
||||||
:search-input.sync="foodSearch"
|
:search-input.sync="foodSearch"
|
||||||
@ -67,7 +61,7 @@
|
|||||||
dense
|
dense
|
||||||
solo
|
solo
|
||||||
return-object
|
return-object
|
||||||
:items="foods"
|
:items="foods || []"
|
||||||
item-text="name"
|
item-text="name"
|
||||||
class="mx-1 py-0"
|
class="mx-1 py-0"
|
||||||
placeholder="Choose Food"
|
placeholder="Choose Food"
|
||||||
@ -85,28 +79,34 @@
|
|||||||
</v-autocomplete>
|
</v-autocomplete>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col sm="12" md="" cols="12">
|
<v-col sm="12" md="" cols="12">
|
||||||
<v-text-field v-model="value.note" hide-details dense solo class="mx-1" placeholder="Notes">
|
<div class="d-flex">
|
||||||
<v-icon v-if="disableAmount" slot="prepend" class="mr-n1" color="error" @click="$emit('delete')">
|
<v-text-field v-model="value.note" hide-details dense solo class="mx-1" placeholder="Notes">
|
||||||
{{ $globals.icons.delete }}
|
<v-icon v-if="disableAmount && $listeners && $listeners.delete" slot="prepend" class="mr-n1 handle">
|
||||||
</v-icon>
|
{{ $globals.icons.arrowUpDown }}
|
||||||
|
</v-icon>
|
||||||
<template slot="append-outer">
|
</v-text-field>
|
||||||
<BaseButtonGroup
|
<BaseButtonGroup
|
||||||
:large="false"
|
hover
|
||||||
class="handle my-auto"
|
:large="false"
|
||||||
:buttons="[
|
class="my-auto"
|
||||||
{
|
:buttons="[
|
||||||
icon: $globals.icons.arrowUpDown,
|
{
|
||||||
text: '',
|
icon: $globals.icons.delete,
|
||||||
event: 'open',
|
text: 'Delete',
|
||||||
children: contextMenuOptions,
|
event: 'delete',
|
||||||
},
|
},
|
||||||
]"
|
{
|
||||||
@toggle-section="toggleTitle"
|
icon: $globals.icons.dotsVertical,
|
||||||
@toggle-original="toggleOriginalText"
|
text: 'Menu',
|
||||||
/>
|
event: 'open',
|
||||||
</template>
|
children: contextMenuOptions,
|
||||||
</v-text-field>
|
},
|
||||||
|
]"
|
||||||
|
@toggle-section="toggleTitle"
|
||||||
|
@toggle-original="toggleOriginalText"
|
||||||
|
@delete="$emit('delete')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<p v-if="showOriginalText" class="text-caption">Original Text: {{ value.originalText }}</p>
|
<p v-if="showOriginalText" class="text-caption">Original Text: {{ value.originalText }}</p>
|
||||||
|
@ -71,116 +71,126 @@
|
|||||||
:disabled="!edit"
|
:disabled="!edit"
|
||||||
:value="value"
|
:value="value"
|
||||||
handle=".handle"
|
handle=".handle"
|
||||||
|
v-bind="{
|
||||||
|
animation: 200,
|
||||||
|
group: 'description',
|
||||||
|
ghostClass: 'ghost',
|
||||||
|
}"
|
||||||
@input="updateIndex"
|
@input="updateIndex"
|
||||||
@start="drag = true"
|
@start="drag = true"
|
||||||
@end="drag = false"
|
@end="drag = false"
|
||||||
>
|
>
|
||||||
<div v-for="(step, index) in value" :key="step.id">
|
<TransitionGroup type="transition" :name="!drag ? 'flip-list' : ''">
|
||||||
<v-app-bar
|
<div v-for="(step, index) in value" :key="step.id" class="list-group-item">
|
||||||
v-if="showTitleEditor[step.id]"
|
<v-app-bar
|
||||||
class="primary mx-1 mt-6"
|
v-if="showTitleEditor[step.id]"
|
||||||
style="cursor: pointer"
|
class="primary mx-1 mt-6"
|
||||||
dark
|
style="cursor: pointer"
|
||||||
dense
|
dark
|
||||||
rounded
|
|
||||||
@click="toggleCollapseSection(index)"
|
|
||||||
>
|
|
||||||
<v-toolbar-title v-if="!edit" class="headline">
|
|
||||||
<v-app-bar-title v-text="step.title"> </v-app-bar-title>
|
|
||||||
</v-toolbar-title>
|
|
||||||
<v-text-field
|
|
||||||
v-if="edit"
|
|
||||||
v-model="step.title"
|
|
||||||
class="headline pa-0 mt-5"
|
|
||||||
dense
|
dense
|
||||||
solo
|
rounded
|
||||||
flat
|
@click="toggleCollapseSection(index)"
|
||||||
:placeholder="$t('recipe.section-title')"
|
|
||||||
background-color="primary"
|
|
||||||
>
|
>
|
||||||
</v-text-field>
|
<v-toolbar-title v-if="!edit" class="headline">
|
||||||
</v-app-bar>
|
<v-app-bar-title v-text="step.title"> </v-app-bar-title>
|
||||||
<v-hover v-slot="{ hover }">
|
</v-toolbar-title>
|
||||||
<v-card
|
<v-text-field
|
||||||
class="ma-1"
|
v-if="edit"
|
||||||
:class="[{ 'on-hover': hover }, isChecked(index)]"
|
v-model="step.title"
|
||||||
:elevation="hover ? 12 : 2"
|
class="headline pa-0 mt-5"
|
||||||
:ripple="false"
|
dense
|
||||||
@click="toggleDisabled(index)"
|
solo
|
||||||
>
|
flat
|
||||||
<v-card-title :class="{ 'pb-0': !isChecked(index) }">
|
:placeholder="$t('recipe.section-title')"
|
||||||
<v-btn v-if="edit" fab x-small color="white" class="mr-2" elevation="0" @click="value.splice(index, 1)">
|
background-color="primary"
|
||||||
<v-icon size="24" color="error">{{ $globals.icons.delete }}</v-icon>
|
>
|
||||||
</v-btn>
|
</v-text-field>
|
||||||
|
</v-app-bar>
|
||||||
{{ $t("recipe.step-index", { step: index + 1 }) }}
|
<v-hover v-slot="{ hover }">
|
||||||
|
<v-card
|
||||||
<template v-if="edit">
|
class="ma-1"
|
||||||
<v-icon class="handle ml-auto mr-2">{{ $globals.icons.arrowUpDown }}</v-icon>
|
:class="[{ 'on-hover': hover }, isChecked(index)]"
|
||||||
<div>
|
:elevation="hover ? 12 : 2"
|
||||||
<BaseButtonGroup
|
:ripple="false"
|
||||||
:buttons="[
|
@click="toggleDisabled(index)"
|
||||||
{
|
>
|
||||||
icon: $globals.icons.dotsVertical,
|
<v-card-title :class="{ 'pb-0': !isChecked(index) }">
|
||||||
text: '',
|
<span class="handle">
|
||||||
event: 'open',
|
<v-icon v-if="edit" size="26" class="pb-1">{{ $globals.icons.arrowUpDown }}</v-icon>
|
||||||
children: [
|
{{ $t("recipe.step-index", { step: index + 1 }) }}
|
||||||
{
|
</span>
|
||||||
text: 'Toggle Section',
|
<template v-if="edit">
|
||||||
event: 'toggle-section',
|
<div class="ml-auto">
|
||||||
},
|
<BaseButtonGroup
|
||||||
{
|
:large="false"
|
||||||
text: 'Link Ingredients',
|
:buttons="[
|
||||||
event: 'link-ingredients',
|
{
|
||||||
},
|
icon: $globals.icons.delete,
|
||||||
{
|
text: $tc('general.delete'),
|
||||||
text: 'Merge Above',
|
event: 'delete',
|
||||||
event: 'merge-above',
|
},
|
||||||
},
|
{
|
||||||
],
|
icon: $globals.icons.dotsVertical,
|
||||||
},
|
text: '',
|
||||||
{
|
event: 'open',
|
||||||
icon: previewStates[index] ? $globals.icons.edit : $globals.icons.eye,
|
children: [
|
||||||
text: previewStates[index] ? $tc('general.edit') : 'Preview Markdown',
|
{
|
||||||
event: 'preview-step',
|
text: 'Toggle Section',
|
||||||
},
|
event: 'toggle-section',
|
||||||
]"
|
},
|
||||||
@merge-above="mergeAbove(index - 1, index)"
|
{
|
||||||
@toggle-section="toggleShowTitle(step.id)"
|
text: 'Link Ingredients',
|
||||||
@link-ingredients="openDialog(index, step.ingredientReferences, step.text)"
|
event: 'link-ingredients',
|
||||||
@preview-step="togglePreviewState(index)"
|
},
|
||||||
/>
|
{
|
||||||
|
text: 'Merge Above',
|
||||||
|
event: 'merge-above',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: previewStates[index] ? $globals.icons.edit : $globals.icons.eye,
|
||||||
|
text: previewStates[index] ? 'Edit Markdown' : 'Preview Markdown',
|
||||||
|
event: 'preview-step',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
@merge-above="mergeAbove(index - 1, index)"
|
||||||
|
@toggle-section="toggleShowTitle(step.id)"
|
||||||
|
@link-ingredients="openDialog(index, step.ingredientReferences, step.text)"
|
||||||
|
@preview-step="togglePreviewState(index)"
|
||||||
|
@delete="value.splice(index, 1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<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">
|
||||||
|
<MarkdownEditor
|
||||||
|
v-model="value[index]['text']"
|
||||||
|
:preview.sync="previewStates[index]"
|
||||||
|
:display-preview="false"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-for="ing in step.ingredientReferences"
|
||||||
|
:key="ing.referenceId"
|
||||||
|
v-html="getIngredientByRefId(ing.referenceId)"
|
||||||
|
/>
|
||||||
|
</v-card-text>
|
||||||
|
<v-expand-transition>
|
||||||
|
<div v-show="!isChecked(index) && !edit" class="m-0 p-0">
|
||||||
|
<v-card-text class="markdown">
|
||||||
|
<VueMarkdown class="markdown" :source="step.text"> </VueMarkdown>
|
||||||
|
</v-card-text>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</v-expand-transition>
|
||||||
|
</v-card>
|
||||||
<v-fade-transition>
|
</v-hover>
|
||||||
<v-icon v-show="isChecked(index)" size="24" class="ml-auto" color="success">
|
</div>
|
||||||
{{ $globals.icons.checkboxMarkedCircle }}
|
</TransitionGroup>
|
||||||
</v-icon>
|
|
||||||
</v-fade-transition>
|
|
||||||
</v-card-title>
|
|
||||||
<v-card-text v-if="edit">
|
|
||||||
<MarkdownEditor
|
|
||||||
v-model="value[index]['text']"
|
|
||||||
:preview.sync="previewStates[index]"
|
|
||||||
:display-preview="false"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
v-for="ing in step.ingredientReferences"
|
|
||||||
:key="ing.referenceId"
|
|
||||||
v-html="getIngredientByRefId(ing.referenceId)"
|
|
||||||
/>
|
|
||||||
</v-card-text>
|
|
||||||
<v-expand-transition>
|
|
||||||
<div v-show="!isChecked(index) && !edit" class="m-0 p-0">
|
|
||||||
<v-card-text class="markdown">
|
|
||||||
<VueMarkdown class="markdown" :source="step.text"> </VueMarkdown>
|
|
||||||
</v-card-text>
|
|
||||||
</div>
|
|
||||||
</v-expand-transition>
|
|
||||||
</v-card>
|
|
||||||
</v-hover>
|
|
||||||
</div>
|
|
||||||
</draggable>
|
</draggable>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
@ -481,7 +491,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const drag = ref(false);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
drag,
|
||||||
togglePreviewState,
|
togglePreviewState,
|
||||||
toggleCollapseSection,
|
toggleCollapseSection,
|
||||||
previewStates,
|
previewStates,
|
||||||
@ -521,4 +534,23 @@ export default defineComponent({
|
|||||||
.markdown >>> ol > li {
|
.markdown >>> ol > li {
|
||||||
display: list-item;
|
display: list-item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flip-list-move {
|
||||||
|
transition: transform 0.5s;
|
||||||
|
}
|
||||||
|
.no-move {
|
||||||
|
transition: transform 0s;
|
||||||
|
}
|
||||||
|
.ghost {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.list-group {
|
||||||
|
min-height: 38px;
|
||||||
|
}
|
||||||
|
.list-group-item {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
.list-group-item i {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,29 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="value.length > 0 || edit">
|
<div v-if="value.length > 0 || edit" class="mt-8">
|
||||||
<h2 class="my-4">{{ $t("recipe.note") }}</h2>
|
<h2 class="my-4">{{ $t("recipe.note") }}</h2>
|
||||||
<v-card v-for="(note, index) in value" :key="'note' + index" class="mt-1">
|
<div v-for="(note, index) in value" :key="'note' + index" class="mt-1">
|
||||||
<div v-if="edit">
|
<v-card v-if="edit">
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row align="center">
|
<div class="d-flex align-center">
|
||||||
<v-btn fab x-small color="white" class="mr-2" elevation="0" @click="removeByIndex(value, index)">
|
<v-text-field v-model="value[index]['title']" :label="$t('recipe.title')" />
|
||||||
<v-icon color="error">{{ $globals.icons.delete }}</v-icon>
|
<v-btn icon class="mr-2" elevation="0" @click="removeByIndex(value, index)">
|
||||||
|
<v-icon>{{ $globals.icons.delete }}</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-text-field v-model="value[index]['title']" :label="$t('recipe.title')"></v-text-field>
|
</div>
|
||||||
</v-row>
|
<v-textarea v-model="value[index]['text']" auto-grow :placeholder="$t('recipe.note')" />
|
||||||
|
|
||||||
<v-textarea v-model="value[index]['text']" auto-grow :placeholder="$t('recipe.note')"> </v-textarea>
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</div>
|
</v-card>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<v-card-title class="py-2">
|
<v-card-title class="text-subtitle-1 font-weight-medium py-1">
|
||||||
{{ note.title }}
|
{{ note.title }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-divider class="mx-2"></v-divider>
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<VueMarkdown :source="note.text"> </VueMarkdown>
|
<VueMarkdown :source="note.text"> </VueMarkdown>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</div>
|
</div>
|
||||||
</v-card>
|
</div>
|
||||||
|
|
||||||
<div v-if="edit" class="d-flex justify-end">
|
<div v-if="edit" class="d-flex justify-end">
|
||||||
<BaseButton class="ml-auto my-2" @click="addNote"> {{ $t("general.new") }}</BaseButton>
|
<BaseButton class="ml-auto my-2" @click="addNote"> {{ $t("general.new") }}</BaseButton>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-item-group>
|
<v-item-group>
|
||||||
<template v-for="btn in buttons">
|
<template v-for="btn in buttons">
|
||||||
<v-menu v-if="btn.children" :key="'menu-' + btn.event" active-class="pa-0" offset-x left>
|
<v-menu v-if="btn.children" :key="'menu-' + btn.event" active-class="pa-0" offset-y top left>
|
||||||
<template #activator="{ on, attrs }">
|
<template #activator="{ on, attrs }">
|
||||||
<v-btn tile :large="large" icon v-bind="attrs" v-on="on">
|
<v-btn tile :large="large" icon v-bind="attrs" v-on="on">
|
||||||
<v-icon>
|
<v-icon>
|
||||||
|
@ -215,7 +215,10 @@
|
|||||||
"upload-a-recipe": "Upload a Recipe",
|
"upload-a-recipe": "Upload a Recipe",
|
||||||
"upload-individual-zip-file": "Upload an individual .zip file exported from another Mealie instance.",
|
"upload-individual-zip-file": "Upload an individual .zip file exported from another Mealie instance.",
|
||||||
"url-form-hint": "Copy and paste a link from your favorite recipe website",
|
"url-form-hint": "Copy and paste a link from your favorite recipe website",
|
||||||
"view-scraped-data": "View Scraped Data"
|
"view-scraped-data": "View Scraped Data",
|
||||||
|
"trim-whitespace-description": "Trim leading and trailing whitespace as well as blank lines",
|
||||||
|
"trim-prefix-description": "Trim first character from each line",
|
||||||
|
"split-by-numbered-line-description": "Attempts to split a paragraph by matching '1)' or '1.' patterns"
|
||||||
},
|
},
|
||||||
"page": {
|
"page": {
|
||||||
"404-page-not-found": "404 Page not found",
|
"404-page-not-found": "404 Page not found",
|
||||||
|
@ -127,14 +127,29 @@
|
|||||||
<!-- Advanced Editor -->
|
<!-- Advanced Editor -->
|
||||||
<div v-if="form">
|
<div v-if="form">
|
||||||
<h2 class="mb-4">{{ $t("recipe.ingredients") }}</h2>
|
<h2 class="mb-4">{{ $t("recipe.ingredients") }}</h2>
|
||||||
<draggable v-if="recipe.recipeIngredient.length > 0" v-model="recipe.recipeIngredient" handle=".handle">
|
<draggable
|
||||||
<RecipeIngredientEditor
|
v-if="recipe.recipeIngredient.length > 0"
|
||||||
v-for="(ingredient, index) in recipe.recipeIngredient"
|
v-model="recipe.recipeIngredient"
|
||||||
:key="ingredient.referenceId"
|
handle=".handle"
|
||||||
v-model="recipe.recipeIngredient[index]"
|
v-bind="{
|
||||||
:disable-amount="recipe.settings.disableAmount"
|
animation: 200,
|
||||||
@delete="recipe.recipeIngredient.splice(index, 1)"
|
group: 'description',
|
||||||
/>
|
disabled: false,
|
||||||
|
ghostClass: 'ghost',
|
||||||
|
}"
|
||||||
|
@start="drag = true"
|
||||||
|
@end="drag = false"
|
||||||
|
>
|
||||||
|
<TransitionGroup type="transition" :name="!drag ? 'flip-list' : ''">
|
||||||
|
<RecipeIngredientEditor
|
||||||
|
v-for="(ingredient, index) in recipe.recipeIngredient"
|
||||||
|
:key="ingredient.referenceId"
|
||||||
|
v-model="recipe.recipeIngredient[index]"
|
||||||
|
class="list-group-item"
|
||||||
|
:disable-amount="recipe.settings.disableAmount"
|
||||||
|
@delete="recipe.recipeIngredient.splice(index, 1)"
|
||||||
|
/>
|
||||||
|
</TransitionGroup>
|
||||||
</draggable>
|
</draggable>
|
||||||
<v-skeleton-loader v-else boilerplate elevation="2" type="list-item"> </v-skeleton-loader>
|
<v-skeleton-loader v-else boilerplate elevation="2" type="list-item"> </v-skeleton-loader>
|
||||||
<div class="d-flex justify-end mt-2">
|
<div class="d-flex justify-end mt-2">
|
||||||
@ -355,7 +370,7 @@
|
|||||||
:tag-selector="true"
|
:tag-selector="true"
|
||||||
:show-label="false"
|
:show-label="false"
|
||||||
/>
|
/>
|
||||||
<RecipeChips v-else :items="recipe.tags" url-prefix="tags"/>
|
<RecipeChips v-else :items="recipe.tags" url-prefix="tags" />
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
@ -820,8 +835,11 @@ export default defineComponent({
|
|||||||
return "Parse ingredients";
|
return "Parse ingredients";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const drag = ref(false);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Wake Lock
|
// Wake Lock
|
||||||
|
drag,
|
||||||
wakeIsSupported,
|
wakeIsSupported,
|
||||||
isActive,
|
isActive,
|
||||||
lockScreen,
|
lockScreen,
|
||||||
@ -857,3 +875,24 @@ export default defineComponent({
|
|||||||
head: {},
|
head: {},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="css">
|
||||||
|
.flip-list-move {
|
||||||
|
transition: transform 0.5s;
|
||||||
|
}
|
||||||
|
.no-move {
|
||||||
|
transition: transform 0s;
|
||||||
|
}
|
||||||
|
.ghost {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.list-group {
|
||||||
|
min-height: 38px;
|
||||||
|
}
|
||||||
|
.list-group-item {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
.list-group-item i {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user