From 53055040c6f263c3a40f4e3c98ffda6447e8aa3a Mon Sep 17 00:00:00 2001 From: Git Manager GUI Date: Thu, 28 May 2026 20:21:50 +0200 Subject: [PATCH] Upload folder via GUI - js --- js/main.js | 341 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 js/main.js diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..de28488 --- /dev/null +++ b/js/main.js @@ -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'); + }); + }); +})();