diff --git a/index.html b/index.html index d977bc1..a1631fe 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,10 @@ + + 24mycloud + @@ -687,6 +759,26 @@ const MOCK = [ function ago(h) { return new Date(Date.now() - h*3600000).toISOString(); } let D = { repos: [] }; +let prevState = { commits: new Set(), stats: {} }; + +function animateValue(el, newVal) { + const old = el.textContent; + if (old === String(newVal)) return; + el.classList.add('updating'); + setTimeout(() => { + el.textContent = newVal; + el.classList.remove('updating'); + }, 150); +} + +function bumpBadge(id) { + const el = document.getElementById(id); + if (!el) return; + el.classList.remove('bump'); + void el.offsetWidth; + el.classList.add('bump'); + setTimeout(() => el.classList.remove('bump'), 300); +} // ===== PARTICLES ===== (function(){ @@ -790,11 +882,24 @@ async function loadData() { } // ===== RENDER ===== +let isFirstRender = true; + function render() { rStats(); rFeed(); rProjects(); rActivity(); rIssues(); rSvcs(); rStor(); rCerts(); rNavSvc(); - document.getElementById('nRC').textContent = D.repos.length; + + const rc = D.repos.length; const ti = D.repos.reduce((s,r)=>s+(r.issues?.length||0),0); - document.getElementById('nIC').textContent = ti||'0'; + + const nRC = document.getElementById('nRC'); + const nIC = document.getElementById('nIC'); + if (nRC.textContent !== String(rc)) { nRC.textContent = rc; bumpBadge('nRC'); } + if (nIC.textContent !== String(ti||'0')) { nIC.textContent = ti||'0'; bumpBadge('nIC'); } + + // Track commits for next diff + const newSet = new Set(); + D.repos.forEach(r => r.commits.forEach(c => newSet.add(c.sha))); + prevState.commits = newSet; + isFirstRender = false; } function rStats() { @@ -807,16 +912,35 @@ function rStats() { if(Date.now()-t<86400000)ar++; } }); + + // Animate existing stat values if they exist + const existing = document.querySelectorAll('.st-val[data-key]'); + if (existing.length && !isFirstRender) { + const vals = { repos: D.repos.length, commits: tc, push: lp?tAgo(new Date(lp).toISOString()):'—', active: ar }; + existing.forEach(el => { + const k = el.dataset.key; + if (vals[k] !== undefined && el.textContent !== String(vals[k])) { + animateValue(el, vals[k]); + } + }); + // Update push label + const lbl = document.getElementById('pushLabel'); + if (lbl) lbl.textContent = `Последний push · ${lpN}`; + return; + } + document.getElementById('stG').innerHTML = ` -
${D.repos.length}
Репозиториев
-
${tc?'сегодня':''}
${tc}
Коммитов сегодня
-
${lp?tAgo(new Date(lp).toISOString()):'—'}
Последний push · ${lpN}
-
${ar}
Активных (24ч)
`; +
${D.repos.length}
Репозиториев
+
${tc?'сегодня':''}
${tc}
Коммитов сегодня
+
${lp?tAgo(new Date(lp).toISOString()):'—'}
Последний push · ${lpN}
+
${ar}
Активных (24ч)
`; } function cmRow(c,rn,sr){ const m=c.commit.message.split('\n')[0],t=cType(m); - return `
${esc(m)}
${sr?`${rn}`:''} ${c.sha.slice(0,7)} ${c.commit.author.name}
${hm(c.commit.author.date)}
`; + const isNew = !isFirstRender && !prevState.commits.has(c.sha); + const cls = isNew ? 'cm flash-new' : 'cm'; + return `
${esc(m)}
${sr?`${rn}`:''} ${c.sha.slice(0,7)} ${c.commit.author.name}
${hm(c.commit.author.date)}
`; } function rFeed(){