parsley/app/javascript/components/RecipeEdit.vue
2024-10-02 16:20:07 -05:00

265 lines
6.4 KiB
Vue

<template>
<div class="recipe-edit">
<template v-if="!forLogging">
<div class="columns">
<div class="column">
<app-text-field label="Name" v-model="recipe.name"></app-text-field>
</div>
<div class="column">
<app-text-field label="Source" v-model="recipe.source"></app-text-field>
</div>
</div>
<app-text-field label="Description" type="textarea" v-model="recipe.description"></app-text-field>
<div class="field">
<label class="label is-small-mobile">Tags</label>
<app-tag-editor v-model="recipe.tags"></app-tag-editor>
</div>
</template>
<div class="columns">
<div class="column">
<app-text-field label="Yields" v-model="recipe.yields"></app-text-field>
</div>
<div class="column">
<app-text-field label="Total Time" type="number" v-model="recipe.total_time"></app-text-field>
</div>
<div class="column">
<app-text-field label="Active Time" v-model="recipe.active_time"></app-text-field>
</div>
</div>
<recipe-edit-ingredient-editor :ingredients="recipe.ingredients"></recipe-edit-ingredient-editor>
<br>
<div class="field">
<label class="label title is-4">Directions <button @click="isDescriptionHelpOpen = true" class="button is-small is-link"><app-icon icon="question-mark"></app-icon></button></label>
<div class="control columns">
<div class="column">
<textarea ref="step_text_area" class="textarea directions-input" v-model="recipe.step_text"></textarea>
</div>
<div class="column">
<div class="box content" v-html="stepPreview">
</div>
</div>
</div>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" v-model="recipe.is_ingredient" />
Is Ingredient
</label>
</div>
<app-modal title="Markdown Help" :open="isDescriptionHelpOpen" @dismiss="isDescriptionHelpOpen = false">
<p>
The description editor uses <a href="https://www.markdownguide.org/cheat-sheet/">Markdown</a>. Follow the link for a full
description of the syntax, but below is a quick reference.
</p>
<table class="table">
<thead>
<tr>
<th>Style</th>
<th>Syntax</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>Heading</td>
<td>
<pre>
# Biggest Heading
## Smaller Heading
###### Smallest Heading
</pre>
</td>
<td class="content">
<h1>Biggest Heading</h1>
<h2>Smaller Heading</h2>
<h6>Smallest Heading</h6>
</td>
</tr>
<tr>
<td>Numbered Lists</td>
<td>
<pre>
1. First Item
1. Second Item
1. subitem A
1. subitem B
1. Thrid Item
</pre>
</td>
<td class="content">
<ol>
<li>First Item</li>
<li>Second Item
<ol>
<li>subitem A</li>
<li>subitem B</li>
</ol>
</li>
<li>Thrid Item</li>
</ol>
</td>
</tr>
<tr>
<td>Lists</td>
<td>
<pre>
* First Item
* Second Item
* subitem A
* subitem B
* Third Item
</pre>
</td>
<td class="content">
<ul>
<li>First Item</li>
<li>Second Item
<ul>
<li>subitem A</li>
<li>subitem B</li>
</ul></li>
<li>Third Item</li>
</ul>
</td>
</tr>
<tr>
<td>Basic Styles</td>
<td>
<pre>
*italics*
**bold**
***bold italics***
_underline_
==highlight==
</pre>
</td>
<td class="content">
<p>
<em>italics</em><br>
<strong>bold</strong><br>
<strong><em>bold italics</em></strong><br>
<u>underline</u><br>
<mark>highlight</mark>
</p>
</td>
</tr>
</tbody>
</table>
<h3 class="title is-3">Basic Example</h3>
<h5 class="subtitle is=3">Input</h5>
<pre>
## For the dough
1. Mix dry ingredients
1. Fold in egg whites
1. Sprinkle on sardines
## For the sauce
1. Blend clams ==thoroughly==
1. Melt beef lard and add clam slurry
### Optional (Toppings)
* Raw onion
* Sliced hard boiled eggs
</pre>
<h5 class="subtitle is=3">Output</h5>
<div class="content box">
<h2>For the dough</h2>
<ol>
<li>Mix dry ingredients</li>
<li>Fold in egg whites</li>
<li>Sprinkle on sardines</li>
</ol>
<h2>For the sauce</h2>
<ol>
<li>Blend clams <mark>thoroughly</mark></li>
<li>Melt beef lard and add clam slurry</li>
</ol>
<h3>Optional (Toppings)</h3>
<ul>
<li>Raw onion</li>
<li>Sliced hard boiled eggs</li>
</ul>
</div>
</app-modal>
</div>
</template>
<script setup>
import { computed, ref, useTemplateRef, watch } from "vue";
import { useAutosize } from "../lib/useAutosize";
import debounce from "lodash/debounce";
import api from "../lib/Api";
import RecipeEditIngredientEditor from "./RecipeEditIngredientEditor";
const props = defineProps({
recipe: {
required: true,
type: Object
},
forLogging: {
required: false,
type: Boolean,
default: false
}
});
const stepTextArea = useTemplateRef("step_text_area");
const stepPreviewCache = ref(null);
const isDescriptionHelpOpen = ref(false);
useAutosize(stepTextArea);
const stepPreview = computed(() => {
if (stepPreviewCache.value === null) {
return props.recipe.rendered_steps;
} else {
return stepPreviewCache.value;
}
});
const updatePreview = debounce(function() {
api.postPreviewSteps(props.recipe.step_text)
.then(data => stepPreviewCache.value = data.rendered_steps)
.catch(err => stepPreviewCache.value = "?? Error ??");
}, 750);
watch(
() => props.recipe.step_text,
() => updatePreview()
);
</script>
<style lang="scss" scoped>
.recipe-edit {
margin-bottom: 1rem;
}
.directions-input {
height: 100%;
}
</style>