Files
EverShelf/index.html
T
dadaloop82 d13f744aea feat: v1.1.0 - Docker, i18n, setup wizard, rate limiting, OpenAPI
New features:
- Docker support (Dockerfile + docker-compose.yml)
- GitHub Actions CI pipeline (PHP lint, JS lint, Docker build, i18n validation)
- Internationalization system with 3 languages (it, en, de) and 347 translation keys
- First-run setup wizard (4-step configuration)
- File-based API rate limiting (120/15/5 req/min tiers)
- OpenAPI 3.1.0 specification for all 43 API endpoints
- CONTRIBUTING.md with translation and development guide
- Screenshots directory placeholder

Modified:
- README.md: Docker badges, install instructions, translations section
- api/index.php: rate limiting middleware
- assets/js/app.js: i18n system, setup wizard, t() function
- assets/css/style.css: setup wizard styles
- index.html: data-i18n attributes, setup wizard overlay, language settings
- .gitignore: rate_limits exclusion
2026-04-10 06:03:11 +00:00

1156 lines
69 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="theme-color" content="#2d5016">
<meta name="author" content="Stimpfl Daniel">
<meta name="description" content="Self-hosted pantry manager with barcode scanning, AI identification, and shopping list integration.">
<title>Dispensa Manager</title>
<link rel="manifest" href="manifest.json">
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🏠</text></svg>">
<link rel="stylesheet" href="assets/css/style.css?v=20260329a">
<!-- QuaggaJS for barcode scanning -->
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
</head>
<body>
<!-- Top Header -->
<header class="app-header">
<div class="header-content">
<h1 class="header-title" onclick="showPage('dashboard')" data-i18n="nav.title">🏠 Dispensa</h1>
<div class="header-actions">
<button class="header-scan-btn header-gemini-btn" onclick="showPage('chat')" title="Chat con Gemini" data-i18n-title="chat.title">
<svg class="gemini-icon" viewBox="0 0 24 24" width="28" height="28" fill="white"><path d="M12 0C12 6.627 6.627 12 0 12c6.627 0 12 5.373 12 12 0-6.627 5.373-12 12-12-6.627 0-12-5.373-12-12z"/></svg>
</button>
<button class="header-scan-btn" id="btn-header-scan" title="Scansiona prodotto (tieni premuto per modalità spesa)" data-i18n-title="scan.hint">
📷
</button>
</div>
</div>
</header>
<!-- Main Content Area -->
<main class="app-content" id="app-content">
<!-- ===== DASHBOARD ===== -->
<section class="page active" id="page-dashboard">
<div class="dashboard-stats" id="dashboard-stats">
<div class="stat-card" onclick="showPage('inventory', 'dispensa')">
<span class="stat-icon">🗄️</span>
<span class="stat-value" id="stat-dispensa">0</span>
<span class="stat-label" data-i18n="locations.dispensa">Dispensa</span>
</div>
<div class="stat-card" onclick="showPage('inventory', 'frigo')">
<span class="stat-icon">🧊</span>
<span class="stat-value" id="stat-frigo">0</span>
<span class="stat-label" data-i18n="locations.frigo">Frigo</span>
</div>
<div class="stat-card" onclick="showPage('inventory', 'freezer')">
<span class="stat-icon">❄️</span>
<span class="stat-value" id="stat-freezer">0</span>
<span class="stat-label" data-i18n="locations.freezer">Freezer</span>
</div>
<div class="stat-card" onclick="showPage('shopping')">
<span class="stat-icon">🛒</span>
<span class="stat-value" id="stat-spesa">-</span>
<span class="stat-label" data-i18n="nav.shopping">Spesa</span>
<span class="stat-urgent" id="stat-urgent" style="display:none"></span>
</div>
</div>
<!-- Quick recipe suggestion -->
<div class="quick-recipe-bar" id="quick-recipe-bar" style="display:none">
<button class="btn-quick-recipe" onclick="quickRecipeSuggestion()">
<span>🍳</span>
<span class="quick-recipe-text" data-i18n="dashboard.quick_recipe">🍳 Ricetta veloce con prodotti in scadenza</span>
<span></span>
</button>
</div>
<!-- Alert for expired items (on top) -->
<div class="alert-section alert-danger" id="alert-expired" style="display:none">
<h3 data-i18n="dashboard.expired_title">🚫 Scaduti</h3>
<div id="expired-list"></div>
</div>
<!-- Alert for soonest expiring items -->
<div class="alert-section" id="alert-expiring" style="display:none">
<h3 data-i18n="dashboard.expiring_title">⏰ Prossime Scadenze</h3>
<div id="expiring-list"></div>
</div>
<!-- Waste vs consumption mini chart -->
<div class="waste-chart-section" id="waste-chart-section" style="display:none">
<h3 data-i18n="dashboard.stats_period">📊 Ultimi 30 giorni</h3>
<div class="waste-chart-bar" id="waste-chart-bar"></div>
<div class="waste-chart-legend" id="waste-chart-legend"></div>
</div>
<!-- Opened (partially used) products -->
<div class="alert-section alert-opened" id="alert-opened" style="display:none">
<h3 data-i18n="dashboard.opened_title">📦 Prodotti Aperti</h3>
<div id="opened-list"></div>
</div>
<!-- Review suspicious quantities -->
<div class="alert-section alert-review" id="alert-review" style="display:none">
<h3 data-i18n="dashboard.review_title">🔍 Da revisionare</h3>
<p class="review-hint" data-i18n="dashboard.review_hint">Quantità che sembrano anomale. Conferma se corrette o modifica.</p>
<div id="review-list"></div>
</div>
</section>
<!-- ===== INVENTORY LIST ===== -->
<section class="page" id="page-inventory">
<div class="page-header">
<button class="back-btn" onclick="showPage('dashboard')" data-i18n="btn.back">← Indietro</button>
<h2 id="inventory-title" data-i18n="inventory.title">Dispensa</h2>
</div>
<div class="location-tabs" id="location-tabs">
<button class="tab active" onclick="filterLocation('')" data-loc="" data-i18n="inventory.filter_all">Tutti</button>
<button class="tab" onclick="filterLocation('dispensa')" data-loc="dispensa">🗄️ Dispensa</button>
<button class="tab" onclick="filterLocation('frigo')" data-loc="frigo">🧊 Frigo</button>
<button class="tab" onclick="filterLocation('freezer')" data-loc="freezer">❄️ Freezer</button>
<button class="tab" onclick="filterLocation('altro')" data-loc="altro">📦 Altro</button>
</div>
<div class="search-bar">
<input type="text" id="inventory-search" placeholder="🔍 Cerca prodotto..." oninput="filterInventory()" data-i18n-placeholder="inventory.search_placeholder">
</div>
<div class="inventory-list" id="inventory-list"></div>
</section>
<!-- ===== SCAN PAGE ===== -->
<section class="page" id="page-scan">
<div class="page-header">
<button class="back-btn" onclick="stopScanner(); showPage('dashboard')" data-i18n="btn.back">← Indietro</button>
<h2 data-i18n="scan.title">Scansiona Prodotto</h2>
</div>
<div class="spesa-mode-banner" id="spesa-mode-banner" style="display:none">
<div class="spesa-banner-left">
<span data-i18n="scan.mode_shopping">🛒 Modalità Spesa</span>
<span class="spesa-stat"></span>
</div>
<button class="btn btn-small" onclick="endSpesaMode()" data-i18n="scan.mode_shopping_end">✅ Fine spesa</button>
</div>
<div class="scan-container">
<div class="scanner-viewport" id="scanner-viewport">
<div class="scanner-overlay">
<div class="scanner-line"></div>
</div>
<button class="scan-zoom-btn" id="scan-zoom-btn" onclick="toggleScanZoom()" title="Zoom">x1</button>
<video id="scanner-video" autoplay playsinline></video>
<canvas id="scanner-canvas" style="display:none"></canvas>
</div>
<div class="scan-result" id="scan-result" style="display:none"></div>
<div class="barcode-manual-entry">
<div class="barcode-input-row">
<input type="text" id="manual-barcode-input" class="form-input" placeholder="Inserisci codice a barre..." inputmode="numeric" pattern="[0-9]*" onkeydown="if(event.key==='Enter')submitManualBarcode()" data-i18n-placeholder="scan.barcode_placeholder">
<button class="btn btn-primary" onclick="submitManualBarcode()">🔍 Cerca</button>
</div>
</div>
<div class="quick-name-entry">
<div class="quick-name-divider"><span>oppure scrivi il nome</span></div>
<div class="barcode-input-row">
<input type="text" id="quick-product-name" class="form-input" placeholder="Es: Mele, Zucchine, Pane..." list="common-products" autocomplete="off" onkeydown="if(event.key==='Enter')submitQuickName()">
<button class="btn btn-accent" onclick="submitQuickName()">✅ Vai</button>
</div>
</div>
<div class="scan-actions">
<button class="btn btn-large btn-secondary" onclick="startManualEntry()">
✏️ Inserimento Manuale
</button>
<button class="btn btn-large btn-accent" onclick="captureForAI()">
🤖 Identifica con AI
</button>
</div>
<p class="scan-hint">Scansiona il barcode, scrivi il nome del prodotto, oppure usa l'AI per identificarlo</p>
<div id="scan-debug-log" style="display:none;margin-top:12px;padding:10px;background:#1a1a2e;color:#0f0;font-family:monospace;font-size:0.7rem;max-height:200px;overflow-y:auto;border-radius:8px;white-space:pre-wrap"></div>
<button class="btn btn-small btn-secondary" style="margin-top:8px;opacity:0.5" onclick="toggleScanDebug()">🐛 Debug Log</button>
</div>
</section>
<!-- ===== PRODUCT ACTION (IN/OUT after scan) ===== -->
<section class="page" id="page-action">
<div class="page-header">
<button class="back-btn" id="action-back-btn" onclick="showPage('scan')">← Indietro</button>
<h2>Cosa vuoi fare?</h2>
</div>
<!-- Banner: shopping list scan context -->
<div id="shopping-scan-target-banner" class="shopping-scan-target-banner" style="display:none"></div>
<div class="product-preview product-preview-large" id="action-product-preview"></div>
<div class="inventory-status-bar" id="action-inventory-status" style="display:none"></div>
<div class="action-buttons" id="action-buttons-container">
<button class="btn btn-huge btn-success" onclick="showAddForm()">
<span class="btn-icon">📥</span>
<span class="btn-text">AGGIUNGI<br><small>in dispensa/frigo</small></span>
</button>
<button class="btn btn-huge btn-danger" onclick="showUseForm()">
<span class="btn-icon">📤</span>
<span class="btn-text">USA / CONSUMA<br><small>dalla dispensa/frigo</small></span>
</button>
</div>
</section>
<!-- ===== ADD TO INVENTORY FORM ===== -->
<section class="page" id="page-add">
<div class="page-header">
<button class="back-btn" onclick="showPage('action')">← Indietro</button>
<h2>Aggiungi alla Dispensa</h2>
</div>
<div class="product-preview-small" id="add-product-preview"></div>
<form class="form" onsubmit="submitAdd(event)">
<div class="form-group">
<label>📍 Dove lo metti?</label>
<div class="location-selector">
<button type="button" class="loc-btn active" onclick="selectLocation(this, 'dispensa')">🗄️ Dispensa</button>
<button type="button" class="loc-btn" onclick="selectLocation(this, 'frigo')">🧊 Frigo</button>
<button type="button" class="loc-btn" onclick="selectLocation(this, 'freezer')">❄️ Freezer</button>
<button type="button" class="loc-btn" onclick="selectLocation(this, 'altro')">📦 Altro</button>
</div>
<input type="hidden" id="add-location" value="dispensa">
</div>
<div class="form-group">
<label>📦 Quantità</label>
<div class="qty-unit-row">
<div class="qty-control flex-1">
<button type="button" class="qty-btn" onclick="adjustAddQty(-1)"></button>
<input type="number" id="add-quantity" value="1" min="0.1" step="any" class="qty-input">
<button type="button" class="qty-btn" onclick="adjustAddQty(1)">+</button>
</div>
<select id="add-unit" class="form-input unit-select" onchange="onAddUnitChange()">
<option value="pz">pz</option>
<option value="conf">conf</option>
<option value="g">g</option>
<option value="ml">ml</option>
</select>
</div>
<div id="add-conf-size-row" class="conf-size-row" style="display:none">
<label class="conf-size-label">📦 Ogni confezione contiene:</label>
<div class="conf-size-inputs">
<input type="number" id="add-conf-size" class="form-input conf-size-input" min="1" step="any" placeholder="es. 300">
<select id="add-conf-unit" class="form-input conf-size-unit">
<option value="g">g</option>
<option value="ml">ml</option>
</select>
</div>
</div>
<div id="add-weight-info" class="form-hint" style="display:none"></div>
</div>
<div class="form-group" id="add-vacuum-group">
<label class="toggle-row" onclick="toggleVacuumSealed()">
<span>🫙 Sotto vuoto</span>
<span class="toggle-switch" id="add-vacuum-toggle">
<input type="checkbox" id="add-vacuum-sealed" onchange="onVacuumSealedChange()">
<span class="toggle-slider"></span>
</span>
</label>
<p class="form-hint" id="add-vacuum-hint" style="display:none">La scadenza verrà estesa automaticamente</p>
</div>
<div class="form-group" id="add-expiry-section">
<!-- Populated dynamically by showAddForm() -->
</div>
<button type="submit" class="btn btn-large btn-success full-width">✅ Aggiungi</button>
</form>
</section>
<!-- ===== USE FROM INVENTORY FORM ===== -->
<section class="page" id="page-use">
<div class="page-header">
<button class="back-btn" onclick="showPage('action')">← Indietro</button>
<h2>Usa / Consuma</h2>
</div>
<div class="product-preview-small" id="use-product-preview"></div>
<div class="use-inventory-info" id="use-inventory-info"></div>
<div id="use-expiry-hint" style="display:none"></div>
<form class="form" onsubmit="submitUse(event)">
<div class="form-group">
<label>📍 Da dove?</label>
<div class="location-selector" id="use-location-selector">
<button type="button" class="loc-btn active" onclick="selectUseLocation(this, 'dispensa')">🗄️ Dispensa</button>
<button type="button" class="loc-btn" onclick="selectUseLocation(this, 'frigo')">🧊 Frigo</button>
<button type="button" class="loc-btn" onclick="selectUseLocation(this, 'freezer')">❄️ Freezer</button>
<button type="button" class="loc-btn" onclick="selectUseLocation(this, 'altro')">📦 Altro</button>
</div>
<input type="hidden" id="use-location" value="dispensa">
</div>
<div class="form-group">
<label>Quanto hai usato?</label>
<div class="use-unit-switch" id="use-unit-switch" style="display:none">
<button type="button" class="use-unit-btn active" id="use-unit-sub" onclick="switchUseUnit('sub')"></button>
<button type="button" class="use-unit-btn" id="use-unit-conf" onclick="switchUseUnit('conf')">Confezioni</button>
</div>
<div class="use-options">
<button type="button" class="btn btn-large btn-danger full-width use-all-btn" onclick="submitUseAll()">
🗑️ Usato TUTTO / Finito
</button>
<div class="use-partial">
<p id="use-partial-hint">Oppure specifica la quantità usata:</p>
<div class="qty-control">
<button type="button" class="qty-btn" id="use-qty-minus" onclick="adjustUseQty(-1)"></button>
<input type="number" id="use-quantity" value="1" min="0.1" step="any" class="qty-input">
<button type="button" class="qty-btn" id="use-qty-plus" onclick="adjustUseQty(1)">+</button>
</div>
<button type="submit" class="btn btn-large btn-warning full-width mt-2">📤 Usa questa quantità</button>
</div>
</div>
</div>
</form>
</section>
<!-- ===== MANUAL / EDIT PRODUCT FORM ===== -->
<section class="page" id="page-product-form">
<div class="page-header">
<button class="back-btn" onclick="showPage('scan')">← Indietro</button>
<h2 id="product-form-title">Nuovo Prodotto</h2>
</div>
<form class="form" onsubmit="submitProduct(event)">
<input type="hidden" id="pf-id">
<div id="pf-ai-fill-row" class="form-group">
<button type="button" class="btn btn-accent full-width" onclick="captureForAIFormFill()">
📷 Scatta foto e identifica con AI
</button>
<p class="form-hint" style="text-align:center;margin-top:4px">L'AI compilerà automaticamente i campi del prodotto</p>
</div>
<div class="form-group">
<label>🏷️ Nome Prodotto *</label>
<input type="text" id="pf-name" class="form-input" required placeholder="Es: Latte intero, Pasta penne rigate..."
list="common-products" autocomplete="off">
<datalist id="common-products">
<option value="Latte intero">
<option value="Latte parzialmente scremato">
<option value="Latte scremato">
<option value="Yogurt bianco">
<option value="Yogurt greco">
<option value="Mozzarella">
<option value="Burrata">
<option value="Parmigiano Reggiano">
<option value="Grana Padano">
<option value="Ricotta">
<option value="Mascarpone">
<option value="Burro">
<option value="Panna fresca">
<option value="Uova">
<option value="Prosciutto cotto">
<option value="Prosciutto crudo">
<option value="Bresaola">
<option value="Salame">
<option value="Mortadella">
<option value="Petto di pollo">
<option value="Macinato di manzo">
<option value="Salmone fresco">
<option value="Tonno in scatola">
<option value="Sgombro in scatola">
<option value="Pasta spaghetti">
<option value="Pasta penne rigate">
<option value="Pasta fusilli">
<option value="Riso">
<option value="Riso basmati">
<option value="Farina 00">
<option value="Pane fresco">
<option value="Pan carrè">
<option value="Fette biscottate">
<option value="Passata di pomodoro">
<option value="Pomodori pelati">
<option value="Olio extravergine d'oliva">
<option value="Aceto balsamico">
<option value="Sale fino">
<option value="Zucchero">
<option value="Caffè macinato">
<option value="Biscotti">
<option value="Nutella">
<option value="Marmellata">
<option value="Miele">
<option value="Cereali">
<option value="Lenticchie">
<option value="Ceci">
<option value="Fagioli">
<option value="Insalata mista">
<option value="Pomodori">
<option value="Zucchine">
<option value="Patate">
<option value="Cipolle">
<option value="Mele">
<option value="Banane">
<option value="Arance">
<option value="Acqua naturale">
<option value="Succo d'arancia">
<option value="Birra">
<option value="Vino rosso">
</datalist>
</div>
<div class="form-group">
<label>🏢 Marca</label>
<input type="text" id="pf-brand" class="form-input" placeholder="Es: Barilla, Granarolo, Mutti..."
list="common-brands" autocomplete="off">
<datalist id="common-brands">
<option value="Barilla">
<option value="De Cecco">
<option value="Rummo">
<option value="Voiello">
<option value="Divella">
<option value="Granarolo">
<option value="Parmalat">
<option value="Müller">
<option value="Danone">
<option value="Galbani">
<option value="Ferrero">
<option value="Lavazza">
<option value="Illy">
<option value="Mulino Bianco">
<option value="Pan di Stelle">
<option value="Mutti">
<option value="Cirio">
<option value="De Rica">
<option value="Star">
<option value="Knorr">
<option value="Findus">
<option value="4 Salti in Padella">
<option value="Rio Mare">
<option value="Valfrutta">
<option value="Auricchio">
<option value="Zanetti">
<option value="Beretta">
<option value="Rovagnati">
<option value="Amadori">
<option value="AIA">
<option value="Esselunga">
<option value="Conad">
<option value="Coop">
</datalist>
</div>
<div class="form-group">
<label>📂 Categoria</label>
<select id="pf-category" class="form-input" onchange="onCategoryChange(false)">
<option value="">-- Seleziona --</option>
<option value="latticini">🥛 Latticini</option>
<option value="carne">🥩 Carne</option>
<option value="pesce">🐟 Pesce</option>
<option value="frutta">🍎 Frutta</option>
<option value="verdura">🥬 Verdura</option>
<option value="pasta">🍝 Pasta & Riso</option>
<option value="pane">🍞 Pane & Forno</option>
<option value="surgelati">🧊 Surgelati</option>
<option value="bevande">🥤 Bevande</option>
<option value="condimenti">🧂 Condimenti</option>
<option value="snack">🍪 Snack & Dolci</option>
<option value="conserve">🥫 Conserve</option>
<option value="cereali">🌾 Cereali & Legumi</option>
<option value="igiene">🧴 Igiene</option>
<option value="pulizia">🧹 Pulizia Casa</option>
<option value="altro">📦 Altro</option>
</select>
</div>
<div class="form-row">
<div class="form-group flex-1">
<label>📏 Unità di misura</label>
<select id="pf-unit" class="form-input" onchange="onPfUnitChange()">
<option value="pz">Pezzi</option>
<option value="g">Grammi</option>
<option value="ml">ml</option>
<option value="conf">Confezione</option>
</select>
</div>
<div class="form-group flex-1">
<label>🔢 Quantità default</label>
<input type="number" id="pf-defqty" class="form-input" value="1" min="0.1" step="any">
</div>
</div>
<div id="pf-conf-size-row" class="conf-size-row" style="display:none">
<label class="conf-size-label">📦 Ogni confezione contiene:</label>
<div class="conf-size-inputs">
<input type="number" id="pf-conf-size" class="form-input conf-size-input" min="1" step="any" placeholder="es. 300">
<select id="pf-conf-unit" class="form-input conf-size-unit">
<option value="g">g</option>
<option value="ml">ml</option>
</select>
</div>
</div>
<div class="form-group">
<label>📝 Note</label>
<textarea id="pf-notes" class="form-input" rows="2" placeholder="Es: senza lattosio, bio, conservare in frigo dopo apertura..."></textarea>
</div>
<div class="form-group">
<label>🔖 Barcode</label>
<div class="expiry-input-row">
<input type="text" id="pf-barcode" class="form-input" placeholder="Codice a barre (se disponibile)" inputmode="numeric">
<button type="button" class="btn btn-accent btn-scan-expiry" id="pf-barcode-scan-btn" onclick="scanBarcodeForForm()" title="Scansiona barcode">📷</button>
</div>
<p class="form-hint" id="pf-barcode-hint" style="display:none">⚠️ Aggiungi il barcode così al prossimo acquisto basta scansionarlo!</p>
</div>
<input type="hidden" id="pf-image">
<div class="product-image-preview" id="pf-image-preview" style="display:none">
<img id="pf-image-img" src="" alt="Product">
</div>
<button type="submit" class="btn btn-large btn-primary full-width">💾 Salva Prodotto</button>
</form>
</section>
<!-- ===== ALL PRODUCTS PAGE ===== -->
<section class="page" id="page-products">
<div class="page-header">
<button class="back-btn" onclick="showPage('dashboard')">← Indietro</button>
<h2>📦 Tutti i Prodotti</h2>
</div>
<div class="search-bar">
<input type="text" id="products-search" placeholder="🔍 Cerca prodotto..." oninput="searchAllProducts()">
</div>
<div class="products-list" id="products-list"></div>
</section>
<!-- ===== RECIPE PAGE ===== -->
<section class="page" id="page-recipe">
<div class="page-header">
<button class="back-btn" onclick="showPage('dashboard')" data-i18n="btn.back">← Indietro</button>
<h2 data-i18n="recipes.title">🍳 Ricette</h2>
</div>
<div class="recipe-page-container">
<button class="btn btn-large btn-success full-width" onclick="openRecipeDialog()" data-i18n="recipes.generate">
✨ Genera nuova ricetta
</button>
<div id="recipe-archive" class="recipe-archive"></div>
</div>
</section>
<!-- ===== SHOPPING LIST (BRING!) PAGE ===== -->
<section class="page" id="page-shopping">
<div class="page-header">
<button class="back-btn" onclick="showPage('dashboard')" data-i18n="btn.back">← Indietro</button>
<h2 data-i18n="shopping.title">🛒 Lista della Spesa</h2>
</div>
<div class="shopping-container">
<div class="bring-status" id="bring-status">
<div class="bring-loading" data-i18n="shopping.bring_loading">Connessione a Bring!...</div>
</div>
<!-- Tab navigation -->
<div class="shopping-tabs" id="shopping-tabs" style="display:none">
<button class="shopping-tab active" id="tab-acquisto" onclick="switchShoppingTab('acquisto')">
🛍️ Da comprare <span class="shopping-tab-count" id="tab-count-acquisto">0</span>
</button>
<button class="shopping-tab" id="tab-previsione" onclick="switchShoppingTab('previsione')">
🧠 In previsione <span class="shopping-tab-count" id="tab-count-previsione">0</span>
</button>
</div>
<!-- Tab panel: Da comprare -->
<div id="tab-panel-acquisto" class="tab-panel-shopping active">
<!-- Price total banner -->
<div class="spesa-total-banner" id="spesa-total-banner" style="display:none">
<div class="spesa-total-row">
<span class="spesa-total-label" data-i18n="shopping.total_label">💰 Totale stimato</span>
<span class="spesa-total-value" id="spesa-total-value">€ 0,00</span>
</div>
<div class="spesa-total-detail" id="spesa-total-detail"></div>
</div>
<div class="shopping-current" id="shopping-current" style="display:none">
<div class="shopping-section-header">
<h3>🛍️ Da comprare</h3>
<span class="shopping-count" id="shopping-count">0</span>
</div>
<div class="shopping-items" id="shopping-items"></div>
</div>
<div class="shopping-suggestions" id="shopping-suggestions" style="display:none">
<div class="shopping-section-header">
<h3>💡 Suggerimenti AI</h3>
</div>
<div class="seasonal-tip" id="seasonal-tip" style="display:none"></div>
<div class="suggestion-items" id="suggestion-items"></div>
<div class="suggestion-actions" id="suggestion-actions" style="display:none">
<button class="btn btn-success" onclick="addSelectedSuggestions()">
✅ Aggiungi selezionati a Bring!
</button>
</div>
</div>
<div class="shopping-actions">
<button class="btn btn-large btn-accent" onclick="searchAllPrices()" id="btn-search-prices">
🔍 Cerca tutti i prezzi
</button>
<button class="btn btn-large btn-accent" onclick="generateSuggestions()" id="btn-suggest">
🤖 Suggerisci cosa comprare
</button>
</div>
</div>
<!-- Tab panel: In previsione -->
<div id="tab-panel-previsione" class="tab-panel-shopping">
<!-- Smart shopping predictions -->
<div class="smart-shopping" id="smart-shopping">
<div class="smart-shopping-empty" id="smart-shopping-empty" style="display:none">
<div class="empty-state" style="padding:30px">
<div class="empty-state-icon">🧠</div>
<p>Nessuna previsione disponibile.<br>Aggiungi prodotti alla dispensa per ricevere previsioni intelligenti.</p>
</div>
</div>
<div id="smart-shopping-content">
<div class="shopping-section-header" style="margin-bottom:4px">
<h3>🧠 Previsioni intelligenti</h3>
<span class="shopping-count" id="smart-count">0</span>
</div>
<div class="smart-last-update-row">
<span id="smart-last-update" class="smart-last-update"></span>
</div>
<div class="smart-filter-row" id="smart-filter-row">
<button class="smart-filter active" data-filter="all" onclick="filterSmart('all')">Tutti</button>
<button class="smart-filter" data-filter="critical" onclick="filterSmart('critical')">🔴 Urgenti</button>
<button class="smart-filter" data-filter="high" onclick="filterSmart('high')">🟠 Presto</button>
<button class="smart-filter" data-filter="medium" onclick="filterSmart('medium')">🟡 Pianifica</button>
<button class="smart-filter" data-filter="low" onclick="filterSmart('low')">🟢 Previsione</button>
</div>
<div class="smart-items" id="smart-items"></div>
<div class="smart-actions" id="smart-actions" style="display:none">
<button class="btn btn-success full-width" onclick="addSmartToBring()">
🛒 Aggiungi selezionati a Bring!
</button>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ===== AI IDENTIFICATION PAGE ===== -->
<section class="page" id="page-ai">
<div class="page-header">
<button class="back-btn" onclick="stopScanner(); showPage('scan')">← Indietro</button>
<h2>🤖 Identificazione AI</h2>
</div>
<div class="ai-container">
<div class="ai-capture" id="ai-capture">
<video id="ai-video" autoplay playsinline></video>
<canvas id="ai-canvas" style="display:none"></canvas>
</div>
<div class="ai-preview" id="ai-preview" style="display:none">
<img id="ai-image" src="" alt="Captured">
</div>
<div class="ai-actions">
<button class="btn btn-large btn-accent" onclick="takePhotoForAI()" id="ai-capture-btn">
📸 Scatta Foto
</button>
<button class="btn btn-large btn-secondary" onclick="retakePhotoAI()" id="ai-retake-btn" style="display:none">
🔄 Riscatta
</button>
</div>
<div class="ai-result" id="ai-result" style="display:none"></div>
<p class="scan-hint">Scatta una foto del prodotto e l'AI cercherà di identificarlo</p>
</div>
</section>
<!-- Log Page -->
<section id="page-log" class="page">
<div class="page-header">
<h2 data-i18n="log.title">📒 Log Operazioni</h2>
</div>
<div id="log-list" class="log-list"></div>
<button class="btn btn-secondary full-width mt-2" id="log-load-more" style="display:none" onclick="loadLog(true)" data-i18n="btn.load_more">
Carica altri...
</button>
</section>
<!-- ===== SETTINGS PAGE ===== -->
<section class="page" id="page-settings">
<div class="page-header">
<button class="back-btn" onclick="showPage('dashboard')" data-i18n="btn.back">← Indietro</button>
<h2 data-i18n="settings.title">⚙️ Configurazione</h2>
</div>
<div class="settings-tabs">
<button class="settings-tab active" onclick="switchSettingsTab(this, 'tab-api')" data-tab="tab-api" title="API Keys">🔑</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-bring')" data-tab="tab-bring" title="Bring!">🛒</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-recipe')" data-tab="tab-recipe" title="Ricette">🍳</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-mealplan')" data-tab="tab-mealplan" title="Piano Settimanale">📅</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-appliances')" data-tab="tab-appliances" title="Elettrodomestici">🔌</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-spesa')" data-tab="tab-spesa" title="Spesa Online">🛍️</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-camera')" data-tab="tab-camera" title="Fotocamera">📷</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-security')" data-tab="tab-security" title="Sicurezza">🔒</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-tts')" data-tab="tab-tts" title="Voce (TTS)" data-i18n-title="settings.tab_tts">🔊</button>
<button class="settings-tab" onclick="switchSettingsTab(this, 'tab-language')" data-tab="tab-language" title="Lingua" data-i18n-title="settings.tab_language">🌐</button>
</div>
<div class="settings-panels">
<!-- API Keys Tab -->
<div class="settings-panel active" id="tab-api">
<div class="settings-card">
<h4 data-i18n="settings.gemini.title">🤖 Google Gemini AI</h4>
<p class="settings-hint" data-i18n="settings.gemini.hint">Chiave API per identificazione prodotti, scadenze e ricette.</p>
<div class="form-group">
<label>API Key Gemini</label>
<input type="password" id="setting-gemini-key" class="form-input" placeholder="AIza...">
<button class="btn btn-small btn-secondary mt-2" onclick="togglePasswordVisibility('setting-gemini-key')">👁️ Mostra/Nascondi</button>
</div>
</div>
</div>
<!-- Bring! Tab -->
<div class="settings-panel" id="tab-bring">
<div class="settings-card">
<h4 data-i18n="settings.bring.title">🛒 Bring! Shopping List</h4>
<p class="settings-hint" data-i18n="settings.bring.hint">Credenziali per l'integrazione con la lista della spesa Bring!</p>
<div class="form-group">
<label>📧 Email Bring!</label>
<input type="email" id="setting-bring-email" class="form-input" placeholder="email@esempio.com">
</div>
<div class="form-group">
<label>🔒 Password Bring!</label>
<input type="password" id="setting-bring-password" class="form-input" placeholder="Password">
<button class="btn btn-small btn-secondary mt-2" onclick="togglePasswordVisibility('setting-bring-password')">👁️ Mostra/Nascondi</button>
</div>
</div>
</div>
<!-- Recipe Tab -->
<div class="settings-panel" id="tab-recipe">
<div class="settings-card">
<h4 data-i18n="settings.recipe.title">🍳 Preferenze Ricette</h4>
<p class="settings-hint" data-i18n="settings.recipe.hint">Configura le opzioni predefinite per la generazione delle ricette.</p>
<div class="form-group">
<label>👥 Persone predefinite</label>
<div class="qty-control">
<button type="button" class="qty-btn" onclick="adjustQty('setting-default-persons', -1)"></button>
<input type="number" id="setting-default-persons" value="1" min="1" max="20" class="qty-input">
<button type="button" class="qty-btn" onclick="adjustQty('setting-default-persons', 1)">+</button>
</div>
</div>
<div class="form-group">
<label>🎯 Opzioni ricetta predefinite</label>
<div class="recipe-pref-checks">
<label class="checkbox-label"><input type="checkbox" id="setting-pref-veloce"> ⚡ Pasto Veloce</label>
<label class="checkbox-label"><input type="checkbox" id="setting-pref-pocafame"> 🥗 Poca Fame</label>
<label class="checkbox-label"><input type="checkbox" id="setting-pref-scadenze"> ⏰ Priorità Scadenze</label>
<label class="checkbox-label"><input type="checkbox" id="setting-pref-healthy"> 💚 Extra Salutare</label>
<label class="checkbox-label"><input type="checkbox" id="setting-pref-opened"> 📦 Priorità Cose Aperte</label>
<label class="checkbox-label"><input type="checkbox" id="setting-pref-zerowaste"> ♻️ Zero Sprechi</label>
</div>
</div>
<div class="form-group">
<label>🚫 Intolleranze / Restrizioni</label>
<textarea id="setting-dietary" class="form-input" rows="2" placeholder="Es: senza glutine, senza lattosio, vegetariano..."></textarea>
</div>
</div>
</div>
<!-- Weekly Meal Plan Tab -->
<div class="settings-panel" id="tab-mealplan">
<div class="settings-card">
<h4 data-i18n="settings.mealplan.title">📅 Piano Pasti Settimanale</h4>
<p class="settings-hint" data-i18n="settings.mealplan.hint">Imposta la tipologia di pasto per ogni giorno. Sarà usata come guida nella generazione delle ricette.</p>
<div class="form-group" style="margin-bottom:10px">
<label class="toggle-row">
<span>✅ Attiva piano pasti settimanale</span>
<span class="toggle-switch">
<input type="checkbox" id="setting-meal-plan-enabled" onchange="onMealPlanEnabledChange(this)">
<span class="toggle-slider"></span>
</span>
</label>
</div>
<div id="meal-plan-config-section">
<div id="meal-plan-grid" class="mplan-grid"></div>
<div id="meal-plan-picker" class="mplan-picker" style="display:none"></div>
<div style="margin-top:12px; display:flex; gap:8px; flex-wrap:wrap">
<button class="btn btn-small btn-secondary" onclick="resetMealPlan()">↺ Ripristina default</button>
</div>
<div class="settings-hint" style="margin-top:10px">
🌤️ = Pranzo &nbsp;·&nbsp; 🌙 = Cena &nbsp;·&nbsp; Tocca un badge per cambiarlo.
</div>
</div>
</div>
<div class="settings-card" id="meal-plan-legend-card">
<h4>📋 Tipologie disponibili</h4>
<div class="mplan-legend"></div>
</div>
</div>
<!-- Appliances Tab -->
<div class="settings-panel" id="tab-appliances">
<div class="settings-card">
<h4 data-i18n="settings.appliances.title">🔌 Elettrodomestici Disponibili</h4>
<p class="settings-hint" data-i18n="settings.appliances.hint">Indica gli elettrodomestici che hai a disposizione. Saranno considerati nella generazione delle ricette.</p>
<div class="appliances-list" id="appliances-list"></div>
<div class="form-group mt-2">
<div class="barcode-input-row">
<input type="text" id="new-appliance-input" class="form-input" placeholder="Es: Macchina del pane, Bimby, Friggitrice ad aria..." onkeydown="if(event.key==='Enter'){event.preventDefault();addAppliance()}">
<button class="btn btn-accent" onclick="addAppliance()"></button>
</div>
</div>
<div class="common-appliances mt-2">
<p class="settings-hint">Aggiungi velocemente:</p>
<div class="appliance-quick-tags">
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Forno')">🔥 Forno</button>
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Microonde')">📡 Microonde</button>
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Friggitrice ad aria')">🍟 Friggitrice ad aria</button>
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Macchina del pane')">🍞 Macchina pane</button>
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Bimby/Moulinex Cookeo')">🤖 Bimby/Cookeo</button>
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Planetaria')">🌀 Planetaria</button>
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Vaporiera')">♨️ Vaporiera</button>
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Pentola a pressione')">🫕 Pentola pressione</button>
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Tostapane')">🍞 Tostapane</button>
<button class="btn btn-small btn-secondary" onclick="addApplianceQuick('Frullatore/Mixer')">🍹 Frullatore</button>
</div>
</div>
</div>
</div>
<!-- Spesa Online Tab -->
<div class="settings-panel" id="tab-spesa">
<div class="settings-card">
<h4>🛍️ Spesa Online</h4>
<p class="settings-hint">Configura il provider per la spesa online.</p>
<div class="form-group">
<label>🏪 Provider</label>
<div class="provider-selector">
<button class="provider-btn active" onclick="selectSpesaProvider(this, 'dupliclick')">
<span class="provider-icon">🛒</span>
<span class="provider-name">DupliClick</span>
<span class="provider-desc">Gruppo Poli</span>
</button>
</div>
</div>
<div id="spesa-provider-config">
<div class="form-group">
<label>📧 Email</label>
<input type="email" id="setting-spesa-email" class="form-input" placeholder="email@esempio.com">
</div>
<div class="form-group">
<label>🔒 Password</label>
<input type="password" id="setting-spesa-password" class="form-input" placeholder="Password">
<button class="btn btn-small btn-secondary mt-2" onclick="togglePasswordVisibility('setting-spesa-password')">👁️ Mostra/Nascondi</button>
</div>
<button class="btn btn-large btn-accent full-width mt-2" id="spesa-login-btn" onclick="spesaLogin()">
🔐 Accedi
</button>
<div id="spesa-login-status" style="display:none"></div>
<div id="spesa-login-result" style="display:none"></div>
<div class="form-group mt-2">
<label>🤖 Prompt AI selezione prodotto</label>
<textarea id="setting-spesa-ai-prompt" class="form-input" rows="4" placeholder="Istruzioni per l'AI quando deve scegliere tra più prodotti..."></textarea>
<p class="settings-hint">L'AI usa questo prompt per scegliere il prodotto più appropriato tra i risultati. Lascia vuoto per il comportamento predefinito.</p>
</div>
</div>
</div>
</div>
<!-- Camera Tab -->
<div class="settings-panel" id="tab-camera">
<div class="settings-card">
<h4 data-i18n="settings.camera.title">📷 Fotocamera</h4>
<p class="settings-hint" data-i18n="settings.camera.hint">Scegli quale fotocamera utilizzare per la scansione barcode e l'identificazione AI.</p>
<div class="form-group">
<label>📸 Fotocamera predefinita</label>
<select id="setting-camera-facing" class="form-input">
<option value="environment">📱 Posteriore (default)</option>
<option value="user">🤳 Anteriore</option>
</select>
<p class="settings-hint mt-2">Se hai più fotocamere, puoi selezionarne una specifica dall'elenco sopra dopo aver concesso i permessi.</p>
<button class="btn btn-small btn-secondary mt-2" onclick="loadCameraDevices()">🔄 Rileva fotocamere</button>
</div>
</div>
</div>
<!-- Security Tab -->
<div class="settings-panel" id="tab-security">
<div class="settings-card">
<h4>🔒 Certificato HTTPS</h4>
<p class="settings-hint">Se il browser mostra l'errore "La connessione non è privata" (ERR_CERT_AUTHORITY_INVALID), devi installare il certificato CA nel dispositivo.</p>
<div class="form-group">
<a href="ca.crt" download="Dispensa_CA.crt" class="btn btn-large btn-accent full-width" style="text-align:center;text-decoration:none;display:block">📥 Scarica Certificato CA</a>
</div>
<div class="settings-hint" style="margin-top:12px;line-height:1.6">
<strong>Istruzioni per Chrome (Android):</strong><br>
1. Scarica il certificato qui sopra<br>
2. Vai in <em>Impostazioni → Sicurezza e privacy → Altre impostazioni di sicurezza → Installa da archivio dispositivo</em><br>
3. Seleziona il file <em>Dispensa_CA.crt</em> scaricato<br>
4. Scegli "CA" e conferma<br>
5. Riavvia Chrome<br><br>
<strong>Istruzioni per Chrome (PC):</strong><br>
1. Scarica il certificato qui sopra<br>
2. Vai in <em>chrome://settings/certificates</em> (o Impostazioni → Privacy e sicurezza → Sicurezza → Gestisci certificati)<br>
3. Tab "Autorità" → Importa → seleziona il file<br>
4. Spunta "Considera attendibile per identificare siti web"<br>
5. Riavvia Chrome
</div>
</div>
</div>
<!-- TTS Tab -->
<div class="settings-panel" id="tab-tts">
<div class="settings-card">
<h4 data-i18n="settings.tts.title">🔊 Voce & TTS</h4>
<p class="settings-hint" data-i18n="settings.tts.hint">Configura la sintesi vocale tramite qualsiasi API REST esterna. I passi della ricetta e i timer scaduti verranno inviati all'endpoint configurato.</p>
<div class="form-group" style="margin-bottom:10px">
<label class="toggle-row">
<span>✅ Attiva TTS</span>
<span class="toggle-switch">
<input type="checkbox" id="setting-tts-enabled">
<span class="toggle-slider"></span>
</span>
</label>
</div>
<div class="form-group">
<label>🌐 URL Endpoint</label>
<input type="url" id="setting-tts-url" class="form-input" placeholder="https://...">
</div>
<div class="form-group">
<label>📡 Metodo HTTP</label>
<select id="setting-tts-method" class="form-input">
<option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="PATCH">PATCH</option>
<option value="GET">GET</option>
</select>
</div>
<div class="form-group">
<label>🔐 Autenticazione</label>
<select id="setting-tts-auth-type" class="form-input" onchange="onTtsAuthTypeChange(this.value)">
<option value="bearer">Bearer Token</option>
<option value="header">Header personalizzato</option>
<option value="none">Nessuna</option>
</select>
</div>
<div class="form-group" id="tts-token-group">
<label>🔑 Bearer Token</label>
<input type="password" id="setting-tts-token" class="form-input" placeholder="eyJhbGci...">
<button class="btn btn-small btn-secondary mt-2" onclick="togglePasswordVisibility('setting-tts-token')">👁️ Mostra/Nascondi</button>
</div>
<div id="tts-custom-header-group" style="display:none">
<div class="form-group">
<label>📋 Nome header</label>
<input type="text" id="setting-tts-auth-header-name" class="form-input" placeholder="X-API-Key">
</div>
<div class="form-group">
<label>📋 Valore header</label>
<input type="text" id="setting-tts-auth-header-value" class="form-input" placeholder="...">
</div>
</div>
<div class="form-group">
<label>📄 Content-Type</label>
<select id="setting-tts-content-type" class="form-input">
<option value="application/json">application/json</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
<option value="text/plain">text/plain</option>
</select>
</div>
<div class="form-group">
<label>🗝️ Campo testo nel payload</label>
<input type="text" id="setting-tts-payload-key" class="form-input" placeholder="message">
<p class="settings-hint">Nome del campo JSON che conterrà il testo da leggere (es: <code>message</code>, <code>text</code>).</p>
</div>
<div class="form-group">
<label> Campi extra (JSON)</label>
<textarea id="setting-tts-extra-fields" class="form-input" rows="3" placeholder='{"entity_id": "media_player.living_room"}'></textarea>
<p class="settings-hint">Campi aggiuntivi da includere nel payload, in formato JSON. Lascia vuoto se non necessario.</p>
</div>
<button class="btn btn-large btn-accent full-width mt-2" onclick="testTTS()">🔊 Invia Test Vocale</button>
<div id="tts-test-status" style="display:none;margin-top:8px"></div>
</div>
</div>
<!-- Language Tab -->
<div class="settings-panel" id="tab-language">
<div class="settings-card">
<h4 data-i18n="settings.language.title">🌐 Lingua / Language</h4>
<p class="settings-hint" data-i18n="settings.language.hint">Seleziona la lingua dell'interfaccia. Select the interface language.</p>
<div class="form-group">
<label data-i18n="settings.language.label">🌐 Lingua</label>
<select id="setting-language" class="form-input" onchange="changeLanguage(this.value)">
</select>
<p class="settings-hint mt-2" data-i18n="settings.language.restart_notice">La pagina verrà ricaricata per applicare la nuova lingua.</p>
</div>
</div>
</div>
</div>
<button class="btn btn-large btn-success full-width mt-2" onclick="saveSettings()" data-i18n="btn.save_config">💾 Salva Configurazione</button>
<div id="settings-status" class="settings-status" style="display:none"></div>
</section>
<!-- ===== GEMINI CHAT ===== -->
<section class="page" id="page-chat">
<div class="chat-container">
<div class="chat-header-bar">
<div class="chat-header-info">
<svg class="gemini-icon-sm" viewBox="0 0 24 24" width="22" height="22" fill="#6366f1"><path d="M12 0C12 6.627 6.627 12 0 12c6.627 0 12 5.373 12 12 0-6.627 5.373-12 12-12-6.627 0-12-5.373-12-12z"/></svg>
<span class="chat-title" data-i18n="chat.title">Gemini Chef</span>
</div>
<button class="btn-chat-clear" onclick="clearChat()" title="Nuova conversazione" data-i18n-title="chat.clear">🗑️</button>
</div>
<div class="chat-messages" id="chat-messages">
<div class="chat-welcome">
<svg class="gemini-icon-lg" viewBox="0 0 24 24" width="48" height="48" fill="#6366f1"><path d="M12 0C12 6.627 6.627 12 0 12c6.627 0 12 5.373 12 12 0-6.627 5.373-12 12-12-6.627 0-12-5.373-12-12z"/></svg>
<h3 data-i18n="chat.welcome">Ciao! Sono il tuo assistente cucina</h3>
<p data-i18n="chat.welcome_desc">Chiedimi di prepararti un succo, uno spuntino, un piatto veloce... Conosco la tua dispensa, i tuoi elettrodomestici e le tue preferenze!</p>
<div class="chat-suggestions">
<button class="chat-suggestion" onclick="sendChatSuggestion('Cosa posso preparare per uno spuntino veloce?')" data-i18n="chat.suggestion_snack">🍿 Spuntino veloce</button>
<button class="chat-suggestion" onclick="sendChatSuggestion('Fammi un succo o frullato con quello che ho')" data-i18n="chat.suggestion_juice">🥤 Succo/Frullato</button>
<button class="chat-suggestion" onclick="sendChatSuggestion('Ho fame ma voglio qualcosa di leggero')" data-i18n="chat.suggestion_light">🥗 Qualcosa di leggero</button>
<button class="chat-suggestion" onclick="sendChatSuggestion('Cosa sta per scadere e come posso usarlo?')" data-i18n="chat.suggestion_expiry">⏰ Usa le scadenze</button>
</div>
</div>
</div>
<div class="chat-input-bar">
<input type="text" id="chat-input" class="chat-input" placeholder="Chiedi qualcosa..." onkeydown="if(event.key==='Enter')sendChatMessage()" data-i18n-placeholder="chat.placeholder">
<button class="btn-chat-send" id="btn-chat-send" onclick="sendChatMessage()">
<svg viewBox="0 0 24 24" width="22" height="22" fill="white"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
</button>
</div>
</div>
</section>
</main>
<!-- Bottom Navigation -->
<nav class="bottom-nav">
<button class="nav-btn" onclick="showPage('dashboard')" data-page="dashboard">
<span class="nav-icon">🏠</span>
<span class="nav-label" data-i18n="nav.home">Home</span>
</button>
<button class="nav-btn" onclick="showPage('inventory', '')" data-page="inventory">
<span class="nav-icon">📋</span>
<span class="nav-label" data-i18n="nav.inventory">Dispensa</span>
</button>
<button class="nav-btn" onclick="showPage('recipe')" data-page="recipe">
<span class="nav-icon">🍳</span>
<span class="nav-label" data-i18n="nav.recipes">Ricette</span>
</button>
<button class="nav-btn" onclick="showPage('shopping')" data-page="shopping">
<span class="nav-icon">🛒</span>
<span class="nav-label" data-i18n="nav.shopping">Spesa</span>
</button>
<button class="nav-btn" onclick="showPage('log')" data-page="log">
<span class="nav-icon">📒</span>
<span class="nav-label" data-i18n="nav.log">Log</span>
</button>
<button class="nav-btn" onclick="showPage('settings')" data-page="settings">
<span class="nav-icon">⚙️</span>
<span class="nav-label">Config</span>
</button>
</nav>
<!-- Recipe Dialog -->
<div class="modal-overlay" id="recipe-overlay" style="display:none" onclick="closeRecipeDialog()">
<div class="modal-content recipe-dialog" onclick="event.stopPropagation()">
<div id="recipe-mealplan-banner" class="recipe-mealplan-banner" style="display:none"></div>
<div id="recipe-ask" class="recipe-ask">
<h3 id="recipe-meal-title">🍳 Ricetta</h3>
<p class="recipe-desc">Genero una ricetta sana con gli ingredienti in dispensa, dando priorità a quelli in scadenza.</p>
<div class="form-group" style="text-align:left">
<label>🕐 Per quale pasto?</label>
<div class="recipe-meal-grid" id="recipe-meal-grid" onchange="updateRecipeMealTitle()"></div>
</div>
<div id="recipe-mealplan-hint" class="recipe-mealplan-hint" style="display:none"></div>
<div class="form-group">
<label>👥 Quante persone?</label>
<div class="qty-control">
<button type="button" class="qty-btn" onclick="adjustRecipePersons(-1)"></button>
<input type="number" id="recipe-persons" value="1" min="1" max="20" class="qty-input">
<button type="button" class="qty-btn" onclick="adjustRecipePersons(1)">+</button>
</div>
</div>
<div class="form-group" style="text-align:left">
<label>🎯 Tipo di pasto</label>
<div class="recipe-options-grid">
<label class="recipe-option-chip recipe-opt-mealplan-chip" id="recipe-opt-mealplan-wrap" style="display:none"><input type="checkbox" id="recipe-opt-mealplan" checked onchange="onMealPlanChipChange(this)"> <span id="recipe-opt-mealplan-label"></span></label>
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-veloce"> ⚡ Pasto Veloce</label>
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-pocafame"> 🥗 Poca Fame</label>
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-scadenze"> ⏰ Priorità Scadenze</label>
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-healthy"> 💚 Extra Salutare</label>
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-opened"> 📦 Priorità Cose Aperte</label>
<label class="recipe-option-chip"><input type="checkbox" id="recipe-opt-zerowaste"> ♻️ Zero Sprechi</label>
</div>
</div>
<button class="btn btn-large btn-success full-width" onclick="generateRecipe()">
✨ Genera Ricetta
</button>
<button class="btn btn-large btn-secondary full-width mt-2" onclick="closeRecipeDialog()">
Annulla
</button>
</div>
<div id="recipe-loading" style="display:none" class="recipe-loading">
<div class="loading-spinner"></div>
<p>Sto preparando la ricetta...</p>
</div>
<div id="recipe-result" style="display:none" class="recipe-result">
<div id="recipe-content"></div>
<button class="btn btn-large btn-cooking full-width mt-2" onclick="startCookingMode()">
👨‍🍳 Modalità Cucina
</button>
<button class="btn btn-large btn-secondary full-width mt-2" onclick="regenerateRecipe()">
🔄 Generane un'altra
</button>
<button class="btn btn-large btn-primary full-width mt-2" onclick="closeRecipeDialog()">
✅ Chiudi
</button>
</div>
</div>
</div>
<!-- Setup Wizard (first-run) -->
<div class="modal-overlay" id="setup-wizard" style="display:none">
<div class="modal-content setup-wizard-content" onclick="event.stopPropagation()">
<div class="setup-header">
<h2>🏠 Dispensa Manager</h2>
<div class="setup-progress" id="setup-progress"></div>
</div>
<div class="setup-body" id="setup-body"></div>
<div class="setup-footer">
<button class="btn btn-secondary" id="setup-prev" onclick="setupWizardNav(-1)" style="display:none">← Indietro</button>
<button class="btn btn-accent" id="setup-next" onclick="setupWizardNav(1)">Avanti →</button>
</div>
</div>
</div>
<!-- Toast notification -->
<div class="toast" id="toast"></div>
<!-- Loading Overlay -->
<div class="loading-overlay" id="loading" style="display:none">
<div class="loading-spinner"></div>
<p data-i18n="app.loading">Caricamento...</p>
</div>
<!-- Modal for product details from inventory -->
<div class="modal-overlay" id="modal-overlay" style="display:none" onclick="closeModal()">
<div class="modal-content" id="modal-content" onclick="event.stopPropagation()"></div>
</div>
<!-- Screensaver Overlay -->
<div id="screensaver" class="screensaver-overlay" style="display:none">
<div class="screensaver-content">
<div class="screensaver-clock" id="screensaver-clock"></div>
<div id="screensaver-mealplan" class="screensaver-mealplan" style="display:none"></div>
<div class="screensaver-fact" id="screensaver-fact"></div>
</div>
<div class="screensaver-shortcuts">
<button class="screensaver-shortcut-btn" id="screensaver-recipe-btn" title="Ricette">
🍳
</button>
<button class="screensaver-shortcut-btn" id="screensaver-scan-btn" title="Scansiona prodotto (tieni premuto per modalità spesa)">
📷
</button>
</div>
</div>
<!-- ===== COOKING MODE OVERLAY ===== -->
<div id="cooking-overlay" class="cooking-overlay" style="display:none" aria-live="polite">
<div id="cooking-flash-overlay" class="cooking-flash-overlay"></div>
<div class="cooking-header">
<button class="cooking-close-btn" onclick="closeCookingMode()" title="Chiudi"></button>
<span class="cooking-title" id="cooking-title"></span>
<button class="cooking-tts-btn" id="cooking-tts-btn" onclick="toggleCookingTTS()" title="Leggi ad alta voce">🔊</button>
</div>
<div id="cooking-timers-bar" class="cooking-timers-bar" style="display:none"></div>
<div class="cooking-body">
<div class="cooking-step-header">
<div class="cooking-step-num" id="cooking-step-num">1 / 1</div>
<button class="cooking-restart-btn" onclick="restartCookingMode()" title="Ricomincia dall'inizio">↺ Ricomincia</button>
</div>
<div class="cooking-progress-dots" id="cooking-progress-dots"></div>
<div class="cooking-step-text" id="cooking-step-text"></div>
<button class="cooking-replay-btn" id="cooking-replay" onclick="replayCookingTTS()" title="Rileggi questo passo">🔊 Rileggi</button>
<div class="cooking-timer-suggest" id="cooking-timer-suggest" style="display:none">
<button class="cooking-timer-add-btn" onclick="addSuggestedCookingTimer()">
<span id="cooking-timer-suggest-text">⏱️ 00:00 · Timer</span>
</button>
</div>
<div class="cooking-step-ings" id="cooking-step-ings" style="display:none"></div>
</div>
<div class="cooking-nav">
<button class="cooking-nav-btn cooking-prev-btn" id="cooking-prev" onclick="navigateCookingStep(-1)">◀ Precedente</button>
<button class="cooking-nav-btn cooking-next-btn" id="cooking-next" onclick="navigateCookingStep(1)">Successivo ▶</button>
</div>
</div>
<script src="assets/js/app.js?v=20260330c"></script>
</body>
</html>