feat: zero-waste tips during cooking mode (#76)
This commit is contained in:
@@ -6875,6 +6875,64 @@ body.cooking-mode-active .app-header {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* ===== ZERO-WASTE TIP CARD (cooking mode) ===== */
|
||||
.cooking-zerowaste-tip {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
background: rgba(16, 185, 129, 0.10);
|
||||
border: 1.5px solid rgba(16, 185, 129, 0.35);
|
||||
border-radius: 12px;
|
||||
padding: 12px 14px;
|
||||
margin: 10px 16px 0;
|
||||
position: relative;
|
||||
animation: zwFadeIn 0.3s ease;
|
||||
flex-direction: column;
|
||||
}
|
||||
@keyframes zwFadeIn {
|
||||
from { opacity: 0; transform: translateY(6px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.cooking-zerowaste-label {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: #059669;
|
||||
}
|
||||
.cooking-zerowaste-scrap {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 700;
|
||||
color: #065f46;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.cooking-zerowaste-text {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text);
|
||||
margin: 4px 0 0;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.cooking-zerowaste-close {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 10px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
color: #6b7280;
|
||||
padding: 2px 4px;
|
||||
line-height: 1;
|
||||
}
|
||||
.cooking-zerowaste-close:hover { color: #374151; }
|
||||
[data-theme="dark"] .cooking-zerowaste-tip {
|
||||
background: rgba(16, 185, 129, 0.08);
|
||||
border-color: rgba(16, 185, 129, 0.25);
|
||||
}
|
||||
[data-theme="dark"] .cooking-zerowaste-scrap { color: #6ee7b7; }
|
||||
[data-theme="dark"] .cooking-zerowaste-label { color: #34d399; }
|
||||
[data-theme="dark"] .cooking-zerowaste-close { color: #9ca3af; }
|
||||
|
||||
/* ===== DARK MODE ===== */
|
||||
[data-theme="dark"] {
|
||||
--bg: #0f172a;
|
||||
|
||||
@@ -2538,6 +2538,9 @@ async function loadSettingsUI() {
|
||||
// Dark mode setting
|
||||
const dmEl = document.getElementById('setting-dark-mode');
|
||||
if (dmEl) dmEl.value = s.dark_mode || 'auto';
|
||||
// Zero-waste tips setting
|
||||
const zwEl = document.getElementById('setting-zerowaste-tips');
|
||||
if (zwEl) zwEl.checked = s.zerowaste_tips_enabled === true;
|
||||
|
||||
// Populate About section version
|
||||
_loadAboutSection();
|
||||
@@ -2864,6 +2867,9 @@ async function saveSettings() {
|
||||
// Dark mode
|
||||
const dmSaveEl = document.getElementById('setting-dark-mode');
|
||||
if (dmSaveEl) { s.dark_mode = dmSaveEl.value; _applyTheme(); }
|
||||
// Zero-waste tips
|
||||
const zwSaveEl = document.getElementById('setting-zerowaste-tips');
|
||||
if (zwSaveEl) s.zerowaste_tips_enabled = zwSaveEl.checked;
|
||||
// Meal plan enabled toggle
|
||||
const mpEnabledEl = document.getElementById('setting-meal-plan-enabled');
|
||||
if (mpEnabledEl) s.meal_plan_enabled = mpEnabledEl.checked;
|
||||
@@ -12429,6 +12435,7 @@ function startCookingMode() {
|
||||
_cookingRecipe = JSON.parse(JSON.stringify(recipe));
|
||||
_cookingStep = 0;
|
||||
_cookingVisited = new Set();
|
||||
_dismissedZeroWasteTips = new Set();
|
||||
clearAllCookingTimers();
|
||||
}
|
||||
_cookingTTS = true;
|
||||
@@ -12478,6 +12485,7 @@ function restartCookingMode() {
|
||||
_cookingStep = 0;
|
||||
_cookingWheelLastDelta = 0;
|
||||
_cookingVisited = new Set();
|
||||
_dismissedZeroWasteTips = new Set();
|
||||
clearAllCookingTimers();
|
||||
renderCookingStep();
|
||||
}
|
||||
@@ -12699,10 +12707,42 @@ function renderCookingStep() {
|
||||
// Timer: detect duration in step text and show suggestion
|
||||
setupCookingTimerSuggestion(cleanStep);
|
||||
|
||||
// Zero-waste tip for this step
|
||||
_renderZeroWasteTip(_cookingStep);
|
||||
|
||||
// TTS: auto-speak is handled by navigateCookingStep() and startCookingMode() callers.
|
||||
// Use replayCookingTTS() to re-read the current step manually ("Rileggi" button).
|
||||
}
|
||||
|
||||
// ===== ZERO-WASTE TIPS =====
|
||||
let _dismissedZeroWasteTips = new Set(); // dismissed tip indices for this cooking session
|
||||
|
||||
function _renderZeroWasteTip(stepIdx) {
|
||||
const tipEl = document.getElementById('cooking-zerowaste-tip');
|
||||
if (!tipEl) return;
|
||||
// Check setting
|
||||
const s = getSettings();
|
||||
if (!s.zerowaste_tips_enabled) { tipEl.style.display = 'none'; return; }
|
||||
// Already dismissed for this step in this session
|
||||
if (_dismissedZeroWasteTips.has(stepIdx)) { tipEl.style.display = 'none'; return; }
|
||||
// Find tip for current step
|
||||
const tips = (_cookingRecipe && _cookingRecipe.zero_waste_tips) || [];
|
||||
const tip = tips.find(t => t.step === stepIdx);
|
||||
if (!tip) { tipEl.style.display = 'none'; return; }
|
||||
// Populate and show
|
||||
const scrapEl = document.getElementById('cooking-zerowaste-scrap');
|
||||
const textEl = document.getElementById('cooking-zerowaste-text');
|
||||
if (scrapEl) scrapEl.textContent = tip.scrap || '';
|
||||
if (textEl) textEl.textContent = tip.tip || '';
|
||||
tipEl.style.display = 'flex';
|
||||
}
|
||||
|
||||
function _dismissZeroWasteTip() {
|
||||
_dismissedZeroWasteTips.add(_cookingStep);
|
||||
const tipEl = document.getElementById('cooking-zerowaste-tip');
|
||||
if (tipEl) tipEl.style.display = 'none';
|
||||
}
|
||||
|
||||
function _buildTtsRequest(text, s) {
|
||||
const url = s.tts_url || '';
|
||||
const method = s.tts_method || 'POST';
|
||||
|
||||
Reference in New Issue
Block a user