Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
251 lines
13 KiB
JavaScript
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 (_) {}
|
|
}
|
|
})();
|