First almost fully functioning MVP.
Lacking: - Seasons cannot be added/edited - image upload - layout recipe/adding
This commit is contained in:
parent
4afaf7f6f3
commit
3d0d3f41e2
@ -1,6 +1,7 @@
|
|||||||
<script lang='ts'>
|
<script lang='ts'>
|
||||||
export let href
|
export let href
|
||||||
import "$lib/components/nordtheme.css"
|
import "$lib/components/nordtheme.css"
|
||||||
|
import "$lib/css/action_button.css"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -8,14 +9,13 @@ import "$lib/components/nordtheme.css"
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
bottom:0;
|
bottom:0;
|
||||||
right:0;
|
right:0;
|
||||||
width: 2rem;
|
width: 1rem;
|
||||||
height: 2rem;
|
height: 1rem;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
border-radius: 1000px;
|
border-radius: 1000px;
|
||||||
margin: 2rem;
|
margin: 2rem;
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
background-color: var(--red);
|
background-color: var(--red);
|
||||||
box-shadow: 0em 0em 0.2em 0.2em rgba(0,0,0,0.2);
|
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
@ -24,7 +24,7 @@ align-content: center;
|
|||||||
:global(.icon_svg){
|
:global(.icon_svg){
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
fill: var(--nord4);
|
fill: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root{
|
:root{
|
||||||
@ -33,7 +33,7 @@ fill: var(--nord4);
|
|||||||
.container:hover,
|
.container:hover,
|
||||||
.container:focus-within
|
.container:focus-within
|
||||||
{
|
{
|
||||||
background-color: var(--nord3);
|
background-color: var(--nord0);
|
||||||
box-shadow: 0em 0em 0.5em 0.5em rgba(0,0,0,0.2);
|
box-shadow: 0em 0em 0.5em 0.5em rgba(0,0,0,0.2);
|
||||||
/*transform: scale(1.2,1.2);*/
|
/*transform: scale(1.2,1.2);*/
|
||||||
animation: shake 0.5s;
|
animation: shake 0.5s;
|
||||||
@ -73,6 +73,6 @@ box-shadow: 0em 0em 0.5em 0.5em rgba(0,0,0,0.2);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<a class=container {href}>
|
<a class="container action_button" {href}>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</a>
|
</a>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
export let recipe
|
export let recipe
|
||||||
export let current_month
|
export let current_month
|
||||||
export let icon_override = false;
|
export let icon_override = false;
|
||||||
|
export let search = "search_me"
|
||||||
|
|
||||||
if(icon_override){
|
if(icon_override){
|
||||||
current_month = recipe.season[0]
|
current_month = recipe.season[0]
|
||||||
@ -29,9 +30,9 @@ if(icon_override){
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
transition: 200ms;
|
|
||||||
background-color: var(--blue);
|
background-color: var(--blue);
|
||||||
box-shadow: 0em 0em 2em 0.1em rgba(0, 0, 0, 0.3);
|
box-shadow: 0em 0em 2em 0.1em rgba(0, 0, 0, 0.3);
|
||||||
|
transition: 200ms;
|
||||||
}
|
}
|
||||||
.card .icon{
|
.card .icon{
|
||||||
text-decoration: unset;
|
text-decoration: unset;
|
||||||
@ -45,17 +46,24 @@ if(icon_override){
|
|||||||
border-radius:1000px;
|
border-radius:1000px;
|
||||||
box-shadow: 0em 0em 2em 0.1em rgba(0, 0, 0, 0.6);
|
box-shadow: 0em 0em 2em 0.1em rgba(0, 0, 0, 0.6);
|
||||||
}
|
}
|
||||||
|
.card:hover,
|
||||||
|
.card:focus-within{
|
||||||
|
transform: scale(1.02,1.02);
|
||||||
|
background-color: var(--red);
|
||||||
|
box-shadow: 0.2em 0.2em 2em 1em rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
.card:active{
|
||||||
|
scale: 0.95 0.95;
|
||||||
|
}
|
||||||
.card .icon:hover,
|
.card .icon:hover,
|
||||||
.card .icon:focus-visible
|
.card .icon:focus-visible
|
||||||
{
|
{
|
||||||
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
||||||
transform:scale(1.2, 1.2)
|
transform:scale(1.2, 1.2)
|
||||||
}
|
}
|
||||||
.card:hover,
|
.icon:active{
|
||||||
.card:focus-within{
|
scale: 0.8 0.8;
|
||||||
transform: scale(1.02,1.02);
|
rotate: 30deg;
|
||||||
background-color: var(--red);
|
|
||||||
box-shadow: 0.2em 0.2em 2em 1em rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card img{
|
.card img{
|
||||||
@ -116,7 +124,10 @@ if(icon_override){
|
|||||||
background-color: var(--orange);
|
background-color: var(--orange);
|
||||||
box-shadow: 0.2em 0.2em 0.2em 0.1em rgba(0, 0, 0, 0.3);
|
box-shadow: 0.2em 0.2em 0.2em 0.1em rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
.card .tag:active{
|
||||||
|
transition: 100ms;
|
||||||
|
scale: 0.8 0.8;
|
||||||
|
}
|
||||||
.card .title .category{
|
.card .title .category{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
box-shadow: 0em 0em 1em 0.1em rgba(0, 0, 0, 0.6);
|
box-shadow: 0em 0em 1em 0.1em rgba(0, 0, 0, 0.6);
|
||||||
@ -138,6 +149,10 @@ if(icon_override){
|
|||||||
background-color: var(--nord3);
|
background-color: var(--nord3);
|
||||||
transform: scale(1.05, 1.05)
|
transform: scale(1.05, 1.05)
|
||||||
}
|
}
|
||||||
|
.card .category:active{
|
||||||
|
scale: 0.9 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
.card:hover .icon,
|
.card:hover .icon,
|
||||||
.card:focus-visible .icon
|
.card:focus-visible .icon
|
||||||
{
|
{
|
||||||
@ -174,7 +189,7 @@ if(icon_override){
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<a class=card href="/rezepte/{recipe.short_name}" data-tags=[{recipe.tags}]>
|
<a class="card {search}" href="/rezepte/{recipe.short_name}" data-tags=[{recipe.tags}]>
|
||||||
{#if icon_override || recipe.season.includes(current_month)}
|
{#if icon_override || recipe.season.includes(current_month)}
|
||||||
<a class=icon href="/rezepte/season/{current_month}">{recipe.icon}</a>
|
<a class=icon href="/rezepte/season/{current_month}">{recipe.icon}</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -2,9 +2,15 @@
|
|||||||
|
|
||||||
import Cross from '$lib/assets/icons/Cross.svelte'
|
import Cross from '$lib/assets/icons/Cross.svelte'
|
||||||
|
|
||||||
export let tags:string[] = []
|
// all data shared with rest of page in card_data
|
||||||
let new_tag
|
export let card_data
|
||||||
|
|
||||||
|
if(!card_data.tags){
|
||||||
|
card_data.tags = []
|
||||||
|
}
|
||||||
|
|
||||||
|
//locals
|
||||||
|
let new_tag
|
||||||
let image_preview_url
|
let image_preview_url
|
||||||
|
|
||||||
// Winter: ❄️
|
// Winter: ❄️
|
||||||
@ -13,7 +19,6 @@ let image_preview_url
|
|||||||
// Fastenzeit: ✝️
|
// Fastenzeit: ✝️
|
||||||
// Herbst: 🍂
|
// Herbst: 🍂
|
||||||
// Sommer: ☀️
|
// Sommer: ☀️
|
||||||
import upload_src from "$lib/assets/icons/upload.svg"
|
|
||||||
|
|
||||||
|
|
||||||
export function show_local_image(){
|
export function show_local_image(){
|
||||||
@ -38,15 +43,15 @@ export function remove_selected_images(){
|
|||||||
|
|
||||||
export function add_to_tags(){
|
export function add_to_tags(){
|
||||||
if(new_tag){
|
if(new_tag){
|
||||||
if(! tags.includes(new_tag)){
|
if(! card_data.tags.includes(new_tag)){
|
||||||
tags.push(new_tag)
|
card_data.tags.push(new_tag)
|
||||||
tags = tags;
|
card_data.tags = card_data.tags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new_tag = ""
|
new_tag = ""
|
||||||
}
|
}
|
||||||
export function remove_from_tags(tag){
|
export function remove_from_tags(tag){
|
||||||
tags = tags.filter(item => item !== tag)
|
card_data.tags = card_data.tags.filter(item => item !== tag)
|
||||||
}
|
}
|
||||||
export function add_on_enter(event){
|
export function add_on_enter(event){
|
||||||
if(event.key === 'Enter'){
|
if(event.key === 'Enter'){
|
||||||
@ -55,14 +60,14 @@ export function add_on_enter(event){
|
|||||||
}
|
}
|
||||||
export function remove_on_enter(event, tag){
|
export function remove_on_enter(event, tag){
|
||||||
if(event.key === 'Enter'){
|
if(event.key === 'Enter'){
|
||||||
tags = tags.filter(item => item !== tag)
|
card_data.tags = card_data.tags.filter(item => item !== tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
.card{
|
.card{
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-left: 100px;
|
margin-inline: auto;
|
||||||
--card-width: 300px;
|
--card-width: 300px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -127,11 +132,6 @@ export function remove_on_enter(event, tag){
|
|||||||
z-index: 4;
|
z-index: 4;
|
||||||
transition:200ms;
|
transition:200ms;
|
||||||
}
|
}
|
||||||
.delete svg{
|
|
||||||
width: 2rem;
|
|
||||||
height: 2rem;
|
|
||||||
fill: white;
|
|
||||||
}
|
|
||||||
.delete:hover{
|
.delete:hover{
|
||||||
transform: scale(1.2, 1.2);
|
transform: scale(1.2, 1.2);
|
||||||
}
|
}
|
||||||
@ -333,7 +333,7 @@ input::placeholder{
|
|||||||
|
|
||||||
<div class=card href="" >
|
<div class=card href="" >
|
||||||
|
|
||||||
<input class=icon placeholder=😀/>
|
<input class=icon placeholder=😀 bind:value={card_data.icon}/>
|
||||||
{#if image_preview_url}
|
{#if image_preview_url}
|
||||||
<img src={image_preview_url} class=img_preview width=300px height=300px />
|
<img src={image_preview_url} class=img_preview width=300px height=300px />
|
||||||
{/if}
|
{/if}
|
||||||
@ -351,13 +351,13 @@ input::placeholder{
|
|||||||
</div>
|
</div>
|
||||||
<input type="file" id=img_picker accept="image/webp image/jpeg" on:change={show_local_image}>
|
<input type="file" id=img_picker accept="image/webp image/jpeg" on:change={show_local_image}>
|
||||||
<div class=title>
|
<div class=title>
|
||||||
<input class=category placeholder=Kategorie.../>
|
<input class=category placeholder=Kategorie... bind:value={card_data.category}/>
|
||||||
<div>
|
<div>
|
||||||
<input class=name placeholder=Name.../>
|
<input class=name placeholder=Name... bind:value={card_data.name}/>
|
||||||
<input class=description placeholder=Kurzbeschreibung.../>
|
<input class=description placeholder=Kurzbeschreibung... bind:value={card_data.description}/>
|
||||||
</div>
|
</div>
|
||||||
<div class=tags>
|
<div class=tags>
|
||||||
{#each tags as tag}
|
{#each card_data.tags as tag}
|
||||||
<div class="tag" tabindex="0" on:keypress={remove_on_enter(event ,tag)} on:click='{remove_from_tags(tag)}'>{tag}</div>
|
<div class="tag" tabindex="0" on:keypress={remove_on_enter(event ,tag)} on:click='{remove_from_tags(tag)}'>{tag}</div>
|
||||||
{/each}
|
{/each}
|
||||||
<div class="tag input_wrapper"><span class=input>+</span><input class="tag_input" type="text" on:keypress={add_on_enter} on:focusout={add_to_tags} size="1" bind:value={new_tag} placeholder=Stichwort...></div>
|
<div class="tag input_wrapper"><span class=input>+</span><input class="tag_input" type="text" on:keypress={add_on_enter} on:focusout={add_to_tags} size="1" bind:value={new_tag} placeholder=Stichwort...></div>
|
||||||
|
@ -5,11 +5,11 @@ import Cross from '$lib/assets/icons/Cross.svelte'
|
|||||||
import Plus from '$lib/assets/icons/Plus.svelte'
|
import Plus from '$lib/assets/icons/Plus.svelte'
|
||||||
import Check from '$lib/assets/icons/Check.svelte'
|
import Check from '$lib/assets/icons/Check.svelte'
|
||||||
|
|
||||||
let ingredients_lists = [
|
import "$lib/css/action_button.css"
|
||||||
{name: "",
|
|
||||||
ingredients: [],
|
import { do_on_key } from '$lib/components/do_on_key.js'
|
||||||
}
|
|
||||||
]
|
export let ingredients
|
||||||
|
|
||||||
let new_ingredient = {
|
let new_ingredient = {
|
||||||
amount: "",
|
amount: "",
|
||||||
@ -22,6 +22,7 @@ let edit_ingredient = {
|
|||||||
amount: "",
|
amount: "",
|
||||||
unit: "",
|
unit: "",
|
||||||
name: "",
|
name: "",
|
||||||
|
sublist: "",
|
||||||
list_index: "",
|
list_index: "",
|
||||||
ingredient_index: "",
|
ingredient_index: "",
|
||||||
}
|
}
|
||||||
@ -40,112 +41,345 @@ function get_sublist_index(sublist_name, list){
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
export function show_modal_edit_subheading_ingredient(list_index){
|
export function show_modal_edit_subheading_ingredient(list_index){
|
||||||
edit_heading.name = ingredients_lists[list_index].name
|
edit_heading.name = ingredients[list_index].name
|
||||||
edit_heading.list_index = list_index
|
edit_heading.list_index = list_index
|
||||||
const el = document.querySelector('#edit_subheading_ingredient_modal')
|
const el = document.querySelector('#edit_subheading_ingredient_modal')
|
||||||
el.showModal()
|
el.showModal()
|
||||||
}
|
}
|
||||||
export function edit_subheading_and_close_modal(){
|
export function edit_subheading_and_close_modal(){
|
||||||
ingredients_lists[edit_heading.list_index].name = edit_heading.name
|
ingredients[edit_heading.list_index].name = edit_heading.name
|
||||||
const el = document.querySelector('#edit_subheading_ingredient_modal')
|
const el = document.querySelector('#edit_subheading_ingredient_modal')
|
||||||
el.close()
|
el.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function add_new_ingredient(){
|
export function add_new_ingredient(){
|
||||||
let list_index = get_sublist_index(new_ingredient.sublist, ingredients_lists)
|
if(!new_ingredient.name){
|
||||||
if(list_index == -1){
|
return
|
||||||
ingredients_lists.push({
|
|
||||||
name: new_ingredient.sublist,
|
|
||||||
ingredients: [],
|
|
||||||
})
|
|
||||||
list_index = ingredients_lists.length - 1
|
|
||||||
}
|
}
|
||||||
ingredients_lists[list_index].ingredients.push({ ...new_ingredient})
|
let list_index = get_sublist_index(new_ingredient.sublist, ingredients)
|
||||||
ingredients_lists = ingredients_lists //tells svelte to update dom
|
if(list_index == -1){
|
||||||
|
ingredients.push({
|
||||||
|
name: new_ingredient.sublist,
|
||||||
|
list: [],
|
||||||
|
})
|
||||||
|
list_index = ingredients.length - 1
|
||||||
|
}
|
||||||
|
ingredients[list_index].list.push({ ...new_ingredient})
|
||||||
|
ingredients = ingredients //tells svelte to update dom
|
||||||
}
|
}
|
||||||
export function remove_list(list_index){
|
export function remove_list(list_index){
|
||||||
ingredients_lists.splice(list_index, 1);
|
if(ingredients[list_index].list.length > 1){
|
||||||
ingredients_lists = ingredients_lists //tells svelte to update dom
|
const response = confirm("Bist du dir sicher, dass du diese Liste löschen möchtest? Alle Zutaten der Liste werden hiermit auch gelöscht.");
|
||||||
|
if(!response){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ingredients.splice(list_index, 1);
|
||||||
|
ingredients = ingredients //tells svelte to update dom
|
||||||
}
|
}
|
||||||
export function remove_ingredient(list_index, ingredient_index){
|
export function remove_ingredient(list_index, ingredient_index){
|
||||||
ingredients_lists[list_index].ingredients.splice(ingredient_index, 1)
|
ingredients[list_index].list.splice(ingredient_index, 1)
|
||||||
ingredients_lists = ingredients_lists //tells svelte to update dom
|
ingredients = ingredients //tells svelte to update dom
|
||||||
}
|
}
|
||||||
|
|
||||||
export function show_modal_edit_ingredient(list_index, ingredient_index){
|
export function show_modal_edit_ingredient(list_index, ingredient_index){
|
||||||
edit_ingredient = {...ingredients_lists[list_index].ingredients[ingredient_index]}
|
edit_ingredient = {...ingredients[list_index].list[ingredient_index]}
|
||||||
edit_ingredient.list_index = list_index
|
edit_ingredient.list_index = list_index
|
||||||
edit_ingredient.ingredient_index = ingredient_index
|
edit_ingredient.ingredient_index = ingredient_index
|
||||||
|
edit_ingredient.sublist = ingredients[list_index].name
|
||||||
const modal_el = document.querySelector("#edit_ingredient_modal");
|
const modal_el = document.querySelector("#edit_ingredient_modal");
|
||||||
modal_el.showModal();
|
modal_el.showModal();
|
||||||
}
|
}
|
||||||
export function edit_ingredient_and_close_modal(){
|
export function edit_ingredient_and_close_modal(){
|
||||||
ingredients_lists[edit_ingredient.list_index].ingredients[edit_ingredient.ingredient_index] = {
|
ingredients[edit_ingredient.list_index].list[edit_ingredient.ingredient_index] = {
|
||||||
amount: edit_ingredient.amount,
|
amount: edit_ingredient.amount,
|
||||||
unit: edit_ingredient.unit,
|
unit: edit_ingredient.unit,
|
||||||
name: edit_ingredient.name,
|
name: edit_ingredient.name,
|
||||||
}
|
}
|
||||||
|
ingredients[edit_ingredient.list_index].name = edit_ingredient.sublist
|
||||||
const modal_el = document.querySelector("#edit_ingredient_modal");
|
const modal_el = document.querySelector("#edit_ingredient_modal");
|
||||||
modal_el.close();
|
modal_el.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function show_keys(event){
|
||||||
|
console.log(event.ctrlKey, event.key)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
input::placeholder{
|
||||||
|
all:unset;
|
||||||
|
}
|
||||||
|
input{
|
||||||
|
all:unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.heading{
|
||||||
|
all: unset;
|
||||||
|
background-color: var(--nord0);
|
||||||
|
padding: 1rem;
|
||||||
|
padding-inline: 2rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 1000px;
|
||||||
|
color: white;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transition: 200ms;
|
||||||
|
}
|
||||||
|
input.heading:hover{
|
||||||
|
background-color: var(--nord1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading_wrapper{
|
||||||
|
position: relative;
|
||||||
|
width: 300px;
|
||||||
|
margin-inline: auto;
|
||||||
|
transition: 200ms;
|
||||||
|
}
|
||||||
|
.heading_wrapper:hover
|
||||||
|
{
|
||||||
|
transform:scale(1.1,1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading_wrapper button{
|
||||||
|
position: absolute;
|
||||||
|
bottom: -1.5rem;
|
||||||
|
right: -5rem;
|
||||||
|
}
|
||||||
|
.adder{
|
||||||
|
margin-inline: auto;
|
||||||
|
position: relative;
|
||||||
|
margin-block: 3rem;
|
||||||
|
width: 400px;
|
||||||
|
border-radius: 20px;
|
||||||
|
transition: 200ms;
|
||||||
|
}
|
||||||
|
.shadow{
|
||||||
|
box-shadow: 0 0 1em 0.2em rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
.shadow:hover{
|
||||||
|
box-shadow: 0 0 1em 0.4em rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
.adder button{
|
||||||
|
position: absolute;
|
||||||
|
right: -1.5rem;
|
||||||
|
bottom: -1.5rem;
|
||||||
|
}
|
||||||
|
.category{
|
||||||
|
all: unset;
|
||||||
|
position: absolute;
|
||||||
|
--font_size: 1.5rem;
|
||||||
|
top: -1em;
|
||||||
|
left: -1em;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
background-color: var(--nord0);
|
||||||
|
color: var(--nord4);
|
||||||
|
border-radius: 1000000px;
|
||||||
|
width: 23ch;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
transition: 100ms;
|
||||||
|
box-shadow: 0.5em 0.5em 1em 0.4em rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
.category:hover{
|
||||||
|
background-color: var(--nord1);
|
||||||
|
transform: scale(1.05,1.05);
|
||||||
|
}
|
||||||
|
.adder:hover,
|
||||||
|
.adder:focus-within
|
||||||
|
{
|
||||||
|
transform: scale(1.05, 1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add_ingredient{
|
||||||
|
font-family: sans-serif;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
padding: 2rem;
|
||||||
|
padding-top: 2.5rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
background-color: var(--blue);
|
||||||
|
color: #bbb;
|
||||||
|
transition: 200ms;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
.add_ingredient input{
|
||||||
|
border: 2px solid var(--nord4);
|
||||||
|
color: var(--nord4);
|
||||||
|
border-radius: 1000px;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
transition: 100ms;
|
||||||
|
}
|
||||||
|
.add_ingredient input:hover,
|
||||||
|
.add_ingredient input:focus-visible
|
||||||
|
{
|
||||||
|
border-color: white;
|
||||||
|
color: white;
|
||||||
|
transform: scale(1.02, 1.02);
|
||||||
|
|
||||||
|
}
|
||||||
|
.add_ingredient input:nth-of-type(1){
|
||||||
|
max-width: 8ch;
|
||||||
|
}
|
||||||
|
.add_ingredient input:nth-of-type(2){
|
||||||
|
max-width: 8ch;
|
||||||
|
}
|
||||||
|
.add_ingredient input:nth-of-type(3){
|
||||||
|
max-width: 30ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog{
|
||||||
|
box-sizing: content-box;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(255,255,255, 0.001);
|
||||||
|
border: unset;
|
||||||
|
margin: 0;
|
||||||
|
transition: 500ms;
|
||||||
|
}
|
||||||
|
dialog[open]{
|
||||||
|
animation: show 200ms ease forwards;
|
||||||
|
}
|
||||||
|
@keyframes show{
|
||||||
|
from {
|
||||||
|
backdrop-filter: blur(0px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dialog .adder{
|
||||||
|
margin-top: 5rem;
|
||||||
|
}
|
||||||
|
dialog h2{
|
||||||
|
font-size: 3rem;
|
||||||
|
font-family: sans-serif;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30vh;
|
||||||
|
margin-top: 30dvh;
|
||||||
|
filter: drop-shadow(0 0 0.4em 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{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-left: 2rem;
|
||||||
|
}
|
||||||
|
li:nth-child(2n){
|
||||||
|
background-color: var(--nord4);
|
||||||
|
|
||||||
|
}
|
||||||
|
li:nth-child(2n+1){
|
||||||
|
background-color: var(--nord6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button_subtle{
|
||||||
|
padding: 0em;
|
||||||
|
animation: unset;
|
||||||
|
margin: 0.2em 0.1em;
|
||||||
|
background-color: transparent;
|
||||||
|
box-shadow: unset;
|
||||||
|
}
|
||||||
|
.button_subtle:hover{
|
||||||
|
scale: 1.2 1.2;
|
||||||
|
}
|
||||||
|
h3{
|
||||||
|
margin-inline: auto;
|
||||||
|
width: fit-content;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
max-width: 1000px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
{#each ingredients_lists as list, list_index}
|
{#each ingredients as list, list_index}
|
||||||
<h3>
|
<h3>
|
||||||
|
<div>
|
||||||
{#if list.name }
|
{#if list.name }
|
||||||
{list.name}
|
{list.name}
|
||||||
{:else}
|
{:else}
|
||||||
Leer
|
Leer
|
||||||
{/if}
|
{/if}
|
||||||
<button class=edit on:click="{() => show_modal_edit_subheading_ingredient(list_index)}">
|
</div>
|
||||||
<Pen></Pen> </button>
|
<div class=mod_icons>
|
||||||
<button class=remove on:click="{() => remove_list(list_index)}">
|
<button class="action_button button_subtle" on:click="{() => show_modal_edit_subheading_ingredient(list_index)}">
|
||||||
<Cross></Cross>
|
<Pen fill=var(--nord1)></Pen> </button>
|
||||||
|
<button class="action_button button_subtle" on:click="{() => remove_list(list_index)}">
|
||||||
|
<Cross fill=var(--nord1)></Cross>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{#each list.ingredients as ingredient, ingredient_index}
|
{#each list.list as ingredient, ingredient_index}
|
||||||
<li>{ingredient.amount} {ingredient.unit} {ingredient.name}
|
<li><div class=li_wrapper><div>{ingredient.amount} {ingredient.unit} {ingredient.name}</div>
|
||||||
<button class=edit 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></Pen>
|
<Pen fill=var(--nord1) height=1em width=1em></Pen>
|
||||||
</button>
|
|
||||||
<button class=remove on:click="{() => remove_ingredient(list_index, ingredient_index)}">
|
|
||||||
<Cross></Cross>
|
|
||||||
</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></div>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<input type="text" bind:value={new_ingredient.sublist} placeholder="Unterkategorie (optional)">
|
<div class="adder shadow">
|
||||||
<div class=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)}>
|
||||||
<input type="text" id=amount placeholder="250..." bind:value={new_ingredient.amount}>
|
<div class=add_ingredient>
|
||||||
<input type="text" id=unit placeholder="mL..." bind:value={new_ingredient.unit}>
|
<input type="text" placeholder="250..." bind:value={new_ingredient.amount} on:keypress={(event) => do_on_key(event, 'Enter', false, add_new_ingredient)}>
|
||||||
<input type="text" id=name placeholder="Milch..." bind:value={new_ingredient.name}>
|
<input type="text" placeholder="mL..." bind:value={new_ingredient.unit} on:keypress={(event) => do_on_key(event, 'Enter', false, add_new_ingredient)}>
|
||||||
<button on:click={() => add_new_ingredient()}>
|
<input type="text" placeholder="Milch..." bind:value={new_ingredient.name} on:keypress={(event) => do_on_key(event, 'Enter', false, add_new_ingredient)}>
|
||||||
<Plus></Plus>
|
<button on:click={() => add_new_ingredient()} class=action_button>
|
||||||
|
<Plus fill=white style="width: 2rem; height: 2rem;"></Plus>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<dialog class=ingredient id=edit_ingredient_modal>
|
<dialog id=edit_ingredient_modal>
|
||||||
<input type="text" id=amount placeholder="250..." bind:value={edit_ingredient.amount}>
|
<h2>Zutat verändern</h2>
|
||||||
<input type="text" id=unit placeholder="mL..." bind:value={edit_ingredient.unit}>
|
<div class=adder>
|
||||||
<input type="text" id=name placeholder="Milch..." bind:value={edit_ingredient.name}>
|
<input class=category type="text" bind:value={edit_ingredient.sublist} placeholder="Kategorie (optional)">
|
||||||
<button on:click={edit_ingredient_and_close_modal}>
|
<div class=add_ingredient on:keypress={(event) => do_on_key(event, 'Enter', false, add_new_ingredient)}>
|
||||||
<Check></Check>
|
<input type="text" placeholder="250..." bind:value={edit_ingredient.amount} on:keypress={(event) => do_on_key(event, 'Enter', false, add_new_ingredient)}>
|
||||||
|
<input type="text" placeholder="mL..." bind:value={edit_ingredient.unit} on:keypress={(event) => do_on_key(event, 'Enter', false, add_new_ingredient)}>
|
||||||
|
<input type="text" placeholder="Milch..." bind:value={edit_ingredient.name} on:keypress={(event) => do_on_key(event, 'Enter', false, edit_ingredient_and_close_modal)}>
|
||||||
|
<button class=action_button on:click={edit_ingredient_and_close_modal}>
|
||||||
|
<Check fill=white style="width: 2rem; height: 2rem;"></Check>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<dialog id=edit_subheading_ingredient_modal>
|
<dialog id=edit_subheading_ingredient_modal>
|
||||||
<input type="text" bind:value={edit_heading.name}>
|
<h2>Kategorie umbenennen</h2>
|
||||||
<button on:click={edit_subheading_and_close_modal}>
|
<div class=heading_wrapper>
|
||||||
<Check></Check>
|
<input class=heading type="text" bind:value={edit_heading.name} on:keypress={(event) => do_on_key(event, 'Enter', false, add_new_ingredient)}>
|
||||||
|
<button class=action_button on:click={edit_subheading_and_close_modal}>
|
||||||
|
<Check fill=white style="width:2rem; height:2rem;"></Check>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
@ -6,16 +6,16 @@ import Plus from '$lib/assets/icons/Plus.svelte'
|
|||||||
import Check from '$lib/assets/icons/Check.svelte'
|
import Check from '$lib/assets/icons/Check.svelte'
|
||||||
|
|
||||||
import '$lib/components/nordtheme.css'
|
import '$lib/components/nordtheme.css'
|
||||||
|
import "$lib/css/action_button.css"
|
||||||
|
|
||||||
|
import { do_on_key } from '$lib/components/do_on_key.js'
|
||||||
|
|
||||||
const step_placeholder = "Kartoffeln schälen..."
|
const step_placeholder = "Kartoffeln schälen..."
|
||||||
let instructions = [{
|
export let instructions
|
||||||
name: "",
|
|
||||||
steps: [],
|
|
||||||
}]
|
|
||||||
|
|
||||||
let new_step = {
|
let new_step = {
|
||||||
name: "",
|
name: "",
|
||||||
step: "Kartoffeln schälen..."
|
step: step_placeholder
|
||||||
}
|
}
|
||||||
|
|
||||||
let edit_heading = {
|
let edit_heading = {
|
||||||
@ -37,6 +37,9 @@ export function remove_list(list_index){
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function add_new_step(){
|
export function add_new_step(){
|
||||||
|
if(new_step.step == step_placeholder){
|
||||||
|
return
|
||||||
|
}
|
||||||
let list_index = get_sublist_index(new_step.name, instructions)
|
let list_index = get_sublist_index(new_step.name, instructions)
|
||||||
if(list_index == -1){
|
if(list_index == -1){
|
||||||
instructions.push({
|
instructions.push({
|
||||||
@ -51,9 +54,6 @@ export function add_new_step(){
|
|||||||
const el = document.querySelector("#step")
|
const el = document.querySelector("#step")
|
||||||
el.innerHTML = step_placeholder
|
el.innerHTML = step_placeholder
|
||||||
instructions = instructions //tells svelte to update dom
|
instructions = instructions //tells svelte to update dom
|
||||||
|
|
||||||
new_step.step = ""
|
|
||||||
add_placeholder()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function remove_step(list_index, step_index){
|
export function remove_step(list_index, step_index){
|
||||||
@ -107,7 +107,7 @@ export function clear_step(){
|
|||||||
export function add_placeholder(){
|
export function add_placeholder(){
|
||||||
const el = document.querySelector("#step")
|
const el = document.querySelector("#step")
|
||||||
if(el.innerHTML == ""){
|
if(el.innerHTML == ""){
|
||||||
el.innerHTML = "Kartoffeln schälen..."
|
el.innerHTML = step_placeholder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -117,6 +117,43 @@ input::placeholder{
|
|||||||
all:unset;
|
all:unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
input.heading{
|
||||||
|
all: unset;
|
||||||
|
background-color: var(--nord0);
|
||||||
|
padding: 1rem;
|
||||||
|
padding-inline: 2rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 1000px;
|
||||||
|
color: white;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transition: 200ms;
|
||||||
|
}
|
||||||
|
input.heading:hover,
|
||||||
|
input.heading:focus-visible
|
||||||
|
{
|
||||||
|
background-color: var(--nord1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading_wrapper{
|
||||||
|
position: relative;
|
||||||
|
width: 300px;
|
||||||
|
margin-inline: auto;
|
||||||
|
transition: 200ms;
|
||||||
|
}
|
||||||
|
.heading_wrapper:hover,
|
||||||
|
.heading_wrapper:focus-visible
|
||||||
|
{
|
||||||
|
transform:scale(1.1,1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading_wrapper button{
|
||||||
|
position: absolute;
|
||||||
|
bottom: -1.5rem;
|
||||||
|
right: -5rem;
|
||||||
|
}
|
||||||
.adder{
|
.adder{
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -129,24 +166,9 @@ input::placeholder{
|
|||||||
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);
|
||||||
}
|
}
|
||||||
.adder button{
|
.adder button{
|
||||||
all:unset;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -1.5rem;
|
right: -1.5rem;
|
||||||
bottom: -1.5rem;
|
bottom: -1.5rem;
|
||||||
cursor: pointer;
|
|
||||||
display:flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: var(--red);
|
|
||||||
border-radius:100000px;
|
|
||||||
padding: 1rem;
|
|
||||||
transition: 100ms;
|
|
||||||
box-shadow: 0 0 1em 0.4em rgba(0,0,0,0.3);
|
|
||||||
}
|
|
||||||
.adder button:hover{
|
|
||||||
background-color: var(--nord0);
|
|
||||||
transform: scale(1.1,1.1);
|
|
||||||
box-shadow: 0 0 1em 0.8em rgba(0,0,0,0.3);
|
|
||||||
}
|
}
|
||||||
.category{
|
.category{
|
||||||
all: unset;
|
all: unset;
|
||||||
@ -164,11 +186,15 @@ input::placeholder{
|
|||||||
transition: 100ms;
|
transition: 100ms;
|
||||||
box-shadow: 0.5em 0.5em 1em 0.4em rgba(0,0,0,0.3);
|
box-shadow: 0.5em 0.5em 1em 0.4em rgba(0,0,0,0.3);
|
||||||
}
|
}
|
||||||
.category:hover{
|
.category:hover,
|
||||||
|
.category:focus-visible
|
||||||
|
{
|
||||||
background-color: var(--nord1);
|
background-color: var(--nord1);
|
||||||
transform: scale(1.05,1.05);
|
transform: scale(1.05,1.05);
|
||||||
}
|
}
|
||||||
.adder:hover{
|
.adder:hover,
|
||||||
|
.adder:focus-within
|
||||||
|
{
|
||||||
transform: scale(1.1, 1.1);
|
transform: scale(1.1, 1.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,9 +219,11 @@ dialog{
|
|||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: rgba(0, 0, 0, 0.6);
|
background-color: rgba(255,255,255, 0.001);
|
||||||
border: unset;
|
border: unset;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
transition: 200ms;
|
||||||
}
|
}
|
||||||
dialog .adder{
|
dialog .adder{
|
||||||
margin-top: 5rem;
|
margin-top: 5rem;
|
||||||
@ -205,35 +233,21 @@ dialog h2{
|
|||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
color: white;
|
color: white;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 30%;
|
margin-top: 30vh;
|
||||||
}
|
margin-top: 30dvh;
|
||||||
|
filter: drop-shadow(0 0 0.4em black)
|
||||||
@keyframes shake{
|
drop-shadow(0 0 1em black)
|
||||||
0%{
|
|
||||||
transform: rotate(0)
|
|
||||||
scale(1,1);
|
|
||||||
}
|
|
||||||
25%{
|
|
||||||
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
|
||||||
transform: rotate(30deg)
|
|
||||||
scale(1.2,1.2)
|
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
50%{
|
dialog[open]{
|
||||||
|
animation: show 200ms ease forwards;
|
||||||
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
|
||||||
transform: rotate(-30deg)
|
|
||||||
scale(1.2,1.2);
|
|
||||||
}
|
}
|
||||||
74%{
|
@keyframes show{
|
||||||
|
from {
|
||||||
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
backdrop-filter: blur(0px);
|
||||||
transform: rotate(30deg)
|
|
||||||
scale(1.2, 1.2);
|
|
||||||
}
|
}
|
||||||
100%{
|
to {
|
||||||
transform: rotate(0)
|
backdrop-filter: blur(10px);
|
||||||
scale(1,1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -269,10 +283,10 @@ dialog h2{
|
|||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<div class='adder shadow'>
|
<div class='adder shadow'>
|
||||||
<input class=category type="text" bind:value={new_step.name} placeholder="Unterkategorie (optional)">
|
<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}></p>
|
<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>
|
||||||
<button on:click={() => add_new_step()}>
|
<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>
|
||||||
|
|
||||||
@ -281,18 +295,21 @@ dialog h2{
|
|||||||
<dialog id=edit_step_modal>
|
<dialog id=edit_step_modal>
|
||||||
<h2>Schritt verändern</h2>
|
<h2>Schritt verändern</h2>
|
||||||
<div class=adder>
|
<div class=adder>
|
||||||
<input class=category type="text" bind:value={edit_step.name} placeholder="Unterkategorie (optional)">
|
<input class=category type="text" bind:value={edit_step.name} placeholder="Unterkategorie (optional)" on:keypress={(event) => do_on_key(event, 'Enter', false , edit_step_and_close_modal)}>
|
||||||
<div class=add_step>
|
<div class=add_step>
|
||||||
<p id=step contenteditable bind:innerHTML={edit_step.step}></p>
|
<p id=step contenteditable bind:innerHTML={edit_step.step} on:keypress={(event) => do_on_key(event, 'Enter', true , edit_step_and_close_modal)}></p>
|
||||||
<button on:click="{() => edit_step_and_close_modal()}" >
|
<button class=action_button on:click="{() => edit_step_and_close_modal()}" >
|
||||||
<Check fill=white style="height: 2rem; width: 2rem"></Check>
|
<Check fill=white style="height: 2rem; width: 2rem"></Check>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<dialog id=edit_subheading_steps_modal>
|
<dialog id=edit_subheading_steps_modal>
|
||||||
<input type="text" bind:value={edit_heading.name}>
|
<h2>Kategorie umbenennen</h2>
|
||||||
<button on:click={edit_subheading_steps_and_close_modal}>
|
<div class=heading_wrapper>
|
||||||
<Check></Check>
|
<input class="heading" type="text" bind:value={edit_heading.name} on:keypress={(event) => do_on_key(event, 'Enter', false, edit_subheading_steps_and_close_modal)}>
|
||||||
|
<button on:click={edit_subheading_steps_and_close_modal} class=action_button>
|
||||||
|
<Check fill=white style="height: 2rem; width: 2rem"></Check>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
76
src/lib/components/RecipeEditor.svelte
Normal file
76
src/lib/components/RecipeEditor.svelte
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let card_data ={
|
||||||
|
}
|
||||||
|
let short_name
|
||||||
|
let password
|
||||||
|
let datecreated = new Date()
|
||||||
|
let datemodified = datecreated
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
export let season = []
|
||||||
|
import SeasonSelect from '$lib/components/SeasonSelect.svelte';
|
||||||
|
|
||||||
|
import CreateIngredientList from '$lib/components/CreateIngredientList.svelte';
|
||||||
|
export let ingredients = []
|
||||||
|
|
||||||
|
import CreateStepList from '$lib/components/CreateStepList.svelte';
|
||||||
|
export let instructions = []
|
||||||
|
|
||||||
|
async function doPost () {
|
||||||
|
const res = await fetch('/api/add', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
recipe: {
|
||||||
|
season: season,
|
||||||
|
...card_data,
|
||||||
|
images: [{
|
||||||
|
mediapath: short_name + '.webp',
|
||||||
|
alt: "",
|
||||||
|
caption: ""
|
||||||
|
}],
|
||||||
|
short_name,
|
||||||
|
datecreated,
|
||||||
|
datemodified,
|
||||||
|
instructions,
|
||||||
|
ingredients,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
bearer: password,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const json = await res.json()
|
||||||
|
result = JSON.stringify(json)
|
||||||
|
console.log(result)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
input.temp{
|
||||||
|
all: unset;
|
||||||
|
display: block;
|
||||||
|
margin: 1rem auto;
|
||||||
|
padding: 0.2em 1em;
|
||||||
|
border-radius: 1000px;
|
||||||
|
background-color: var(--nord4);
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<CardAdd {card_data}></CardAdd>
|
||||||
|
|
||||||
|
<input class=temp bind:value={short_name} placeholder="Kurzname"/>
|
||||||
|
|
||||||
|
<SeasonSelect {season}></SeasonSelect>
|
||||||
|
<button on:click={() => console.log(season)}>PRINTOUT season</button>
|
||||||
|
|
||||||
|
<h2>Zutaten</h2>
|
||||||
|
<CreateIngredientList {ingredients}></CreateIngredientList>
|
||||||
|
<h2>Zubereitung</h2>
|
||||||
|
<CreateStepList {instructions} ></CreateStepList>
|
||||||
|
<input class=temp type="password" placeholder=Passwort bind:value={password}>
|
@ -1,11 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL v3.0
|
import {onMount} from "svelte";
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
import "$lib/css/nordtheme.css";
|
||||||
for (e of document.getElementsByClassName("js-only")) {
|
|
||||||
e.classList.remove("js-only");
|
|
||||||
}
|
|
||||||
|
|
||||||
const recipes = document.querySelectorAll(".card");
|
|
||||||
|
onMount(() => {
|
||||||
|
const recipes = document.querySelectorAll(".search_me");
|
||||||
console.log("######", recipes)
|
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");
|
||||||
@ -21,23 +20,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const searchString = `${recipe.textContent} ${recipe.dataset.tags}`.toLowerCase().normalize('NFD').replace(/\p{Diacritic}/gu, "");
|
const searchString = `${recipe.textContent} ${recipe.dataset.tags}`.toLowerCase().normalize('NFD').replace(/\p{Diacritic}/gu, "");
|
||||||
const isMatch = searchTerms.every(term => searchString.includes(term));
|
const isMatch = searchTerms.every(term => searchString.includes(term));
|
||||||
|
|
||||||
recipe.hidden = !isMatch;
|
recipe.style.display = (isMatch ? 'block' : 'none');
|
||||||
recipe.classList.toggle("matched-recipe", hasFilter && isMatch);
|
recipe.classList.toggle("matched-recipe", hasFilter && isMatch);
|
||||||
})
|
})
|
||||||
|
|
||||||
recipes.forEach(recipe => {
|
|
||||||
if(recipe.hidden == false){
|
|
||||||
recipe.parentElement.previousElementSibling.hidden = false;}
|
|
||||||
})
|
|
||||||
if(click_only_result){
|
|
||||||
let matched_recipes = document.querySelectorAll(".matched-recipe");
|
|
||||||
if(matched_recipes.length == 1 &&
|
|
||||||
matched_recipes[0].parentElement.previousElementSibling != noch_zu_probieren_header){
|
|
||||||
matched_recipes[0].lastElementChild.click();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
search.addEventListener("input", () => {
|
search.addEventListener("input", () => {
|
||||||
do_search();
|
do_search();
|
||||||
@ -46,7 +32,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
clearSearch.addEventListener("click", () => {
|
clearSearch.addEventListener("click", () => {
|
||||||
search.value = "";
|
search.value = "";
|
||||||
recipes.forEach(recipe => {
|
recipes.forEach(recipe => {
|
||||||
recipe.hidden = false;
|
recipe.style.display = 'block';
|
||||||
recipe.classList.remove("matched-recipe");
|
recipe.classList.remove("matched-recipe");
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -61,45 +47,66 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
do_search(click_only_result=true);
|
do_search(click_only_result=true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// @license-end
|
// @license-end
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
input#search {
|
input#search {
|
||||||
all: unset;
|
all: unset;
|
||||||
background: #222;
|
font-family: sans-serif;
|
||||||
|
background: var(--nord0);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 0.7rem 1rem;
|
padding: 0.7rem 2rem;
|
||||||
border-radius: 5px;
|
border-radius: 1000px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
input::placeholder{
|
||||||
|
color: var(--nord6);
|
||||||
|
}
|
||||||
|
|
||||||
.search {
|
.search {
|
||||||
width: 400px;
|
width: 500px;
|
||||||
max-width: 85vw;
|
max-width: 85vw;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 2.5rem auto 1.2rem;
|
margin: 2.5rem auto 1.2rem;
|
||||||
|
font-size: 1.6rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
transition: 100ms;
|
||||||
|
filter: drop-shadow(0.4em 0.5em 0.4em rgba(0,0,0,0.4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search:hover,
|
||||||
|
.search:focus-within
|
||||||
|
{
|
||||||
|
scale: 1.02 1.02;
|
||||||
|
filter: drop-shadow(0.4em 0.5em 1em rgba(0,0,0,0.6))
|
||||||
|
}
|
||||||
button#clear-search {
|
button#clear-search {
|
||||||
all: unset;
|
all: unset;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 6px;
|
right: 0.5em;
|
||||||
height: 30px;
|
width: 1.5em;
|
||||||
width: 30px;
|
height: 1.5em;
|
||||||
color: #888;
|
color: var(--nord6);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color 180ms ease-in-out;
|
transition: color 180ms ease-in-out;
|
||||||
}
|
}
|
||||||
button#clear-search:hover {
|
button#clear-search:hover {
|
||||||
color: #eee;
|
color: white;
|
||||||
|
scale: 1.1 1.1;
|
||||||
|
}
|
||||||
|
button#clear-search:active{
|
||||||
|
transition: 50ms;
|
||||||
|
scale: 0.8 0.8;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="search js-only">
|
<div class="search js-only">
|
||||||
<input type="text" id="search" placeholder="Suche nach Stichwörtern...">
|
<input type="text" id="search" placeholder="Suche nach Stichwörtern...">
|
||||||
<button id="clear-search">
|
<button id="clear-search">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><title>Sucheintrag löschen</title><path d="M135.19 390.14a28.79 28.79 0 0021.68 9.86h246.26A29 29 0 00432 371.13V140.87A29 29 0 00403.13 112H156.87a28.84 28.84 0 00-21.67 9.84v0L46.33 256l88.86 134.11z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M336.67 192.33L206.66 322.34M336.67 322.34L206.66 192.33M336.67 192.33L206.66 322.34M336.67 322.34L206.66 192.33"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><title>Sucheintrag löschen</title><path d="M135.19 390.14a28.79 28.79 0 0021.68 9.86h246.26A29 29 0 00432 371.13V140.87A29 29 0 00403.13 112H156.87a28.84 28.84 0 00-21.67 9.84v0L46.33 256l88.86 134.11z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M336.67 192.33L206.66 322.34M336.67 322.34L206.66 192.33M336.67 192.33L206.66 322.34M336.67 322.34L206.66 192.33"></path></svg></button>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '$lib/components/nordtheme.css';
|
import '$lib/components/nordtheme.css';
|
||||||
import Recipes from '$lib/components/Recipes.svelte';
|
import Recipes from '$lib/components/Recipes.svelte';
|
||||||
|
import Search from './Search.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"]
|
||||||
let month : number;
|
let month : number;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
a.month{
|
a.month{
|
||||||
text-decoration: unset;
|
text-decoration: unset;
|
||||||
|
font-family: sans-serif;
|
||||||
border-radius: 1000px;
|
border-radius: 1000px;
|
||||||
background-color: var(--blue);
|
background-color: var(--blue);
|
||||||
color: var(--nord5);
|
color: var(--nord5);
|
||||||
@ -36,7 +39,9 @@ a.month:hover{
|
|||||||
<a class=month href="/rezepte/season/{i+1}">{month}</a>
|
<a class=month href="/rezepte/season/{i+1}">{month}</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
<section>
|
||||||
|
<Search></Search>
|
||||||
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<slot name=recipes></slot>
|
<slot name=recipes></slot>
|
||||||
</section>
|
</section>
|
||||||
|
80
src/lib/components/SeasonSelect.svelte
Normal file
80
src/lib/components/SeasonSelect.svelte
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<script lang=ts>
|
||||||
|
import "$lib/components/nordtheme.css"
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
let months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
||||||
|
|
||||||
|
export let season : Number[]
|
||||||
|
|
||||||
|
export function set_season(){
|
||||||
|
let temp = []
|
||||||
|
const el = document.getElementById("labels");
|
||||||
|
for(var i = 0; i < el.children.length; i++){
|
||||||
|
if(el.children[i].children[0].children[0].checked){
|
||||||
|
temp.push(i+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
season = temp
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
write_season(season)
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
label{
|
||||||
|
background-color: var(--nord0);
|
||||||
|
color: white;
|
||||||
|
padding: 0.25em 1em;
|
||||||
|
border-radius: 1000px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: 100ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox_container{
|
||||||
|
transition: 100ms;
|
||||||
|
}
|
||||||
|
.checkbox_container:hover{
|
||||||
|
transform: scale(1.1,1.1);
|
||||||
|
}
|
||||||
|
label:hover{
|
||||||
|
background-color: var(--lightblue);
|
||||||
|
}
|
||||||
|
|
||||||
|
label:has(input:checked){
|
||||||
|
background-color: var(--blue);
|
||||||
|
}
|
||||||
|
input[type=checkbox],
|
||||||
|
input[type=checkbox]::before,
|
||||||
|
input[type=checkbox]::after
|
||||||
|
{
|
||||||
|
all: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#labels{
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
gap: min(1rem, 1dvh);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id=labels>
|
||||||
|
{#each months as month}
|
||||||
|
<div class=checkbox_container>
|
||||||
|
<label><input type="checkbox" name="checkbox" value="value" on:click={set_season}>{month}</label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<button on:click={() => console.log("season", season)}> PRINT SEASON FROM SEASON_SELECT</button>
|
8
src/lib/components/do_on_key.js
Normal file
8
src/lib/components/do_on_key.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export function do_on_key(event, key, needsctrl, fn){
|
||||||
|
if(event.key == key){
|
||||||
|
if(needsctrl && !event.ctrlKey){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
}
|
56
src/lib/css/action_button.css
Normal file
56
src/lib/css/action_button.css
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
.action_button{
|
||||||
|
all: unset;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: var(--red);
|
||||||
|
transition: 200ms;
|
||||||
|
box-shadow: 0 0 1em 0.2em rgba(0,0,0,0.3);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 1000px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.action_button:hover,
|
||||||
|
.action_button:focus
|
||||||
|
{
|
||||||
|
background-color: var(--nord0);
|
||||||
|
transform: scale(1.2,1.2);
|
||||||
|
box-shadow: 0 0 1em 0.4em rgba(0,0,0,0.3);
|
||||||
|
animation: shake 0.5s ease forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action_button:active{
|
||||||
|
transition: 50ms;
|
||||||
|
scale: 0.8 0.8;
|
||||||
|
rotate: 30deg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@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(15deg)
|
||||||
|
scale(1.2,1.2)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
50%{
|
||||||
|
|
||||||
|
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
||||||
|
transform: rotate(-15deg)
|
||||||
|
scale(1.2,1.2);
|
||||||
|
}
|
||||||
|
74%{
|
||||||
|
|
||||||
|
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
|
||||||
|
transform: rotate(15deg)
|
||||||
|
scale(1.2, 1.2);
|
||||||
|
}
|
||||||
|
100%{
|
||||||
|
transform: rotate(0)
|
||||||
|
scale(1.2, 1.2);
|
||||||
|
}
|
||||||
|
}
|
25
src/lib/css/nordtheme.css
Normal file
25
src/lib/css/nordtheme.css
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
:root{
|
||||||
|
--nord0: #2E3440;
|
||||||
|
--nord1: #3B4252;
|
||||||
|
--nord2: #434C5E;
|
||||||
|
--nord3: #4C566A;
|
||||||
|
--nord4: #D8DEE9;
|
||||||
|
--nord5: #E5E9F0;
|
||||||
|
--nord6: #ECEFF4;
|
||||||
|
--nord7: #8FBCBB;
|
||||||
|
--nord8: #88C0D0;
|
||||||
|
--nord9: #81A1C1;
|
||||||
|
--nord10: #5E81AC;
|
||||||
|
--nord11: #BF616A;
|
||||||
|
--nord12: #D08770;
|
||||||
|
--nord13: #EBCB8B;
|
||||||
|
--nord14: #A3BE8C;
|
||||||
|
--nord15: #B48EAD;
|
||||||
|
--lightblue: var(--nord9);
|
||||||
|
--blue: var(--nord10);
|
||||||
|
--red: var(--nord11);
|
||||||
|
--orange: var(--nord12);
|
||||||
|
--yellow: var(--nord13);
|
||||||
|
--green: var(--nord14);
|
||||||
|
--purple: var(--nord15);
|
||||||
|
}
|
@ -2,7 +2,7 @@ import mongoose from 'mongoose';
|
|||||||
|
|
||||||
const RecipeSchema = new mongoose.Schema(
|
const RecipeSchema = new mongoose.Schema(
|
||||||
{
|
{
|
||||||
short_name: {type: String, required: true},
|
short_name: {type: String, required: true, unique: true},
|
||||||
name : {type: String, required: true,},
|
name : {type: String, required: true,},
|
||||||
category : {type: String, required: true,},
|
category : {type: String, required: true,},
|
||||||
icon: {type: String, required: true},
|
icon: {type: String, required: true},
|
||||||
|
@ -12,12 +12,14 @@ export const POST: RequestHandler = async ({request}) => {
|
|||||||
console.log("RECIPE:", recipe_json)
|
console.log("RECIPE:", recipe_json)
|
||||||
console.log("BEARER:", bearer_token)
|
console.log("BEARER:", bearer_token)
|
||||||
if(bearer_token === BEARER_TOKEN){
|
if(bearer_token === BEARER_TOKEN){
|
||||||
|
console.log("PASSWORD CORRECT")
|
||||||
await dbConnect();
|
await dbConnect();
|
||||||
await Recipe.create(recipe_json);
|
await Recipe.create(recipe_json);
|
||||||
await dbDisconnect();
|
await dbDisconnect();
|
||||||
return {status: 400}
|
return {status: 400} //TODO: cleanup error throwing
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
console.log("PASSWORD INCORRECT")
|
||||||
return {status: 403}
|
return {status: 403}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
25
src/routes/api/edit/+server.ts
Normal file
25
src/routes/api/edit/+server.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
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}) => {
|
||||||
|
console.log("AT EDIT API")
|
||||||
|
let message = await request.json()
|
||||||
|
const recipe_json = message.recipe
|
||||||
|
const bearer_token = message.headers.bearer
|
||||||
|
console.log("RECIPE:", recipe_json)
|
||||||
|
console.log("BEARER:", bearer_token)
|
||||||
|
if(bearer_token === BEARER_TOKEN){
|
||||||
|
await dbConnect();
|
||||||
|
await Recipe.findOneAndUpdate({short_name: message.old_short_name }, recipe_json);
|
||||||
|
await dbDisconnect();
|
||||||
|
return {status: 400} //TODO: cleanup error throwing
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
console.log("PASSWORD INCORRECT")
|
||||||
|
return {status: 403}
|
||||||
|
}
|
||||||
|
};
|
@ -8,30 +8,17 @@
|
|||||||
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>
|
||||||
<style>
|
|
||||||
.accordion{
|
|
||||||
display:flex;
|
|
||||||
background-color: #111111;
|
|
||||||
flex-direction: row;
|
|
||||||
margin-inline: auto;
|
|
||||||
padding-inline: 1rem;
|
|
||||||
padding-block: 3rem;
|
|
||||||
margin-block: 3rem;
|
|
||||||
align-items:center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<h1>Rezepte</h1>
|
<h1>Rezepte</h1>
|
||||||
<h2>In Saison</h2>
|
<h2>In Saison</h2>
|
||||||
<section>
|
<section>
|
||||||
<MediaScroller>
|
<MediaScroller>
|
||||||
{#each data.season as recipe}
|
{#each data.season as recipe}
|
||||||
<Card {recipe} {current_month}></Card>
|
<Card {recipe} {current_month} search=""></Card>
|
||||||
{/each}
|
{/each}
|
||||||
</MediaScroller>
|
</MediaScroller>
|
||||||
</section>
|
</section>
|
||||||
<!--<Search></Search>-->
|
<Search></Search>
|
||||||
<h2>Alle Rezepte</h2>
|
<h2>Alle Rezepte</h2>
|
||||||
<Recipes>
|
<Recipes>
|
||||||
{#each data.all_brief as recipe}
|
{#each data.all_brief as recipe}
|
||||||
|
@ -1,41 +1,43 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
let name
|
export let card_data ={
|
||||||
|
}
|
||||||
let short_name
|
let short_name
|
||||||
let category
|
let password
|
||||||
let icon
|
|
||||||
let description
|
|
||||||
let datecreated = new Date()
|
let datecreated = new Date()
|
||||||
let datemodified = datecreated
|
let datemodified = datecreated
|
||||||
let tags
|
|
||||||
|
|
||||||
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 SeasonSelect from '$lib/components/SeasonSelect.svelte';
|
||||||
import Search from '$lib/components/Search.svelte';
|
export let season = []
|
||||||
|
|
||||||
import CreateIngredientList from '$lib/components/CreateIngredientList.svelte';
|
import CreateIngredientList from '$lib/components/CreateIngredientList.svelte';
|
||||||
|
export let ingredients = []
|
||||||
|
|
||||||
import CreateStepList from '$lib/components/CreateStepList.svelte';
|
import CreateStepList from '$lib/components/CreateStepList.svelte';
|
||||||
export let data: PageData;
|
export let instructions = []
|
||||||
export let current_month = new Date().getMonth() + 1
|
|
||||||
async function doPost () {
|
async function doPost () {
|
||||||
const res = await fetch('/api/add', {
|
const res = await fetch('/api/add', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
bearer: "password1234",
|
|
||||||
recipe: {
|
recipe: {
|
||||||
|
season: get_season(),
|
||||||
|
...card_data,
|
||||||
|
images: [{
|
||||||
|
mediapath: short_name + '.webp',
|
||||||
|
alt: "",
|
||||||
|
caption: ""
|
||||||
|
}],
|
||||||
short_name,
|
short_name,
|
||||||
name,
|
|
||||||
category,
|
|
||||||
datecreated,
|
datecreated,
|
||||||
datemodified,
|
datemodified,
|
||||||
tags,
|
instructions,
|
||||||
description,
|
ingredients,
|
||||||
icon
|
|
||||||
|
|
||||||
},
|
},
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
bearer: "password1234",
|
bearer: password,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -44,68 +46,31 @@
|
|||||||
result = JSON.stringify(json)
|
result = JSON.stringify(json)
|
||||||
console.log(result)
|
console.log(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
input{
|
input.temp{
|
||||||
all: unset;
|
all: unset;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 1rem;
|
margin: 1rem auto;
|
||||||
padding: 0.2em 1em;
|
padding: 0.2em 1em;
|
||||||
border-radius: 1000px;
|
border-radius: 1000px;
|
||||||
background-color: var(--nord4);
|
background-color: var(--nord4);
|
||||||
|
|
||||||
}
|
}
|
||||||
.ingredient{
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
.ingredient > input{
|
|
||||||
display: inline;
|
|
||||||
margin-inline: 0.25em;
|
|
||||||
}
|
|
||||||
.ingredient>#unit{
|
|
||||||
max-width: 40px;
|
|
||||||
}
|
|
||||||
.ingredient>#amount{
|
|
||||||
max-width: 100px;
|
|
||||||
}
|
|
||||||
.ingredient button{
|
|
||||||
all: unset;
|
|
||||||
background-color: var(--red);
|
|
||||||
padding: 0.3em;
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 1000px;
|
|
||||||
display:flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 100ms;
|
|
||||||
}
|
|
||||||
.ingredient button svg{
|
|
||||||
fill: white;
|
|
||||||
width: 1.5rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
}
|
|
||||||
.ingredient button:hover{
|
|
||||||
background-color: var(--orange);
|
|
||||||
transform: scale(1.1, 1.1);
|
|
||||||
}
|
|
||||||
.ingredient button:hover svg{
|
|
||||||
transform: scale(1.1, 1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<h1>Rezept hinzufügen</h1>
|
<h1>Rezept hinzufügen</h1>
|
||||||
|
|
||||||
<CardAdd></CardAdd>
|
<CardAdd {card_data}></CardAdd>
|
||||||
|
|
||||||
|
<input class=temp bind:value={short_name} placeholder="Kurzname"/>
|
||||||
|
|
||||||
|
<SeasonSelect {season}></SeasonSelect>
|
||||||
|
|
||||||
|
|
||||||
<input bind:value={short_name} placeholder="Kurzname"/>
|
|
||||||
<h2>Zutaten</h2>
|
<h2>Zutaten</h2>
|
||||||
<CreateIngredientList></CreateIngredientList>
|
<CreateIngredientList {ingredients}></CreateIngredientList>
|
||||||
<h2>Zubereitung</h2>
|
<h2>Zubereitung</h2>
|
||||||
<CreateStepList></CreateStepList>
|
<CreateStepList {instructions} ></CreateStepList>
|
||||||
|
<input class=temp type="password" placeholder=Passwort bind:value={password}>
|
||||||
|
<button on:click={doPost}>ADD RECIPE</button>
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import Recipes from '$lib/components/Recipes.svelte';
|
import Recipes from '$lib/components/Recipes.svelte';
|
||||||
|
import Search from '$lib/components/Search.svelte';
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
export let current_month = new Date().getMonth() + 1;
|
export let current_month = new Date().getMonth() + 1;
|
||||||
import Card from '$lib/components/Card.svelte'
|
import Card from '$lib/components/Card.svelte'
|
||||||
</script>
|
</script>
|
||||||
<h1>Rezepte</h1>
|
<h1>Rezepte</h1>
|
||||||
<h2>In Kategorie {data.category}</h2>
|
<h2>In Kategorie {data.category}</h2>
|
||||||
|
<Search></Search>
|
||||||
<section>
|
<section>
|
||||||
<Recipes>
|
<Recipes>
|
||||||
{#each data.recipes as recipe}
|
{#each data.recipes as recipe}
|
||||||
|
1
src/routes/rezepte/edit/.jukit/.jukit_info.json
Normal file
1
src/routes/rezepte/edit/.jukit/.jukit_info.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"terminal": "nvimterm"}
|
102
src/routes/rezepte/edit/[name]/+page.svelte
Normal file
102
src/routes/rezepte/edit/[name]/+page.svelte
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let data: PageData;
|
||||||
|
let old_short_name = data.recipe.short_name
|
||||||
|
|
||||||
|
export let card_data ={
|
||||||
|
icon: data.recipe.icon,
|
||||||
|
category: data.recipe.category,
|
||||||
|
name: data.recipe.name,
|
||||||
|
description: data.recipe.description,
|
||||||
|
tags: data.recipe.tags,
|
||||||
|
}
|
||||||
|
let images = data.recipe.images
|
||||||
|
let season = data.recipe.season
|
||||||
|
|
||||||
|
let short_name = data.recipe.short_name
|
||||||
|
let password
|
||||||
|
let datecreated = data.recipe.datecreated
|
||||||
|
let datemodified = new Date()
|
||||||
|
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
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';
|
||||||
|
export let ingredients = data.recipe.ingredients
|
||||||
|
|
||||||
|
import CreateStepList from '$lib/components/CreateStepList.svelte';
|
||||||
|
export let instructions = data.recipe.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 () {
|
||||||
|
const res = await fetch('/api/edit', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
recipe: {
|
||||||
|
...card_data,
|
||||||
|
images, // TODO
|
||||||
|
season: get_season(),
|
||||||
|
short_name,
|
||||||
|
datecreated,
|
||||||
|
datemodified,
|
||||||
|
instructions,
|
||||||
|
ingredients,
|
||||||
|
},
|
||||||
|
old_short_name,
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
bearer: password,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const json = await res.json()
|
||||||
|
result = JSON.stringify(json)
|
||||||
|
console.log(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
input{
|
||||||
|
all: unset;
|
||||||
|
display: block;
|
||||||
|
margin: 1rem auto;
|
||||||
|
padding: 0.2em 1em;
|
||||||
|
border-radius: 1000px;
|
||||||
|
background-color: var(--nord4);
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h1>Rezept hinzufügen</h1>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<button on:click={console.log(JSON.stringify(card_data, null, 4))}>Prinout Card Data</button>
|
||||||
|
<input bind:value={short_name} placeholder="Kurzname"/>
|
||||||
|
<h2>Zutaten</h2>
|
||||||
|
<CreateIngredientList {ingredients}></CreateIngredientList>
|
||||||
|
<h2>Zubereitung</h2>
|
||||||
|
<CreateStepList {instructions} ></CreateStepList>
|
||||||
|
<input type="password" placeholder=Passwort bind:value={password}>
|
||||||
|
<button on:click={doPost}>EDIT RECIPE</button>
|
8
src/routes/rezepte/edit/[name]/+page.ts
Normal file
8
src/routes/rezepte/edit/[name]/+page.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import type { PageLoad } from "./$types";
|
||||||
|
|
||||||
|
export async function load({ fetch, params}) {
|
||||||
|
let current_month = new Date().getMonth() + 1
|
||||||
|
const res = await fetch(`/api/items/${params.name}`);
|
||||||
|
const recipe = await res.json();
|
||||||
|
return {recipe};
|
||||||
|
};
|
1
src/routes/rezepte/edit/[name]/.jukit/.jukit_info.json
Normal file
1
src/routes/rezepte/edit/[name]/.jukit/.jukit_info.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"terminal": "nvimterm"}
|
@ -11,9 +11,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SeasonLayout>
|
<SeasonLayout>
|
||||||
|
|
||||||
<h2 slot=test>Rezepte des Monats </h2>
|
<h2 slot=test>Rezepte des Monats </h2>
|
||||||
|
|
||||||
<Recipes slot=recipes>
|
<Recipes slot=recipes>
|
||||||
{#each data.season as recipe}
|
{#each data.season as recipe}
|
||||||
<Card {recipe} {current_month}></Card>
|
<Card {recipe} {current_month}></Card>
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
export let current_month = new Date().getMonth() + 1;
|
export let current_month = new Date().getMonth() + 1;
|
||||||
import Card from '$lib/components/Card.svelte'
|
import Card from '$lib/components/Card.svelte'
|
||||||
|
import Search from '$lib/components/Search.svelte';
|
||||||
</script>
|
</script>
|
||||||
<h1>Rezepte</h1>
|
<h1>Rezepte</h1>
|
||||||
<h2>In Tag {data.tag}</h2>
|
<h2>In Tag {data.tag}</h2>
|
||||||
|
<Search></Search>
|
||||||
<section>
|
<section>
|
||||||
<Recipes>
|
<Recipes>
|
||||||
{#each data.recipes as recipe}
|
{#each data.recipes as recipe}
|
||||||
|
Loading…
Reference in New Issue
Block a user