homepage/src/lib/components/CreateStepList.svelte

470 lines
11 KiB
Svelte
Raw Normal View History

<script lang='ts'>
import Pen from '$lib/assets/icons/Pen.svelte'
import Cross from '$lib/assets/icons/Cross.svelte'
import Plus from '$lib/assets/icons/Plus.svelte'
import Check from '$lib/assets/icons/Check.svelte'
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..."
export let instructions
export let add_info
let new_step = {
name: "",
step: step_placeholder
}
let edit_heading = {
name:"",
list_index: "",
}
function get_sublist_index(sublist_name, list){
for(var i =0; i < list.length; i++){
if(list[i].name == sublist_name){
return i
}
}
return -1
}
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 = instructions //tells svelte to update dom
}
export function add_new_step(){
if(new_step.step == step_placeholder){
return
}
let list_index = get_sublist_index(new_step.name, instructions)
if(list_index == -1){
instructions.push({
name: new_step.name,
steps: [ new_step.step ],
})
list_index = instructions.length - 1
}
else{
instructions[list_index].steps.push(new_step.step)
}
const el = document.querySelector("#step")
el.innerHTML = step_placeholder
instructions = instructions //tells svelte to update dom
}
export function remove_step(list_index, step_index){
instructions[list_index].steps.splice(step_index, 1)
instructions = instructions //tells svelte to update dom
}
let edit_step = {
name: "",
step: "",
list_index: 0,
step_index: 0,
}
export function show_modal_edit_step(list_index, step_index){
edit_step = {
step: instructions[list_index].steps[step_index],
name: instructions[list_index].name,
}
edit_step.list_index = list_index
edit_step.step_index = step_index
const modal_el = document.querySelector("#edit_step_modal");
modal_el.showModal();
}
export function edit_step_and_close_modal(){
instructions[edit_step.list_index].steps[edit_step.step_index] = edit_step.step
const modal_el = document.querySelector("#edit_step_modal");
modal_el.close();
}
export function show_modal_edit_subheading_step(list_index){
edit_heading.name = instructions[list_index].name
edit_heading.list_index = list_index
const el = document.querySelector('#edit_subheading_steps_modal')
el.showModal()
}
export function edit_subheading_steps_and_close_modal(){
instructions[edit_heading.list_index].name = edit_heading.name
const modal_el = document.querySelector("#edit_subheading_steps_modal");
modal_el.close();
}
export function clear_step(){
const el = document.querySelector("#step")
if(el.innerHTML == step_placeholder){
el.innerHTML = ""
}
}
export function add_placeholder(){
const el = document.querySelector("#step")
if(el.innerHTML == ""){
el.innerHTML = step_placeholder
}
}
</script>
<style>
input::placeholder{
all:unset;
}
li > div{
display:flex;
flex-direction: row;
justify-items: space-between;
align-items:center;
2023-06-25 10:17:12 +02:00
user-select: none;
}
li > div > div:first-child{
flex-grow: 1;
cursor: pointer;
}
li > div > div:last-child{
display: flex;
flex-direction: row;
}
input.heading{
box-sizing: border-box;
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: min(300px, 95dvw);
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: -1.5rem;
}
.adder{
margin-inline: auto;
position: relative;
margin-block: 3rem;
width: 90%;
border-radius: 20px;
transition: 200ms;
background-color: var(--blue);
padding: 1.5rem 2rem;
}
dialog .adder{
width: 400px;
}
.shadow{
box-shadow: 0 0 1em 0.2em rgba(0,0,0,0.3);
}
.adder button{
position: absolute;
right: -1.5rem;
bottom: -1.5rem;
}
.category{
position: absolute;
2023-06-25 10:17:12 +02:00
border: none;
--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,
.category:focus-visible
{
background-color: var(--nord1);
transform: scale(1.05,1.05);
}
.adder:hover,
.adder:focus-within
{
transform: scale(1.1, 1.1);
}
.add_step p{
font-family: sans-serif;
width: 100%;
font-size: 1.2rem;
border-radius: 20px;
border: 2px solid var(--nord4);
border-radius: 30px;
padding: 0.5em 1em;
color: var(--nord4);
transition: 100ms;
}
.add_step p:hover,
.add_step p:focus-visible
{
color: white;
scale: 1.02 1.02;
}
dialog{
box-sizing: content-box;
width: 100%;
height: 100%;
background-color: rgba(255,255,255, 0.001);
border: unset;
margin: 0;
transition: 200ms;
}
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)
;
}
2023-06-25 10:17:12 +02:00
dialog .adder input::placeholder{
font-size: 1.2rem;
}
@media screen and (max-width: 500px){
dialog h2{
margin-top: 2rem;
}
dialog .adder{
width: 85%;
padding-inline: 0.5em;
}
dialog .adder .category{
width: 70%;
}
}
2023-07-13 15:25:42 +02:00
dialog[open]::backdrop{
animation: show 200ms ease forwards;
}
@keyframes show{
from {
backdrop-filter: blur(0px);
}
to {
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;
2023-06-25 10:17:12 +02:00
cursor: pointer;
user-select: none;
}
.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>
<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>
2023-06-27 19:01:06 +02:00
<div><h4>Kochen:</h4>
<p contenteditable type="text" bind:innerText={add_info.cooking}></p>
</div>
<div><h4>Auf dem Teller:</h4>
2023-06-25 14:49:52 +02:00
<p contenteditable type="text" bind:innerText={add_info.total_time}></p>
</div>
</div>
<h2>Zubereitung</h2>
{#each instructions as list, list_index}
2023-07-03 00:09:00 +02:00
<!-- svelte-ignore a11y-click-events-have-key-events -->
2023-06-25 10:17:12 +02:00
<h3 on:click={() => show_modal_edit_subheading_step(list_index)}>
{#if list.name}
{list.name}
{:else}
Leer
{/if}
<div>
<button class="action_button button_subtle" on:click="{() => show_modal_edit_subheading_step(list_index)}">
<Pen fill=var(--nord1)></Pen> </button>
<button class="action_button button_subtle" on:click="{() => remove_list(list_index)}">
<Cross fill=var(--nord1)></Cross>
</button>
</div>
</h3>
<ol>
{#each list.steps as step, step_index}
2023-07-03 00:09:00 +02:00
<!-- svelte-ignore a11y-click-events-have-key-events -->
<li><div><div on:click={() => show_modal_edit_step(list_index, step_index)}>{step}</div>
<div><button class="action_button button_subtle" on:click={() => show_modal_edit_step(list_index, step_index)}>
<Pen fill=var(--nord1)></Pen>
</button>
<button class="action_button button_subtle" on:click="{() => remove_step(list_index, step_index)}">
<Cross fill=var(--nord1)></Cross>
</button>
</div></div>
</li>
{/each}
</ol>
{/each}
</div>
<div class='adder shadow'>
2023-07-03 00:09:00 +02:00
<input class=category type="text" bind:value={new_step.name} placeholder="Kategorie (optional)"on:keydown={(event) => do_on_key(event, 'Enter', false , add_new_step)} >
<div class=add_step>
2023-07-03 00:09:00 +02:00
<p id=step contenteditable on:focus='{clear_step}' on:blur={add_placeholder} bind:innerText={new_step.step} on:keydown={(event) => do_on_key(event, 'Enter', true , add_new_step)}></p>
<button on:click={() => add_new_step()} class=action_button>
<Plus fill=white style="height: 2rem; width: 2rem"></Plus>
</button>
</div>
</div>
<dialog id=edit_step_modal>
<h2>Schritt verändern</h2>
<div class=adder>
2023-07-03 00:09:00 +02:00
<input class=category type="text" bind:value={edit_step.name} placeholder="Unterkategorie (optional)" on:keydown={(event) => do_on_key(event, 'Enter', false , edit_step_and_close_modal)}>
<div class=add_step>
2023-07-03 00:09:00 +02:00
<p id=step contenteditable bind:innerText={edit_step.step} on:keydown={(event) => do_on_key(event, 'Enter', true , edit_step_and_close_modal)}></p>
<button class=action_button on:click="{() => edit_step_and_close_modal()}" >
<Check fill=white style="height: 2rem; width: 2rem"></Check>
</button>
</div>
</dialog>
<dialog id=edit_subheading_steps_modal>
<h2>Kategorie umbenennen</h2>
<div class=heading_wrapper>
2023-07-03 00:09:00 +02:00
<input class="heading" type="text" bind:value={edit_heading.name} on:keydown={(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>
</div>
</dialog>