fix(ux): banner aperto senza 'Usa comunque'/'Ignora'; preloader ruota 3D; config default non bloccante
Banner prodotti aperti: - Rimosse le opzioni 'Usa comunque' e 'Ignora' (non hanno senso se il prodotto è solo aperto — rimangono solo 'L\''ho finito!', 'L\''ho buttato', 'Correggi data') - Per prodotti scaduti non aperti il comportamento rimane invariato Preloader startup check: - Sostituito il mini-label monospace con una ruota 3D (stile cooking wheel) - Testo grande, colorato: VERDE=ok, ARANCIONE=warning, ROSSO=errore - Il check precedente sale in cima (rotateX tilt, dimmed) mentre il nuovo entra dal basso con animazione 3D - setProgress() ora guida la ruota; slowAnim() aggiorna solo la barra Defaults / non-bloccante: - Gemini API key non impostata → ok:true 'non configurata' (verde) - Bring! token non ancora generato → ok:true (verde, auto-generato al 1° accesso) - La configurazione mancante mostra ✅ informativo, non ⚠️ warning
This commit is contained in:
+4
-3
@@ -279,8 +279,8 @@ if (($_GET['action'] ?? '') === 'health_check') {
|
||||
$checks['gemini_key'] = ['ok' => strlen($geminiKey) > 20, 'optional' => true,
|
||||
'hint' => strlen($geminiKey) <= 20 ? 'Chiave Gemini AI sembra troppo corta — verifica il valore in .env' : null];
|
||||
} else {
|
||||
$checks['gemini_key'] = ['ok' => false, 'optional' => true,
|
||||
'hint' => 'GEMINI_API_KEY non configurata — le funzioni AI non saranno disponibili'];
|
||||
$checks['gemini_key'] = ['ok' => true, 'optional' => true,
|
||||
'value' => 'non configurata', 'hint' => 'Configura GEMINI_API_KEY in .env per abilitare le funzioni AI'];
|
||||
}
|
||||
|
||||
// ── 11. Bring! — solo se EMAIL+PASSWORD sono impostate ───────────────────
|
||||
@@ -298,7 +298,8 @@ if (($_GET['action'] ?? '') === 'health_check') {
|
||||
$bringTokenOk = !empty($bringData['access_token'] ?? ($bringData['accessToken'] ?? ''));
|
||||
if (!$bringTokenOk) $bringTokenHint = 'Token Bring! presente ma non valido — verrà rinnovato automaticamente al prossimo accesso';
|
||||
} else {
|
||||
$bringTokenHint = 'Token Bring! non ancora generato — verrà creato al primo accesso alla lista spesa';
|
||||
$bringTokenOk = true; // non ancora generato, si crea al primo accesso — non è un errore
|
||||
$bringTokenHint = 'Verrà generato automaticamente al primo accesso alla lista spesa';
|
||||
}
|
||||
$checks['bring_token'] = ['ok' => $bringTokenOk, 'optional' => true, 'hint' => $bringTokenHint];
|
||||
}
|
||||
|
||||
+51
-9
@@ -122,8 +122,8 @@ body {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: 250px;
|
||||
max-width: 88vw;
|
||||
width: 310px;
|
||||
max-width: 92vw;
|
||||
animation: zwFadeIn 0.2s ease;
|
||||
}
|
||||
.preloader-bar-track {
|
||||
@@ -142,17 +142,59 @@ body {
|
||||
}
|
||||
.preloader-bar.bar-error { background: linear-gradient(90deg, #f87171, #ef4444); }
|
||||
.preloader-bar.bar-warn { background: linear-gradient(90deg, #fbbf24, #f59e0b); }
|
||||
.preloader-check-label {
|
||||
color: rgba(255,255,255,0.60);
|
||||
font-size: 0.74rem;
|
||||
font-family: monospace;
|
||||
.preloader-check-label { display: none; } /* replaced by check-wheel */
|
||||
|
||||
/* ── Startup check wheel (3-D scroll) ──────────────────────────────── */
|
||||
.check-wheel {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 108px;
|
||||
perspective: 640px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.check-wheel-current {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: clamp(0.88rem, 2.6vw, 1.08rem);
|
||||
font-weight: 700;
|
||||
padding: 10px 14px;
|
||||
border-radius: 14px;
|
||||
border: 1px solid rgba(52,211,153,0.35);
|
||||
background: rgba(52,211,153,0.08);
|
||||
color: #34d399;
|
||||
transform-style: preserve-3d;
|
||||
animation: checkWheelIn 0.30s ease;
|
||||
letter-spacing: 0.01em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.check-wheel-current.state-ok { color: #34d399; background: rgba(52,211,153,0.08); border-color: rgba(52,211,153,0.35); }
|
||||
.check-wheel-current.state-warn { color: #fbbf24; background: rgba(251,191,36,0.08); border-color: rgba(251,191,36,0.35); }
|
||||
.check-wheel-current.state-error { color: #f87171; background: rgba(248,113,113,0.08); border-color: rgba(248,113,113,0.35); }
|
||||
.check-wheel-prev {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 6%; right: 6%;
|
||||
text-align: center;
|
||||
font-size: clamp(0.67rem, 1.8vw, 0.82rem);
|
||||
font-weight: 600;
|
||||
color: rgba(203,213,225,0.45);
|
||||
opacity: 0.52;
|
||||
transform: rotateX(54deg) scale(0.85);
|
||||
transform-origin: center bottom;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
min-height: 1.1em;
|
||||
letter-spacing: 0.01em;
|
||||
pointer-events: none;
|
||||
font-family: monospace;
|
||||
}
|
||||
@keyframes checkWheelIn {
|
||||
from { transform: translateY(24px) rotateX(-18deg); opacity: 0.35; }
|
||||
to { transform: translateY(0) rotateX(0deg); opacity: 1; }
|
||||
}
|
||||
.preloader-warnings {
|
||||
max-width: 310px;
|
||||
|
||||
+20
-6
@@ -4352,15 +4352,17 @@ function renderBannerItem() {
|
||||
detailEl.innerHTML = `${baseDetail} <span class="banner-safety-tip banner-safety-${safety.level}">${safety.icon} ${safety.tip}</span>`;
|
||||
let btns = '';
|
||||
btns += `<button class="btn-banner btn-banner-finish" onclick="bannerFinishAll()">${t('dashboard.banner_expired_action_finished')}</button>`;
|
||||
if (safety.level !== 'danger') {
|
||||
if (!isOpenedExpiry && safety.level !== 'danger') {
|
||||
btns += `<button class="btn-banner btn-banner-use" onclick="bannerQuickUse()">${t('dashboard.banner_expired_action_use')}</button>`;
|
||||
}
|
||||
btns += `<button class="btn-banner btn-banner-throw" onclick="bannerThrowAway()">${t('dashboard.banner_expired_action_throw')}</button>`;
|
||||
btns += `<button class="btn-banner btn-banner-edit" onclick="editBannerExpiry()">${t('dashboard.banner_expired_action_edit')}</button>`;
|
||||
if (safety.level === 'danger') {
|
||||
if (!isOpenedExpiry && safety.level === 'danger') {
|
||||
btns += `<button class="btn-banner btn-banner-use btn-banner-use-danger" onclick="bannerQuickUse()">${t('dashboard.banner_expired_action_use')}</button>`;
|
||||
}
|
||||
btns += `<button class="btn-banner btn-banner-ok" onclick="dismissBannerExpired()">${t('dashboard.banner_review_dismiss')}</button>`;
|
||||
if (!isOpenedExpiry) {
|
||||
btns += `<button class="btn-banner btn-banner-ok" onclick="dismissBannerExpired()">${t('dashboard.banner_review_dismiss')}</button>`;
|
||||
}
|
||||
actionsEl.innerHTML = btns;
|
||||
|
||||
} else if (entry.type === 'review') {
|
||||
@@ -14897,7 +14899,7 @@ async function _runStartupCheck() {
|
||||
if (spinnerEl) spinnerEl.style.display = 'none';
|
||||
wrapEl.style.display = '';
|
||||
|
||||
// Helper: set progress bar + label
|
||||
// Helper: set progress bar + 3D check wheel
|
||||
let _curPct = 0;
|
||||
const setProgress = (pct, label, state) => {
|
||||
_curPct = pct;
|
||||
@@ -14905,14 +14907,26 @@ async function _runStartupCheck() {
|
||||
barEl.style.width = pct + '%';
|
||||
barEl.className = 'preloader-bar' + (state === 'error' ? ' bar-error' : state === 'warn' ? ' bar-warn' : '');
|
||||
}
|
||||
if (labelEl) labelEl.textContent = label || '';
|
||||
const wheelPrev = document.getElementById('check-wheel-prev');
|
||||
const wheelCurr = document.getElementById('check-wheel-current');
|
||||
if (wheelCurr) {
|
||||
const prevText = wheelCurr.textContent.trim();
|
||||
if (wheelPrev && prevText && prevText !== '\u00a0') wheelPrev.textContent = prevText;
|
||||
wheelCurr.textContent = label || '';
|
||||
const sc = state === 'error' ? 'state-error' : state === 'warn' ? 'state-warn' : 'state-ok';
|
||||
wheelCurr.className = 'check-wheel-current ' + sc;
|
||||
void wheelCurr.offsetWidth; // re-trigger CSS animation
|
||||
}
|
||||
};
|
||||
|
||||
// Phase 1: animate 0→15% while fetching (so it never looks stuck)
|
||||
setProgress(0, tl('connecting', 'Connessione al server...'));
|
||||
let _fetchDone = false;
|
||||
const slowAnim = setInterval(() => {
|
||||
if (!_fetchDone && _curPct < 13) setProgress(_curPct + 1, labelEl?.textContent);
|
||||
if (!_fetchDone && _curPct < 13) {
|
||||
_curPct++;
|
||||
if (barEl) barEl.style.width = _curPct + '%';
|
||||
}
|
||||
}, 100);
|
||||
|
||||
// Make the request
|
||||
|
||||
+4
-1
@@ -59,7 +59,10 @@
|
||||
<div class="preloader-bar-track">
|
||||
<div id="preloader-bar" class="preloader-bar"></div>
|
||||
</div>
|
||||
<div id="preloader-check-label" class="preloader-check-label"> </div>
|
||||
<div id="preloader-check-wheel" class="check-wheel">
|
||||
<div class="check-wheel-prev" id="check-wheel-prev"></div>
|
||||
<div class="check-wheel-current state-ok" id="check-wheel-current"> </div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="preloader-warnings" class="preloader-warnings" style="display:none"></div>
|
||||
<div id="preloader-error-msg" class="preloader-error-msg" style="display:none"></div>
|
||||
|
||||
Reference in New Issue
Block a user