Files
ttt-site/loading/index.html
2025-08-29 18:01:00 +02:00

232 lines
9.4 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta http-equiv="Cache-Control" content="no-store" />
<meta name="color-scheme" content="dark light" />
<title>Verbinde …</title>
<style>
:root{
--bg:#0b0f14; --bg2:#0d1420; --card:#0f1620; --card2:#0c121a;
--stroke:#1a2634; --muted:#8aa0b3; --text:#e8f0f7;
--accent:#73d7ff; --ok:#8affc1;
}
*{box-sizing:border-box} html,body{height:100%}
body{
margin:0; color:var(--text);
font:16px/1.45 system-ui,-apple-system,"Segoe UI",Roboto,Ubuntu,"Helvetica Neue",Arial;
background:
radial-gradient(1200px 800px at 80% -10%,#132033 0%,transparent 60%),
linear-gradient(180deg,var(--bg),var(--bg) 60%,var(--bg2));
}
.container{min-height:100%; display:flex; align-items:center; justify-content:center; padding:24px}
.card{
width:min(980px,94vw);
background:linear-gradient(180deg,var(--card),var(--card2));
border:1px solid var(--stroke); border-radius:16px; padding:26px 28px;
box-shadow:0 10px 30px rgba(0,0,0,.35)
}
h1{margin:0 0 8px; font-size:28px; letter-spacing:.2px}
.logo{font-weight:700; letter-spacing:.5px}
.meta{display:flex; flex-wrap:wrap; gap:10px 12px; color:var(--muted); font-size:14px; margin-bottom:12px}
.badge{border:1px solid var(--stroke); padding:6px 10px; border-radius:999px; background:#111926}
.grid{display:grid; grid-template-columns:1fr 1fr; gap:18px}
@media (max-width:760px){.grid{grid-template-columns:1fr}}
.box{border:1px solid var(--stroke); border-radius:14px; padding:16px; background:var(--card2)}
.box strong{display:block; margin-bottom:6px}
a{color:var(--accent); text-decoration:none}
/* Phasen-Chips */
.phases{list-style:none;padding:0;margin:10px 0 12px;display:flex;gap:8px;flex-wrap:wrap}
.phases li{padding:6px 10px;border:1px solid var(--stroke);border-radius:999px;background:var(--card2);opacity:.55;transition:opacity .25s ease, box-shadow .25s ease}
.phases li.on{opacity:1; box-shadow:0 0 0 9999px inset rgba(115,215,255,.07)}
/* Fortschrittsbalken */
.row{display:grid; gap:12px}
.label{display:flex; justify-content:space-between; gap:12px; font-size:14px; color:#cfe7ff}
.sub{color:var(--muted); font-size:12px; margin-top:4px; white-space:nowrap; text-overflow:ellipsis; overflow:hidden}
.bar{height:10px; background:#0b1420; border-radius:999px; overflow:hidden; position:relative}
.fill{height:100%; width:0%; background:linear-gradient(90deg,var(--accent),var(--ok)); transition:width .15s ease-in-out}
.bar.indet::before{
content:""; position:absolute; inset:0;
background:linear-gradient(90deg, transparent 0%, rgba(255,255,255,.15) 35%, transparent 70%);
animation:flow 1.2s linear infinite;
}
@keyframes flow{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}
.kbd{border:1px solid #2a3a4f; background:#0b1320; border-radius:6px; padding:2px 6px}
.tip{opacity:.95; font-size:14px}
.footer{display:flex; gap:12px; flex-wrap:wrap; margin-top:12px; color:var(--muted); font-size:13px}
.small{font-size:12px; color:#9fb3c9}
</style>
</head>
<body>
<noscript><div style="padding:12px;background:#300;border-bottom:1px solid #633;color:#fff;font:14px/1.3 monospace">
Dieses Overlay benötigt JavaScript, um Server/Map/Modus und Fortschritt zu zeigen.</div></noscript>
<div class="container"><div class="card">
<!-- Kopfzeile -->
<div class="meta">
<span class="badge">Server: <span id="sv"></span></span>
<span class="badge">Map: <span id="map"></span></span>
<span class="badge">Modus: <span id="gm"></span></span>
<span class="badge">Du: <span id="me"></span></span>
</div>
<h1 class="logo">Willkommen auf <span id="sv2">deinem Server</span> 👋</h1>
<!-- Phasen -->
<ul class="phases">
<li id="ph-work" class="on">Workshop prüfen</li>
<li id="ph-srv">Server-Content</li>
<li id="ph-init">Initialisierung</li>
</ul>
<div class="grid">
<!-- Fortschritt -->
<div class="box">
<strong>Fortschritt</strong>
<div class="row" style="margin-top:6px">
<div>
<div class="label"><span>Workshop</span><span id="w-pct">0%</span></div>
<div class="bar" id="w-bar"><div class="fill" id="w-fill"></div></div>
<div class="sub" id="w-sub">Warte auf Daten …</div>
</div>
<div>
<div class="label"><span>Server-Content</span><span id="s-pct">0%</span></div>
<div class="bar" id="s-bar"><div class="fill" id="s-fill"></div></div>
<div class="sub" id="s-sub">Warte auf Daten …</div>
</div>
<div>
<div class="label"><span>Initialisierung</span><span id="i-pct"></span></div>
<div class="bar indet" id="i-bar"></div>
<div class="sub" id="i-sub">Warte auf Client-Info …</div>
</div>
</div>
<div class="small" style="margin-top:10px">Datei: <span id="file"></span></div>
</div>
<!-- Tipps / Links -->
<div class="box">
<strong>Tipps</strong>
<ul class="tip" style="margin:10px 0 0 18px">
<li>Drücke <span class="kbd">F1</span> für Hilfe/Regeln.</li>
<li><span class="kbd">F2</span> öffnet den TTT2-Shop.</li>
<li><span class="kbd">Tab</span> zeigt die Rollen-Übersicht.</li>
</ul>
<div class="footer">
<span>Website: <a href="https://ttt.dk0.dev" target="_blank" rel="noreferrer">ttt.dk0.dev</a></span>
</div>
</div>
</div>
</div></div>
<script>
(() => {
const $ = id => document.getElementById(id);
// Elemente
const ph = { work:$('ph-work'), srv:$('ph-srv'), init:$('ph-init') };
const work = { fill:$('w-fill'), pct:$('w-pct'), sub:$('w-sub'), total:0, need:0, last:0, done:false };
const srv = { fill:$('s-fill'), pct:$('s-pct'), sub:$('s-sub'), total:0, need:0, last:0, done:false };
const init = { pct:$('i-pct'), sub:$('i-sub') };
let phase = 'work';
function setPhase(next){
phase = next;
// Chips visuell updaten
[ph.work, ph.srv, ph.init].forEach(el => el.classList.remove('on'));
if (next === 'work') ph.work.classList.add('on');
if (next === 'srv') ph.srv.classList.add('on');
if (next === 'init') ph.init.classList.add('on');
}
function setPct(obj, v){
v = Math.max(obj.last || 0, Math.min(100, Math.round(v)));
obj.last = v;
obj.fill.style.width = v + '%';
obj.pct.textContent = v + '%';
}
function updateBars(){
// Workshop
if (work.total > 0){
const done = Math.max(0, work.total - (work.need||0));
setPct(work, (done / work.total) * 100);
work.sub.textContent = `${done} / ${work.total} Dateien`;
if (!work.done && done >= work.total){ work.done = true; setPhase('srv'); }
}
// Server
if (srv.total > 0){
const done = Math.max(0, srv.total - (srv.need||0));
setPct(srv, (done / srv.total) * 100);
srv.sub.textContent = `${done} / ${srv.total} Dateien`;
if (!srv.done && done >= srv.total){ srv.done = true; setPhase('init'); }
}
}
// ===== von GMod aufgerufene Funktionen =====
window.GameDetails = function(serverName, serverURL, mapName, maxPlayers, steamID, gamemode){
$('sv').textContent = serverName || 'Unbekannt';
$('sv2').textContent = serverName || 'deinem Server';
$('map').textContent = mapName || 'Unbekannt';
$('gm').textContent = gamemode || 'TTT2';
$('me').textContent = steamID || '—';
};
// GMod ruft diese zweimal in „Wellen“ auf: erst Workshop, dann Server-DLs.
window.SetFilesTotal = function(total){
total = Number(total) || 0;
// Heuristik: Wenn im Workshop die Gesamtzahl plötzlich kleiner wird, dann startet Server-Content
if (phase === 'work' && work.total && total && total < work.total && (work.last >= 95 || work.done)){
work.done = true; setPhase('srv');
}
if (phase === 'work'){ work.total = total; }
else if (phase === 'srv'){ srv.total = total; }
updateBars();
};
window.SetFilesNeeded = function(need){
need = Number(need) || 0;
if (phase === 'work'){ work.need = need; }
else if (phase === 'srv'){ srv.need = need; }
updateBars();
};
window.DownloadingFile = function(path){
$('file').textContent = (path||'').split('/').slice(-3).join('/');
};
window.SetStatusChanged = function(status){
const s = (status || '').toLowerCase();
// Phasenwechsel anhand Status
if (s.includes('workshop')) setPhase('work');
if (s.includes('download') || s.includes('materials') || s.includes('models') || s.includes('.bsp')) setPhase('srv');
if (s.includes('sending client info') || s.includes('precaching') || s.includes('client info') || s.includes('spawn'))
setPhase('init');
// Untertitel je nach Phase
if (phase === 'work') work.sub.textContent = status || '';
if (phase === 'srv') srv.sub.textContent = status || '';
if (phase === 'init'){ init.sub.textContent = status || 'Initialisiere …'; init.pct.textContent = '…'; }
};
// Kleiner Fallback fürs Testen im normalen Browser (kein Muss)
if (!('GameDetails' in window)) {
// Dummy-Werte
window.GameDetails('Gaming Mäuse - TTT', '', 'ttt_lego', 16, 'STEAM_0:1:123456', 'terrortown');
// Fake-Progress
let a=0,b=0; const fake = setInterval(()=>{
if (a < 100){ work.total=100; work.need=100-a; a+=7; updateBars(); }
else if (b < 100){ setPhase('srv'); srv.total=100; srv.need=100-b; b+=12; updateBars(); }
else { setPhase('init'); clearInterval(fake); }
}, 500);
}
})();
</script>
</body>
</html>