1e51ef7def
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/ - 12 code-workspace-Files - STATUS-*.md - viele M/D/R-Änderungen an bereits getrackten Files - .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
129 lines
7.3 KiB
HTML
129 lines
7.3 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Weltküche · Vorschau aller 30 Gerichte</title>
|
||
<style>
|
||
:root { --moss:#1f4b37; --sage:#4a7c4e; --sand:#e8c547; --beige:#e8e4d8; --ink:#2a2a2a; --muted:#6a6a6a; --line:rgba(0,0,0,.08); }
|
||
*{box-sizing:border-box}
|
||
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:var(--beige);color:var(--ink);margin:0;padding:1.2rem;line-height:1.5}
|
||
.wrap{max-width:1280px;margin:0 auto}
|
||
h1{font-size:1.8rem;margin:0 0 .3rem;color:var(--moss);letter-spacing:-.01em}
|
||
.sub{color:var(--muted);font-size:.85rem;margin-bottom:1.5rem}
|
||
.filter{display:flex;gap:.5rem;margin-bottom:1.5rem;flex-wrap:wrap}
|
||
.filter button{padding:.4rem .9rem;border:1.5px solid var(--line);background:#fff;border-radius:18px;font-size:.78rem;font-weight:700;cursor:pointer;color:var(--ink)}
|
||
.filter button.active{background:var(--moss);color:#fff;border-color:var(--moss)}
|
||
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1rem}
|
||
.dish{background:#fff;border-radius:12px;border:1px solid var(--line);overflow:hidden;display:flex;flex-direction:column}
|
||
.dish img{width:100%;height:240px;object-fit:cover;background:var(--beige);display:block}
|
||
.dish img.missing{opacity:0.3}
|
||
.dish-body{padding:.9rem 1rem 1rem;flex:1;display:flex;flex-direction:column}
|
||
.dish-head{display:flex;align-items:flex-start;gap:.5rem;margin-bottom:.3rem}
|
||
.dish-emoji{font-size:1.6rem;line-height:1}
|
||
.dish-name{font-weight:800;font-size:1.05rem;color:var(--moss);flex:1}
|
||
.dish-origin{font-size:.74rem;color:var(--muted);margin-bottom:.6rem;font-weight:600}
|
||
.dish-tags{display:flex;gap:.3rem;flex-wrap:wrap;margin-bottom:.6rem}
|
||
.tag{font-size:.65rem;background:var(--beige);padding:.15rem .5rem;border-radius:8px;color:var(--muted);font-weight:600}
|
||
.dish-nutrition{display:grid;grid-template-columns:repeat(3,1fr);gap:.3rem;font-size:.7rem;margin-bottom:.7rem;background:var(--beige);padding:.5rem;border-radius:6px}
|
||
.dish-nutrition span{display:flex;justify-content:space-between}
|
||
.dish-nutrition b{color:var(--moss)}
|
||
details{margin-bottom:.5rem;font-size:.78rem;border-top:1px dashed var(--line);padding-top:.5rem}
|
||
details summary{cursor:pointer;color:var(--sage);font-weight:700;font-size:.74rem;text-transform:uppercase;letter-spacing:.04em}
|
||
details ol{margin:.4rem 0 .3rem;padding-left:1.3rem;font-size:.72rem;line-height:1.5}
|
||
details li{margin-bottom:.3rem}
|
||
.ings{display:flex;gap:.25rem;flex-wrap:wrap;font-size:.65rem;color:var(--muted)}
|
||
.ings code{background:var(--beige);padding:.05rem .35rem;border-radius:4px;font-family:monospace}
|
||
.fact{font-size:.75rem;color:var(--muted);font-style:italic;margin-top:auto;padding-top:.5rem;border-top:1px dashed var(--line)}
|
||
.category-badge{display:inline-block;font-size:.64rem;padding:.1rem .45rem;border-radius:8px;font-weight:700;letter-spacing:.03em;text-transform:uppercase}
|
||
.category-badge.regional-at{background:#d4e6da;color:#1f4b37}
|
||
.category-badge.dach{background:#f0e2c3;color:#8a6516}
|
||
.category-badge.europa{background:#eee5ed;color:#5a3a6a}
|
||
.category-badge.exotisch{background:#efd6cb;color:#9c4d2e}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
<h1>🍽 Weltküche — Vorschau aller 30 Gerichte</h1>
|
||
<p class="sub">Tranche A (5 AT-regional) · B (10 DACH) · C (10 Europa) · D (5 exotisch). Bild-Status wird live geladen.</p>
|
||
<div class="filter" id="filter">
|
||
<button data-cat="all" class="active">Alle (30)</button>
|
||
<button data-cat="regional-at">🇦🇹 AT-regional (5)</button>
|
||
<button data-cat="dach">🇦🇹🇩🇪🇨🇭 DACH (10)</button>
|
||
<button data-cat="europa">🇪🇺 Europa (10)</button>
|
||
<button data-cat="exotisch">🌍 Exotisch (5)</button>
|
||
</div>
|
||
<div class="grid" id="grid">Lade…</div>
|
||
</div>
|
||
<script>
|
||
async function loadJson(path) {
|
||
try { const r = await fetch(path); return await r.json(); }
|
||
catch(e) { return {}; }
|
||
}
|
||
function esc(s){return String(s||'').replace(/[<>&"]/g,c=>({'<':'<','>':'>','&':'&','"':'"'}[c]));}
|
||
function renderDish(id, d) {
|
||
const n = d.nutrition || {};
|
||
const r = d.recipe || {};
|
||
return `<div class="dish" data-cat="${d.category}">
|
||
<img src="${d.imagePath}" alt="${esc(d.name)}" onerror="this.classList.add('missing');this.src='data:image/svg+xml;utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 60%22><rect fill=%22%23e8e4d8%22 width=%22100%22 height=%2260%22/><text x=%2250%22 y=%2235%22 text-anchor=%22middle%22 font-family=%22sans-serif%22 font-size=%228%22 fill=%22%236a6a6a%22>kein Bild</text></svg>';">
|
||
<div class="dish-body">
|
||
<div class="dish-head">
|
||
<span class="dish-emoji">${d.emoji}</span>
|
||
<span class="dish-name">${esc(d.name)}</span>
|
||
<span class="category-badge ${d.category}">${d.category}</span>
|
||
</div>
|
||
<div class="dish-origin">📍 ${esc(d.origin)} · <strong>${d.diff}</strong>${d.diff_note?' · <span style="color:var(--muted);font-weight:400">'+esc(d.diff_note)+'</span>':''}</div>
|
||
<div class="dish-tags">${(d.tags||[]).map(t=>'<span class="tag">'+esc(t)+'</span>').join('')}</div>
|
||
<div class="dish-nutrition">
|
||
<span>kcal <b>${n.kcal||'–'}</b></span>
|
||
<span>Eiweiß <b>${n.protein_g||'–'} g</b></span>
|
||
<span>KH <b>${n.carbs_g||'–'} g</b></span>
|
||
<span>Fett <b>${n.fat_g||'–'} g</b></span>
|
||
<span>Ballast <b>${n.fiber_g||'–'} g</b></span>
|
||
<span>Salz <b>${n.salt_g||'–'} g</b></span>
|
||
</div>
|
||
<details>
|
||
<summary>📋 Rezept (${r.portions||'?'} Portionen, ${r.time_min||'?'} min)</summary>
|
||
<ol>${(r.steps||[]).map(s=>'<li>'+esc(s)+'</li>').join('')}</ol>
|
||
${r.tipp?'<p style="font-size:.72rem;color:var(--moss)"><b>💡 Tipp:</b> '+esc(r.tipp)+'</p>':''}
|
||
</details>
|
||
<details>
|
||
<summary>📚 Lehrplan-Bezug</summary>
|
||
${Object.entries(d.lehrplan||{}).map(([k,v])=>'<p style="font-size:.72rem;margin:.3rem 0"><b>'+k.toUpperCase()+':</b> '+esc(v)+'</p>').join('')}
|
||
</details>
|
||
<details>
|
||
<summary>🧪 Welt-Zutaten + Pantry</summary>
|
||
<p style="font-size:.72rem;margin:.3rem 0"><b>Welt-Zutaten:</b> <span class="ings">${(d.ings||[]).map(i=>'<code>'+esc(i)+'</code>').join(' ')}</span></p>
|
||
<p style="font-size:.72rem;margin:.3rem 0"><b>Pantry (lokal):</b> ${(d.pantry||[]).map(esc).join(', ')}</p>
|
||
</details>
|
||
<p class="fact">💡 ${esc(d.fact)}</p>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
async function init() {
|
||
const [a, b, c, dd] = await Promise.all([
|
||
loadJson('assets/data/dishes.json'),
|
||
loadJson('assets/data/dishes-tranche-b.json'),
|
||
loadJson('assets/data/dishes-tranche-c.json'),
|
||
loadJson('assets/data/dishes-tranche-d.json'),
|
||
]);
|
||
const all = {...a, ...b, ...c, ...dd};
|
||
delete all._meta;
|
||
const grid = document.getElementById('grid');
|
||
grid.innerHTML = '';
|
||
for (const id in all) {
|
||
grid.insertAdjacentHTML('beforeend', renderDish(id, all[id]));
|
||
}
|
||
document.getElementById('filter').addEventListener('click', e => {
|
||
if (e.target.tagName !== 'BUTTON') return;
|
||
const cat = e.target.dataset.cat;
|
||
document.querySelectorAll('#filter button').forEach(b => b.classList.toggle('active', b===e.target));
|
||
document.querySelectorAll('.dish').forEach(el => {
|
||
el.style.display = (cat==='all' || el.dataset.cat===cat) ? '' : 'none';
|
||
});
|
||
});
|
||
}
|
||
init();
|
||
</script>
|
||
</body>
|
||
</html>
|