From 942da4b6a53ec9e062b16aa19e41a170dc4cdac3 Mon Sep 17 00:00:00 2001 From: King Omar Date: Sun, 12 Jul 2026 16:50:24 +1000 Subject: [PATCH] Add light/dark theme toggle to all pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Flash-prevention script in reads radical_theme from localStorage and sets data-theme on before first paint — no FOUC - Fixed ☀️/🌙 button (top-right, z-index 9999) on index, admin, and login using CSS ::before so the icon is driven by data-theme with no JS initialization - Light mode: #F5F3EF warm off-white body, #E8E6E2 cards, #CCC borders, #111 text - Pink accent (#ff0099) unchanged in both modes - Signed-in users: theme saved to radical_user localStorage object and applied on load so preference follows their session Co-Authored-By: Claude Sonnet 4.6 --- admin.html | 34 +++++++++++++++++++++++++++ index.html | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ login.html | 34 +++++++++++++++++++++++++++ styles.css | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 202 insertions(+) diff --git a/admin.html b/admin.html index 4b34715..b5b0214 100644 --- a/admin.html +++ b/admin.html @@ -105,9 +105,37 @@ body{font-family:'Roboto Mono',monospace;background:var(--bg);color:var(--text); .recent-time{font-size:11px;color:var(--muted);white-space:nowrap} .loading{text-align:center;padding:40px;color:var(--muted)} +/* ── Theme toggle ── */ +#theme-toggle{position:fixed;top:14px;right:14px;z-index:9999;background:rgba(0,0,0,.55);border:1px solid #444;border-radius:50%;width:38px;height:38px;font-size:0;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .2s,border-color .2s;padding:0} +#theme-toggle::before{content:"☀️";font-size:17px;line-height:1} +#theme-toggle:hover{background:rgba(255,0,153,.18);border-color:#ff0099} +/* ── Light mode ── */ +html[data-theme="light"]{--bg:#F5F3EF;--card:#E8E6E2;--border:#CCCCCC;--text:#333;--muted:#777} +html[data-theme="light"] body{background:var(--bg);color:var(--text)} +html[data-theme="light"] #theme-toggle{background:rgba(245,243,239,.88);border-color:#BBB} +html[data-theme="light"] #theme-toggle::before{content:"🌙"} +html[data-theme="light"] #theme-toggle:hover{background:rgba(255,0,153,.1);border-color:#ff0099} +html[data-theme="light"] .top-bar{background:#E0DED9} +html[data-theme="light"] .stat-value{color:#111} +html[data-theme="light"] .aec-track{background:#CCC} +html[data-theme="light"] .state-track{background:#CCC} +html[data-theme="light"] .data-table th{background:#DDD;color:#555} +html[data-theme="light"] .data-table td{border-bottom-color:#DDD} +html[data-theme="light"] .data-table tr:hover td{background:#DEDAD6} +html[data-theme="light"] .data-table .name-cell{color:#111} +html[data-theme="light"] #pw-input{background:#FFF;color:#111;border-color:#CCC} +html[data-theme="light"] .search-box{background:#FFF;color:#111;border-color:#CCC} +html[data-theme="light"] .state-filter{background:#FFF;color:#111;border-color:#CCC} +html[data-theme="light"] .petition-row{border-bottom-color:#DDD} +html[data-theme="light"] .petition-row:hover{background:#DEDAD6} +html[data-theme="light"] .recent-row{border-bottom-color:#DDD} +html[data-theme="light"] .recent-row:hover{background:#DEDAD6} +html[data-theme="light"] .recent-name{color:#111} + +
@@ -394,6 +422,12 @@ function fmtDate(ts) { function esc(s) { return String(s).replace(/&/g,'&').replace(//g,'>'); } + +function toggleTheme() { + const next = document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light'; + document.documentElement.setAttribute('data-theme', next); + try { localStorage.setItem('radical_theme', next); } catch(e) {} +} diff --git a/index.html b/index.html index e1bd50e..568ebe0 100644 --- a/index.html +++ b/index.html @@ -250,6 +250,59 @@ .postcode-badge span{color:#ff0099} /* ── Inline milestone strip on proposal cards ── */ .card-milestone{margin-top:8px} +/* ── LIGHT MODE: index.html-specific overrides ── */ +html[data-theme="light"] .stats-bar{background:#E8E6E2;border-color:#CCC;color:#555} +html[data-theme="light"] .stat-divider{color:#BBB} +html[data-theme="light"] .leaderboard-section{border-color:#ff0099} +html[data-theme="light"] .leaderboard-item{border-bottom-color:#DDD} +html[data-theme="light"] .leaderboard-item:hover{background:#DEDAD6} +html[data-theme="light"] .leaderboard-text{color:#111} +html[data-theme="light"] .leaderboard-rank{color:#777} +html[data-theme="light"] .leaderboard-postcode{color:#777} +html[data-theme="light"] .milestone-bar-track{background:#CCC} +html[data-theme="light"] .milestone-label{color:#666} +html[data-theme="light"] .membership-modal-overlay{background:rgba(0,0,0,.55)} +html[data-theme="light"] .membership-modal{background:#F5F3EF} +html[data-theme="light"] .membership-modal-intro{color:#555} +html[data-theme="light"] .mm-input{background:#FFF;border-color:#CCC;color:#111} +html[data-theme="light"] .mm-input option{background:#FFF;color:#111} +html[data-theme="light"] .mm-field label{color:#555} +html[data-theme="light"] .mm-check label{color:#555} +html[data-theme="light"] .mm-later{color:#777} +html[data-theme="light"] .mm-later:hover{color:#444} +html[data-theme="light"] .email-modal-overlay{background:rgba(0,0,0,.55)} +html[data-theme="light"] .email-modal{background:#F5F3EF} +html[data-theme="light"] .email-modal p{color:#555} +html[data-theme="light"] .email-modal-input{background:#FFF;border-color:#CCC;color:#111} +html[data-theme="light"] .email-modal-skip{color:#777} +html[data-theme="light"] .email-modal-skip:hover{color:#333} +html[data-theme="light"] .constitution-section{background:#EBEBEA;border-color:#CCC} +html[data-theme="light"] .constitution-header{background:#E0DED9} +html[data-theme="light"] .constitution-header:hover{background:#D8D6D2} +html[data-theme="light"] .constitution-title{color:#111} +html[data-theme="light"] .constitution-meta{color:#777} +html[data-theme="light"] .constitution-body{background:#F5F3EF} +html[data-theme="light"] .constitution-draft-notice{background:#FFF8EE;border-color:#E8CFA0;color:#555} +html[data-theme="light"] .constitution-adopted{color:#777} +html[data-theme="light"] .const-section{border-bottom-color:#DDD} +html[data-theme="light"] .const-clause{color:#333} +html[data-theme="light"] .const-clause strong{color:#111} +html[data-theme="light"] .const-clause em{color:#555} +html[data-theme="light"] .const-sub{color:#555} +html[data-theme="light"] .const-end{color:#777;border-top-color:#DDD} +html[data-theme="light"] .about-section{background:#EBEBEA;border-color:#CCC} +html[data-theme="light"] .about-body{color:#333} +html[data-theme="light"] .about-body strong{color:#111} +html[data-theme="light"] .about-lead{color:#222} +html[data-theme="light"] .about-divider{border-top-color:#DDD} +html[data-theme="light"] .about-switzerland{background:#E0DED9;border-color:#CCC} +html[data-theme="light"] .about-swiss-heading{color:#111} +html[data-theme="light"] .about-step{background:#E0DED9} +html[data-theme="light"] .about-footer-note{color:#777;border-top-color:#DDD} +html[data-theme="light"] .join-input{background:#FFF;border-color:#CCC;color:#111} +html[data-theme="light"] .join-input option{background:#FFF;color:#111} +html[data-theme="light"] .join-field label{color:#555} +html[data-theme="light"] .join-check label{color:#555} @@ -332,8 +385,10 @@ } + +

RADICAL

@@ -765,9 +820,23 @@ function getMediaURL(path) { }); // Initialize application + function applyTheme(t) { + document.documentElement.setAttribute('data-theme', t); + try { localStorage.setItem('radical_theme', t); } catch(e) {} +} +function toggleTheme() { + const next = document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light'; + applyTheme(next); + if (typeof currentUser !== 'undefined' && currentUser?.id) { + currentUser.theme = next; + try { localStorage.setItem('radical_user', JSON.stringify(currentUser)); } catch(e) {} + } +} + async function initializeApp() { updateUIText(); await loadUserData(); + if (currentUser?.theme) applyTheme(currentUser.theme); loadVerifiedUsers(); setupEventListeners(); await Promise.allSettled([fetchProposals(), fetchLeaderboard(), fetchStats()]); diff --git a/login.html b/login.html index d47c82f..440736d 100644 --- a/login.html +++ b/login.html @@ -583,9 +583,37 @@ color: #444; line-height: 1.5; } + + /* ── Theme toggle ── */ + #theme-toggle{position:fixed;top:14px;right:14px;z-index:9999;background:rgba(0,0,0,.55);border:1px solid #444;border-radius:50%;width:38px;height:38px;font-size:0;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .2s,border-color .2s;padding:0} + #theme-toggle::before{content:"☀️";font-size:17px;line-height:1} + #theme-toggle:hover{background:rgba(255,0,153,.18);border-color:#ff0099} + /* ── Light mode ── */ + html[data-theme="light"]{--light:#111;--border:#CCC;--dark:#F5F3EF} + html[data-theme="light"] body{background:#F5F3EF;color:#111} + html[data-theme="light"] #theme-toggle{background:rgba(245,243,239,.88);border-color:#BBB} + html[data-theme="light"] #theme-toggle::before{content:"🌙"} + html[data-theme="light"] #theme-toggle:hover{background:rgba(255,0,153,.1);border-color:#ff0099} + html[data-theme="light"] .login-container{background-color:rgba(235,234,232,0.92)} + html[data-theme="light"] .emoji-grid{background-color:rgba(255,255,255,0.9)} + html[data-theme="light"] .emoji-item:hover{background-color:rgba(0,0,0,.06)} + html[data-theme="light"] .dictator-card{background-color:rgba(255,255,255,0.7)} + html[data-theme="light"] .target-card{background-color:rgba(255,255,255,0.7)} + html[data-theme="light"] .target-card:hover{background-color:rgba(235,234,232,0.9)} + html[data-theme="light"] .target-card.selected{background-color:rgba(255,0,153,.08)} + html[data-theme="light"] .search-input{background-color:rgba(255,255,255,0.9);color:#111} + html[data-theme="light"] .how-it-works{background:#EBEBEA;border-color:#CCC} + html[data-theme="light"] .hiw-step{color:#555} + html[data-theme="light"] .hiw-step strong{color:#111} + html[data-theme="light"] .anon-option{background:#EBEBEA;border-color:#CCC} + html[data-theme="light"] .anon-note{color:#777} + html[data-theme="light"] .tagline{color:#333} + html[data-theme="light"] .tooltip{background-color:rgba(245,243,239,0.97);color:#111} + +

RADICAL

@@ -1349,6 +1377,12 @@ function attemptLogin() { setTimeout(() => { window.location.href = '/'; }, 2500); }, 1000); } + + function toggleTheme() { + const next = document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light'; + document.documentElement.setAttribute('data-theme', next); + try { localStorage.setItem('radical_theme', next); } catch(e) {} + } \ No newline at end of file diff --git a/styles.css b/styles.css index 6e13c10..d0fe7ca 100644 --- a/styles.css +++ b/styles.css @@ -1219,3 +1219,68 @@ a { } } + +/* ─── THEME TOGGLE BUTTON ──────────────────────────────────────────────── */ +#theme-toggle { + position: fixed; + top: 14px; + right: 14px; + z-index: 9999; + background: rgba(0,0,0,0.55); + border: 1px solid #444; + border-radius: 50%; + width: 38px; + height: 38px; + font-size: 0; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background .2s, border-color .2s; + padding: 0; +} +#theme-toggle::before { + content: "☀️"; + font-size: 17px; + line-height: 1; +} +#theme-toggle:hover { + background: rgba(255,0,153,0.18); + border-color: #ff0099; +} + +/* ─── LIGHT MODE ───────────────────────────────────────────────────────── */ +html[data-theme="light"] { + --secondary: #111111; + --darker: #E8E6E2; + --light: #111111; + --border: #CCCCCC; + --text: #111111; + --text-muted: #666666; + --card-bg: rgba(235,234,232,0.9); +} +html[data-theme="light"] body { background-color: #F5F3EF; } +html[data-theme="light"] #theme-toggle { background: rgba(245,243,239,0.88); border-color: #BBB; } +html[data-theme="light"] #theme-toggle::before { content: "🌙"; } +html[data-theme="light"] #theme-toggle:hover { background: rgba(255,0,153,0.1); border-color: #ff0099; } +html[data-theme="light"] .proposal-input { background-color: #FFFFFF; box-shadow: inset 0 0 5px rgba(0,0,0,.06); } +html[data-theme="light"] .sort-select { background-color: #FFFFFF; } +html[data-theme="light"] .form-input { background-color: #FFFFFF; } +html[data-theme="light"] .share-link-field { background-color: #FFFFFF; } +html[data-theme="light"] .comment-input { background-color: #FFFFFF; } +html[data-theme="light"] .meme-upload { background-color: rgba(255,255,255,.5); } +html[data-theme="light"] .meme-upload-label { background-color: #FFFFFF; } +html[data-theme="light"] .meme-preview { background-color: #FFFFFF; } +html[data-theme="light"] .proposal-meme { background-color: rgba(255,255,255,.4); } +html[data-theme="light"] .meme-remove { background-color: rgba(255,255,255,.9); color: #111; } +html[data-theme="light"] .meme-remove:hover { background-color: #ff0099; color: #000; } +html[data-theme="light"] .modal-overlay { background-color: rgba(0,0,0,.55); } +html[data-theme="light"] .modal-container { background: #EBEBEA; } +html[data-theme="light"] .post-button:disabled { background-color: #CCC; color: #999; } +html[data-theme="light"] .petition-submit-btn:disabled { background-color: #CCC; color: #999; } +html[data-theme="light"] .comment-submit:disabled { background-color: #CCC; color: #999; } +html[data-theme="light"] .comment-item { border-bottom-color: #DDD; } +html[data-theme="light"] .social-share-button { background-color: #FFFFFF; } +html[data-theme="light"] .share-button { background: #FFFFFF; } +html[data-theme="light"] .music-controls { background: rgba(235,234,232,.95); } +html[data-theme="light"] .trending-badge { background-color: #333; color: #F5F3EF; }