diff --git a/assets/css/style.css b/assets/css/style.css index b2b2dba..352b7d8 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -2120,6 +2120,11 @@ body { z-index: 250; } +/* Raise modal above cooking overlay when in cooking mode */ +.cooking-mode-active #modal-overlay { + z-index: 600; +} + .modal-content { background: var(--bg-card); border-radius: var(--radius) var(--radius) 0 0; @@ -2929,6 +2934,220 @@ body { line-height: 1.3; } +/* ===== SHOPPING SECTION (REPARTO) HEADERS ===== */ +.shopping-section-divider { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 2px 4px; + font-size: 0.8rem; + font-weight: 700; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.06em; + border-bottom: 1px solid var(--border); + margin-top: 4px; +} + +.shopping-section-divider:first-child { + margin-top: 0; + padding-top: 2px; + border-bottom: none; +} + +.shopping-section-divider span.sec-icon { + font-size: 1rem; +} + +/* ===== COOKING MODE ===== */ +.cooking-overlay { + position: fixed; + inset: 0; + background: #0a0a0a; + z-index: 500; + display: flex; + flex-direction: column; + color: #fff; + overflow: hidden; + touch-action: pan-y; +} + +.cooking-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 14px 16px; + background: rgba(255,255,255,0.05); + border-bottom: 1px solid rgba(255,255,255,0.10); + flex-shrink: 0; + min-height: 54px; +} + +.cooking-title { + flex: 1; + text-align: center; + font-size: 0.95rem; + font-weight: 600; + color: rgba(255,255,255,0.8); + margin: 0 8px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.cooking-close-btn, +.cooking-tts-btn { + background: rgba(255,255,255,0.08); + border: 1px solid rgba(255,255,255,0.15); + color: #fff; + border-radius: 50%; + width: 38px; + height: 38px; + font-size: 1rem; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: background 0.2s; + flex-shrink: 0; +} + +.cooking-close-btn:active, +.cooking-tts-btn:active { + background: rgba(255,255,255,0.2); +} + +.cooking-body { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 24px 20px; + gap: 20px; + overflow-y: auto; + -webkit-overflow-scrolling: touch; +} + +.cooking-step-num { + font-size: 0.85rem; + font-weight: 700; + color: rgba(255,255,255,0.4); + letter-spacing: 0.1em; + text-align: center; + flex-shrink: 0; +} + +.cooking-step-text { + font-size: clamp(1.4rem, 5vw, 2.2rem); + line-height: 1.5; + font-weight: 500; + color: #fff; + text-align: center; + max-width: 560px; + width: 100%; +} + +.cooking-step-ings { + width: 100%; + max-width: 480px; + display: flex; + flex-direction: column; + gap: 8px; +} + +.cooking-ing-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + background: rgba(255,255,255,0.07); + border: 1px solid rgba(255,255,255,0.12); + border-radius: 10px; + padding: 10px 14px; +} + +.cooking-ing-name { + font-size: 0.95rem; + color: rgba(255,255,255,0.9); + flex: 1; + min-width: 0; +} + +.cooking-use-btn { + flex-shrink: 0; + background: #16a34a; + border: none; + color: #fff; + border-radius: 8px; + padding: 6px 14px; + font-size: 0.82rem; + font-weight: 700; + cursor: pointer; + transition: background 0.2s; + white-space: nowrap; +} + +.cooking-use-btn:active { + background: #15803d; +} + +.cooking-use-btn.btn-used { + background: #374151; + cursor: default; +} + +.cooking-nav { + display: flex; + gap: 12px; + padding: 14px 16px; + background: rgba(255,255,255,0.04); + border-top: 1px solid rgba(255,255,255,0.08); + flex-shrink: 0; +} + +.cooking-nav-btn { + flex: 1; + padding: 14px 10px; + border-radius: 10px; + font-size: 1rem; + font-weight: 700; + border: 1.5px solid rgba(255,255,255,0.2); + background: rgba(255,255,255,0.08); + color: #fff; + cursor: pointer; + transition: background 0.2s; + text-align: center; +} + +.cooking-nav-btn:disabled { + opacity: 0.3; + cursor: default; +} + +.cooking-next-btn { + background: rgba(22, 163, 74, 0.35); + border-color: rgba(22, 163, 74, 0.6); +} + +.cooking-next-btn.is-finish { + background: rgba(22, 163, 74, 0.6); +} + +.cooking-nav-btn:not(:disabled):active { + background: rgba(255,255,255,0.2); +} + +/* Cooking button in recipe dialog */ +.btn-cooking { + background: linear-gradient(135deg, #1e3a5f, #2d5016); + color: #fff; +} + +.btn-cooking:hover, .btn-cooking:active { + opacity: 0.9; +} + /* ===== LOG PAGE ===== */ .log-list { display: flex; diff --git a/assets/js/app.js b/assets/js/app.js index c14c623..6a83419 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -75,6 +75,34 @@ const CATEGORY_LOCATION = { 'cereali': 'dispensa', 'igiene': 'altro', 'pulizia': 'altro', 'altro': 'dispensa' }; +// Shopping section (reparto) map β groups categories into grocery departments +const SHOPPING_SECTIONS = [ + { key: 'frutta_verdura', icon: 'π₯¬', label: 'Frutta & Verdura', cats: new Set(['frutta','verdura']) }, + { key: 'carne_pesce', icon: 'π₯©', label: 'Carne & Pesce', cats: new Set(['carne','pesce']) }, + { key: 'latticini', icon: 'π₯', label: 'Latticini & Fresco', cats: new Set(['latticini']) }, + { key: 'pane_dolci', icon: 'π', label: 'Pane & Dolci', cats: new Set(['pane','snack','cereali']) }, + { key: 'pasta', icon: 'π', label: 'Pasta & Cereali', cats: new Set(['pasta']) }, + { key: 'conserve', icon: 'π₯«', label: 'Conserve & Salse', cats: new Set(['conserve','condimenti']) }, + { key: 'surgelati', icon: 'βοΈ', label: 'Surgelati', cats: new Set(['surgelati']) }, + { key: 'bevande', icon: 'π₯€', label: 'Bevande', cats: new Set(['bevande']) }, + { key: 'pulizia_igiene', icon: 'π§΄', label: 'Pulizia & Igiene', cats: new Set(['igiene','pulizia']) }, + { key: 'altro', icon: 'π¦', label: 'Altro', cats: new Set(['altro']) }, +]; + +function getItemSection(name) { + const cat = guessCategoryFromName(name) || 'altro'; + for (const s of SHOPPING_SECTIONS) { if (s.cats.has(cat)) return s; } + return SHOPPING_SECTIONS[SHOPPING_SECTIONS.length - 1]; +} + +const URGENCY_WEIGHT = { critical: 4, high: 3, medium: 2, low: 1 }; +const URGENCY_BG = { + critical: 'rgba(194,65,12,0.14)', + high: 'rgba(234,88,12,0.09)', + medium: 'rgba(245,158,11,0.07)', + low: 'rgba(34,197,94,0.05)', +}; + // Map Open Food Facts categories to local categories function mapToLocalCategory(ofCategory, productName) { if (!ofCategory) { @@ -4404,11 +4432,40 @@ function renderSmartShopping() { low: { color: '#22c55e', bg: 'rgba(34,197,94,0.08)', icon: 'π’', label: 'Previsione' }, }; - container.innerHTML = items.map((item, idx) => { - const u = urgencyConfig[item.urgency] || urgencyConfig.low; - const catIcon = CATEGORY_ICONS[mapToLocalCategory(item.category, item.name)] || 'π¦'; - const checked = !item.on_bring ? 'checked' : ''; - const globalIdx = smartShoppingItems.indexOf(item); + // Group by section + const smartSectionMap = new Map(); + items.forEach(item => { + const sec = getItemSection(item.name); + if (!smartSectionMap.has(sec.key)) smartSectionMap.set(sec.key, { sec, items: [] }); + smartSectionMap.get(sec.key).items.push(item); + }); + + let smartHtml = ''; + for (const secDef of SHOPPING_SECTIONS) { + const group = smartSectionMap.get(secDef.key); + if (!group) continue; + smartHtml += `