fix(textbooks): шпаргалка показывает человеч. названия достижений вместо id

Было: 'ring36', 'start' — внутренние id-ы достижений
Стало: 'Начало пути по корням!', 'Нашёл сторону ринга'

STATE.achievements теперь Map(id → text). Старый формат массива id-ов читается с обратной совместимостью (id используется как текст). При сохранении пишется как объект.
This commit is contained in:
Maxim Dolgolyov
2026-05-27 11:21:33 +03:00
parent e43f14b5e1
commit 8838f963a3
+14 -6
View File
@@ -395,7 +395,7 @@ input,select,textarea{font-family:inherit}
const STATE = { const STATE = {
current: 'p1', current: 'p1',
progress: { p1: 0, p2: 0, p3: 0, p4: 0, p5: 0, p6: 0, final: 0 }, progress: { p1: 0, p2: 0, p3: 0, p4: 0, p5: 0, p6: 0, final: 0 },
achievements: new Set(), achievements: new Map(), // id → human-readable text
squaresBest: Infinity, squaresBest: Infinity,
}; };
@@ -404,7 +404,15 @@ function loadProgress(){
const s = localStorage.getItem('algebra8_ch1_progress'); const s = localStorage.getItem('algebra8_ch1_progress');
if(s){ Object.assign(STATE.progress, JSON.parse(s)); } if(s){ Object.assign(STATE.progress, JSON.parse(s)); }
const a = localStorage.getItem('algebra8_ch1_achievements'); const a = localStorage.getItem('algebra8_ch1_achievements');
if(a){ STATE.achievements = new Set(JSON.parse(a)); } if(a){
const parsed = JSON.parse(a);
if(Array.isArray(parsed)){
// старый формат [id, id, ...] — id-ы как текст
parsed.forEach(id => STATE.achievements.set(id, id));
} else if(parsed && typeof parsed === 'object'){
STATE.achievements = new Map(Object.entries(parsed));
}
}
const sb = localStorage.getItem('algebra8_ch1_squaresBest'); const sb = localStorage.getItem('algebra8_ch1_squaresBest');
if(sb) STATE.squaresBest = +sb; if(sb) STATE.squaresBest = +sb;
}catch(e){} }catch(e){}
@@ -412,7 +420,7 @@ function loadProgress(){
function saveProgress(){ function saveProgress(){
try{ try{
localStorage.setItem('algebra8_ch1_progress', JSON.stringify(STATE.progress)); localStorage.setItem('algebra8_ch1_progress', JSON.stringify(STATE.progress));
localStorage.setItem('algebra8_ch1_achievements', JSON.stringify([...STATE.achievements])); localStorage.setItem('algebra8_ch1_achievements', JSON.stringify(Object.fromEntries(STATE.achievements)));
if(isFinite(STATE.squaresBest)) localStorage.setItem('algebra8_ch1_squaresBest', String(STATE.squaresBest)); if(isFinite(STATE.squaresBest)) localStorage.setItem('algebra8_ch1_squaresBest', String(STATE.squaresBest));
}catch(e){} }catch(e){}
} }
@@ -437,7 +445,7 @@ function refreshProgressUI(){
} }
function achievement(id, text){ function achievement(id, text){
if(STATE.achievements.has(id)) return; if(STATE.achievements.has(id)) return;
STATE.achievements.add(id); STATE.achievements.set(id, text);
saveProgress(); saveProgress();
const pop = document.getElementById('ach-popup'); const pop = document.getElementById('ach-popup');
document.getElementById('ach-text').textContent = text; document.getElementById('ach-text').textContent = text;
@@ -579,8 +587,8 @@ function buildSidebar(id){
// achievements // achievements
if(STATE.achievements.size > 0){ if(STATE.achievements.size > 0){
html += `<div class="sidecard"><h4>Достижения <span style="color:var(--warn);float:right">${STATE.achievements.size}</span></h4>`; html += `<div class="sidecard"><h4>Достижения <span style="color:var(--warn);float:right">${STATE.achievements.size}</span></h4>`;
[...STATE.achievements].slice(-4).forEach(a=>{ [...STATE.achievements.values()].slice(-4).forEach(text=>{
html += `<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">✓ ${a}</div>`; html += `<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">✓ ${text}</div>`;
}); });
html += '</div>'; html += '</div>';
} }