11381138# toggle-feet-btn : hover {
11391139 background-color : rgba (36 , 61 , 51 , 0.9 );
11401140 border-color : var (--color-gold );
1141+ }
1142+ /* ══ SoO-Theme: Blut/Bronze (Schlacht um Orgrimmar) ══ */
1143+
1144+ [data-theme = "soo" ] {
1145+ --color-gold : # d97706 ;
1146+ --color-jade : # ef4444 ;
1147+ --color-parchment : # f5e6d3 ;
1148+ --color-dark-green-bg : rgba (45 , 18 , 18 , 0.92 );
1149+ --color-medium-green-bg : rgba (65 , 30 , 25 , 0.88 );
1150+ --color-dark-text : # 2d0d0d ;
1151+ --color-gold-border : rgba (217 , 119 , 6 , 0.5 );
1152+ --color-gold-border-light : rgba (217 , 119 , 6 , 0.25 );
1153+ }
1154+
1155+ html [data-theme = "soo" ] body {
1156+ background-color : # 180909 !important ;
1157+ }
1158+
1159+ /* Video bei SoO komplett ausblenden */
1160+ html [data-theme = "soo" ] # background-video {
1161+ display : none !important ;
1162+ }
1163+
1164+ /* Video-Toggle-Button bei SoO ausblenden (sinnlos da kein Video) */
1165+ html [data-theme = "soo" ] # toggle-video-btn {
1166+ display : none !important ;
1167+ }
1168+
1169+ /* Nav-Links im SoO-Theme */
1170+ [data-theme = "soo" ] .nav-link {
1171+ background-color : rgba (120 , 40 , 30 , 0.6 ) !important ;
1172+ }
1173+
1174+ [data-theme = "soo" ] .nav-link : hover ,
1175+ [data-theme = "soo" ] .nav-link .active-tab {
1176+ background-color : rgba (180 , 60 , 40 , 0.85 ) !important ;
1177+ }
1178+
1179+ /* Accent-Farben umdrehen */
1180+ [data-theme = "soo" ] .text-blue-450 {
1181+ color : var (--color-gold ) !important ;
1182+ }
1183+
1184+ /* Blaue Button-Farben auf Crimson ändern */
1185+ [data-theme = "soo" ] .bg-blue-600 { background-color : # b91c1c !important ; }
1186+ [data-theme = "soo" ] .bg-blue-700 { background-color : # 991b1b !important ; }
1187+ [data-theme = "soo" ] .hover\:bg-blue-500 : hover { background-color : # dc2626 !important ; }
1188+ [data-theme = "soo" ] .hover\:bg-blue-700 : hover { background-color : # 7f1d1d !important ; }
1189+
1190+ /* Raid-Selector Styling */
1191+ [data-theme = "soo" ] # raid-selector {
1192+ border-color : var (--color-gold-border ) !important ;
1193+ color : var (--color-parchment ) !important ;
11411194}
11421195 </ style >
11431196</ head >
@@ -1325,6 +1378,81 @@ <h3 id="player-edit-modal-title" class="text-xl font-bold text-gold mb-4 border-
13251378const debouncedUpdateSummary = debounce ( ( ) => {
13261379 if ( window . updatePlannerSummary ) window . updatePlannerSummary ( ) ;
13271380} , 500 ) ;
1381+ // ── Raid-ID aus URL-Hash oder sessionStorage extrahieren ──
1382+ function getCurrentRaidId ( ) {
1383+ // 1. URL-Hash hat höchste Priorität (z.B. "#siegeoforgrimmar/immerseus")
1384+ const hash = window . location . hash . substring ( 1 ) ;
1385+ if ( hash ) {
1386+ const pageId = hash . split ( '&' ) [ 0 ] ; // vor & für Sektionen
1387+ // Format: "raidId/bossId" (Boss-Seite) oder nur "pageId" (comp, loot, etc.)
1388+ if ( pageId . includes ( '/' ) ) {
1389+ const raidFromHash = pageId . split ( '/' ) [ 0 ] ;
1390+ // Validieren dass es eine bekannte Raid-ID ist
1391+ if ( window . RAID_THEME_CONFIG && window . RAID_THEME_CONFIG [ raidFromHash ] ) {
1392+ return raidFromHash ;
1393+ }
1394+ // Fallback: Auch wenn kein Theme-Config, Raid-ID akzeptieren
1395+ // (weil das immer noch die richtige Info ist)
1396+ if ( raidFromHash === 'throneofthunder' || raidFromHash === 'siegeoforgrimmar' ) {
1397+ return raidFromHash ;
1398+ }
1399+ }
1400+ }
1401+
1402+ // 2. sessionStorage als Fallback
1403+ const stored = sessionStorage . getItem ( 'lastSelectedRaid' ) ;
1404+ if ( stored ) return stored ;
1405+
1406+ // 3. raid-selector wenn da
1407+ const selector = document . getElementById ( 'raid-selector' ) ;
1408+ if ( selector && selector . value ) return selector . value ;
1409+
1410+ // 4. Default
1411+ return 'throneofthunder' ;
1412+ }
1413+
1414+ // ── Theme anhand aktueller URL/State anwenden ──
1415+ function applyThemeFromContext ( ) {
1416+ const raidId = getCurrentRaidId ( ) ;
1417+ if ( window . applyThemeForRaid ) {
1418+ window . applyThemeForRaid ( raidId ) ;
1419+ }
1420+ }
1421+
1422+ // ── Initial beim Page-Load (möglichst früh) ──
1423+ // Kein Warten auf DOMContentLoaded hier — wir setzen das Attribute
1424+ // direkt auf <html>, das funktioniert auch ohne body.
1425+ ( function immediateThemeInit ( ) {
1426+ try {
1427+ const raidId = getCurrentRaidId ( ) ;
1428+ // RAID_THEME_CONFIG ist evtl. noch nicht da, daher Inline-Mapping
1429+ const isSoo = raidId === 'siegeoforgrimmar' ;
1430+ if ( isSoo ) {
1431+ document . documentElement . setAttribute ( 'data-theme' , 'soo' ) ;
1432+ } else {
1433+ document . documentElement . removeAttribute ( 'data-theme' ) ;
1434+ }
1435+ } catch ( e ) { /* Silent */ }
1436+ } ) ( ) ;
1437+
1438+ // ── Bei hashchange neu anwenden ──
1439+ window . addEventListener ( 'hashchange' , applyThemeFromContext ) ;
1440+
1441+ // ── Bei DOMContentLoaded voll-initialisieren (Banner etc.) ──
1442+ document . addEventListener ( 'DOMContentLoaded' , applyThemeFromContext ) ;
1443+
1444+ // ── Mutation-Observer für dynamisch geladenes Banner ──
1445+ const bannerObserver = new MutationObserver ( ( ) => {
1446+ if ( document . getElementById ( 'raid-main-banner' ) ) {
1447+ applyThemeFromContext ( ) ;
1448+ }
1449+ } ) ;
1450+ // Observer erst nach DOMContentLoaded starten
1451+ document . addEventListener ( 'DOMContentLoaded' , ( ) => {
1452+ if ( document . body ) {
1453+ bannerObserver . observe ( document . body , { childList : true , subtree : true } ) ;
1454+ }
1455+ } ) ;
13281456
13291457function updateAssignmentPools ( ) {
13301458 const pools = { } ;
@@ -3139,13 +3267,13 @@ <h3>Nachricht</h3>
31393267 setDoc ( userStatusRef , { online : true , last_changed : serverTimestamp ( ) } , { merge : true } ) ;
31403268 } ;
31413269 updatePresenceTimestamp ( ) ;
3142- heartbeatIntervalId = setInterval ( updatePresenceTimestamp , 5 * 60 * 1000 ) ;
3270+ heartbeatIntervalId = setInterval ( updatePresenceTimestamp , 15 * 60 * 1000 ) ;
31433271
31443272 onSnapshot ( collection ( db , "presence" ) , snap => {
31453273 const nowInSeconds = Date . now ( ) / 1000 ;
31463274 const onlineUsersCount = snap . docs . filter ( doc => {
31473275 const data = doc . data ( ) ;
3148- return data . online && data . last_changed && ( nowInSeconds - data . last_changed . seconds < 360 ) ;
3276+ return data . online && data . last_changed && ( nowInSeconds - data . last_changed . seconds < 1000 ) ;
31493277 } ) . length ;
31503278 presenceIndicator . innerHTML = `<div class="w-3 h-3 bg-green-400 rounded-full animate-pulse"></div><span>${ onlineUsersCount } </span> Online` ;
31513279 } ) ;
@@ -3356,6 +3484,61 @@ <h3>Nachricht</h3>
33563484 updateVideoState ( ) ;
33573485 } ) ;
33583486 updateVideoState ( ) ;
3487+ // ── Theme-Konfiguration pro Raid ──
3488+ window . RAID_THEME_CONFIG = {
3489+ "throneofthunder" : {
3490+ theme : "mop" , // Standard Jade/Gold
3491+ banner : "static/8d4ce2f0-7e56-444d-a321-4e5c9a26ec20.jpg"
3492+ } ,
3493+ "siegeoforgrimmar" : {
3494+ theme : "soo" , // Blut/Bronze
3495+ banner : "static/banner-soo.jpg"
3496+ }
3497+ // Weitere Raids hier ergänzen — die behalten das Standard-Theme
3498+ } ;
3499+
3500+ // Default-Banner für alle Raids ohne eigene Config
3501+ const DEFAULT_BANNER = "static/8d4ce2f0-7e56-444d-a321-4e5c9a26ec20.jpg" ;
3502+
3503+ window . applyThemeForRaid = function ( raidId ) {
3504+ const cfg = window . RAID_THEME_CONFIG [ raidId ] || { theme : "mop" , banner : DEFAULT_BANNER } ;
3505+
3506+ // 1. CSS-Theme setzen
3507+ if ( cfg . theme === "mop" ) {
3508+ document . documentElement . removeAttribute ( "data-theme" ) ;
3509+ } else {
3510+ document . documentElement . setAttribute ( "data-theme" , cfg . theme ) ;
3511+ }
3512+
3513+ // 2. Banner auf Comp-Seite wechseln
3514+ const bannerImg = document . getElementById ( "raid-main-banner" ) ;
3515+ if ( bannerImg ) {
3516+ const newSrc = cfg . banner || DEFAULT_BANNER ;
3517+ // Fallback wenn Banner nicht existiert
3518+ bannerImg . onerror = ( ) => {
3519+ console . warn ( "[Theme] Banner nicht gefunden, Fallback:" , newSrc ) ;
3520+ bannerImg . src = DEFAULT_BANNER ;
3521+ bannerImg . onerror = null ;
3522+ } ;
3523+ // Nur aktualisieren wenn sich die Quelle wirklich ändert
3524+ if ( ! bannerImg . src . endsWith ( newSrc ) && ! bannerImg . src . endsWith ( newSrc . replace ( "static/" , "" ) ) ) {
3525+ bannerImg . src = newSrc ;
3526+ }
3527+ }
3528+
3529+ // 3. Hintergrundvideo steuern (CSS versteckt es, aber wir pausieren es auch)
3530+ const video = document . getElementById ( "background-video" ) ;
3531+ if ( video ) {
3532+ if ( cfg . theme === "soo" ) {
3533+ video . pause ( ) ;
3534+ } else {
3535+ const videoState = localStorage . getItem ( 'backgroundVideoState' ) || 'on' ;
3536+ if ( videoState === 'on' ) {
3537+ video . play ( ) . catch ( ( ) => { } ) ;
3538+ }
3539+ }
3540+ }
3541+ } ;
33593542 raidSelector . addEventListener ( 'change' , async ( e ) => {
33603543 const newRaidId = e . target . value ;
33613544
@@ -3365,6 +3548,7 @@ <h3>Nachricht</h3>
33653548
33663549 console . log ( "Raid gewechselt auf:" , newRaidId ) ;
33673550 updateBossNav ( newRaidId ) ;
3551+ window . applyThemeForRaid ( newRaidId ) ;
33683552 // 2. Setup Grid neu initialisieren (Wichtig für Import!)
33693553 // Wir prüfen, ob wir auf der Comp-Seite sind, und erzwingen ein Neuladen
33703554 if ( window . location . hash === '#comp' || window . location . hash === '' ) {
@@ -7463,6 +7647,7 @@ <h3 class="text-xl font-bold text-emerald-400 tracking-wide font-serif flex item
74637647 } ;
74647648 } ) ;
74657649} ;
7650+
74667651 </ script >
74677652< button id ="toggle-video-btn " title ="Hintergrundvideo an/aus " class ="fixed bottom-4 right-4 z-50 ">
74687653 < i class ="fas fa-video "> </ i >
0 commit comments