Does not work: uploading images
Adding/Editing/Deleting works SeasonsSelect works Nice recipe layout
This commit is contained in:
parent
3d0d3f41e2
commit
9392ff6ada
@ -19,7 +19,11 @@ background-color: var(--red);
|
|||||||
display: grid;
|
display: grid;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
.container{
|
||||||
|
margin: 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
:global(.icon_svg){
|
:global(.icon_svg){
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
|
@ -215,12 +215,19 @@ input::placeholder{
|
|||||||
color:var(--nord0);
|
color:var(--nord0);
|
||||||
}
|
}
|
||||||
.card .description{
|
.card .description{
|
||||||
|
box-sizing:border-box;
|
||||||
|
border: 2px solid var(--nord5);
|
||||||
|
border-radius: 30px;
|
||||||
padding-inline: 1em;
|
padding-inline: 1em;
|
||||||
|
padding-block: 0.5em;
|
||||||
|
margin-inline: 1em;
|
||||||
|
margin-top: 0;
|
||||||
color: var(--nord4);
|
color: var(--nord4);
|
||||||
width: calc(300px - 2em); /*??*/
|
width: calc(300px - 2em); /*??*/
|
||||||
}
|
}
|
||||||
.card .description:hover{
|
.card .description:hover{
|
||||||
color: var(--nord0);
|
color: var(--nord0);
|
||||||
|
border: 2px solid var(--nord0);
|
||||||
}
|
}
|
||||||
.card .tags{
|
.card .tags{
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -354,7 +361,7 @@ input::placeholder{
|
|||||||
<input class=category placeholder=Kategorie... bind:value={card_data.category}/>
|
<input class=category placeholder=Kategorie... bind:value={card_data.category}/>
|
||||||
<div>
|
<div>
|
||||||
<input class=name placeholder=Name... bind:value={card_data.name}/>
|
<input class=name placeholder=Name... bind:value={card_data.name}/>
|
||||||
<input class=description placeholder=Kurzbeschreibung... bind:value={card_data.description}/>
|
<p contenteditable class=description placeholder=Kurzbeschreibung... bind:innerText={card_data.description}></p>
|
||||||
</div>
|
</div>
|
||||||
<div class=tags>
|
<div class=tags>
|
||||||
{#each card_data.tags as tag}
|
{#each card_data.tags as tag}
|
||||||
|
@ -10,6 +10,7 @@ import "$lib/css/action_button.css"
|
|||||||
import { do_on_key } from '$lib/components/do_on_key.js'
|
import { do_on_key } from '$lib/components/do_on_key.js'
|
||||||
|
|
||||||
export let ingredients
|
export let ingredients
|
||||||
|
export let portions
|
||||||
|
|
||||||
let new_ingredient = {
|
let new_ingredient = {
|
||||||
amount: "",
|
amount: "",
|
||||||
@ -107,7 +108,6 @@ export function show_keys(event){
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
input::placeholder{
|
input::placeholder{
|
||||||
all:unset;
|
all:unset;
|
||||||
}
|
}
|
||||||
@ -117,6 +117,7 @@ input{
|
|||||||
|
|
||||||
input.heading{
|
input.heading{
|
||||||
all: unset;
|
all: unset;
|
||||||
|
box-sizing: border-box;
|
||||||
background-color: var(--nord0);
|
background-color: var(--nord0);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
padding-inline: 2rem;
|
padding-inline: 2rem;
|
||||||
@ -146,13 +147,14 @@ input.heading:hover{
|
|||||||
.heading_wrapper button{
|
.heading_wrapper button{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -1.5rem;
|
bottom: -1.5rem;
|
||||||
right: -5rem;
|
right: -2rem;
|
||||||
}
|
}
|
||||||
.adder{
|
.adder{
|
||||||
|
box-sizing: border-box;
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-block: 3rem;
|
margin-block: 3rem;
|
||||||
width: 400px;
|
width: 90%;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
}
|
}
|
||||||
@ -269,32 +271,11 @@ dialog h2{
|
|||||||
drop-shadow(0 0 1em black)
|
drop-shadow(0 0 1em black)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
ul{
|
|
||||||
width: fit-content;
|
|
||||||
margin-inline: auto;
|
|
||||||
}
|
|
||||||
li{
|
|
||||||
font-size: 1.2rem;
|
|
||||||
max-width: 1000px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.li_wrapper{
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.mod_icons{
|
.mod_icons{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
margin-left: 2rem;
|
margin-left: 2rem;
|
||||||
}
|
}
|
||||||
li:nth-child(2n){
|
|
||||||
background-color: var(--nord4);
|
|
||||||
|
|
||||||
}
|
|
||||||
li:nth-child(2n+1){
|
|
||||||
background-color: var(--nord6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button_subtle{
|
.button_subtle{
|
||||||
padding: 0em;
|
padding: 0em;
|
||||||
animation: unset;
|
animation: unset;
|
||||||
@ -306,16 +287,64 @@ li:nth-child(2n+1){
|
|||||||
scale: 1.2 1.2;
|
scale: 1.2 1.2;
|
||||||
}
|
}
|
||||||
h3{
|
h3{
|
||||||
margin-inline: auto;
|
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
.ingredients_grid{
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: grid;
|
||||||
|
font-size: 1.1em;
|
||||||
|
grid-template-columns: 2fr 3fr 1fr;
|
||||||
|
grid-template-rows: auto;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
align-items: center;
|
||||||
|
row-gap: 0.5em;
|
||||||
|
column-gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ingredients_grid > *{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.ingredients_grid>*:nth-child(3n+1){
|
||||||
|
min-width: 5ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list_wrapper{
|
||||||
|
padding-inline: 2em;
|
||||||
|
padding-block: 1em;
|
||||||
|
}
|
||||||
|
.list_wrapper p[contenteditable]{
|
||||||
|
border: 2px solid grey;
|
||||||
|
border-radius: 1000px;
|
||||||
|
padding: 0.25em 1em;
|
||||||
|
background-color: white;
|
||||||
|
transition: 200ms;
|
||||||
|
}
|
||||||
|
.list_wrapper p[contenteditable]:hover,
|
||||||
|
.list_wrapper p[contenteditable]:focus-within{
|
||||||
|
scale: 1.05 1.05;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 500px){
|
||||||
|
dialog h2{
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
dialog .heading_wrapper{
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
.ingredients_grid .mod_icons{
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<div class=list_wrapper>
|
||||||
|
<h4>Portionen:</h4>
|
||||||
|
<p contenteditable type="text" bind:innerText={portions}></p>
|
||||||
|
|
||||||
|
<h2>Zutaten</h2>
|
||||||
{#each ingredients as list, list_index}
|
{#each ingredients as list, list_index}
|
||||||
<h3>
|
<h3>
|
||||||
<div>
|
<div>
|
||||||
@ -329,23 +358,20 @@ h3{
|
|||||||
<button class="action_button button_subtle" on:click="{() => show_modal_edit_subheading_ingredient(list_index)}">
|
<button class="action_button button_subtle" on:click="{() => show_modal_edit_subheading_ingredient(list_index)}">
|
||||||
<Pen fill=var(--nord1)></Pen> </button>
|
<Pen fill=var(--nord1)></Pen> </button>
|
||||||
<button class="action_button button_subtle" on:click="{() => remove_list(list_index)}">
|
<button class="action_button button_subtle" on:click="{() => remove_list(list_index)}">
|
||||||
<Cross fill=var(--nord1)></Cross>
|
<Cross fill=var(--nord1)></Cross></button>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
<ul>
|
<div class=ingredients_grid>
|
||||||
{#each list.list as ingredient, ingredient_index}
|
{#each list.list as ingredient, ingredient_index}
|
||||||
<li><div class=li_wrapper><div>{ingredient.amount} {ingredient.unit} {ingredient.name}</div>
|
<div on:click={() => show_modal_edit_ingredient(list_index, ingredient_index)} >{ingredient.amount} {ingredient.unit}</div>
|
||||||
|
<div on:click={() => show_modal_edit_ingredient(list_index, ingredient_index)} >{ingredient.name}</div>
|
||||||
<div class=mod_icons><button class="action_button button_subtle" on:click={() => show_modal_edit_ingredient(list_index, ingredient_index)}>
|
<div class=mod_icons><button class="action_button button_subtle" on:click={() => show_modal_edit_ingredient(list_index, ingredient_index)}>
|
||||||
<Pen fill=var(--nord1) height=1em width=1em></Pen>
|
<Pen fill=var(--nord1) height=1em width=1em></Pen></button>
|
||||||
</button>
|
<button class="action_button button_subtle" on:click="{() => remove_ingredient(list_index, ingredient_index)}"><Cross fill=var(--nord1) height=1em width=1em></Cross></button></div>
|
||||||
<button class="action_button button_subtle" on:click="{() => remove_ingredient(list_index, ingredient_index)}">
|
|
||||||
<Cross fill=var(--nord1) height=1em width=1em></Cross>
|
|
||||||
</button></div></div>
|
|
||||||
</li>
|
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="adder shadow">
|
<div class="adder shadow">
|
||||||
<input class=category type="text" bind:value={new_ingredient.sublist} placeholder="Kategorie (optional)" on:keypress={(event) => do_on_key(event, 'Enter', false, add_new_ingredient)}>
|
<input class=category type="text" bind:value={new_ingredient.sublist} placeholder="Kategorie (optional)" on:keypress={(event) => do_on_key(event, 'Enter', false, add_new_ingredient)}>
|
||||||
@ -358,7 +384,6 @@ h3{
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<dialog id=edit_ingredient_modal>
|
<dialog id=edit_ingredient_modal>
|
||||||
<h2>Zutat verändern</h2>
|
<h2>Zutat verändern</h2>
|
||||||
<div class=adder>
|
<div class=adder>
|
||||||
|
@ -12,6 +12,7 @@ import { do_on_key } from '$lib/components/do_on_key.js'
|
|||||||
|
|
||||||
const step_placeholder = "Kartoffeln schälen..."
|
const step_placeholder = "Kartoffeln schälen..."
|
||||||
export let instructions
|
export let instructions
|
||||||
|
export let add_info
|
||||||
|
|
||||||
let new_step = {
|
let new_step = {
|
||||||
name: "",
|
name: "",
|
||||||
@ -32,6 +33,12 @@ function get_sublist_index(sublist_name, list){
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
export function remove_list(list_index){
|
export function remove_list(list_index){
|
||||||
|
if(instructions[list_index].steps.length > 1){
|
||||||
|
const response = confirm("Bist du dir sicher, dass du diese Liste löschen möchtest? Alle Zubereitungsschritte der Liste werden hiermit auch gelöscht.");
|
||||||
|
if(!response){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
instructions.splice(list_index, 1);
|
instructions.splice(list_index, 1);
|
||||||
instructions = instructions //tells svelte to update dom
|
instructions = instructions //tells svelte to update dom
|
||||||
}
|
}
|
||||||
@ -117,9 +124,23 @@ input::placeholder{
|
|||||||
all:unset;
|
all:unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
li > div{
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-items: space-between;
|
||||||
|
align-items:center;
|
||||||
|
}
|
||||||
|
li > div > div:first-child{
|
||||||
|
flex-grow: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
li > div > div:last-child{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
input.heading{
|
input.heading{
|
||||||
all: unset;
|
all: unset;
|
||||||
|
box-sizing: border-box;
|
||||||
background-color: var(--nord0);
|
background-color: var(--nord0);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
padding-inline: 2rem;
|
padding-inline: 2rem;
|
||||||
@ -139,7 +160,7 @@ input.heading:focus-visible
|
|||||||
|
|
||||||
.heading_wrapper{
|
.heading_wrapper{
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 300px;
|
width: min(300px, 95dvw);
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
}
|
}
|
||||||
@ -152,15 +173,20 @@ input.heading:focus-visible
|
|||||||
.heading_wrapper button{
|
.heading_wrapper button{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -1.5rem;
|
bottom: -1.5rem;
|
||||||
right: -5rem;
|
right: -1.5rem;
|
||||||
}
|
}
|
||||||
.adder{
|
.adder{
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-block: 3rem;
|
margin-block: 3rem;
|
||||||
width: 50ch;
|
width: 90%;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
|
background-color: var(--blue);
|
||||||
|
padding: 1.5rem 2rem;
|
||||||
|
}
|
||||||
|
dialog .adder{
|
||||||
|
width: 400px;
|
||||||
}
|
}
|
||||||
.shadow{
|
.shadow{
|
||||||
box-shadow: 0 0 1em 0.2em rgba(0,0,0,0.3);
|
box-shadow: 0 0 1em 0.2em rgba(0,0,0,0.3);
|
||||||
@ -202,17 +228,18 @@ input.heading:focus-visible
|
|||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
padding: 2rem;
|
|
||||||
padding-top: 2.5rem;
|
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
background-color: var(--blue);
|
border: 2px solid var(--nord4);
|
||||||
color: #bbb;
|
border-radius: 30px;
|
||||||
transition: 200ms;
|
padding: 0.5em 1em;
|
||||||
|
color: var(--nord4);
|
||||||
|
transition: 100ms;
|
||||||
}
|
}
|
||||||
.add_step p:hover,
|
.add_step p:hover,
|
||||||
.add_step p:focus-visible
|
.add_step p:focus-visible
|
||||||
{
|
{
|
||||||
color: white;
|
color: white;
|
||||||
|
scale: 1.02 1.02;
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog{
|
dialog{
|
||||||
@ -239,6 +266,21 @@ dialog h2{
|
|||||||
drop-shadow(0 0 1em black)
|
drop-shadow(0 0 1em black)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@media screen and (max-width: 500px){
|
||||||
|
dialog h2{
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
dialog .adder{
|
||||||
|
width: 85%;
|
||||||
|
padding-inline: 0.5em;
|
||||||
|
}
|
||||||
|
dialog .adder .category{
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
dialog .adder input::placeholder{
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
dialog[open]{
|
dialog[open]{
|
||||||
animation: show 200ms ease forwards;
|
animation: show 200ms ease forwards;
|
||||||
}
|
}
|
||||||
@ -250,10 +292,122 @@ dialog[open]{
|
|||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ol li::marker{
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--blue);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
.instructions{
|
||||||
|
flex-basis: 0;
|
||||||
|
flex-grow: 2;
|
||||||
|
background-color: var(--nord5);
|
||||||
|
padding-block: 1rem;
|
||||||
|
padding-inline: 2rem;
|
||||||
|
}
|
||||||
|
.instructions ol{
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
.instructions li{
|
||||||
|
margin-block: 0.5em;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.additional_info{
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
.additional_info > *{
|
||||||
|
flex-grow: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 1em;
|
||||||
|
background-color: #FAFAFE;
|
||||||
|
box-shadow: 0.3em 0.3em 1em 0.2em rgba(0,0,0,0.3);
|
||||||
|
/*max-width: 30%*/
|
||||||
|
}
|
||||||
|
.additional_info > div > *:not(h4){
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
h4{
|
||||||
|
line-height: 1em;
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
.button_subtle{
|
||||||
|
padding: 0em;
|
||||||
|
animation: unset;
|
||||||
|
margin: 0.2em 0.1em;
|
||||||
|
background-color: transparent;
|
||||||
|
box-shadow: unset;
|
||||||
|
display:inline;
|
||||||
|
}
|
||||||
|
.button_subtle:hover{
|
||||||
|
scale: 1.2 1.2;
|
||||||
|
}
|
||||||
|
h3{
|
||||||
|
display:flex;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
.additional_info input{
|
||||||
|
all:unset;
|
||||||
|
display: inline;
|
||||||
|
width: 10ch;
|
||||||
|
border-radius: 1000px;
|
||||||
|
border: 2px solid grey;
|
||||||
|
padding: 0em 0.5em;
|
||||||
|
}
|
||||||
|
.additional_info input::placeholder{
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
.additional_info p[contenteditable]{
|
||||||
|
display: inline;
|
||||||
|
padding: 0.25em 1em;
|
||||||
|
border: 2px solid grey;
|
||||||
|
border-radius: 1000px;
|
||||||
|
}
|
||||||
|
.additional_info div:has(p[contenteditable]){
|
||||||
|
transition: 200ms;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.additional_info div:has(p[contenteditable]):hover,
|
||||||
|
.additional_info div:has(p[contenteditable]):focus-within
|
||||||
|
{
|
||||||
|
transform: scale(1.1, 1.1);
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 500px){
|
||||||
|
dialog h2{
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
dialog .heading_wrapper{
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<div class=instructions>
|
||||||
|
<div class=additional_info>
|
||||||
|
|
||||||
|
<div><h4>Vorbereitung:</h4>
|
||||||
|
<p contenteditable type="text" bind:innerText={add_info.preparation}></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div><h4>Stockgare:</h4>
|
||||||
|
<p contenteditable type="text" bind:innerText={add_info.fermentation.bulk}></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div><h4>Stückgare:</h4>
|
||||||
|
<p contenteditable type="text" bind:innerText={add_info.fermentation.final}></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div><h4>Backen:</h4>
|
||||||
|
<div><p type="text" bind:innerText={add_info.baking.length} contenteditable placeholder="40 min..."></p></div> bei <div><p type="text" bind:innerText={add_info.baking.temperature} contenteditable placeholder=200...></p></div> °C <div><p type="text" bind:innerText={add_info.baking.mode} contenteditable placeholder="Ober-/Unterhitze..."></p></div></div>
|
||||||
|
|
||||||
|
<div><h4>Auf dem Teller:</h4>
|
||||||
|
<div><p contenteditable type="text" bind:innerText={add_info.total_time}></p></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Zubereitung</h2>
|
||||||
{#each instructions as list, list_index}
|
{#each instructions as list, list_index}
|
||||||
<h3>
|
<h3>
|
||||||
{#if list.name}
|
{#if list.name}
|
||||||
@ -261,31 +415,34 @@ dialog[open]{
|
|||||||
{:else}
|
{:else}
|
||||||
Leer
|
Leer
|
||||||
{/if}
|
{/if}
|
||||||
<button class=edit on:click="{() => show_modal_edit_subheading_step(list_index)}">
|
<div>
|
||||||
<Pen></Pen> </button>
|
<button class="action_button button_subtle" on:click="{() => show_modal_edit_subheading_step(list_index)}">
|
||||||
<button class=remove on:click="{() => remove_list(list_index)}">
|
<Pen fill=var(--nord1)></Pen> </button>
|
||||||
<Cross></Cross>
|
<button class="action_button button_subtle" on:click="{() => remove_list(list_index)}">
|
||||||
|
<Cross fill=var(--nord1)></Cross>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
<ol>
|
<ol>
|
||||||
{#each list.steps as step, step_index}
|
{#each list.steps as step, step_index}
|
||||||
<li>{step}
|
<li><div><div on:click={() => show_modal_edit_step(list_index, step_index)}>{step}</div>
|
||||||
<button class=edit on:click={() => show_modal_edit_step(list_index, step_index)}>
|
<div><button class="action_button button_subtle" on:click={() => show_modal_edit_step(list_index, step_index)}>
|
||||||
<Pen></Pen>
|
<Pen fill=var(--nord1)></Pen>
|
||||||
</button>
|
</button>
|
||||||
<button class=remove on:click="{() => remove_step(list_index, step_index)}">
|
<button class="action_button button_subtle" on:click="{() => remove_step(list_index, step_index)}">
|
||||||
<Cross></Cross>
|
<Cross fill=var(--nord1)></Cross>
|
||||||
</button>
|
</button>
|
||||||
|
</div></div>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ol>
|
</ol>
|
||||||
{/each}
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class='adder shadow'>
|
<div class='adder shadow'>
|
||||||
<input class=category type="text" bind:value={new_step.name} placeholder="Kategorie (optional)"on:keypress={(event) => do_on_key(event, 'Enter', false , add_new_step)} >
|
<input class=category type="text" bind:value={new_step.name} placeholder="Kategorie (optional)"on:keypress={(event) => do_on_key(event, 'Enter', false , add_new_step)} >
|
||||||
<div class=add_step>
|
<div class=add_step>
|
||||||
<p id=step contenteditable on:focus='{clear_step}' on:blur={add_placeholder} bind:innerHTML={new_step.step} on:keypress={(event) => do_on_key(event, 'Enter', true , add_new_step)}></p>
|
<p id=step contenteditable on:focus='{clear_step}' on:blur={add_placeholder} bind:innerText={new_step.step} on:keypress={(event) => do_on_key(event, 'Enter', true , add_new_step)}></p>
|
||||||
<button on:click={() => add_new_step()} class=action_button>
|
<button on:click={() => add_new_step()} class=action_button>
|
||||||
<Plus fill=white style="height: 2rem; width: 2rem"></Plus>
|
<Plus fill=white style="height: 2rem; width: 2rem"></Plus>
|
||||||
</button>
|
</button>
|
||||||
|
45
src/lib/components/IngredientsPage.svelte
Normal file
45
src/lib/components/IngredientsPage.svelte
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<script>
|
||||||
|
export let data
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
*{
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
.ingredients{
|
||||||
|
flex-basis: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-block: 1rem;
|
||||||
|
padding-inline: 2rem;
|
||||||
|
}
|
||||||
|
.ingredients_grid{
|
||||||
|
display: grid;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
grid-template-columns: 1fr 3fr;
|
||||||
|
grid-template-rows: auto;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
row-gap: 0.5em;
|
||||||
|
column-gap: 0.5em;
|
||||||
|
}
|
||||||
|
h4{
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{#if data.ingredients}
|
||||||
|
<div class=ingredients>
|
||||||
|
{#if data.portions}
|
||||||
|
<h4>Portionen:</h4>
|
||||||
|
{data.portions}
|
||||||
|
{/if}
|
||||||
|
<h2>Zutaten</h2>
|
||||||
|
{#each data.ingredients as list}
|
||||||
|
{#if list.name}
|
||||||
|
<h3>{list.name}</h3>
|
||||||
|
{/if}
|
||||||
|
<div class=ingredients_grid>
|
||||||
|
{#each list.list as item}
|
||||||
|
<div class=amount>{item.amount} {item.unit}</div><div class=name>{@html item.name}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
90
src/lib/components/InstructionsPage.svelte
Normal file
90
src/lib/components/InstructionsPage.svelte
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<script>
|
||||||
|
export let data
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
*{
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
ol li::marker{
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--blue);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
.instructions{
|
||||||
|
flex-basis: 0;
|
||||||
|
flex-grow: 2;
|
||||||
|
background-color: var(--nord5);
|
||||||
|
padding-block: 1rem;
|
||||||
|
padding-inline: 2rem;
|
||||||
|
}
|
||||||
|
.instructions ol{
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
.instructions li{
|
||||||
|
margin-block: 0.5em;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.additional_info{
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
.additional_info > *{
|
||||||
|
flex-grow: 0;
|
||||||
|
padding: 1em;
|
||||||
|
background-color: #FAFAFE;
|
||||||
|
box-shadow: 0.3em 0.3em 1em 0.2em rgba(0,0,0,0.3);
|
||||||
|
max-width: 30%
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 500px){
|
||||||
|
.additional_info > *{
|
||||||
|
max-width: 60%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h4{
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=instructions>
|
||||||
|
<div class=additional_info>
|
||||||
|
{#if data.preparation}
|
||||||
|
<div><h4>Vorbereitung:</h4>{data.preparation}</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
|
{#if data.fermentation}
|
||||||
|
{#if data.fermentation.bulk}
|
||||||
|
<div><h4>Stockgare:</h4>{data.fermentation.bulk}</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if data.fermentation.final}
|
||||||
|
<div><h4>Stückgare:</h4> {data.fermentation.final}</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if data.baking.temperature}
|
||||||
|
<div><h4>Backen:</h4> {data.baking.length} bei {data.baking.temperature} °C {data.baking.mode}</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if data.total_time}
|
||||||
|
<div><h4>Auf dem Teller:</h4>{data.total_time}</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if data.instructions}
|
||||||
|
<h2>Zubereitung</h2>
|
||||||
|
{#each data.instructions as list}
|
||||||
|
{#if list.name}
|
||||||
|
<h3>{list.name}</h3>
|
||||||
|
{/if}
|
||||||
|
<ol>
|
||||||
|
{#each list.steps as step}
|
||||||
|
<li>{@html step}</li>
|
||||||
|
{/each}
|
||||||
|
</ol>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</div>
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const recipes = document.querySelectorAll(".search_me");
|
const recipes = document.querySelectorAll(".search_me");
|
||||||
console.log("######", recipes)
|
|
||||||
const search = document.getElementById("search");
|
const search = document.getElementById("search");
|
||||||
const clearSearch = document.getElementById("clear-search");
|
const clearSearch = document.getElementById("clear-search");
|
||||||
|
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
<script lang=ts>
|
<script lang=ts>
|
||||||
import "$lib/components/nordtheme.css"
|
import "$lib/components/nordtheme.css"
|
||||||
|
import { season } from '$lib/js/season_store.js'
|
||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
let months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
let months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
||||||
|
|
||||||
export let season : Number[]
|
|
||||||
|
|
||||||
|
let season_local
|
||||||
|
|
||||||
|
season.subscribe((s) => {
|
||||||
|
season_local = s
|
||||||
|
});
|
||||||
|
|
||||||
export function set_season(){
|
export function set_season(){
|
||||||
let temp = []
|
let temp = []
|
||||||
@ -13,18 +20,18 @@ export function set_season(){
|
|||||||
temp.push(i+1)
|
temp.push(i+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
season = temp
|
season.update((s) => temp)
|
||||||
}
|
}
|
||||||
|
|
||||||
function write_season(season){
|
function write_season(season){
|
||||||
const el = document.getElementById("labels");
|
const el = document.getElementById("labels");
|
||||||
for(var i = 0; i < season.length; i++){
|
for(var i = 0; i < season.length; i++){
|
||||||
el.children[i].children[0].children[0].checked = true
|
el.children[season[i]-1].children[0].children[0].checked = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
write_season(season)
|
write_season(season_local)
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@ -75,6 +82,3 @@ input[type=checkbox]::after
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<button on:click={() => console.log("season", season)}> PRINT SEASON FROM SEASON_SELECT</button>
|
|
||||||
|
3
src/lib/js/season_store.js
Normal file
3
src/lib/js/season_store.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
export const season = writable([]);
|
@ -16,16 +16,17 @@ const RecipeSchema = new mongoose.Schema(
|
|||||||
description: {type: String, required: true},
|
description: {type: String, required: true},
|
||||||
tags : [String],
|
tags : [String],
|
||||||
season : [Number],
|
season : [Number],
|
||||||
baking: { temperature: String,
|
baking: { temperature: {type:String, default: ""},
|
||||||
length: String,
|
length: {type:String, default: ""},
|
||||||
mode: String,
|
mode: {type:String, default: ""},
|
||||||
},
|
},
|
||||||
preparation : String,
|
preparation : {type:String, default: ""},
|
||||||
fermentation: {bulk: String,
|
fermentation: { bulk: {type:String, default: ""},
|
||||||
final: String,
|
final: {type:String, default: ""},
|
||||||
|
|
||||||
},
|
},
|
||||||
portions : String,
|
portions :{type:String, default: ""},
|
||||||
total_time : String,
|
total_time : {type:String, default: ""},
|
||||||
ingredients : [ { name: {type: String, default: ""},
|
ingredients : [ { name: {type: String, default: ""},
|
||||||
list: [{name: {type: String, default: ""},
|
list: [{name: {type: String, default: ""},
|
||||||
unit: String,
|
unit: String,
|
||||||
@ -34,6 +35,7 @@ const RecipeSchema = new mongoose.Schema(
|
|||||||
}],
|
}],
|
||||||
instructions : [{name: {type: String, default: ""},
|
instructions : [{name: {type: String, default: ""},
|
||||||
steps: [String]}],
|
steps: [String]}],
|
||||||
|
preamble : String,
|
||||||
addendum : String,
|
addendum : String,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -4,10 +4,12 @@ import "$lib/components/nordtheme.css"
|
|||||||
<style>
|
<style>
|
||||||
:global(*){
|
:global(*){
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
font-family: sans-serif;
|
||||||
}
|
}
|
||||||
:global(body){
|
:global(body){
|
||||||
margin:0;
|
margin:0;
|
||||||
padding:0;
|
padding:0;
|
||||||
|
background-color: #fbf9f3;
|
||||||
}
|
}
|
||||||
li{
|
li{
|
||||||
list-style-type:none;
|
list-style-type:none;
|
||||||
@ -17,9 +19,10 @@ li{
|
|||||||
li>a{
|
li>a{
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 1.5rem;
|
font-size: 1.2rem;
|
||||||
color: inherit
|
color: inherit
|
||||||
}
|
}
|
||||||
|
|
||||||
li:hover,
|
li:hover,
|
||||||
li:focus-within
|
li:focus-within
|
||||||
{
|
{
|
||||||
@ -27,7 +30,6 @@ li:focus-within
|
|||||||
color: var(--red);
|
color: var(--red);
|
||||||
transform: scale(1.1,1.1);
|
transform: scale(1.1,1.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
padding-block: 2rem;
|
padding-block: 2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -38,6 +40,16 @@ ul {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
}
|
}
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
ul{
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
li:hover,
|
||||||
|
li:focus-within{
|
||||||
|
transform: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nav{
|
nav{
|
||||||
background-color: var(--nord0);
|
background-color: var(--nord0);
|
||||||
}
|
}
|
||||||
@ -49,7 +61,7 @@ nav{
|
|||||||
footer{
|
footer{
|
||||||
padding-block: 1rem;
|
padding-block: 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: auto;
|
margin-top: 3rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class=wrapper style="">
|
<div class=wrapper style="">
|
1
src/routes/.jukit/.jukit_info.json
Normal file
1
src/routes/.jukit/.jukit_info.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"terminal": "nvimterm"}
|
@ -16,7 +16,7 @@ export const POST: RequestHandler = async ({request}) => {
|
|||||||
await dbConnect();
|
await dbConnect();
|
||||||
await Recipe.create(recipe_json);
|
await Recipe.create(recipe_json);
|
||||||
await dbDisconnect();
|
await dbDisconnect();
|
||||||
return {status: 400} //TODO: cleanup error throwing
|
return {status: 200} //TODO: cleanup error throwing
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
console.log("PASSWORD INCORRECT")
|
console.log("PASSWORD INCORRECT")
|
||||||
|
23
src/routes/api/delete/+server.ts
Normal file
23
src/routes/api/delete/+server.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
import { Recipe } from '../../../models/Recipe';
|
||||||
|
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
||||||
|
import type {RecipeModelType} from '../../../types/types';
|
||||||
|
import { BEARER_TOKEN } from '$env/static/private'
|
||||||
|
// header: use for bearer token for now
|
||||||
|
// recipe json in body
|
||||||
|
export const POST: RequestHandler = async ({request}) => {
|
||||||
|
let message = await request.json()
|
||||||
|
const short_name = message.old_short_name
|
||||||
|
const bearer_token = message.headers.bearer
|
||||||
|
if(bearer_token === BEARER_TOKEN){
|
||||||
|
console.log("PASSWORD CORRECT")
|
||||||
|
await dbConnect();
|
||||||
|
await Recipe.findOneAndDelete({short_name: short_name});
|
||||||
|
await dbDisconnect();
|
||||||
|
return {status: 400} //TODO: cleanup error throwing
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
console.log("PASSWORD INCORRECT")
|
||||||
|
return {status: 403}
|
||||||
|
}
|
||||||
|
};
|
@ -3,6 +3,7 @@ import { Recipe } from '../../../models/Recipe';
|
|||||||
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
import { dbConnect, dbDisconnect } from '../../../utils/db';
|
||||||
import type {RecipeModelType} from '../../../types/types';
|
import type {RecipeModelType} from '../../../types/types';
|
||||||
import { BEARER_TOKEN } from '$env/static/private'
|
import { BEARER_TOKEN } from '$env/static/private'
|
||||||
|
import { error } from '@sveltejs/kit';
|
||||||
// header: use for bearer token for now
|
// header: use for bearer token for now
|
||||||
// recipe json in body
|
// recipe json in body
|
||||||
export const POST: RequestHandler = async ({request}) => {
|
export const POST: RequestHandler = async ({request}) => {
|
||||||
@ -10,16 +11,15 @@ export const POST: RequestHandler = async ({request}) => {
|
|||||||
let message = await request.json()
|
let message = await request.json()
|
||||||
const recipe_json = message.recipe
|
const recipe_json = message.recipe
|
||||||
const bearer_token = message.headers.bearer
|
const bearer_token = message.headers.bearer
|
||||||
console.log("RECIPE:", recipe_json)
|
|
||||||
console.log("BEARER:", bearer_token)
|
|
||||||
if(bearer_token === BEARER_TOKEN){
|
if(bearer_token === BEARER_TOKEN){
|
||||||
await dbConnect();
|
await dbConnect();
|
||||||
await Recipe.findOneAndUpdate({short_name: message.old_short_name }, recipe_json);
|
await Recipe.findOneAndUpdate({short_name: message.old_short_name }, recipe_json);
|
||||||
await dbDisconnect();
|
await dbDisconnect();
|
||||||
return {status: 400} //TODO: cleanup error throwing
|
const res = new Response(JSON.stringify({ message: "Updated Recipe successfully"}), { status: 200 })
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
console.log("PASSWORD INCORRECT")
|
console.log("INCORRECT PASSWORD")
|
||||||
return {status: 403}
|
throw error(403, "Password incorrect")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
13
src/routes/api/items/icon/+server.ts
Normal file
13
src/routes/api/items/icon/+server.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||||
|
import { Recipe } from '../../../../models/Recipe';
|
||||||
|
import { dbConnect, dbDisconnect } from '../../../../utils/db';
|
||||||
|
import type {BriefRecipeType} from '../../../../types/types';
|
||||||
|
|
||||||
|
export const GET: RequestHandler = async ({params}) => {
|
||||||
|
await dbConnect();
|
||||||
|
let icons = (await Recipe.distinct('icon').lean());
|
||||||
|
await dbDisconnect();
|
||||||
|
|
||||||
|
icons = JSON.parse(JSON.stringify(icons));
|
||||||
|
return json(icons);
|
||||||
|
};
|
13
src/routes/api/items/icon/[icon]/+server.ts
Normal file
13
src/routes/api/items/icon/[icon]/+server.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||||
|
import { Recipe } from '../../../../../models/Recipe';
|
||||||
|
import { dbConnect, dbDisconnect } from '../../../../../utils/db';
|
||||||
|
import type {BriefRecipeType} from '../../../../../types/types';
|
||||||
|
|
||||||
|
export const GET: RequestHandler = async ({params}) => {
|
||||||
|
await dbConnect();
|
||||||
|
let recipes = (await Recipe.find({tags: params.icon}, 'name short_name images tags category icon description season').lean()) as BriefRecipeType[];
|
||||||
|
await dbDisconnect();
|
||||||
|
|
||||||
|
recipes = JSON.parse(JSON.stringify(recipes));
|
||||||
|
return json(recipes);
|
||||||
|
};
|
@ -16,10 +16,12 @@ const test_json = [
|
|||||||
caption: "",
|
caption: "",
|
||||||
}],
|
}],
|
||||||
description: "Alles was das Bauernherz erfreuen lässt in einer Mahlzeit.",
|
description: "Alles was das Bauernherz erfreuen lässt in einer Mahlzeit.",
|
||||||
tags: ["Schweiz", "Käse", "Speck", "Nudeln", "Apfelmuß", "Kartoffeln"],
|
preamble: "Dieser Schweizer Klassiker ist wohl das beste Essen nach einem langen Tag von Skifahren. Die Beilage aus Apfelmus ist ein Muss.",
|
||||||
season: [6,7,8,9,10,11,12,1],
|
tags: ["Schweiz", "Käse", "Speck", "Nudeln", "Apfelmuß", "Kartoffeln", "Fleisch"],
|
||||||
|
season: [10,11,12,1],
|
||||||
portions: "4 Hauptspeisen",
|
portions: "4 Hauptspeisen",
|
||||||
total_time: "30 Minuten",
|
preparation: "10 min",
|
||||||
|
total_time: "30 min",
|
||||||
ingredients: [ {
|
ingredients: [ {
|
||||||
name: "",
|
name: "",
|
||||||
list: [
|
list: [
|
||||||
|
77
src/routes/api/seed/json/aelplermagronen.js
Normal file
77
src/routes/api/seed/json/aelplermagronen.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
const obj =
|
||||||
|
{
|
||||||
|
short_name: "aelplermagronen",
|
||||||
|
name : "Älplermagronen",
|
||||||
|
category: "Hauptspeise",
|
||||||
|
icon: "🍂",
|
||||||
|
datecreated: 20230619,
|
||||||
|
datemodified: 20230619,
|
||||||
|
images: [{
|
||||||
|
mediapath: "aelplermagronen.webp",
|
||||||
|
alt: "Älplermagronen serviert mit Apfelmuß",
|
||||||
|
caption: "",
|
||||||
|
}],
|
||||||
|
description: "Alles was das Bauernherz erfreuen lässt in einer Mahlzeit.",
|
||||||
|
tags: ["Schweiz", "Käse", "Speck", "Nudeln", "Apfelmuß", "Kartoffeln"],
|
||||||
|
season: [6,7,8,9,10,11,12,1],
|
||||||
|
portions: "4 Hauptspeisen",
|
||||||
|
total_time: "30 Minuten",
|
||||||
|
ingredients: [ {
|
||||||
|
name: "",
|
||||||
|
list: [
|
||||||
|
{ name: "Speckwürfel",
|
||||||
|
unit: "g",
|
||||||
|
amount: "150"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mittelgroße Zwiebeln",
|
||||||
|
unit: "",
|
||||||
|
amount: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Kartoffeln, festkochend",
|
||||||
|
unit: "g",
|
||||||
|
amount: "400",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Milch",
|
||||||
|
unit: "L",
|
||||||
|
amount: "1-2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Maccaroni",
|
||||||
|
unit: "g",
|
||||||
|
amount: "400",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Appenzeller",
|
||||||
|
unit: "g",
|
||||||
|
amount: "150",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "<a href=apfelmuss>Apfelmuß</a>",
|
||||||
|
unit: "",
|
||||||
|
amount: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
]},
|
||||||
|
],
|
||||||
|
instructions: [
|
||||||
|
{name: "",
|
||||||
|
steps: [
|
||||||
|
"In einem großen Topf oder tiefer Pfanne Speckwürfel anbraten.",
|
||||||
|
"Zwiebel in Halbringe schneiden und im gleichen Topf schwitzen lassen.",
|
||||||
|
"Kartoffeln schälen und in ~1 cm<sup>3</sup> schneiden.",
|
||||||
|
"Wenn Ziwebeln genügend gekocht sind die Kartoffeln hinzufügen und Milch hinzufügen, sodass alles bedeckt ist. Ca. 10 Minuten kochen lassen.",
|
||||||
|
"Ca. 1 L Milch hinzugeben. Für den nächsten Schritt wollen wir die Maccaroni hinzufügen. Damit diese nicht zu breiig werden geben wir erst die Milch zu und lassen sie aufkochen.",
|
||||||
|
"Wenn die der Topf wieder kocht jetzt die Maccaroni hinzugeben.",
|
||||||
|
"Den Käse zerreiben oder in kleine Würfel schneiden.",
|
||||||
|
"Ein bis zwei Minuten bevor die Nudeln durchgekocht sind den Käse hinzugeben und schmelzen lassen.",
|
||||||
|
"Mit Salz und Muskat würzen.",
|
||||||
|
"Den Topf ein bisschen zu früh vom Herd nehmen und ein bisschen auskühlen lassen.",
|
||||||
|
"Mit <a href=apfelkompott>Apfelmuß oder Apfelkompott</a> servieren."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
addendum: "<p>Man kann das Gericht noch dekanter machen indem man zu Teilen Rahm an Stelle von Milch verwendet. Zudem kann man das ganze auch noch in eine Auflaufform geben und im Ofen eine Kruste anbacken</p>",
|
||||||
|
}
|
50
src/routes/api/seed/json/template.js
Normal file
50
src/routes/api/seed/json/template.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
const obj =
|
||||||
|
{
|
||||||
|
short_name: "<++>",
|
||||||
|
name : "<++>",
|
||||||
|
category: "<++>",
|
||||||
|
icon: "<++>",
|
||||||
|
datecreated: 20230619,
|
||||||
|
datemodified: 20230619,
|
||||||
|
images: [{
|
||||||
|
mediapath: "<++>.webp",
|
||||||
|
alt: "<++>",
|
||||||
|
caption: "<++>",
|
||||||
|
}],
|
||||||
|
description: "<++>",
|
||||||
|
tags: [<++>],
|
||||||
|
season: [<++>],
|
||||||
|
baking: {
|
||||||
|
temperature: "<++>",
|
||||||
|
length: "<++>",
|
||||||
|
mode: "<++>",
|
||||||
|
},
|
||||||
|
preparation: "<++>",
|
||||||
|
fermentation: {
|
||||||
|
bulk: "<++>",
|
||||||
|
final: "<++>"
|
||||||
|
},
|
||||||
|
portions: "<++>",
|
||||||
|
total_time: "<++>",
|
||||||
|
ingredients: [ {
|
||||||
|
name: "<++>",
|
||||||
|
list: [
|
||||||
|
{ name: "<++>",
|
||||||
|
unit: "<++>",
|
||||||
|
amount: <++>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "<++>",
|
||||||
|
unit: "<++>",
|
||||||
|
amount: <++>,
|
||||||
|
},
|
||||||
|
]},
|
||||||
|
],
|
||||||
|
instructions: [
|
||||||
|
{name: "<++>",
|
||||||
|
steps: [
|
||||||
|
"<++>",
|
||||||
|
"<++>"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]}
|
@ -8,7 +8,6 @@
|
|||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
export let current_month = new Date().getMonth() + 1
|
export let current_month = new Date().getMonth() + 1
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1>Rezepte</h1>
|
<h1>Rezepte</h1>
|
||||||
<h2>In Saison</h2>
|
<h2>In Saison</h2>
|
||||||
<section>
|
<section>
|
||||||
|
@ -6,19 +6,42 @@
|
|||||||
import "$lib/components/nordtheme.css"
|
import "$lib/components/nordtheme.css"
|
||||||
import MultiImgWrapper from './MultiImgWrapper.svelte'
|
import MultiImgWrapper from './MultiImgWrapper.svelte'
|
||||||
import EditButton from '$lib/components/EditButton.svelte';
|
import EditButton from '$lib/components/EditButton.svelte';
|
||||||
|
import InstructionsPage from '$lib/components/InstructionsPage.svelte';
|
||||||
|
import IngredientsPage from '$lib/components/IngredientsPage.svelte';
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
let hero_img_src = "/images/" + data.images[0].mediapath
|
||||||
export let months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
export let months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
||||||
function season_intervals() {
|
function season_intervals() {
|
||||||
let interval_arr = []
|
let interval_arr = []
|
||||||
let start = 0
|
|
||||||
for(var i = 0; i < data.season.length - 1; i++)
|
|
||||||
{
|
let start_i = 0
|
||||||
if(Math.abs(data.season[i] - data.season[i + 1])%11 > 1){
|
for(var i = 12; i > 0; i--){
|
||||||
interval_arr.push([data.season[start], data.season[i]])
|
if(data.season.includes(i)){
|
||||||
start=i+1
|
start_i = data.season.indexOf(i);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
interval_arr.push([data.season[start], data.season[data.season.length -1]])
|
|
||||||
|
var start = data.season[start_i]
|
||||||
|
var end_i
|
||||||
|
const len = data.season.length
|
||||||
|
for(var i = 0; i < len -1; i++){
|
||||||
|
if(data.season.includes((start + i) %12 + 1)){
|
||||||
|
end_i = (start_i + i + 1) % len
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
interval_arr.push([start, data.season[end_i]])
|
||||||
|
start = data.season[(start + i + 1) % len]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(interval_arr.length == 0){
|
||||||
|
interval_arr.push([start, data.season[end_i]])
|
||||||
|
}
|
||||||
|
|
||||||
return interval_arr
|
return interval_arr
|
||||||
}
|
}
|
||||||
export let season_iv = season_intervals();
|
export let season_iv = season_intervals();
|
||||||
@ -29,20 +52,16 @@ font-family: sans-serif;
|
|||||||
}
|
}
|
||||||
h1{
|
h1{
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0.5em 2em;
|
padding-block: 0.5em;
|
||||||
border-radius: 10000px;
|
border-radius: 10000px;
|
||||||
margin:0;
|
margin:0;
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
}
|
}
|
||||||
.wrapper{
|
|
||||||
margin-inline: auto;
|
|
||||||
max-width: 700px;
|
|
||||||
padding-inline: 2rem;
|
|
||||||
}
|
|
||||||
.tags{
|
.tags{
|
||||||
margin-block: 1rem;
|
margin-block: 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
}
|
}
|
||||||
@ -64,12 +83,109 @@ h1{
|
|||||||
background-color: var(--orange);
|
background-color: var(--orange);
|
||||||
box-shadow: 0.1em 0.1em 0.2em 0.2em rgba(0,0,0,0.3);
|
box-shadow: 0.1em 0.1em 0.2em 0.2em rgba(0,0,0,0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wrapper{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
max-width: 1000px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 700px){
|
||||||
|
.wrapper{
|
||||||
|
flex-direction:column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title_container{
|
||||||
|
max-width: 1000px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
position: relative;
|
||||||
|
width: min(800px, 80vw);
|
||||||
|
margin-inline: auto;
|
||||||
|
transform: translateY(-4rem);
|
||||||
|
background-color: var(--nord6);
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
}
|
||||||
|
.title_container .img{
|
||||||
|
width: 100%;
|
||||||
|
height: 700px;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
.icon{
|
||||||
|
position: absolute;
|
||||||
|
top: -1em;
|
||||||
|
right: -0.75em;
|
||||||
|
text-decoration: unset;
|
||||||
|
background-color: #FAFAFE;
|
||||||
|
padding: 0.5em;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
border-radius: 100000px;
|
||||||
|
transition: 100ms;
|
||||||
|
box-shadow: 0em 0em 1em 0.5em rgba(0,0,0,0.5);
|
||||||
|
}
|
||||||
|
.icon:hover,
|
||||||
|
.icon:focus-visible{
|
||||||
|
scale: 1.2 1.2;
|
||||||
|
animation: shake 0.5s ease forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4{
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
.addendum{
|
||||||
|
max-width: 800px;
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-inline: 2rem;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 800px){
|
||||||
|
.title{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.icon{
|
||||||
|
right: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes shake{
|
||||||
|
0%{
|
||||||
|
transform: rotate(0)
|
||||||
|
scale(1,1);
|
||||||
|
}
|
||||||
|
25%{
|
||||||
|
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
||||||
|
transform: rotate(var(--angle))
|
||||||
|
scale(1.2,1.2)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
50%{
|
||||||
|
|
||||||
|
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
||||||
|
transform: rotate(calc(-1* var(--angle)))
|
||||||
|
scale(1.2,1.2);
|
||||||
|
}
|
||||||
|
74%{
|
||||||
|
|
||||||
|
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
||||||
|
transform: rotate(var(--angle))
|
||||||
|
scale(1.2, 1.2);
|
||||||
|
}
|
||||||
|
100%{
|
||||||
|
transform: rotate(0)
|
||||||
|
scale(1.2,1.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<h1>{data.name}</h1>
|
|
||||||
|
|
||||||
<MultiImgWrapper wrap={data.images.length>1} class=double>
|
<!--<MultiImgWrapper wrap={data.images.length>1} class=double>
|
||||||
{#each data.images as img}
|
{#each data.images as img}
|
||||||
<img width=100% src="/images/{img.mediapath}" alt="{img.alt}">
|
<img width=100% src="/images/{img.mediapath}" alt="{img.alt}">
|
||||||
<figure>
|
<figure>
|
||||||
@ -78,76 +194,40 @@ h1{
|
|||||||
{/if}
|
{/if}
|
||||||
</figure>
|
</figure>
|
||||||
{/each}
|
{/each}
|
||||||
</MultiImgWrapper>
|
</MultiImgWrapper>-->
|
||||||
|
|
||||||
|
|
||||||
|
<div class=title_container>
|
||||||
|
<div class=img style="background-image: url({hero_img_src})"></div>
|
||||||
|
<div class=title>
|
||||||
|
<a class="icon" href='/rezepte/season/{data.season[0]}'>{data.icon}</a>
|
||||||
|
<h1>{data.name}</h1>
|
||||||
|
{#if data.preamble}
|
||||||
|
<p>{data.preamble}</p>
|
||||||
|
{/if}
|
||||||
<div class=tags>
|
<div class=tags>
|
||||||
Saison:
|
<h4>Saison:</h4>
|
||||||
{#each season_iv as season}
|
{#each season_iv as season}
|
||||||
<a class=tag href="/rezepte/season/{season[0]}">{months[season[0] - 1]}-{months[season[1] - 1]}</a>
|
<a class=tag href="/rezepte/season/{season[0]}">{months[season[0] - 1]}-{months[season[1] - 1]}</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>Stichwörter:</h4>
|
||||||
<div class=tags>
|
<div class=tags>
|
||||||
Stichwörter:
|
|
||||||
{#each data.tags as tag}
|
{#each data.tags as tag}
|
||||||
<a href="/rezepte/tag/{tag}" class=tag>{tag}</a>
|
<a href="/rezepte/tag/{tag}" class=tag>{tag}</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if data.preparation}
|
<div class=wrapper>
|
||||||
<div>Vorbereitung: {data.preparation}</div>
|
<IngredientsPage {data}></IngredientsPage>
|
||||||
{/if}
|
<InstructionsPage {data}></InstructionsPage>
|
||||||
|
</div>
|
||||||
|
<div class=addendum>
|
||||||
{#if data.fermentation}
|
|
||||||
{#if data.fermentation.bulk}
|
|
||||||
<div>Stockgare: {data.fermentation.bulk}</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if data.fermentation.final}
|
|
||||||
<div>Stückgare: {data.fermentation.final}</div>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if data.baking}
|
|
||||||
<div>Backen: {data.baking.length} bei {data.baking.temperature} °C {data.baking.mode}</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if data.total_time}
|
|
||||||
<div>Gesamtzeit: {data.total_time}</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
|
|
||||||
{#if data.ingredients}
|
|
||||||
<h2>Zutaten</h2>
|
|
||||||
{#each data.ingredients as list}
|
|
||||||
{#if list.name}
|
|
||||||
<h3>{list.name}</h3>
|
|
||||||
{/if}
|
|
||||||
<ul>
|
|
||||||
{#each list.list as item}
|
|
||||||
<li>{item.amount} {item.unit} {@html item.name}</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
|
|
||||||
{#if data.instructions}
|
|
||||||
<h2>Zubereitung</h2>
|
|
||||||
{#each data.instructions as list}
|
|
||||||
{#if list.name}
|
|
||||||
<h3>{list.name}</h3>
|
|
||||||
{/if}
|
|
||||||
<ol>
|
|
||||||
{#each list.steps as step}
|
|
||||||
<li>{@html step}</li>
|
|
||||||
{/each}
|
|
||||||
</ol>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
{#if data.addendum}
|
{#if data.addendum}
|
||||||
{@html data.addendum}
|
{@html data.addendum}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,39 +1,92 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import Check from '$lib/assets/icons/Check.svelte';
|
||||||
|
import SeasonSelect from '$lib/components/SeasonSelect.svelte';
|
||||||
|
import '$lib/css/action_button.css'
|
||||||
|
|
||||||
|
export let data: PageData;
|
||||||
|
let preamble = ""
|
||||||
|
let addendum = ""
|
||||||
|
|
||||||
|
import { season } from '$lib/js/season_store';
|
||||||
|
season.update(() => [])
|
||||||
|
let season_local
|
||||||
|
season.subscribe((s) => {
|
||||||
|
season_local = s
|
||||||
|
});
|
||||||
|
|
||||||
export let card_data ={
|
export let card_data ={
|
||||||
|
icon: "",
|
||||||
|
category: "",
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
tags: [],
|
||||||
}
|
}
|
||||||
let short_name
|
export let add_info ={
|
||||||
|
preparation: "",
|
||||||
|
fermentation: {
|
||||||
|
bulk: "",
|
||||||
|
final: "",
|
||||||
|
},
|
||||||
|
baking: {
|
||||||
|
length: "",
|
||||||
|
temperature: "",
|
||||||
|
mode: "",
|
||||||
|
},
|
||||||
|
total_time: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
let images = []
|
||||||
|
export let portions = ""
|
||||||
|
|
||||||
|
let short_name = ""
|
||||||
let password
|
let password
|
||||||
let datecreated = new Date()
|
let datecreated = new Date()
|
||||||
let datemodified = datecreated
|
let datemodified = datecreated
|
||||||
|
|
||||||
|
import type { PageData } from './$types';
|
||||||
import CardAdd from '$lib/components/CardAdd.svelte';
|
import CardAdd from '$lib/components/CardAdd.svelte';
|
||||||
|
|
||||||
import SeasonSelect from '$lib/components/SeasonSelect.svelte';
|
|
||||||
export let season = []
|
|
||||||
|
|
||||||
import CreateIngredientList from '$lib/components/CreateIngredientList.svelte';
|
import CreateIngredientList from '$lib/components/CreateIngredientList.svelte';
|
||||||
export let ingredients = []
|
export let ingredients = []
|
||||||
|
|
||||||
import CreateStepList from '$lib/components/CreateStepList.svelte';
|
import CreateStepList from '$lib/components/CreateStepList.svelte';
|
||||||
export let instructions = []
|
export let instructions = []
|
||||||
|
|
||||||
|
|
||||||
|
function get_season(){
|
||||||
|
let season = []
|
||||||
|
const el = document.getElementById("labels");
|
||||||
|
for(var i = 0; i < el.children.length; i++){
|
||||||
|
if(el.children[i].children[0].children[0].checked){
|
||||||
|
season.push(i+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return season
|
||||||
|
}
|
||||||
|
function write_season(season){
|
||||||
|
const el = document.getElementById("labels");
|
||||||
|
for(var i = 0; i < season.length; i++){
|
||||||
|
el.children[i].children[0].children[0].checked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function doPost () {
|
async function doPost () {
|
||||||
|
console.log(add_info.total_time)
|
||||||
const res = await fetch('/api/add', {
|
const res = await fetch('/api/add', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
recipe: {
|
recipe: {
|
||||||
season: get_season(),
|
|
||||||
...card_data,
|
...card_data,
|
||||||
images: [{
|
...add_info,
|
||||||
mediapath: short_name + '.webp',
|
images: {mediapath: short_name + '.webp', alt: "", caption: ""}, // TODO
|
||||||
alt: "",
|
season: season_local,
|
||||||
caption: ""
|
|
||||||
}],
|
|
||||||
short_name,
|
short_name,
|
||||||
datecreated,
|
datecreated,
|
||||||
datemodified,
|
datemodified,
|
||||||
instructions,
|
instructions,
|
||||||
ingredients,
|
ingredients,
|
||||||
|
preamble,
|
||||||
|
addendum,
|
||||||
},
|
},
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
@ -42,35 +95,146 @@
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const json = await res.json()
|
|
||||||
result = JSON.stringify(json)
|
|
||||||
console.log(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
input.temp{
|
input{
|
||||||
all: unset;
|
|
||||||
display: block;
|
display: block;
|
||||||
|
border: unset;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
padding: 0.2em 1em;
|
padding: 0.5em 1em;
|
||||||
border-radius: 1000px;
|
border-radius: 1000px;
|
||||||
background-color: var(--nord4);
|
background-color: var(--nord4);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
transition: 100ms;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
input:hover,
|
||||||
|
input:focus-visible
|
||||||
|
{
|
||||||
|
scale: 1.05 1.05;
|
||||||
|
}
|
||||||
|
.list_wrapper{
|
||||||
|
margin-inline: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
max-width: 1000px;
|
||||||
|
gap: 2rem;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 700px){
|
||||||
|
.list_wrapper{
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input[type=password]{
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
padding-block: 0.5em;
|
||||||
|
display: inline;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.submit_wrapper{
|
||||||
|
position: relative;
|
||||||
|
margin-inline: auto;
|
||||||
|
width: max(300px, 50vw)
|
||||||
|
}
|
||||||
|
.submit_wrapper button{
|
||||||
|
position: absolute;
|
||||||
|
right:-1em;
|
||||||
|
bottom: -0.5em;
|
||||||
|
}
|
||||||
|
.submit_wrapper h2{
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
h1{
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
.title_container{
|
||||||
|
max-width: 1000px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
position: relative;
|
||||||
|
width: min(800px, 80vw);
|
||||||
|
margin-block: 2rem;
|
||||||
|
margin-inline: auto;
|
||||||
|
background-color: var(--nord6);
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
}
|
||||||
|
.title p{
|
||||||
|
border: 2px solid var(--nord1);
|
||||||
|
border-radius: 10000px;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
transition: 200ms;
|
||||||
|
}
|
||||||
|
.title p:hover,
|
||||||
|
.title p:focus-within{
|
||||||
|
scale: 1.02 1.02;
|
||||||
|
}
|
||||||
|
.addendum{
|
||||||
|
font-size: 1.1rem;
|
||||||
|
max-width: 90%;
|
||||||
|
margin-inline: auto;
|
||||||
|
border: 2px solid var(--nord1);
|
||||||
|
border-radius: 45px;
|
||||||
|
padding: 1em 1em;
|
||||||
|
transition: 100ms;
|
||||||
|
}
|
||||||
|
.addendum:hover,
|
||||||
|
.addendum:focus-within
|
||||||
|
{
|
||||||
|
scale: 1.02 1.02;
|
||||||
|
}
|
||||||
|
.addendum_wrapper{
|
||||||
|
max-width: 1000px;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
h3{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<h1>Rezept hinzufügen</h1>
|
<h1>Rezept erstellen</h1>
|
||||||
|
|
||||||
<CardAdd {card_data}></CardAdd>
|
<CardAdd {card_data}></CardAdd>
|
||||||
|
|
||||||
<input class=temp bind:value={short_name} placeholder="Kurzname"/>
|
<h3>Kurzname (für URL):</h3>
|
||||||
|
<input bind:value={short_name} placeholder="Kurzname"/>
|
||||||
|
|
||||||
<SeasonSelect {season}></SeasonSelect>
|
<div class=title_container>
|
||||||
|
<div class=title>
|
||||||
|
<h4>Eine etwas längere Beschreibung:</h4>
|
||||||
|
<p bind:innerText={preamble} contenteditable></p>
|
||||||
|
<div class=tags>
|
||||||
|
<h4>Saison:</h4>
|
||||||
|
<SeasonSelect></SeasonSelect>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2>Zutaten</h2>
|
<div class=list_wrapper>
|
||||||
<CreateIngredientList {ingredients}></CreateIngredientList>
|
<div>
|
||||||
<h2>Zubereitung</h2>
|
<CreateIngredientList {ingredients} {portions}></CreateIngredientList>
|
||||||
<CreateStepList {instructions} ></CreateStepList>
|
</div>
|
||||||
<input class=temp type="password" placeholder=Passwort bind:value={password}>
|
<div>
|
||||||
<button on:click={doPost}>ADD RECIPE</button>
|
<CreateStepList {instructions} {add_info}></CreateStepList>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=addendum_wrapper>
|
||||||
|
<h3>Nachtrag:</h3>
|
||||||
|
<div class=addendum bind:innerText={addendum} contenteditable></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=submit_wrapper>
|
||||||
|
<h2>Neues Rezept hinzufügen:</h2>
|
||||||
|
<input type="password" placeholder=Passwort bind:value={password}>
|
||||||
|
<button class=action_button on:click={doPost}><Check fill=white width=2rem height=2rem></Check></button>
|
||||||
|
</div>
|
||||||
|
@ -1,5 +1,21 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import Check from '$lib/assets/icons/Check.svelte';
|
||||||
|
import Cross from '$lib/assets/icons/Cross.svelte';
|
||||||
|
import SeasonSelect from '$lib/components/SeasonSelect.svelte';
|
||||||
|
import '$lib/css/action_button.css'
|
||||||
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
let preamble = data.recipe.preamble
|
||||||
|
let addendum = data.recipe.addendum
|
||||||
|
|
||||||
|
import { season } from '$lib/js/season_store';
|
||||||
|
season.update(() => data.recipe.season)
|
||||||
|
let season_local
|
||||||
|
season.subscribe((s) => {
|
||||||
|
season_local = s
|
||||||
|
});
|
||||||
|
|
||||||
let old_short_name = data.recipe.short_name
|
let old_short_name = data.recipe.short_name
|
||||||
|
|
||||||
export let card_data ={
|
export let card_data ={
|
||||||
@ -9,8 +25,22 @@
|
|||||||
description: data.recipe.description,
|
description: data.recipe.description,
|
||||||
tags: data.recipe.tags,
|
tags: data.recipe.tags,
|
||||||
}
|
}
|
||||||
|
export let add_info ={
|
||||||
|
preparation: data.recipe.preparation,
|
||||||
|
fermentation: {
|
||||||
|
bulk: data.recipe.fermentation.bulk,
|
||||||
|
final: data.recipe.fermentation.final,
|
||||||
|
},
|
||||||
|
baking: {
|
||||||
|
length: data.recipe.baking.length,
|
||||||
|
temperature: data.recipe.baking.temperature,
|
||||||
|
mode: data.recipe.baking.mode,
|
||||||
|
},
|
||||||
|
total_time: data.recipe.total_time,
|
||||||
|
}
|
||||||
|
|
||||||
let images = data.recipe.images
|
let images = data.recipe.images
|
||||||
let season = data.recipe.season
|
export let portions = data.recipe.portions
|
||||||
|
|
||||||
let short_name = data.recipe.short_name
|
let short_name = data.recipe.short_name
|
||||||
let password
|
let password
|
||||||
@ -19,9 +49,6 @@
|
|||||||
|
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import CardAdd from '$lib/components/CardAdd.svelte';
|
import CardAdd from '$lib/components/CardAdd.svelte';
|
||||||
import MediaScroller from '$lib/components/MediaScroller.svelte';
|
|
||||||
import Card from '$lib/components/Card.svelte';
|
|
||||||
import Search from '$lib/components/Search.svelte';
|
|
||||||
|
|
||||||
import CreateIngredientList from '$lib/components/CreateIngredientList.svelte';
|
import CreateIngredientList from '$lib/components/CreateIngredientList.svelte';
|
||||||
export let ingredients = data.recipe.ingredients
|
export let ingredients = data.recipe.ingredients
|
||||||
@ -29,6 +56,7 @@
|
|||||||
import CreateStepList from '$lib/components/CreateStepList.svelte';
|
import CreateStepList from '$lib/components/CreateStepList.svelte';
|
||||||
export let instructions = data.recipe.instructions
|
export let instructions = data.recipe.instructions
|
||||||
|
|
||||||
|
|
||||||
function get_season(){
|
function get_season(){
|
||||||
let season = []
|
let season = []
|
||||||
const el = document.getElementById("labels");
|
const el = document.getElementById("labels");
|
||||||
@ -46,19 +74,39 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doPost () {
|
async function doDelete(){
|
||||||
|
const response = confirm("Bist du dir sicher, dass du das Rezept löschen willst?")
|
||||||
|
if(!response){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const res = await fetch('/api/delete', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
old_short_name,
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
bearer: password,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
async function doEdit() {
|
||||||
const res = await fetch('/api/edit', {
|
const res = await fetch('/api/edit', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
recipe: {
|
recipe: {
|
||||||
...card_data,
|
...card_data,
|
||||||
|
...add_info,
|
||||||
images, // TODO
|
images, // TODO
|
||||||
season: get_season(),
|
season: season_local,
|
||||||
short_name,
|
short_name,
|
||||||
datecreated,
|
datecreated,
|
||||||
datemodified,
|
datemodified,
|
||||||
instructions,
|
instructions,
|
||||||
ingredients,
|
ingredients,
|
||||||
|
addendum,
|
||||||
|
preamble
|
||||||
},
|
},
|
||||||
old_short_name,
|
old_short_name,
|
||||||
headers: {
|
headers: {
|
||||||
@ -67,36 +115,158 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
const item = await res.json();
|
||||||
const json = await res.json()
|
|
||||||
result = JSON.stringify(json)
|
|
||||||
console.log(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
input{
|
input{
|
||||||
all: unset;
|
|
||||||
display: block;
|
display: block;
|
||||||
|
border: unset;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
padding: 0.2em 1em;
|
padding: 0.5em 1em;
|
||||||
border-radius: 1000px;
|
border-radius: 1000px;
|
||||||
background-color: var(--nord4);
|
background-color: var(--nord4);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
transition: 100ms;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
input:hover,
|
||||||
|
input:focus-visible
|
||||||
|
{
|
||||||
|
scale: 1.05 1.05;
|
||||||
|
}
|
||||||
|
.list_wrapper{
|
||||||
|
margin-inline: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
max-width: 1000px;
|
||||||
|
gap: 2rem;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 700px){
|
||||||
|
.list_wrapper{
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input[type=password]{
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
padding-block: 0.5em;
|
||||||
|
display: inline;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.submit_wrapper{
|
||||||
|
position: relative;
|
||||||
|
margin-inline: auto;
|
||||||
|
width: max(300px, 50vw)
|
||||||
|
}
|
||||||
|
.submit_wrapper button{
|
||||||
|
position: absolute;
|
||||||
|
right:-1em;
|
||||||
|
bottom: -0.5em;
|
||||||
|
}
|
||||||
|
.submit_wrapper h2{
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
h1{
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
.title_container{
|
||||||
|
max-width: 1000px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
position: relative;
|
||||||
|
width: min(800px, 80vw);
|
||||||
|
margin-block: 2rem;
|
||||||
|
margin-inline: auto;
|
||||||
|
background-color: var(--nord6);
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
}
|
||||||
|
.title p{
|
||||||
|
border: 2px solid var(--nord1);
|
||||||
|
border-radius: 10000px;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
transition: 200ms;
|
||||||
|
}
|
||||||
|
.title p:hover,
|
||||||
|
.title p:focus-within{
|
||||||
|
scale: 1.02 1.02;
|
||||||
|
}
|
||||||
|
.addendum{
|
||||||
|
font-size: 1.1rem;
|
||||||
|
max-width: 90%;
|
||||||
|
margin-inline: auto;
|
||||||
|
border: 2px solid var(--nord1);
|
||||||
|
border-radius: 45px;
|
||||||
|
padding: 1em 1em;
|
||||||
|
transition: 100ms;
|
||||||
|
}
|
||||||
|
.addendum:hover,
|
||||||
|
.addendum:focus-within
|
||||||
|
{
|
||||||
|
scale: 1.02 1.02;
|
||||||
|
}
|
||||||
|
.addendum_wrapper{
|
||||||
|
max-width: 1000px;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
h3{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.delete{
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: 2rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<h1>Rezept hinzufügen</h1>
|
<h1>Rezept editieren</h1>
|
||||||
|
|
||||||
<CardAdd {card_data}></CardAdd>
|
<CardAdd {card_data}></CardAdd>
|
||||||
<button on:click={console.log(JSON.stringify(ingredients, null, 4))}>Printout Ingredients</button>
|
|
||||||
<button on:click={console.log(JSON.stringify(instructions, null, 4))}>Printout Instructions</button>
|
<h3>Kurzname (für URL):</h3>
|
||||||
<button on:click={console.log(JSON.stringify(card_data, null, 4))}>Prinout Card Data</button>
|
|
||||||
<input bind:value={short_name} placeholder="Kurzname"/>
|
<input bind:value={short_name} placeholder="Kurzname"/>
|
||||||
<h2>Zutaten</h2>
|
|
||||||
<CreateIngredientList {ingredients}></CreateIngredientList>
|
<div class=title_container>
|
||||||
<h2>Zubereitung</h2>
|
<div class=title>
|
||||||
<CreateStepList {instructions} ></CreateStepList>
|
<h4>Eine etwas längere Beschreibung:</h4>
|
||||||
|
<p bind:innerText={preamble} contenteditable></p>
|
||||||
|
<div class=tags>
|
||||||
|
<h4>Saison:</h4>
|
||||||
|
<SeasonSelect></SeasonSelect>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=list_wrapper>
|
||||||
|
<div>
|
||||||
|
<CreateIngredientList {ingredients} {portions}></CreateIngredientList>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<CreateStepList {instructions} {add_info}></CreateStepList>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=addendum_wrapper>
|
||||||
|
<h3>Nachtrag:</h3>
|
||||||
|
<div class=addendum bind:innerText={addendum} contenteditable></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=submit_wrapper>
|
||||||
|
<h2>Editiertes Rezept abspeichern:</h2>
|
||||||
<input type="password" placeholder=Passwort bind:value={password}>
|
<input type="password" placeholder=Passwort bind:value={password}>
|
||||||
<button on:click={doPost}>EDIT RECIPE</button>
|
<button class=action_button on:click={doEdit}><Check fill=white width=2rem height=2rem></Check></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=submit_wrapper>
|
||||||
|
<h2>Rezept löschen:</h2>
|
||||||
|
<input type="password" placeholder=Passwort bind:value={password}>
|
||||||
|
<button class=action_button on:click={doDelete}><Cross fill=white width=2rem height=2rem></Cross></button>
|
||||||
|
</div>
|
||||||
|
@ -38,6 +38,7 @@ export type RecipeModelType = {
|
|||||||
name?: string;
|
name?: string;
|
||||||
steps: [string]
|
steps: [string]
|
||||||
}]
|
}]
|
||||||
|
preamble?: String
|
||||||
addendum?: string
|
addendum?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user