Upload folder via GUI - js

This commit is contained in:
Git Manager GUI
2026-05-28 20:21:50 +02:00
parent 160c9c507d
commit 53055040c6

341
js/main.js Normal file
View 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');
});
});
})();