Initial commit: What To Cook (WTC) v4.4 - Digitales Kochbuch, Wochenmenueplan & Buchdruck

This commit is contained in:
2026-10-14 20:24:37 +02:00
commit c01d2d7639
171 changed files with 14073 additions and 0 deletions
+227
View File
@@ -0,0 +1,227 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<meta name="theme-color" content="#1e222d">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<title>What To Cook? – Essens-Zufallsgenerator</title>
<link rel="manifest" href="/static/manifest.json">
<link rel="apple-touch-icon" href="/static/icon-192.png">
<link rel="stylesheet" href="/static/style.css">
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🍽️</text></svg>">
</head>
<body>
<div class="app-container">
<!-- Top Header -->
<header class="app-header">
<div class="brand">
<span class="brand-icon">🍽️</span>
<div>
<h1 class="brand-title">What To Cook?</h1>
<p class="brand-subtitle">Zufallsgenerator für Essen</p>
</div>
</div>
<!-- Tab Navigation -->
<nav class="nav-tabs" role="tablist">
<button id="tab-btn-generator" class="nav-tab active" data-tab="generator" role="tab" aria-selected="true">
<span class="icon">🎲</span> Generator
</button>
<a href="/cookbook" class="nav-tab" style="text-decoration: none;">
<span class="icon">📖</span> Kochbuch
</a>
<a href="/cookbook/new" class="nav-tab" style="text-decoration: none;">
<span class="icon">➕</span> Rezept
</a>
<button id="tab-btn-admin" class="nav-tab" data-tab="admin" role="tab" aria-selected="false">
<span class="icon">⚙️</span> Gerichte
</button>
</nav>
</header>
<!-- Main Content Area -->
<main class="app-main">
<!-- ========================================== -->
<!-- TAB 1: GENERATOR -->
<!-- ========================================== -->
<section id="tab-generator" class="tab-panel active" role="tabpanel">
<!-- Banner / Hint -->
<div class="info-card">
<div class="info-content">
<span class="info-icon">💡</span>
<div>
<strong>Bis zu 5 Gerichte konfigurieren:</strong>
Wähle Kategorie & Aufwand pro Gericht. Nicht benötigte Gerichte einfach frei lassen.
</div>
</div>
<div class="active-counter-badge" id="active-slots-counter">
<span id="active-slots-count">2</span> von 5 aktiv
</div>
</div>
<!-- 5 Dish Configuration Slots -->
<div class="slots-container" id="slots-container">
<!-- Rendered dynamically by app.js (1 to 5) -->
</div>
<!-- Floating / Sticky Action Bar -->
<div class="action-bar-wrapper">
<button id="btn-roll-all" class="btn btn-primary btn-hero">
<span class="btn-icon">🎲</span>
<span class="btn-text">Zufallsgenerator starten</span>
</button>
</div>
<!-- Results Section (Anchor / Modal or Inline display) -->
<section id="results-section" class="results-section hidden">
<div class="results-header">
<div class="results-title-group">
<h2 class="results-title">Ausgeloste Gerichte</h2>
<span class="results-badge" id="results-count-badge">0 Gerichte</span>
</div>
<button id="btn-reroll-all" class="btn btn-outline btn-sm">
<span class="icon">🔄</span> Alle neu würfeln
</button>
</div>
<div id="results-list" class="results-grid">
<!-- Dynamic Result Cards -->
</div>
<div class="results-footer">
<button id="btn-back-to-config" class="btn btn-secondary">
✏️ Filter anpassen
</button>
</div>
</section>
</section>
<!-- ========================================== -->
<!-- TAB 2: ADMIN / DATABASE -->
<!-- ========================================== -->
<section id="tab-admin" class="tab-panel" role="tabpanel" hidden>
<div class="admin-topbar">
<div>
<h2 class="section-title">Gerichte verwalten</h2>
<p class="section-desc" id="admin-stats-summary">Lade Datenbank...</p>
</div>
<button id="btn-open-add-dish" class="btn btn-primary">
<span>➕</span> Neues Gericht
</button>
</div>
<!-- Admin Filters -->
<div class="admin-filters-card">
<div class="search-input-wrap">
<span class="search-icon">🔍</span>
<input type="text" id="admin-search-input" placeholder="Gericht nach Namen suchen..." autocomplete="off">
<button id="admin-search-clear" class="btn-clear hidden" title="Suche leeren">✕</button>
</div>
<div class="filter-row">
<div class="form-group flex-1">
<label for="admin-filter-category" class="filter-label">Kategorie:</label>
<select id="admin-filter-category" class="custom-select">
<option value="alle">Alle Kategorien</option>
<!-- Filled via JS -->
</select>
</div>
<div class="form-group flex-1">
<label for="admin-filter-effort" class="filter-label">Aufwand:</label>
<select id="admin-filter-effort" class="custom-select">
<option value="alle">Jeder Aufwand</option>
<option value="gering">Gering 🟢</option>
<option value="mittel">Mittel 🟡</option>
<option value="hoch">Hoch 🔴</option>
</select>
</div>
</div>
</div>
<!-- Dishes Table / Cards for Mobile -->
<div class="dishes-list-wrap">
<div class="dishes-list-header">
<span id="dishes-count-label">Gerichte</span>
</div>
<div id="admin-dishes-list" class="admin-dishes-list">
<div class="loading-spinner">Lade Gerichte...</div>
</div>
</div>
</section>
</main>
<!-- Dialog: Add / Edit Dish -->
<dialog id="dish-modal" class="modal">
<div class="modal-box">
<div class="modal-header">
<h3 id="modal-title" class="modal-title">Neues Gericht anlegen</h3>
<button id="btn-close-modal" class="btn-icon-close" aria-label="Schließen">✕</button>
</div>
<form id="dish-form" method="dialog">
<input type="hidden" id="dish-form-id" value="">
<div class="form-group">
<label for="dish-name-input" class="form-label">Name des Gerichts *</label>
<input type="text" id="dish-name-input" class="text-input" placeholder="z. B. Spaghetti Carbonara" required autocomplete="off">
</div>
<div class="form-group">
<label class="form-label">Kategorien * <span class="form-label-hint">(Mehrfachauswahl möglich)</span></label>
<div class="category-checkbox-group" id="modal-category-group">
<!-- Filled via JS as checkbox pills -->
</div>
</div>
<div class="form-group">
<label class="form-label">Arbeitsaufwand *</label>
<div class="effort-radio-group">
<label class="effort-radio-label">
<input type="radio" name="modal-effort" value="gering" required>
<span class="effort-pill effort-gering">Gering 🟢 (≤ 20 Min)</span>
</label>
<label class="effort-radio-label">
<input type="radio" name="modal-effort" value="mittel" checked required>
<span class="effort-pill effort-mittel">Mittel 🟡 (~ 45 Min)</span>
</label>
<label class="effort-radio-label">
<input type="radio" name="modal-effort" value="hoch" required>
<span class="effort-pill effort-hoch">Hoch 🔴 (> 60 Min)</span>
</label>
</div>
</div>
<div class="modal-actions">
<button type="button" id="btn-cancel-modal" class="btn btn-secondary">Abbrechen</button>
<button type="submit" id="btn-save-modal" class="btn btn-primary">Speichern</button>
</div>
</form>
</div>
</dialog>
<!-- Dialog: Delete Confirm -->
<dialog id="delete-modal" class="modal">
<div class="modal-box modal-box-sm">
<h3 class="modal-title">Gericht löschen?</h3>
<p id="delete-modal-text" class="modal-text">Möchtest du dieses Gericht wirklich aus der Datenbank entfernen?</p>
<div class="modal-actions">
<button id="btn-cancel-delete" class="btn btn-secondary">Abbrechen</button>
<button id="btn-confirm-delete" class="btn btn-danger">Unwiderruflich löschen</button>
</div>
</div>
</dialog>
<!-- Toast Notifications -->
<div id="toast-container" class="toast-container" aria-live="polite"></div>
</div>
<script src="/static/app.js"></script>
</body>
</html>