diff --git a/index.html b/index.html index f684e91..9f5b62e 100644 --- a/index.html +++ b/index.html @@ -153,7 +153,7 @@ header{display:flex;align-items:center;justify-content:space-between;padding:0 1 /* Unit header */ .unit-header{margin-bottom:18px} .unit-meta{min-width:0} -.unit-cat-badge{font-size:10px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--accent);background:var(--accent-dim);border:1px solid var(--accent-border);border-radius:20px;padding:3px 9px;display:inline-block;margin-bottom:6px} +.unit-cat-badge{font-size:10px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--accent);background:var(--accent-dim);border:1px solid var(--accent-border);border-radius:20px;padding:3px 9px;display:inline-flex;align-items:center} .unit-title{font-size:19px;font-weight:600;letter-spacing:-.01em;line-height:1.3} /* Concept text */ @@ -369,6 +369,7 @@ header{display:flex;align-items:center;justify-content:space-between;padding:0 1 /* Concept expand */ .concept-expand-btn{display:inline-flex;align-items:center;gap:5px;font-size:11px;color:var(--accent);background:none;border:none;cursor:pointer;padding:4px 0 0;font-family:'Geist',sans-serif;font-weight:500} .concept-expand-btn:hover{opacity:.75} +.concept-chevron-wrap{display:inline-flex;min-width:11px;height:11px;align-items:center;justify-content:center;flex-shrink:0}
@@ -425,8 +426,11 @@ header{display:flex;align-items:center;justify-content:space-between;padding:0 1 - diff --git a/js/app.js b/js/app.js index 24139fd..4a0c47c 100644 --- a/js/app.js +++ b/js/app.js @@ -82,6 +82,9 @@ document.addEventListener('alpine:init', () => { } this.syncUnitToUrl(); this.$nextTick(()=>{ if(window.lucide) lucide.createIcons(); }); + this.$watch('search', ()=>{ + this.$nextTick(()=>{ if(window.lucide) lucide.createIcons(); }); + }); if('serviceWorker' in navigator){ navigator.serviceWorker.register('/sw.js').catch(()=>{}); } @@ -202,6 +205,7 @@ document.addEventListener('alpine:init', () => { const uid=this.currentUnit.id; const total=this.currentUnit.quiz?.length||0; const correct=Object.values(this.quizState).filter(s=>s?.correct).length; + this.saveScore(uid,correct,total); if(correct>=total){ delete this.wrongUnits[uid]; } else { @@ -272,7 +276,6 @@ document.addEventListener('alpine:init', () => { get resultScore(){ const correct=Object.values(this.quizState).filter(s=>s?.correct).length; const total=this.currentUnit?.quiz?.length||0; - if(this.currentUnit) this.saveScore(this.currentUnit.id,correct,total); return correct+' / '+total; }, get resultMsg(){ @@ -379,6 +382,7 @@ document.addEventListener('alpine:init', () => { if(!unit) return; const correct=Object.values(this.weakDrillQuizState).filter(s=>s?.correct).length; const total=unit.quiz?.length||0; + this.saveScore(unit.id,correct,total); this.weakDrillResults.push({unitId:unit.id,num:unit.num,unitTitle:unit.title,correct,total}); // Update wrong tracking if(correct>=total){ @@ -460,7 +464,6 @@ document.addEventListener('alpine:init', () => { this.resetFlashRevealState(); } } else if(this.stepStep===3){ - this.quizState={}; const drills=this.unitDrills; if(drills.length>0){ this.stepStep=2; diff --git a/sw.js b/sw.js index 0007699..703e7bc 100644 --- a/sw.js +++ b/sw.js @@ -1,14 +1,16 @@ // posimai-boki SW — stale-while-revalidate + skipWaiting -const CACHE = 'posimai-boki-v18'; +const CACHE = 'posimai-boki-v19'; const STATIC = ['/', '/index.html', '/manifest.json', '/logo.png', '/js/app.js', '/js/data/drills.js', '/js/data/categories.js']; self.addEventListener('install', e => { e.waitUntil( - caches.open(CACHE).then(c => c.addAll(STATIC.filter(u => { - try { new URL(u, self.location.origin); return true; } catch { return false; } - }))) + Promise.all([ + caches.open(CACHE).then(c => c.addAll(STATIC.filter(u => { + try { new URL(u, self.location.origin); return true; } catch { return false; } + }))), + self.skipWaiting() + ]) ); - self.skipWaiting(); }); self.addEventListener('activate', e => { @@ -29,7 +31,7 @@ self.addEventListener('fetch', e => { const network = fetch(e.request).then(res => { if (res.ok && res.type === 'basic') cache.put(e.request, res.clone()); return res; - }).catch(() => cached); + }).catch(() => cached || new Response('Offline', { status: 503, statusText: 'Service Unavailable' })); return cached || network; }) )