[html]
<div id="pulseProgressHeader" class="pp-wrap">
<!-- ===== TOP / IMAGE / LOG ===== -->
<div class="pp-topgrid">
<div class="pp-card">
<div class="pp-card-h">🏆 ТОП ВКЛАДЧИКОВ</div>
<div id="ppTop" class="pp-toplist">
<div class="pp-empty">Загрузка…</div>
</div>
</div>
<div class="pp-center">
<img class="pp-center-img" src="https://upforme.ru/uploads/001c/84/76/2/446867.png" alt="PULSE Monument">
</div>
<div class="pp-card">
<div class="pp-card-h">📜 ЖУРНАЛ ВКЛАДА</div>
<div id="ppLog" class="pp-log">
<div class="pp-empty">Загрузка…</div>
</div>
</div>
</div>
<!-- ===== BARS ===== -->
<div class="pp-title">🏗️ ПРОГРЕСС СТРОЙКИ PULSE</div>
<div class="pp-row">
<div class="pp-label">Шкала 1</div>
<div class="pp-bar"><div class="pp-fill" id="pp1"></div></div>
<div class="pp-num" id="pp1t">0 / 0</div>
</div>
<div class="pp-row">
<div class="pp-label">Шкала 2</div>
<div class="pp-bar"><div class="pp-fill" id="pp2"></div></div>
<div class="pp-num" id="pp2t">0 / 0</div>
</div>
<div class="pp-row pp-total">
<div class="pp-label">Общая шкала</div>
<div class="pp-bar"><div class="pp-fill" id="pp3"></div></div>
<div class="pp-num" id="pp3t">0%</div>
</div>
<div class="pp-upd" id="ppUpd">Обновление…</div>
</div>
<style>
.pp-wrap{
max-width:980px;margin:14px auto;padding:16px 16px 18px;border-radius:18px;
background:linear-gradient(180deg,#0c0f12,#070708);
border:1px solid rgba(255,120,0,.25);
box-shadow:0 0 28px rgba(255,80,0,.12);
font-family:system-ui,Segoe UI,Roboto,Arial;color:#eaeaea
}
/* top grid */
.pp-topgrid{
display:grid;
grid-template-columns: 1fr 420px 1fr;
gap:14px;
align-items:stretch;
margin-bottom:14px;
}
.pp-card{
background:linear-gradient(180deg,rgba(255,255,255,.04),rgba(255,255,255,.02));
border:1px solid rgba(255,255,255,.06);
border-radius:16px;
box-shadow:0 0 18px rgba(0,0,0,.35);
padding:12px;
min-height:220px;
overflow:hidden;
}
.pp-card-h{
font-weight:800;
letter-spacing:.12em;
text-transform:uppercase;
font-size:12px;
color:#ff6a00;
margin-bottom:10px;
}
.pp-center{
border-radius:16px;
overflow:hidden;
border:1px solid rgba(255,120,0,.22);
box-shadow:0 0 22px rgba(255,80,0,.10);
background:rgba(0,0,0,.35);
min-height:220px;
display:flex;
align-items:center;
justify-content:center;
}
.pp-center-img{
width:100%;
height:620px;
object-fit:contain;
display:block;
padding:10px;
filter: drop-shadow(0 0 14px rgba(255,120,0,.14));
}
.pp-toplist{display:flex;flex-direction:column;gap:8px}
.pp-toprow{
display:grid;
grid-template-columns: 26px 1fr auto;
gap:10px;
align-items:center;
padding:8px 10px;
border-radius:12px;
background:rgba(0,0,0,.30);
border:1px solid rgba(255,255,255,.05);
}
.pp-rank{
width:26px;height:26px;border-radius:10px;
display:flex;align-items:center;justify-content:center;
background:rgba(255,106,0,.12);
border:1px solid rgba(255,106,0,.25);
color:#ffb36a;
font-weight:800;font-size:12px;
}
.pp-name{
font-weight:700;
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.pp-score{
font-weight:900;
color:#ff6a00;
}
.pp-log{
max-height:620px;
overflow:auto;
padding-right:4px;
scrollbar-width:thin;
scrollbar-color: rgba(255,106,0,.6) transparent;
display:flex;
flex-direction:column;
gap:8px;
}
.pp-logrow{
padding:8px 10px;
border-radius:12px;
background:rgba(0,0,0,.28);
border:1px solid rgba(255,255,255,.05);
line-height:1.25;
font-size:12px;
color:#cfcfcf;
}
.pp-logrow b{color:#ffb36a}
.pp-logtime{color:#9a9a9a;font-size:11px;margin-bottom:3px}
/* bars */
.pp-title{
font-weight:900;letter-spacing:1px;margin:6px 0 10px;color:#ff6a00;text-align:center
}
.pp-row{
display:grid;grid-template-columns:160px 1fr 120px;gap:12px;
align-items:center;margin:10px 0
}
.pp-total{margin-top:14px;padding-top:12px;border-top:1px solid rgba(255,255,255,.08)}
.pp-label{font-size:13px;color:#ddd}
.pp-num{font-size:12px;color:#aaa;text-align:right}
.pp-bar{height:12px;border-radius:999px;background:rgba(255,255,255,.08);overflow:hidden}
.pp-fill{height:100%;width:0%;background:linear-gradient(90deg,#ff3b00,#ffb300);transition:width .35s ease}
.pp-upd{margin-top:8px;font-size:12px;color:#888;text-align:center}
.pp-empty{color:#888;font-size:12px;padding:8px 4px}
@media (max-width:700px){
.pp-topgrid{grid-template-columns:1fr; }
.pp-center-img{height:200px}
.pp-card{min-height:auto}
}
@media (max-width:650px){
.pp-row{grid-template-columns:1fr;gap:6px}
.pp-num{text-align:left}
}
</style>
<script>
(function(){
const send = () => {
const requestId = Math.random().toString(16).slice(2);
window.parent.postMessage({ _pulseProgress:true, type:"progressRequest", requestId }, "*");
return new Promise(resolve => {
const handler = (e) => {
if (e.data?._pulseProgress && e.data.type === "progressResponse" && e.data.requestId === requestId) {
window.removeEventListener("message", handler);
resolve(e.data.data);
}
};
window.addEventListener("message", handler);
setTimeout(()=>{ window.removeEventListener("message", handler); resolve(null); }, 4500);
});
};
function fmtDate(ts){
const d = new Date(ts);
// "число месяц год и время"
// для русской локали обычно красиво:
return d.toLocaleString("ru-RU", { day:"2-digit", month:"long", year:"numeric", hour:"2-digit", minute:"2-digit" });
}
function renderTop(top){
const el = document.getElementById("ppTop");
if (!Array.isArray(top) || !top.length){
el.innerHTML = '<div class="pp-empty">Пока нет вкладов</div>';
return;
}
el.innerHTML = top.slice(0,10).map((p, i) => {
const name = String(p.name || "—");
const total = Number(p.total || 0);
return `
<div class="pp-toprow">
<div class="pp-rank">${i+1}</div>
<div class="pp-name" title="${name}">${name}</div>
<div class="pp-score">${total}</div>
</div>
`;
}).join("");
}
function renderLog(logs){
const el = document.getElementById("ppLog");
if (!Array.isArray(logs) || !logs.length){
el.innerHTML = '<div class="pp-empty">Журнал пуст</div>';
return;
}
el.innerHTML = logs.slice(0,35).map(l => {
const ts = Number(l.ts || 0);
const when = ts ? fmtDate(ts) : "—";
const player = String(l.player || "—");
const item = String(l.item || "—");
return `
<div class="pp-logrow">
<div class="pp-logtime">${when}</div>
<div><b>${player}</b> принёс(ла): <b>${item}</b></div>
</div>
`;
}).join("");
}
function applyBars(snap){
if (!snap) return;
document.getElementById("pp1").style.width = (snap.p1 || 0) + "%";
document.getElementById("pp2").style.width = (snap.p2 || 0) + "%";
document.getElementById("pp3").style.width = (snap.p3 || 0) + "%";
document.getElementById("pp1t").textContent = `${snap.points1} / ${snap.target1}`;
document.getElementById("pp2t").textContent = `${snap.points2} / ${snap.target2}`;
document.getElementById("pp3t").textContent = `${Math.round(snap.p3 || 0)}%`;
const d = snap.updatedAt ? new Date(snap.updatedAt) : null;
document.getElementById("ppUpd").textContent = d ? ("Обновлено: " + d.toLocaleString("ru-RU")) : "Обновление…";
}
function applyAll(snap){
applyBars(snap);
renderTop(snap.topPlayers || []);
renderLog(snap.logs || []);
}
async function tick(){
const res = await send();
if (res && res.success && res.snapshot) applyAll(res.snapshot);
}
tick();
setInterval(tick, 15000);
})();
</script>
[/html]
[hideprofile]