c4938457ac
- Normal mode (non-conf) now sets min=0.01 for kg/l, min=1 for g/ml - +/- buttons use unit-aware steps: 0.01 for small kg/l values, 0.1 for values <1, 0.5 for values >=1 (instead of fixed 0.5) - Same fix applied to recipe use form - Allows inputting e.g. 0.07kg (70g) when product is tracked in kg
1003 lines
57 KiB
HTML
1003 lines
57 KiB
HTML
<!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">
|
||
<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')">🏠 Dispensa</h1>
|
||
<div class="header-actions">
|
||
<button class="header-scan-btn header-gemini-btn" onclick="showPage('chat')" title="Chat con Gemini">
|
||
<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)">
|
||
📷
|
||
</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">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">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">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">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">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>🚫 Scaduti</h3>
|
||
<div id="expired-list"></div>
|
||
</div>
|
||
<!-- Alert for soonest expiring items -->
|
||
<div class="alert-section" id="alert-expiring" style="display:none">
|
||
<h3>⏰ 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>📊 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>📦 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>🔍 Da revisionare</h3>
|
||
<p class="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')">← Indietro</button>
|
||
<h2 id="inventory-title">Dispensa</h2>
|
||
</div>
|
||
<div class="location-tabs" id="location-tabs">
|
||
<button class="tab active" onclick="filterLocation('')" data-loc="">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()">
|
||
</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')">← Indietro</button>
|
||
<h2>Scansiona Prodotto</h2>
|
||
</div>
|
||
<div class="spesa-mode-banner" id="spesa-mode-banner" style="display:none">
|
||
<span>🛒 Modalità Spesa attiva</span>
|
||
<button class="btn btn-small" onclick="endSpesaMode()">✅ 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>
|
||
<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()">
|
||
<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="kg">kg</option>
|
||
<option value="ml">ml</option>
|
||
<option value="l">L</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="kg">kg</option>
|
||
<option value="ml">ml</option>
|
||
<option value="l">L</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>
|
||
<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 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="kg">Kg</option>
|
||
<option value="g">Grammi</option>
|
||
<option value="l">Litri</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="kg">kg</option>
|
||
<option value="ml">ml</option>
|
||
<option value="l">L</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>
|
||
<input type="text" id="pf-barcode" class="form-input" placeholder="Codice a barre (se disponibile)">
|
||
</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')">← Indietro</button>
|
||
<h2>🍳 Ricette</h2>
|
||
</div>
|
||
<div class="recipe-page-container">
|
||
<button class="btn btn-large btn-success full-width" onclick="openRecipeDialog()">
|
||
✨ 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')">← Indietro</button>
|
||
<h2>🛒 Lista della Spesa</h2>
|
||
</div>
|
||
<div class="shopping-container">
|
||
<div class="bring-status" id="bring-status">
|
||
<div class="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">💰 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-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>📒 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)">
|
||
Carica altri...
|
||
</button>
|
||
</section>
|
||
|
||
<!-- ===== SETTINGS PAGE ===== -->
|
||
<section class="page" id="page-settings">
|
||
<div class="page-header">
|
||
<button class="back-btn" onclick="showPage('dashboard')">← Indietro</button>
|
||
<h2>⚙️ 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-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>
|
||
</div>
|
||
<div class="settings-panels">
|
||
<!-- API Keys Tab -->
|
||
<div class="settings-panel active" id="tab-api">
|
||
<div class="settings-card">
|
||
<h4>🤖 Google Gemini AI</h4>
|
||
<p class="settings-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>🛒 Bring! Shopping List</h4>
|
||
<p class="settings-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>🍳 Preferenze Ricette</h4>
|
||
<p class="settings-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>
|
||
<!-- Appliances Tab -->
|
||
<div class="settings-panel" id="tab-appliances">
|
||
<div class="settings-card">
|
||
<h4>🔌 Elettrodomestici Disponibili</h4>
|
||
<p class="settings-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>📷 Fotocamera</h4>
|
||
<p class="settings-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>
|
||
</div>
|
||
<button class="btn btn-large btn-success full-width mt-2" onclick="saveSettings()">💾 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">Gemini Chef</span>
|
||
</div>
|
||
<button class="btn-chat-clear" onclick="clearChat()" title="Nuova conversazione">🗑️</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>Ciao! Sono il tuo assistente cucina</h3>
|
||
<p>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?')">🍿 Spuntino veloce</button>
|
||
<button class="chat-suggestion" onclick="sendChatSuggestion('Fammi un succo o frullato con quello che ho')">🥤 Succo/Frullato</button>
|
||
<button class="chat-suggestion" onclick="sendChatSuggestion('Ho fame ma voglio qualcosa di leggero')">🥗 Qualcosa di leggero</button>
|
||
<button class="chat-suggestion" onclick="sendChatSuggestion('Cosa sta per scadere e come posso usarlo?')">⏰ 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()">
|
||
<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">Home</span>
|
||
</button>
|
||
<button class="nav-btn" onclick="showPage('inventory', '')" data-page="inventory">
|
||
<span class="nav-icon">📋</span>
|
||
<span class="nav-label">Dispensa</span>
|
||
</button>
|
||
<button class="nav-btn" onclick="showPage('recipe')" data-page="recipe">
|
||
<span class="nav-icon">🍳</span>
|
||
<span class="nav-label">Ricette</span>
|
||
</button>
|
||
<button class="nav-btn" onclick="showPage('shopping')" data-page="shopping">
|
||
<span class="nav-icon">🛒</span>
|
||
<span class="nav-label">Spesa</span>
|
||
</button>
|
||
<button class="nav-btn" onclick="showPage('log')" data-page="log">
|
||
<span class="nav-icon">📒</span>
|
||
<span class="nav-label">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-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 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"><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>
|
||
|
||
<!-- 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>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 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 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 class="cooking-body">
|
||
<div class="cooking-step-num" id="cooking-step-num">1 / 1</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-wrap" id="cooking-timer-wrap" style="display:none">
|
||
<div class="cooking-timer-display" id="cooking-timer-display">00:00</div>
|
||
<div class="cooking-timer-actions">
|
||
<button class="cooking-timer-btn" id="cooking-timer-start" onclick="toggleCookingTimer()">⏱️ Avvia timer</button>
|
||
<button class="cooking-timer-btn cooking-timer-reset" id="cooking-timer-reset" onclick="resetCookingTimer()" style="display:none">↩ Reset</button>
|
||
</div>
|
||
</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=20260330b"></script>
|
||
</body>
|
||
</html>
|