Upload folder via GUI - js
This commit is contained in:
341
js/main.js
Normal file
341
js/main.js
Normal file
@@ -0,0 +1,341 @@
|
||||
/**
|
||||
* 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');
|
||||
});
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user