site: add server section, highlights carousel, OBT/Season content
- server status cards (online/players/version) via /api/status mcstatus ping - highlights carousel ported from old site (/highlights/ static media) - OBT (war in Zarya, open beta event server) + Season (Prologue, Create: Aeronautics, year-long) sections - nav updated, sections renumbered 01-06
This commit is contained in:
+122
-1
@@ -63,6 +63,124 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function loadServerStatus() {
|
||||
const statusEl = document.getElementById('srv-status');
|
||||
const playersEl = document.getElementById('srv-players');
|
||||
const versionEl = document.getElementById('srv-version');
|
||||
const dot = document.querySelector('#srv-status .status-dot');
|
||||
if (!statusEl) return;
|
||||
|
||||
try {
|
||||
const res = await fetch(API + '/api/status');
|
||||
const data = await res.json();
|
||||
|
||||
if (data.online) {
|
||||
if (dot) dot.className = 'status-dot status-dot--online';
|
||||
statusEl.innerHTML = '<span class="status-dot status-dot--online"></span><span class="status-text--online">Online</span>';
|
||||
if (playersEl) playersEl.textContent = `${data.players_online} / ${data.players_max}`;
|
||||
if (versionEl && data.version) versionEl.textContent = data.version;
|
||||
} else {
|
||||
if (dot) dot.className = 'status-dot status-dot--offline';
|
||||
statusEl.innerHTML = '<span class="status-dot status-dot--offline"></span><span class="status-text--offline">Offline</span>';
|
||||
if (playersEl) playersEl.textContent = '— / —';
|
||||
}
|
||||
} catch (e) {
|
||||
if (dot) dot.className = 'status-dot status-dot--offline';
|
||||
statusEl.innerHTML = '<span class="status-dot status-dot--offline"></span><span>Unavailable</span>';
|
||||
}
|
||||
}
|
||||
|
||||
const HIGHLIGHTS = [
|
||||
{ file: '1.jpg', type: 'image', caption: 'Zern' },
|
||||
{ file: '2.mp4', type: 'video', caption: null },
|
||||
{ file: '3.jpg', type: 'image', caption: 'Это честно не я' },
|
||||
{ file: '4.mp4', type: 'video', caption: null },
|
||||
{ file: '5.jpg', type: 'image', caption: 'Спавн ТЦ (старое)' },
|
||||
{ file: '6.jpg', type: 'image', caption: 'Спавн склад (старое)' },
|
||||
{ file: '7.jpg', type: 'image', caption: null },
|
||||
{ file: '8.jpg', type: 'image', caption: null },
|
||||
{ file: '9.jpg', type: 'image', caption: null },
|
||||
{ file: '10.jpg', type: 'image', caption: null },
|
||||
{ file: '11.jpg', type: 'image', caption: null },
|
||||
{ file: '12.jpg', type: 'image', caption: null },
|
||||
{ file: '13.jpg', type: 'image', caption: null },
|
||||
{ file: '14.jpg', type: 'image', caption: null },
|
||||
{ file: '15.jpg', type: 'image', caption: null },
|
||||
];
|
||||
|
||||
function initCarousel() {
|
||||
const track = document.getElementById('carousel');
|
||||
const dotsWrap = document.getElementById('carouselDots');
|
||||
const prev = document.getElementById('carouselPrev');
|
||||
const next = document.getElementById('carouselNext');
|
||||
if (!track) return;
|
||||
|
||||
HIGHLIGHTS.forEach((h, i) => {
|
||||
const slide = document.createElement('div');
|
||||
slide.className = 'carousel-slide';
|
||||
|
||||
if (h.type === 'video') {
|
||||
const vid = document.createElement('video');
|
||||
vid.src = '/highlights/' + h.file;
|
||||
vid.controls = true;
|
||||
vid.autoplay = true;
|
||||
vid.loop = true;
|
||||
vid.muted = true;
|
||||
vid.playsInline = true;
|
||||
slide.appendChild(vid);
|
||||
} else {
|
||||
const img = document.createElement('img');
|
||||
img.src = '/highlights/' + h.file;
|
||||
img.alt = h.caption || 'Zern highlight';
|
||||
img.loading = 'lazy';
|
||||
slide.appendChild(img);
|
||||
}
|
||||
|
||||
if (h.caption) {
|
||||
const cap = document.createElement('span');
|
||||
cap.className = 'carousel-caption';
|
||||
cap.textContent = h.caption;
|
||||
slide.appendChild(cap);
|
||||
}
|
||||
|
||||
track.appendChild(slide);
|
||||
|
||||
const dot = document.createElement('span');
|
||||
dot.className = 'carousel-dot' + (i === 0 ? ' active' : '');
|
||||
dot.addEventListener('click', () => goto(i));
|
||||
dotsWrap.appendChild(dot);
|
||||
});
|
||||
|
||||
let index = 0;
|
||||
let timer = null;
|
||||
|
||||
function goto(i) {
|
||||
index = (i + HIGHLIGHTS.length) % HIGHLIGHTS.length;
|
||||
track.style.transform = 'translateX(-' + index * 100 + '%)';
|
||||
dotsWrap.querySelectorAll('.carousel-dot').forEach((d, k) => {
|
||||
d.classList.toggle('active', k === index);
|
||||
});
|
||||
}
|
||||
|
||||
function nextSlide() { goto(index + 1); }
|
||||
function prevSlide() { goto(index - 1); }
|
||||
|
||||
function start() {
|
||||
stop();
|
||||
timer = setInterval(nextSlide, 6500);
|
||||
}
|
||||
function stop() {
|
||||
if (timer) { clearInterval(timer); timer = null; }
|
||||
}
|
||||
|
||||
if (prev) prev.addEventListener('click', () => { prevSlide(); start(); });
|
||||
if (next) next.addEventListener('click', () => { nextSlide(); start(); });
|
||||
track.addEventListener('mouseenter', stop);
|
||||
track.addEventListener('mouseleave', start);
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
function stripMarkup(text) {
|
||||
if (!text) return '';
|
||||
return text
|
||||
@@ -150,7 +268,7 @@
|
||||
}
|
||||
|
||||
function initReveal() {
|
||||
const els = document.querySelectorAll('.section-head, .feature-card, .download-card, .news-card');
|
||||
const els = document.querySelectorAll('.section-head, .feature-card, .download-card, .news-card, .server-card, .theme-card, .carousel');
|
||||
if (!('IntersectionObserver' in window)) {
|
||||
els.forEach((el) => el.classList.add('visible'));
|
||||
return;
|
||||
@@ -175,6 +293,9 @@
|
||||
loadLauncherInfo();
|
||||
loadMirrors();
|
||||
loadNews();
|
||||
loadServerStatus();
|
||||
setInterval(loadServerStatus, 15000);
|
||||
initCarousel();
|
||||
initNav();
|
||||
initParallax();
|
||||
initReveal();
|
||||
|
||||
Reference in New Issue
Block a user