simplify structure by remove (rezepte)
This commit is contained in:
5
src/routes/rezepte/+layout.server.ts
Normal file
5
src/routes/rezepte/+layout.server.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { get_username } from '$lib/js/get_username';;
|
||||
|
||||
export const load = (async ({cookies}) => {
|
||||
return { user: await get_username(cookies) }
|
||||
});
|
21
src/routes/rezepte/+layout.svelte
Normal file
21
src/routes/rezepte/+layout.svelte
Normal file
@ -0,0 +1,21 @@
|
||||
<script>
|
||||
import Header from '$lib/components/Header.svelte'
|
||||
import UserHeader from '$lib/components/UserHeader.svelte';
|
||||
export let data
|
||||
let username = ""
|
||||
if(data.user){
|
||||
username = data.user.username
|
||||
}
|
||||
</script>
|
||||
|
||||
<Header>
|
||||
<ul class=site_header slot=links>
|
||||
<li><a href="/rezepte">Alle Rezepte</a></li>
|
||||
<li><a href="/rezepte/season">In Saison</a></li>
|
||||
<li><a href="/rezepte/category">Kategorie</a></li>
|
||||
<li><a href="/rezepte/icon">Icon</a></li>
|
||||
<li><a href="/rezepte/tag">Stichwörter</a></li>
|
||||
</ul>
|
||||
<UserHeader slot=right_side {username}></UserHeader>
|
||||
<slot></slot>
|
||||
</Header>
|
13
src/routes/rezepte/+page.server.ts
Normal file
13
src/routes/rezepte/+page.server.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import type { PageServerLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch }) {
|
||||
let current_month = new Date().getMonth() + 1
|
||||
const res_season = await fetch(`/api/rezepte/items/in_season/` + current_month);
|
||||
const res_all_brief = await fetch(`/api/rezepte/items/all_brief`);
|
||||
const item_season = await res_season.json();
|
||||
const item_all_brief = await res_all_brief.json();
|
||||
return {
|
||||
season: item_season,
|
||||
all_brief: item_all_brief,
|
||||
};
|
||||
};
|
44
src/routes/rezepte/+page.svelte
Normal file
44
src/routes/rezepte/+page.svelte
Normal file
@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import MediaScroller from '$lib/components/MediaScroller.svelte';
|
||||
import AddButton from '$lib/components/AddButton.svelte';
|
||||
import Card from '$lib/components/Card.svelte';
|
||||
import Search from '$lib/components/Search.svelte';
|
||||
export let data: PageData;
|
||||
export let current_month = new Date().getMonth() + 1
|
||||
const categories = ["Hauptspeise", "Nudel", "Brot", "Dessert", "Suppe", "Beilage", "Salat", "Kuchen", "Frühstück", "Sauce", "Zutat", "Getränk", "Aufstrich", "Guetzli", "Unterwegs"]
|
||||
</script>
|
||||
<style>
|
||||
h1{
|
||||
text-align: center;
|
||||
margin-bottom: 0;
|
||||
font-size: 4rem;
|
||||
}
|
||||
</style>
|
||||
<svelte:head>
|
||||
<title>Bocken Rezepte</title>
|
||||
<meta name="description" content="Eine stetig wachsende Ansammlung an Rezepten aus der Bockenschen Küche." />
|
||||
<meta property="og:image" content="https://bocken.org/static/rezepte/thumb/ragu_aus_rindsrippen.webp" />
|
||||
<meta property="og:image:secure_url" content="https://bocken.org/static/rezepte/thumb/ragu_aus_rindsrippen.webp" />
|
||||
<meta property="og:image:type" content="image/webp" />
|
||||
<meta property="og:image:alt" content="Pasta al Ragu mit Linguine" />
|
||||
</svelte:head>
|
||||
|
||||
<h1>Rezepte</h1>
|
||||
|
||||
<Search></Search>
|
||||
|
||||
<MediaScroller title="In Saison">
|
||||
{#each data.season as recipe}
|
||||
<Card {recipe} {current_month}></Card>
|
||||
{/each}
|
||||
</MediaScroller>
|
||||
|
||||
{#each categories as category}
|
||||
<MediaScroller title={category}>
|
||||
{#each data.all_brief.filter(recipe => recipe.category == category) as recipe}
|
||||
<Card {recipe} {current_month}></Card>
|
||||
{/each}
|
||||
</MediaScroller>
|
||||
{/each}
|
||||
<AddButton></AddButton>
|
327
src/routes/rezepte/[name]/+page.svelte
Normal file
327
src/routes/rezepte/[name]/+page.svelte
Normal file
@ -0,0 +1,327 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
export const multiplier = writable(0);
|
||||
|
||||
import type { PageData } from './$types';
|
||||
import "$lib/css/nordtheme.css"
|
||||
import EditButton from '$lib/components/EditButton.svelte';
|
||||
import InstructionsPage from '$lib/components/InstructionsPage.svelte';
|
||||
import IngredientsPage from '$lib/components/IngredientsPage.svelte';
|
||||
import TitleImgParallax from '$lib/components/TitleImgParallax.svelte';
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
import {season} from '$lib/js/season_store';
|
||||
import RecipeNote from '$lib/components/RecipeNote.svelte';
|
||||
import {stripHtmlTags} from '$lib/js/stripHtmlTags';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
let hero_img_src = "https://bocken.org/static/rezepte/full/" + data.short_name + ".webp"
|
||||
let placeholder_src = "https://bocken.org/static/rezepte/placeholder/" + data.short_name + ".webp"
|
||||
export let months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
||||
function season_intervals() {
|
||||
let interval_arr = []
|
||||
|
||||
|
||||
let start_i = 0
|
||||
for(var i = 12; i > 0; i--){
|
||||
if(data.season.includes(i)){
|
||||
start_i = data.season.indexOf(i);
|
||||
}
|
||||
else{
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
export let season_iv = season_intervals();
|
||||
|
||||
afterNavigate(() => {
|
||||
hero_img_src = "https://bocken.org/static/rezepte/full/" + data.short_name + ".webp"
|
||||
placeholder_src = "https://bocken.org/static/rezepte/placeholder/" + data.short_name + ".webp"
|
||||
season_iv = season_intervals();
|
||||
})
|
||||
let display_date = new Date(data.dateCreated);
|
||||
if (data.updatedAt){
|
||||
display_date = new Date(data.updatedAt);
|
||||
}
|
||||
const options = {
|
||||
day: '2-digit',
|
||||
month: 'short', // German abbreviation for the month
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
};
|
||||
const formatted_display_date = display_date.toLocaleDateString('de-DE', options)
|
||||
</script>
|
||||
<style>
|
||||
*{
|
||||
font-family: sans-serif;
|
||||
}
|
||||
h1{
|
||||
text-align: center;
|
||||
padding-block: 0.5em;
|
||||
border-radius: 10000px;
|
||||
margin:0;
|
||||
font-size: 3rem;
|
||||
overflow-wrap: break-word;
|
||||
hyphens: auto;
|
||||
text-wrap: balance;
|
||||
}
|
||||
.category{
|
||||
--size: 1.75rem;
|
||||
position: absolute;
|
||||
top: calc(-1* var(--size) );
|
||||
left:calc(-3/2 * var(--size));
|
||||
background-color: var(--nord0);
|
||||
color: var(--nord6);
|
||||
text-decoration: none;
|
||||
font-size: var(--size);
|
||||
padding: calc(var(--size) * 2/3);
|
||||
border-radius: 1000px;
|
||||
transition: 100ms;
|
||||
box-shadow: 0em 0em 1em 0.3em rgba(0,0,0,0.4);
|
||||
}
|
||||
.category:hover,
|
||||
.category:focus-visible{
|
||||
background-color: var(--nord1);
|
||||
scale: 1.1;
|
||||
}
|
||||
.tags{
|
||||
margin-block: 1rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1em;
|
||||
}
|
||||
.center{
|
||||
justify-content: center;
|
||||
}
|
||||
.tag{
|
||||
all:unset;
|
||||
color: var(--nord0);
|
||||
font-size: 1.1rem;
|
||||
background-color: var(--nord5);
|
||||
border-radius: 10000px;
|
||||
padding: 0.25em 1em;
|
||||
transition: 100ms;
|
||||
box-shadow: 0em 0em 0.5em 0.05em rgba(0,0,0,0.3);
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.tag{
|
||||
background-color: var(--nord0);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
.tag:hover,
|
||||
.tag:focus-visible
|
||||
{
|
||||
cursor: pointer;
|
||||
transform: scale(1.1,1.1);
|
||||
background-color: var(--orange);
|
||||
box-shadow: 0.1em 0.1em 0.5em 0.1em rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.wrapper_wrapper{
|
||||
background-color: #fbf9f3;
|
||||
padding-top: 10rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 3rem;
|
||||
transform: translateY(-7rem);
|
||||
z-index: -2;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.wrapper_wrapper{
|
||||
background-color: var(--background-dark);
|
||||
}
|
||||
}
|
||||
|
||||
.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{
|
||||
position: relative;
|
||||
width: min(800px, 80vw);
|
||||
margin-inline: auto;
|
||||
background-color: var(--nord6);
|
||||
padding: 1rem 2rem;
|
||||
translate: 0 1px; /*bruh*/
|
||||
z-index: 1;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.title{
|
||||
background-color: var(--nord6-dark);
|
||||
}
|
||||
}
|
||||
|
||||
.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.3em rgba(0,0,0,0.4);
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.icon{
|
||||
background-color: var(--accent-dark);
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
top: -1.75rem;
|
||||
}
|
||||
.category{
|
||||
left: 1rem;
|
||||
top: calc(var(--size) * -1.5);
|
||||
}
|
||||
}
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
.description{
|
||||
text-align: center;
|
||||
margin-bottom: 2em;
|
||||
margin-top: -0.5em;
|
||||
}
|
||||
.date{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
<svelte:head>
|
||||
<title>{stripHtmlTags(data.name)} - Bocken'sche Rezepte</title>
|
||||
<meta name="description" content="{stripHtmlTags(data.description)}" />
|
||||
<meta property="og:image" content="https://bocken.org/static/rezepte/thumb/{data.short_name}.webp" />
|
||||
<meta property="og:image:secure_url" content="https://bocken.org/static/rezepte/thumb/{data.short_name}.webp" />
|
||||
<meta property="og:image:type" content="image/webp" />
|
||||
<meta property="og:image:alt" content="{stripHtmlTags(data.name)}" />
|
||||
</svelte:head>
|
||||
|
||||
<TitleImgParallax src={hero_img_src} {placeholder_src}>
|
||||
<div class=title>
|
||||
<a class="category" href='/rezepte/category/{data.category}'>{data.category}</a>
|
||||
<a class="icon" href='/rezepte/icon/{data.icon}'>{data.icon}</a>
|
||||
<h1>{@html data.name}</h1>
|
||||
{#if data.description && ! data.preamble}
|
||||
<p class=description>{data.description}</p>
|
||||
{/if}
|
||||
{#if data.preamble}
|
||||
<p>{@html data.preamble}</p>
|
||||
{/if}
|
||||
<div class=tags>
|
||||
<h4>Saison:</h4>
|
||||
{#each season_iv as season}
|
||||
<a class=tag href="/rezepte/season/{season[0]}">
|
||||
{months[season[0] - 1]}
|
||||
{#if season[1]}
|
||||
- {months[season[1] - 1]}
|
||||
{/if}
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
<h4>Stichwörter:</h4>
|
||||
<div class="tags center">
|
||||
{#each data.tags as tag}
|
||||
<a class=tag href="/rezepte/tag/{tag}">{tag}</a>
|
||||
{/each}
|
||||
</div>
|
||||
{#if data.note}
|
||||
<RecipeNote note={data.note}></RecipeNote>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class=wrapper_wrapper>
|
||||
<div class=wrapper>
|
||||
<IngredientsPage {data}></IngredientsPage>
|
||||
<InstructionsPage {data}></InstructionsPage>
|
||||
</div>
|
||||
<div class=addendum>
|
||||
{#if data.addendum}
|
||||
{@html data.addendum}
|
||||
{/if}
|
||||
</div>
|
||||
<p class=date>Letzte Änderung: {formatted_display_date}</p>
|
||||
</div>
|
||||
</TitleImgParallax>
|
||||
|
||||
<EditButton href="/rezepte/edit/{data.short_name}"></EditButton>
|
10
src/routes/rezepte/[name]/+page.ts
Normal file
10
src/routes/rezepte/[name]/+page.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { error } from "@sveltejs/kit";
|
||||
|
||||
export async function load({ fetch, params}) {
|
||||
const res = await fetch(`/api/rezepte/items/${params.name}`);
|
||||
let item = await res.json();
|
||||
if(!res.ok){
|
||||
throw error(res.status, item.message)
|
||||
}
|
||||
return item;
|
||||
}
|
5
src/routes/rezepte/add/+page.server.ts
Normal file
5
src/routes/rezepte/add/+page.server.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export async function load({locals}) {
|
||||
return {
|
||||
user: locals.user
|
||||
};
|
||||
};
|
287
src/routes/rezepte/add/+page.svelte
Normal file
287
src/routes/rezepte/add/+page.svelte
Normal file
@ -0,0 +1,287 @@
|
||||
<script lang="ts">
|
||||
import Check from '$lib/assets/icons/Check.svelte';
|
||||
import SeasonSelect from '$lib/components/SeasonSelect.svelte';
|
||||
import '$lib/css/action_button.css'
|
||||
import '$lib/css/nordtheme.css'
|
||||
|
||||
let preamble = ""
|
||||
let addendum = ""
|
||||
|
||||
import { season } from '$lib/js/season_store';
|
||||
import { portions } from '$lib/js/portions_store';
|
||||
import { img } from '$lib/js/img_store';
|
||||
season.update(() => [])
|
||||
let season_local
|
||||
season.subscribe((s) => {
|
||||
season_local = s
|
||||
});
|
||||
let portions_local
|
||||
portions.update(() => "")
|
||||
portions.subscribe((p) => {
|
||||
portions_local = p});
|
||||
let img_local
|
||||
img.update(() => "")
|
||||
img.subscribe((i) => {
|
||||
img_local = i});
|
||||
|
||||
|
||||
|
||||
export let card_data ={
|
||||
icon: "",
|
||||
category: "",
|
||||
name: "",
|
||||
description: "",
|
||||
tags: [],
|
||||
}
|
||||
export let add_info ={
|
||||
preparation: "",
|
||||
fermentation: {
|
||||
bulk: "",
|
||||
final: "",
|
||||
},
|
||||
baking: {
|
||||
length: "",
|
||||
temperature: "",
|
||||
mode: "",
|
||||
},
|
||||
total_time: "",
|
||||
cooking: "",
|
||||
}
|
||||
|
||||
let images = []
|
||||
let short_name = ""
|
||||
let datecreated = new Date()
|
||||
let datemodified = datecreated
|
||||
|
||||
import type { PageData } from './$types';
|
||||
import CardAdd from '$lib/components/CardAdd.svelte';
|
||||
|
||||
import CreateIngredientList from '$lib/components/CreateIngredientList.svelte';
|
||||
export let ingredients = []
|
||||
|
||||
import CreateStepList from '$lib/components/CreateStepList.svelte';
|
||||
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 upload_img(){
|
||||
console.log("uploading...")
|
||||
console.log(img_local)
|
||||
const data = {
|
||||
image: img_local,
|
||||
name: short_name,
|
||||
}
|
||||
await fetch(`/api/rezepte/img/add`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
credentials: 'include',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
async function doPost () {
|
||||
|
||||
upload_img()
|
||||
console.log(add_info.total_time)
|
||||
const res = await fetch('/api/rezepte/add', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
recipe: {
|
||||
...card_data,
|
||||
...add_info,
|
||||
images: {mediapath: short_name + '.webp', alt: "", caption: ""}, // TODO
|
||||
season: season_local,
|
||||
short_name,
|
||||
portions: portions_local,
|
||||
datecreated,
|
||||
datemodified,
|
||||
instructions,
|
||||
ingredients,
|
||||
preamble,
|
||||
addendum,
|
||||
},
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
}
|
||||
})
|
||||
});
|
||||
if(res.status === 200){
|
||||
const url = location.href.split('/')
|
||||
url.splice(url.length -1, 1);
|
||||
url.push(short_name)
|
||||
location.assign(url.join('/'))
|
||||
}
|
||||
else{
|
||||
const item = await res.json();
|
||||
alert(item.message)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
input{
|
||||
display: block;
|
||||
border: unset;
|
||||
margin: 1rem auto;
|
||||
padding: 0.5em 1em;
|
||||
border-radius: 1000px;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
button.action_button{
|
||||
animation: unset !important;
|
||||
font-size: 1.3rem;
|
||||
color: white;
|
||||
}
|
||||
.submit_buttons{
|
||||
display: flex;
|
||||
margin-inline: auto;
|
||||
max-width: 1000px;
|
||||
margin-block: 1rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
}
|
||||
.submit_buttons p{
|
||||
padding: 0;
|
||||
padding-right: 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
@media (prefers-color-scheme: dark){
|
||||
.title{
|
||||
background-color: var(--nord6-dark);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<svelte:head>
|
||||
<title>Rezept erstellen</title>
|
||||
<meta name="description" content="Hier können neue Rezepte hinzugefügt werden" />
|
||||
</svelte:head>
|
||||
|
||||
<h1>Rezept erstellen</h1>
|
||||
|
||||
<CardAdd {card_data}></CardAdd>
|
||||
|
||||
<h3>Kurzname (für URL):</h3>
|
||||
<input bind:value={short_name} placeholder="Kurzname"/>
|
||||
|
||||
<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>
|
||||
|
||||
<div class=list_wrapper>
|
||||
<div>
|
||||
<CreateIngredientList {ingredients}></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_buttons>
|
||||
<button class=action_button on:click={doPost}><p>Hinzufügen</p><Check fill=white width=2rem height=2rem></Check></button>
|
||||
</div>
|
22
src/routes/rezepte/category/+page.svelte
Normal file
22
src/routes/rezepte/category/+page.svelte
Normal file
@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import "$lib/css/nordtheme.css";
|
||||
export let data: PageData;
|
||||
import TagCloud from '$lib/components/TagCloud.svelte';
|
||||
import TagBall from '$lib/components/TagBall.svelte';
|
||||
</script>
|
||||
<style>
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 3rem;
|
||||
}
|
||||
</style>
|
||||
<h1>Kategorien</h1>
|
||||
<section>
|
||||
<TagCloud>
|
||||
{#each data.categories as tag}
|
||||
<TagBall {tag} ref="/rezepte/category">
|
||||
</TagBall>
|
||||
{/each}
|
||||
</TagCloud>
|
||||
</section>
|
7
src/routes/rezepte/category/+page.ts
Normal file
7
src/routes/rezepte/category/+page.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch}) {
|
||||
const res = await fetch(`/api/rezepte/items/category`);
|
||||
const categories= await res.json();
|
||||
return {categories}
|
||||
};
|
24
src/routes/rezepte/category/[category]/+page.svelte
Normal file
24
src/routes/rezepte/category/[category]/+page.svelte
Normal file
@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import Recipes from '$lib/components/Recipes.svelte';
|
||||
import Search from '$lib/components/Search.svelte';
|
||||
export let data: PageData;
|
||||
export let current_month = new Date().getMonth() + 1;
|
||||
import Card from '$lib/components/Card.svelte'
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
</script>
|
||||
<style>
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 3em;
|
||||
}
|
||||
</style>
|
||||
<h1>Rezepte in Kategorie <q>{data.category}</q>:</h1>
|
||||
<Search></Search>
|
||||
<section>
|
||||
<Recipes>
|
||||
{#each rand_array(data.recipes) as recipe}
|
||||
<Card {recipe} {current_month}></Card>
|
||||
{/each}
|
||||
</Recipes>
|
||||
</section>
|
10
src/routes/rezepte/category/[category]/+page.ts
Normal file
10
src/routes/rezepte/category/[category]/+page.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch, params }) {
|
||||
const res = await fetch(`/api/rezepte/items/category/${params.category}`);
|
||||
const items = await res.json();
|
||||
return {
|
||||
category: params.category,
|
||||
recipes: items
|
||||
}
|
||||
};
|
10
src/routes/rezepte/edit/[name]/+page.server.ts
Normal file
10
src/routes/rezepte/edit/[name]/+page.server.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch, params, locals}) {
|
||||
let current_month = new Date().getMonth() + 1
|
||||
const res = await fetch(`/api/rezepte/items/${params.name}`);
|
||||
const recipe = await res.json();
|
||||
return {recipe: recipe,
|
||||
user: locals.user
|
||||
};
|
||||
};
|
387
src/routes/rezepte/edit/[name]/+page.svelte
Normal file
387
src/routes/rezepte/edit/[name]/+page.svelte
Normal file
@ -0,0 +1,387 @@
|
||||
<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 '$lib/css/nordtheme.css'
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import EditRecipeNote from '$lib/components/EditRecipeNote.svelte';
|
||||
|
||||
export let data: PageData;
|
||||
let preamble = data.recipe.preamble
|
||||
let addendum = data.recipe.addendum
|
||||
let image_preview_url="https://bocken.org/static/rezepte/thumb/" + data.recipe.short_name + ".webp"
|
||||
let note = data.recipe.note
|
||||
|
||||
import { season } from '$lib/js/season_store';
|
||||
import { portions } from '$lib/js/portions_store';
|
||||
|
||||
portions.update(() => data.recipe.portions)
|
||||
let portions_local
|
||||
portions.subscribe((p) => {
|
||||
portions_local = p
|
||||
});
|
||||
|
||||
season.update(() => data.recipe.season)
|
||||
let season_local
|
||||
season.subscribe((s) => {
|
||||
season_local = s
|
||||
});
|
||||
|
||||
|
||||
import { img } from '$lib/js/img_store';
|
||||
let img_local
|
||||
img.update(() => "")
|
||||
img.subscribe((i) => {
|
||||
img_local = i});
|
||||
|
||||
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,
|
||||
}
|
||||
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,
|
||||
cooking: data.recipe.cooking,
|
||||
}
|
||||
|
||||
let images = data.recipe.images
|
||||
|
||||
let short_name = data.recipe.short_name
|
||||
let datecreated = data.recipe.datecreated
|
||||
let datemodified = new Date()
|
||||
|
||||
import type { PageData } from './$types';
|
||||
import CardAdd from '$lib/components/CardAdd.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 doDelete(){
|
||||
const response = confirm("Bist du dir sicher, dass du das Rezept löschen willst?")
|
||||
if(!response){
|
||||
return
|
||||
}
|
||||
const res_img = await fetch('/api/rezepte/img/delete', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name: old_short_name,
|
||||
}),
|
||||
headers : {
|
||||
'content-type': 'application/json',
|
||||
credentials: 'include',
|
||||
}
|
||||
})
|
||||
if(!res_img.ok){
|
||||
const item = await res_img.json();
|
||||
//alert(item.message)
|
||||
return
|
||||
}
|
||||
return
|
||||
const res = await fetch('/api/rezepte/delete', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
old_short_name,
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
if(res.ok){
|
||||
const url = location.href.split('/')
|
||||
url.splice(url.length -2, 2);
|
||||
location.assign(url.join('/'))
|
||||
}
|
||||
else{
|
||||
const item = await res.json();
|
||||
// alert(item.message)
|
||||
}
|
||||
}
|
||||
async function doEdit() {
|
||||
// two cases:
|
||||
//new image uploaded (not implemented yet)
|
||||
// new short_name -> move images as well
|
||||
|
||||
// if new image
|
||||
console.log("img_local", img_local)
|
||||
if(img_local != ""){
|
||||
async function delete_img(){
|
||||
const res = await fetch('/api/rezepte/img/delete', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name: old_short_name,
|
||||
}),
|
||||
headers : {
|
||||
'content-type': 'application/json',
|
||||
credentials: 'include',
|
||||
}
|
||||
})
|
||||
if(!res.ok){
|
||||
const item = await res.json();
|
||||
// alert(item.message)
|
||||
}
|
||||
}
|
||||
async function upload_img(){
|
||||
const data = {
|
||||
image: img_local,
|
||||
name: short_name,
|
||||
}
|
||||
const res = await fetch(`/api/rezepte/img/add`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
credentials: 'include',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
if(!res.ok){
|
||||
const item = await res.json();
|
||||
// alert(item.message)
|
||||
}
|
||||
}
|
||||
delete_img()
|
||||
upload_img()
|
||||
}
|
||||
// case new short_name:
|
||||
else if(short_name != old_short_name){
|
||||
console.log("MOVING")
|
||||
const res_img = await fetch('/api/rezepte/img/mv', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
credentials: 'include',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
old_name: old_short_name,
|
||||
new_name: short_name,
|
||||
})
|
||||
})
|
||||
if(!res_img.ok){
|
||||
const item = await res_img.json();
|
||||
//alert(item.message)
|
||||
return
|
||||
}
|
||||
}
|
||||
const res = await fetch('/api/rezepte/edit', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
recipe: {
|
||||
...card_data,
|
||||
...add_info,
|
||||
images, // TODO
|
||||
season: season_local,
|
||||
short_name,
|
||||
datecreated,
|
||||
portions: portions_local,
|
||||
datemodified,
|
||||
instructions,
|
||||
ingredients,
|
||||
addendum,
|
||||
preamble,
|
||||
note,
|
||||
},
|
||||
old_short_name,
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
credentials: 'include',
|
||||
}
|
||||
})
|
||||
})
|
||||
if(res.ok){
|
||||
const url = location.href.split('/');
|
||||
url.splice(url.length -2, 2);
|
||||
url.push(short_name);
|
||||
location.assign(url.join('/'))
|
||||
}
|
||||
else{
|
||||
const item = await res.json()
|
||||
//alert(item.message)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
input{
|
||||
display: block;
|
||||
border: unset;
|
||||
margin: 1rem auto;
|
||||
padding: 0.5em 1em;
|
||||
border-radius: 1000px;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
@media (prefers-color-scheme: dark){
|
||||
.title{
|
||||
background-color: var(--nord6-dark);
|
||||
}
|
||||
}
|
||||
.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;
|
||||
}
|
||||
button.action_button{
|
||||
animation: unset !important;
|
||||
font-size: 1.3rem;
|
||||
color: white;
|
||||
}
|
||||
.submit_buttons{
|
||||
display: flex;
|
||||
margin-inline: auto;
|
||||
max-width: 1000px;
|
||||
margin-block: 1rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
}
|
||||
.submit_buttons p{
|
||||
padding: 0;
|
||||
padding-right: 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
@media (prefers-color-scheme: dark){
|
||||
:global(body){
|
||||
background-color: var(--background-dark);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<h1>Rezept editieren</h1>
|
||||
<CardAdd {card_data} {image_preview_url} ></CardAdd>
|
||||
|
||||
<h3>Kurzname (für URL):</h3>
|
||||
<input bind:value={short_name} placeholder="Kurzname"/>
|
||||
|
||||
<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>
|
||||
<EditRecipeNote><p contenteditable bind:innerText={note}></p></EditRecipeNote>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=list_wrapper>
|
||||
<div>
|
||||
<CreateIngredientList {ingredients}></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_buttons>
|
||||
<button class=action_button on:click={doDelete}><p>Löschen</p><Cross fill=white width=2rem height=2rem></Cross></button>
|
||||
<button class=action_button on:click={doEdit}><p>Speichern</p><Check fill=white width=2rem height=2rem></Check></button>
|
||||
</div>
|
79
src/routes/rezepte/icon/+page.svelte
Normal file
79
src/routes/rezepte/icon/+page.svelte
Normal file
@ -0,0 +1,79 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import '$lib/components/nordtheme.css';
|
||||
import Recipes from '$lib/components/Recipes.svelte';
|
||||
import MediaScroller from '$lib/components/MediaScroller.svelte';
|
||||
import SeasonLayout from '$lib/components/SeasonLayout.svelte'
|
||||
import Card from '$lib/components/Card.svelte';
|
||||
import Search from '$lib/components/Search.svelte';
|
||||
export let data: PageData;
|
||||
</script>
|
||||
<style>
|
||||
a{
|
||||
--padding: 0.5em;
|
||||
font-size: 3rem;
|
||||
text-decoration: none;
|
||||
padding: var(--padding);
|
||||
background-color: var(--nord4);
|
||||
border-radius: 1000px;
|
||||
box-shadow: 0em 0em 0.5em 0.2em rgba(0, 0, 0, 0.2);
|
||||
text-align: center;
|
||||
--width: calc(1.2em + var(--padding) * 2);
|
||||
width: var(--width);
|
||||
line-height: calc(var(--width) - 2*var(--padding));
|
||||
height: var(--width);
|
||||
|
||||
|
||||
}
|
||||
a:hover,
|
||||
a:focus-visible
|
||||
{
|
||||
--angle: 15deg;
|
||||
animation: shake 0.5s ease forwards;
|
||||
}
|
||||
.flex{
|
||||
display:flex;
|
||||
flex-wrap:wrap;
|
||||
gap: 1rem;
|
||||
max-width: 500px;
|
||||
justify-content: center;
|
||||
margin:4rem auto;
|
||||
}
|
||||
|
||||
@keyframes shake{
|
||||
0%{
|
||||
transform: rotate(0)
|
||||
scale(1,1);
|
||||
}
|
||||
25%{
|
||||
box-shadow: 0em 0em 0.6em 0.3em rgba(0, 0, 0, 0.2);
|
||||
transform: rotate(var(--angle))
|
||||
scale(1.2,1.2)
|
||||
;
|
||||
}
|
||||
50%{
|
||||
|
||||
box-shadow: 0em 0em 0.6em 0.3em rgba(0, 0, 0, 0.2);
|
||||
transform: rotate(calc(-1* var(--angle)))
|
||||
scale(1.2,1.2);
|
||||
}
|
||||
74%{
|
||||
|
||||
box-shadow: 0em 0em 0.6em 0.3em rgba(0, 0, 0, 0.2);
|
||||
transform: rotate(var(--angle))
|
||||
scale(1.2, 1.2);
|
||||
}
|
||||
100%{
|
||||
transform: rotate(0)
|
||||
scale(1.2,1.2);
|
||||
box-shadow: 0em 0em 0.6em 0.3em rgba(0, 0, 0, 0.2);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<div class=flex>
|
||||
{#each data.icons as icon}
|
||||
<a href="/rezepte/icon/{icon}">{icon}</a>
|
||||
{/each}
|
||||
</div>
|
10
src/routes/rezepte/icon/+page.ts
Normal file
10
src/routes/rezepte/icon/+page.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch }) {
|
||||
let current_month = new Date().getMonth() + 1
|
||||
const res_icons = await fetch(`/api/rezepte/items/icon`);
|
||||
const item = await res_icons.json();
|
||||
return {
|
||||
icons: item,
|
||||
};
|
||||
};
|
17
src/routes/rezepte/icon/[icon]/+page.svelte
Normal file
17
src/routes/rezepte/icon/[icon]/+page.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import Recipes from '$lib/components/Recipes.svelte';
|
||||
import IconLayout from '$lib/components/IconLayout.svelte';
|
||||
import MediaScroller from '$lib/components/MediaScroller.svelte';
|
||||
import Card from '$lib/components/Card.svelte';
|
||||
import Search from '$lib/components/Search.svelte';
|
||||
export let data: PageData;
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
</script>
|
||||
<IconLayout icons={data.icons} active_icon={data.icon} >
|
||||
<Recipes slot=recipes>
|
||||
{#each rand_array(data.season) as recipe}
|
||||
<Card {recipe} icon_override=true></Card>
|
||||
{/each}
|
||||
</Recipes>
|
||||
</IconLayout>
|
13
src/routes/rezepte/icon/[icon]/+page.ts
Normal file
13
src/routes/rezepte/icon/[icon]/+page.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch, params }) {
|
||||
const res_season = await fetch(`/api/rezepte/items/icon/` + params.icon);
|
||||
const res_icons = await fetch(`/api/rezepte/items/icon`);
|
||||
const icons = await res_icons.json();
|
||||
const item_season = await res_season.json();
|
||||
return {
|
||||
icons: icons,
|
||||
icon: params.icon,
|
||||
season: item_season,
|
||||
};
|
||||
};
|
20
src/routes/rezepte/season/+page.svelte
Normal file
20
src/routes/rezepte/season/+page.svelte
Normal file
@ -0,0 +1,20 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import '$lib/components/nordtheme.css';
|
||||
import Recipes from '$lib/components/Recipes.svelte';
|
||||
import MediaScroller from '$lib/components/MediaScroller.svelte';
|
||||
import SeasonLayout from '$lib/components/SeasonLayout.svelte'
|
||||
import Card from '$lib/components/Card.svelte';
|
||||
import Search from '$lib/components/Search.svelte';
|
||||
export let data: PageData;
|
||||
export let current_month = new Date().getMonth() + 1
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
</script>
|
||||
|
||||
<SeasonLayout active_index={current_month-1}>
|
||||
<Recipes slot=recipes>
|
||||
{#each rand_array(data.season) as recipe}
|
||||
<Card {recipe} {current_month}></Card>
|
||||
{/each}
|
||||
</Recipes>
|
||||
</SeasonLayout>
|
10
src/routes/rezepte/season/+page.ts
Normal file
10
src/routes/rezepte/season/+page.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch }) {
|
||||
let current_month = new Date().getMonth() + 1
|
||||
const res_season = await fetch(`/api/rezepte/items/in_season/` + current_month);
|
||||
const item_season = await res_season.json();
|
||||
return {
|
||||
season: item_season,
|
||||
};
|
||||
};
|
18
src/routes/rezepte/season/[month]/+page.svelte
Normal file
18
src/routes/rezepte/season/[month]/+page.svelte
Normal file
@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import Recipes from '$lib/components/Recipes.svelte';
|
||||
import SeasonLayout from '$lib/components/SeasonLayout.svelte';
|
||||
import MediaScroller from '$lib/components/MediaScroller.svelte';
|
||||
import Card from '$lib/components/Card.svelte';
|
||||
import Search from '$lib/components/Search.svelte';
|
||||
export let data: PageData;
|
||||
let months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
</script>
|
||||
<SeasonLayout active_index={data.month -1}>
|
||||
<Recipes slot=recipes>
|
||||
{#each rand_array(data.season) as recipe}
|
||||
<Card {recipe} icon_override=true></Card>
|
||||
{/each}
|
||||
</Recipes>
|
||||
</SeasonLayout>
|
12
src/routes/rezepte/season/[month]/+page.ts
Normal file
12
src/routes/rezepte/season/[month]/+page.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch, params }) {
|
||||
const res_season = await fetch(`/api/rezepte/items/in_season/` + params.month);
|
||||
const res_all_brief = await fetch(`/api/rezepte/items/all_brief`);
|
||||
const item_season = await res_season.json();
|
||||
const item_all_brief = await res_all_brief.json();
|
||||
return {
|
||||
month: params.month,
|
||||
season: item_season,
|
||||
};
|
||||
};
|
22
src/routes/rezepte/tag/+page.svelte
Normal file
22
src/routes/rezepte/tag/+page.svelte
Normal file
@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
export let data: PageData;
|
||||
import "$lib/css/nordtheme.css";
|
||||
import TagCloud from '$lib/components/TagCloud.svelte';
|
||||
import TagBall from '$lib/components/TagBall.svelte';
|
||||
</script>
|
||||
<style>
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<h1>Stichwörter</h1>
|
||||
<section>
|
||||
<TagCloud>
|
||||
{#each data.tags as tag}
|
||||
<TagBall {tag} ref="/rezepte/tag">
|
||||
</TagBall>
|
||||
{/each}
|
||||
</TagCloud>
|
||||
</section>
|
7
src/routes/rezepte/tag/+page.ts
Normal file
7
src/routes/rezepte/tag/+page.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch}) {
|
||||
const res = await fetch(`/api/rezepte/items/tag`);
|
||||
const tags = await res.json();
|
||||
return {tags}
|
||||
};
|
24
src/routes/rezepte/tag/[tag]/+page.svelte
Normal file
24
src/routes/rezepte/tag/[tag]/+page.svelte
Normal file
@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import Recipes from '$lib/components/Recipes.svelte';
|
||||
export let data: PageData;
|
||||
export let current_month = new Date().getMonth() + 1;
|
||||
import Card from '$lib/components/Card.svelte'
|
||||
import Search from '$lib/components/Search.svelte';
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
</script>
|
||||
<style>
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
}
|
||||
</style>
|
||||
<h1>Rezepte mit Stichwort <q>{data.tag}</q>:</h1>
|
||||
<Search></Search>
|
||||
<section>
|
||||
<Recipes>
|
||||
{#each rand_array(data.recipes) as recipe}
|
||||
<Card {recipe} {current_month}></Card>
|
||||
{/each}
|
||||
</Recipes>
|
||||
</section>
|
10
src/routes/rezepte/tag/[tag]/+page.ts
Normal file
10
src/routes/rezepte/tag/[tag]/+page.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export async function load({ fetch, params }) {
|
||||
const res_tag = await fetch(`/api/rezepte/items/tag/${params.tag}`);
|
||||
const items_tag = await res_tag.json();
|
||||
return {
|
||||
tag: params.tag,
|
||||
recipes: items_tag
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user