Files
xxx-sphere-web/bin/main/static/js/section-nav.js
Mario e2a71ab096
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
Hashtags eingeführt
2026-04-11 01:14:33 +02:00

251 lines
13 KiB
JavaScript

(function () {
const path = window.location.pathname;
const search = window.location.search;
const I = window.IC || function () { return ''; };
// ── Bereichs-Definitionen ────────────────────────────────────────────────
const SECTIONS = {
common: {
prefixes: ['/games/common/'],
items: [
{ href: '/games/vanilla/neuvanilla.html', icon: 'VANILLA', label: 'Vanilla Game' },
{ href: '/games/bdsm/neubdsm.html', icon: 'BDSM', label: 'BDSM Game' },
{ href: '/games/chastity/neulock.html', icon: 'CHASTITY', label: 'Chastity Game' },
],
},
social: {
prefixes: ['/community/'],
exclude: [
'/community/nachrichten.html',
'/community/benachrichtigungen.html',
],
items: [
{ href: '/community/feed.html', icon: 'FEED', label: 'Feed' },
{ href: '/community/freunde.html', icon: 'FRIENDS', label: 'Freunde' },
{ href: '/community/gruppen.html', icon: 'GROUPS', label: 'Gruppen' },
{ href: '/community/locations.html', icon: 'LOCATION', label: 'Locations' },
{ href: '/community/events.html', icon: 'EVENT', label: 'Veranstaltungen' },
],
},
dating: {
prefixes: ['/dating/'],
items: [
{ href: '/dating/dating.html', icon: 'DATING', label: 'Dating', id: 'snavDatingLink' },
{ href: '/dating/besucher.html', icon: '', label: 'Besucher' },
{ href: '/dating/likes.html', icon: '', label: 'Likes' },
{ href: '/dating/matches.html', icon: '', label: 'Matches' },
],
},
vanilla: {
prefixes: ['/games/vanilla/'],
items: [
{ href: '/games/vanilla/neuvanilla.html', icon: 'PLAY_NEW', label: 'Neue Session', id: 'snavVanillaNeu' },
{ href: '#', icon: 'WAITING', label: 'Aktive Session', id: 'snavVanillaAktiv', hidden: true },
{ href: '/games/vanilla/vanillaingame.html', icon: 'PLAY_ACTIVE', label: 'Im Spiel', id: 'snavVanillaImSpiel', hidden: true },
{ href: '/games/vanilla/aufgaben.html', icon: 'CHECK', label: 'Aufgaben' },
{ href: '/games/vanilla/toys.html', icon: 'TOYS', label: 'Toys' },
{ href: '/games/vanilla/entdecken.html', icon: 'DISCOVER', label: 'Entdecken' },
],
},
bdsm: {
prefixes: ['/games/bdsm/'],
items: [
{ href: '/games/bdsm/neubdsm.html', icon: 'PLAY_NEW', label: 'Neue Session', id: 'snavBdsmNeu' },
{ href: '#', icon: 'WAITING', label: 'Aktive Session', id: 'snavBdsmAktiv', hidden: true },
{ href: '/games/bdsm/bdsmingame.html', icon: 'PLAY_ACTIVE', label: 'Im Spiel', id: 'snavBdsmImSpiel', hidden: true },
{ href: '/games/bdsm/aufgaben.html', icon: 'CHECK', label: 'Aufgaben' },
{ href: '/games/bdsm/toys.html', icon: 'TOYS', label: 'Toys' },
{ href: '/games/bdsm/entdecken.html', icon: 'DISCOVER', label: 'Entdecken' },
],
},
chastity: {
prefixes: ['/games/chastity/'],
items: [
{ href: '/games/chastity/neulock.html', icon: 'NEW_LOCK', label: 'Neues Lock', id: 'snavChastityNeu' },
{ href: '#', icon: 'ACTIVE_LOCK', label: 'Aktives Lock', id: 'snavChastityAktiv', hidden: true },
{ href: '/games/chastity/communityvotes.html', icon: 'VOTES', label: 'Community Votes' },
{ href: '/games/chastity/meine-locks.html', icon: 'LOCK', label: 'Meine Vorlagen' },
{ href: '/games/chastity/entdecken-vorlagen.html', icon: 'DISCOVER', label: 'Entdecken' },
{ href: '/games/chastity/keyholder-finden.html', icon: 'FRIENDS', label: 'Keyholder finden' },
{ href: '/games/chastity/keyholder.html', icon: 'KEY', label: 'Keyholder' },
{ href: '/games/chastity/unlock-history.html', icon: 'HISTORY', label: 'Code-Historie' },
],
},
};
// ── Aktiven Bereich ermitteln ────────────────────────────────────────────
const sectionKey = Object.keys(SECTIONS).find(k => {
const s = SECTIONS[k];
if (!s.prefixes.some(p => path.startsWith(p))) return false;
if (s.exclude && s.exclude.includes(path)) return false;
return true;
});
if (!sectionKey) return;
const section = SECTIONS[sectionKey];
// ── CSS ──────────────────────────────────────────────────────────────────
const style = document.createElement('style');
style.textContent = `
.section-nav {
display: flex;
align-items: center;
gap: 0.15rem;
flex-wrap: wrap;
padding: 0 0 0.6rem 0;
}
.section-nav-link {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.3rem 0.75rem;
border-radius: 7px;
text-decoration: none;
color: var(--color-muted);
font-size: 0.85rem;
font-weight: 500;
white-space: nowrap;
transition: background 0.12s, color 0.12s;
}
.section-nav-link:hover {
background: var(--color-secondary);
color: var(--color-text);
}
.section-nav-link.active {
color: var(--color-primary);
background: rgba(var(--color-primary-rgb, 233,69,96), 0.09);
font-weight: 600;
}
.section-nav-icon {
font-size: 0.9rem;
line-height: 1;
flex-shrink: 0;
}
.section-nav--icons-only .section-nav-label { display: none; }
.section-nav--icons-only .section-nav-link { gap: 0; padding: 0.3rem 0.55rem; }
.section-nav-sep {
border: none;
border-top: 1px solid var(--color-secondary);
margin: 0 0 1.25rem 0;
}
`;
document.head.appendChild(style);
// ── Aktiv-Erkennung ──────────────────────────────────────────────────────
function isActive(item) {
if (item.href === '#') return false;
const [itemPath, itemQuery] = item.href.split('?');
if (itemQuery) return path === itemPath && search === '?' + itemQuery;
return path === itemPath;
}
// ── Nav bauen ────────────────────────────────────────────────────────────
const navEl = document.createElement('nav');
navEl.className = 'section-nav';
section.items.forEach(item => {
const a = document.createElement('a');
a.href = item.href;
a.className = 'section-nav-link' + (isActive(item) ? ' active' : '');
if (item.id) a.id = item.id;
if (item.hidden) a.style.display = 'none';
a.title = item.label;
if (item.icon) a.innerHTML += `<span class="section-nav-icon">${I(item.icon) || ''}</span>`;
a.innerHTML += `<span class="section-nav-label">${item.label}</span>`;
navEl.appendChild(a);
});
const sep = document.createElement('hr');
sep.className = 'section-nav-sep';
// ── Einfügen in .main ────────────────────────────────────────────────────
function checkOverflow() {
// Immer zuerst Labels einblenden und ohne wrap messen —
// so gibt es keine Feedback-Schleife durch Größenänderung nach dem Umschalten
navEl.classList.remove('section-nav--icons-only');
navEl.style.flexWrap = 'nowrap';
const overflows = navEl.scrollWidth > navEl.clientWidth;
navEl.style.flexWrap = '';
if (overflows) navEl.classList.add('section-nav--icons-only');
}
function inject() {
const main = document.querySelector('.main');
if (!main) { setTimeout(inject, 30); return; }
main.insertBefore(sep, main.firstChild);
main.insertBefore(navEl, sep);
loadDynamic();
// Overflow-Erkennung beim Laden und bei Größenänderung
requestAnimationFrame(checkOverflow);
new ResizeObserver(checkOverflow).observe(navEl);
}
inject();
// ── Dynamische Elemente (analog nav.js) ──────────────────────────────────
function hide(id) { const el = document.getElementById(id); if (el) el.style.display = 'none'; }
function show(id) { const el = document.getElementById(id); if (el) el.style.display = ''; }
function setHref(id, h) { const el = document.getElementById(id); if (el) el.href = h; }
async function loadDynamic() {
try {
const res = await fetch('/login/me');
if (!res.ok) return;
const user = await res.json();
if (!user) return;
// Dating-Link
const datingLink = document.getElementById('snavDatingLink');
if (datingLink) {
datingLink.href = user.datingAktiv
? '/dating/dating.html'
: '/konto/einstellungen.html#sec-dating';
}
// BDSM
if (sectionKey === 'bdsm') {
try {
const r = await fetch('/bdsm/einladung/meine-aktive');
if (r.ok) {
const aktiv = await r.json();
hide('snavBdsmNeu'); hide('snavBdsmImSpiel');
show('snavBdsmAktiv');
setHref('snavBdsmAktiv', aktiv.sessionId ? '/games/bdsm/bdsmingame.html' : '/games/bdsm/neubdsm.html');
} else {
const sr = await fetch(`/bdsm?userId=${user.userId}`);
if (sr.status === 200) { hide('snavBdsmNeu'); show('snavBdsmImSpiel'); }
else show('snavBdsmNeu');
}
} catch (_) { show('snavBdsmNeu'); }
}
// Vanilla
if (sectionKey === 'vanilla') {
try {
const r = await fetch('/vanilla/einladung/meine-aktive');
if (r.ok) {
const aktiv = await r.json();
hide('snavVanillaNeu'); hide('snavVanillaImSpiel');
show('snavVanillaAktiv');
setHref('snavVanillaAktiv', aktiv.sessionId ? '/games/vanilla/vanillaingame.html' : '/games/vanilla/neuvanilla.html');
} else {
const sr = await fetch(`/vanilla?userId=${user.userId}`);
if (sr.status === 200) { hide('snavVanillaNeu'); show('snavVanillaImSpiel'); }
else show('snavVanillaNeu');
}
} catch (_) { show('snavVanillaNeu'); }
}
// Chastity
if (sectionKey === 'chastity') {
try {
const r = await fetch('/keyholder/mylock');
if (r.ok) {
const lock = await r.json();
show('snavChastityAktiv');
setHref('snavChastityAktiv', '/games/chastity/activelock.html?lockId=' + lock.lockId);
}
} catch (_) {}
}
} catch (_) {}
}
})();