342 lines
12 KiB
JavaScript
342 lines
12 KiB
JavaScript
/**
|
|
* BlueSky MC Theme - main.js
|
|
*/
|
|
|
|
// =============================================
|
|
// MOBILE NAVBAR
|
|
// =============================================
|
|
const navbar = document.querySelector('.navbar');
|
|
const hamburger = document.querySelector('.hamburger');
|
|
if (hamburger) {
|
|
hamburger.addEventListener('click', () => {
|
|
navbar.classList.toggle('active');
|
|
const links = navbar.querySelector('.links');
|
|
if (links) links.classList.toggle('active');
|
|
});
|
|
}
|
|
|
|
// =============================================
|
|
// ACCORDION
|
|
// =============================================
|
|
document.querySelectorAll('.accordion-item-header').forEach(header => {
|
|
header.addEventListener('click', () => {
|
|
header.classList.toggle('active');
|
|
const body = header.nextElementSibling;
|
|
body.style.maxHeight = header.classList.contains('active') ? body.scrollHeight + 'px' : '0px';
|
|
});
|
|
});
|
|
|
|
// =============================================
|
|
// COPY IP
|
|
// =============================================
|
|
const copyIpButton = document.querySelector('.copy-ip');
|
|
const copyIpAlert = document.querySelector('.ip-copied');
|
|
const serverIp = (typeof BlueSkyConfig !== 'undefined') ? BlueSkyConfig.serverIp : 'mc.example.com';
|
|
|
|
if (copyIpButton) {
|
|
copyIpButton.addEventListener('click', () => {
|
|
try {
|
|
navigator.clipboard.writeText(serverIp);
|
|
copyIpAlert.classList.add('active');
|
|
setTimeout(() => copyIpAlert.classList.remove('active'), 5000);
|
|
} catch (e) {
|
|
if (copyIpAlert) {
|
|
copyIpAlert.textContent = 'Fehler beim Kopieren!';
|
|
copyIpAlert.classList.add('active', 'error');
|
|
setTimeout(() => { copyIpAlert.classList.remove('active','error'); copyIpAlert.textContent = 'War Erfolgreich!'; }, 5000);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// =============================================
|
|
// DISCORD ONLINE USERS
|
|
// =============================================
|
|
const discordEl = document.querySelector('.discord-online-users');
|
|
if (discordEl && typeof BlueSkyConfig !== 'undefined' && BlueSkyConfig.discordServerId) {
|
|
(async () => {
|
|
try {
|
|
const res = await fetch(`https://discord.com/api/guilds/${BlueSkyConfig.discordServerId}/widget.json`);
|
|
const data = await res.json();
|
|
discordEl.textContent = data.presence_count || '0';
|
|
} catch { discordEl.textContent = '0'; }
|
|
})();
|
|
}
|
|
|
|
// =============================================
|
|
// MINECRAFT ONLINE PLAYERS
|
|
// =============================================
|
|
const mcEl = document.querySelector('.minecraft-online-players');
|
|
if (mcEl && typeof BlueSkyConfig !== 'undefined' && BlueSkyConfig.serverIp) {
|
|
(async () => {
|
|
try {
|
|
const res = await fetch(`https://api.mcsrvstat.us/3/${BlueSkyConfig.serverIp}`);
|
|
const data = await res.json();
|
|
mcEl.textContent = data?.players?.online ?? '0';
|
|
} catch { mcEl.textContent = '0'; }
|
|
})();
|
|
}
|
|
|
|
// =============================================
|
|
// UUID LOOKUP — mehrere APIs als Fallback
|
|
// =============================================
|
|
async function getUUID(username) {
|
|
// API 1: Mojang direkt
|
|
try {
|
|
const res = await fetch(`https://api.mojang.com/users/profiles/minecraft/${username}`);
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
if (data?.id) return data.id;
|
|
}
|
|
} catch {}
|
|
|
|
// API 2: PlayerDB
|
|
try {
|
|
const res = await fetch(`https://playerdb.co/api/player/minecraft/${username}`);
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
if (data?.data?.player?.raw_id) return data.data.player.raw_id;
|
|
}
|
|
} catch {}
|
|
|
|
// API 3: MCHeads
|
|
try {
|
|
const res = await fetch(`https://mc-heads.net/minecraft/profile/${username}`);
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
if (data?.id) return data.id;
|
|
}
|
|
} catch {}
|
|
|
|
return null;
|
|
}
|
|
|
|
// =============================================
|
|
// TEAM MEMBER SKINS
|
|
// =============================================
|
|
const memberSkins = document.querySelectorAll('.member-skin');
|
|
if (memberSkins.length > 0) {
|
|
const skinType = (typeof BlueSkyConfig !== 'undefined') ? BlueSkyConfig.skinType : 'bust';
|
|
|
|
memberSkins.forEach(async (img) => {
|
|
const memberDiv = img.closest('.user');
|
|
if (!memberDiv) return;
|
|
|
|
const customSkin = memberDiv.dataset.skin;
|
|
// Eigene URL gesetzt → direkt verwenden
|
|
if (customSkin && customSkin.trim().length > 0) {
|
|
img.src = customSkin;
|
|
return;
|
|
}
|
|
|
|
const inGameName = memberDiv.dataset.ingame;
|
|
if (!inGameName) return;
|
|
|
|
// Lade-Platzhalter
|
|
img.style.opacity = '0.4';
|
|
img.style.filter = 'grayscale(1)';
|
|
|
|
try {
|
|
const uuid = await getUUID(inGameName);
|
|
|
|
if (uuid) {
|
|
// visage.surgeplay.com für hohe Qualität
|
|
const skinUrl = `https://visage.surgeplay.com/${skinType}/256/${uuid}`;
|
|
img.src = skinUrl;
|
|
img.onload = () => {
|
|
img.style.opacity = '1';
|
|
img.style.filter = 'none';
|
|
};
|
|
img.onerror = () => {
|
|
// Fallback: crafthead
|
|
img.src = `https://crafthead.net/${skinType === 'bust' ? 'bust' : skinType === 'head' ? 'avatar' : 'body'}/${uuid}/256`;
|
|
img.style.opacity = '1';
|
|
img.style.filter = 'none';
|
|
};
|
|
} else {
|
|
// Kein UUID gefunden → crafthead direkt mit Username
|
|
img.src = `https://crafthead.net/bust/${inGameName}/256`;
|
|
img.style.opacity = '1';
|
|
img.style.filter = 'none';
|
|
}
|
|
} catch (e) {
|
|
img.src = `https://crafthead.net/bust/${inGameName}/256`;
|
|
img.style.opacity = '1';
|
|
img.style.filter = 'none';
|
|
console.warn('Skin load error for', inGameName, e);
|
|
}
|
|
});
|
|
}
|
|
|
|
// =============================================
|
|
// SMOOTH SCROLL
|
|
// =============================================
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
anchor.addEventListener('click', function(e) {
|
|
const target = document.querySelector(this.getAttribute('href'));
|
|
if (target) { e.preventDefault(); target.scrollIntoView({ behavior: 'smooth' }); }
|
|
});
|
|
});
|
|
|
|
// =============================================
|
|
// WIKI SIDEBAR TOGGLE
|
|
// =============================================
|
|
(function initWikiSidebarToggle() {
|
|
const categories = document.querySelectorAll('.wiki-nav-cat');
|
|
if (!categories.length) return;
|
|
|
|
const updateCategory = (cat, isOpen) => {
|
|
const header = cat.querySelector('.wiki-nav-cat-header');
|
|
const body = cat.querySelector('.wiki-nav-cat-body');
|
|
if (!header || !body) return;
|
|
|
|
cat.classList.toggle('open', isOpen);
|
|
header.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
|
body.style.maxHeight = isOpen ? body.scrollHeight + 'px' : '0px';
|
|
};
|
|
|
|
categories.forEach((cat, index) => {
|
|
const header = cat.querySelector('.wiki-nav-cat-header');
|
|
const body = cat.querySelector('.wiki-nav-cat-body');
|
|
if (!header || !body) return;
|
|
|
|
const bodyId = `wiki-nav-body-${index + 1}`;
|
|
body.id = bodyId;
|
|
|
|
header.setAttribute('role', 'button');
|
|
header.setAttribute('tabindex', '0');
|
|
header.setAttribute('aria-controls', bodyId);
|
|
|
|
const initiallyOpen = cat.classList.contains('open');
|
|
updateCategory(cat, initiallyOpen);
|
|
|
|
header.addEventListener('click', () => {
|
|
const isOpen = !cat.classList.contains('open');
|
|
updateCategory(cat, isOpen);
|
|
});
|
|
|
|
header.addEventListener('keydown', (event) => {
|
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
event.preventDefault();
|
|
const isOpen = !cat.classList.contains('open');
|
|
updateCategory(cat, isOpen);
|
|
}
|
|
});
|
|
});
|
|
|
|
window.addEventListener('resize', () => {
|
|
categories.forEach((cat) => {
|
|
if (!cat.classList.contains('open')) return;
|
|
const body = cat.querySelector('.wiki-nav-cat-body');
|
|
if (!body) return;
|
|
body.style.maxHeight = body.scrollHeight + 'px';
|
|
});
|
|
});
|
|
})();
|
|
|
|
// =============================================
|
|
// WIKI ARTICLE ANSWER ACCORDION
|
|
// =============================================
|
|
(function initWikiAnswerAccordion() {
|
|
const accordions = document.querySelectorAll('[data-wiki-answer]');
|
|
if (!accordions.length) return;
|
|
|
|
const setOpenState = (accordion, open) => {
|
|
const toggle = accordion.querySelector('.wiki-answer-toggle');
|
|
const panel = accordion.querySelector('.wiki-answer-panel');
|
|
if (!toggle || !panel) return;
|
|
|
|
accordion.classList.toggle('is-open', open);
|
|
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
panel.style.maxHeight = open ? panel.scrollHeight + 'px' : '0px';
|
|
};
|
|
|
|
accordions.forEach((accordion) => {
|
|
const toggle = accordion.querySelector('.wiki-answer-toggle');
|
|
if (!toggle) return;
|
|
|
|
setOpenState(accordion, false);
|
|
|
|
toggle.addEventListener('click', () => {
|
|
const shouldOpen = !accordion.classList.contains('is-open');
|
|
setOpenState(accordion, shouldOpen);
|
|
});
|
|
});
|
|
|
|
window.addEventListener('resize', () => {
|
|
accordions.forEach((accordion) => {
|
|
if (!accordion.classList.contains('is-open')) return;
|
|
const panel = accordion.querySelector('.wiki-answer-panel');
|
|
if (!panel) return;
|
|
panel.style.maxHeight = panel.scrollHeight + 'px';
|
|
});
|
|
});
|
|
})();
|
|
|
|
// =============================================
|
|
// RULES ACCORDION
|
|
// =============================================
|
|
(function initRulesAccordion() {
|
|
const cards = document.querySelectorAll('.rule-card');
|
|
if (!cards.length) return;
|
|
|
|
const setOpenState = (card, open) => {
|
|
const toggle = card.querySelector('.rule-toggle');
|
|
const panel = card.querySelector('.rule-content-panel');
|
|
if (!toggle || !panel) return;
|
|
|
|
card.classList.toggle('is-open', open);
|
|
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
panel.style.maxHeight = open ? panel.scrollHeight + 'px' : '0px';
|
|
};
|
|
|
|
cards.forEach((card) => {
|
|
const toggle = card.querySelector('.rule-toggle');
|
|
if (!toggle) return;
|
|
|
|
setOpenState(card, false);
|
|
|
|
toggle.addEventListener('click', () => {
|
|
const shouldOpen = !card.classList.contains('is-open');
|
|
|
|
cards.forEach((otherCard) => {
|
|
if (otherCard !== card) setOpenState(otherCard, false);
|
|
});
|
|
|
|
setOpenState(card, shouldOpen);
|
|
});
|
|
});
|
|
|
|
window.addEventListener('resize', () => {
|
|
cards.forEach((card) => {
|
|
if (!card.classList.contains('is-open')) return;
|
|
const panel = card.querySelector('.rule-content-panel');
|
|
if (!panel) return;
|
|
panel.style.maxHeight = panel.scrollHeight + 'px';
|
|
});
|
|
});
|
|
})();
|
|
|
|
// =============================================
|
|
// WIKI OVERVIEW TABS
|
|
// =============================================
|
|
(function initWikiOverviewTabs() {
|
|
const tabButtons = document.querySelectorAll('.wiki-tab-button');
|
|
const tabPanels = document.querySelectorAll('.wiki-tab-panel');
|
|
if (!tabButtons.length || !tabPanels.length) return;
|
|
|
|
tabButtons.forEach((button) => {
|
|
button.addEventListener('click', () => {
|
|
const targetId = button.getAttribute('data-tab');
|
|
if (!targetId) return;
|
|
|
|
tabButtons.forEach((btn) => btn.classList.remove('active'));
|
|
tabPanels.forEach((panel) => panel.classList.remove('active'));
|
|
|
|
button.classList.add('active');
|
|
const targetPanel = document.getElementById(targetId);
|
|
if (targetPanel) targetPanel.classList.add('active');
|
|
});
|
|
});
|
|
})();
|