mirror of
https://github.com/denshooter/ttt-site.git
synced 2026-01-21 12:43:04 +01:00
232 lines
9.4 KiB
HTML
232 lines
9.4 KiB
HTML
<!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>
|