import Foundation enum RedditThemeStyle { static func earlyInjectionScript(isDarkMode: Bool) -> String { """ (function() { const wantDark = \(isDarkMode ? "true" : "false"); window.__reddoraTheme = { wantsDark: wantDark }; const installMatchMediaOverride = (wantsDark) => { if (window.__reddoraTheme.matchMediaInstalled) return; const original = window.matchMedia.bind(window); window.matchMedia = function(query) { const result = original(query); if (typeof query === 'string' && query.includes('prefers-color-scheme')) { const matches = query.includes('dark') ? wantsDark : !wantsDark; return { matches, media: query, onchange: null, addEventListener: (...args) => result.addEventListener(...args), removeEventListener: (...args) => result.removeEventListener(...args), dispatchEvent: (...args) => result.dispatchEvent(...args), }; } return result; }; window.__reddoraTheme.matchMediaInstalled = true; }; installMatchMediaOverride(wantDark); })(); """ } static func syncScript(isDarkMode: Bool) -> String { """ (function() { const wantDark = \(isDarkMode ? "true" : "false"); window.__reddoraTheme = window.__reddoraTheme || {}; window.__reddoraTheme.wantsDark = wantDark; const installMatchMediaOverride = (wantsDark) => { const original = window.matchMedia.bind(window); window.matchMedia = function(query) { const result = original(query); if (typeof query === 'string' && query.includes('prefers-color-scheme')) { const matches = query.includes('dark') ? wantsDark : !wantsDark; return { matches, media: query, onchange: null, addEventListener: (...args) => result.addEventListener(...args), removeEventListener: (...args) => result.removeEventListener(...args), dispatchEvent: (...args) => result.dispatchEvent(...args), }; } return result; }; window.__reddoraTheme.matchMediaInstalled = true; }; installMatchMediaOverride(wantDark); const isDrawerHidden = (element) => !element || (element.offsetWidth === 0 && element.offsetHeight === 0); const isRedditDarkModeActive = () => { const header = document.querySelector('header'); const themedNode = header?.firstElementChild; if (themedNode) { const background = getComputedStyle(themedNode) .getPropertyValue('--shreddit-content-background') .trim() .toLowerCase(); if (background === '#0e1113' || background === '#1a1a1b') return true; if (background === '#ffffff' || background === '#fff') return false; } const root = document.documentElement; if (root.classList.contains('theme-dark')) return true; if (root.classList.contains('theme-light')) return false; return window.matchMedia('(prefers-color-scheme: dark)').matches; }; const toggleViaDrawer = () => { const drawerButton = document.querySelector('#expand-user-drawer-button'); const drawer = document.querySelector('#user-drawer-content'); const switchInput = document.querySelector( '#darkmode-list-item faceplate-switch-input[name="darkmode-switch-name"]' ); if (!drawerButton || !drawer || !switchInput) return false; const drawerWasHidden = isDrawerHidden(drawer); if (drawerWasHidden) drawerButton.click(); const isChecked = switchInput.checked === true || switchInput.getAttribute('checked') !== null || switchInput.getAttribute('aria-checked') === 'true'; if (isChecked !== wantDark) { switchInput.click(); } if (drawerWasHidden) { setTimeout(() => { if (!isDrawerHidden(drawer)) drawerButton.click(); }, 250); } return true; }; const syncViaAPI = async () => { try { const response = await fetch('/api/v1/me/prefs', { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ nightmode: wantDark }), }); return response.ok; } catch { return false; } }; const run = async () => { const current = isRedditDarkModeActive(); if (current === wantDark) return; if (toggleViaDrawer()) return; const updated = await syncViaAPI(); if (updated) { window.location.reload(); } }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => run(), { once: true }); } else { run(); } })(); """ } }