From 72f2d281f32a43edd3eadcc3553dcfe8e5d4b498 Mon Sep 17 00:00:00 2001
From: Michael Long <mlong@bizjournals.com>
Date: Sun, 3 Jan 2021 21:57:10 -0500
Subject: [PATCH] dark mode for webv4

---
 webv4/components/navbar.xjs |  13 ++-
 webv4/root/css/checkbox.css | 188 ++++++++++++++++++++++++++++++++++++
 webv4/root/css/style.css    | 114 +++++++++++++++++++++-
 webv4/root/index.xjs        |   2 +-
 webv4/root/js/common.js     |  28 ++++++
 5 files changed, 342 insertions(+), 3 deletions(-)
 create mode 100644 webv4/root/css/checkbox.css

diff --git a/webv4/components/navbar.xjs b/webv4/components/navbar.xjs
index 42bf5de0cb..149a76ef0a 100644
--- a/webv4/components/navbar.xjs
+++ b/webv4/components/navbar.xjs
@@ -47,8 +47,19 @@
             <ul class="nav navbar-nav">
                 <?xjs menu(getPageList(settings.web_pages)); ?>
             </ul>
+
             <ul class="nav navbar-nav navbar-right">
-                <?xjs if (user.alias === settings.guest || user.number < 1) { ?>
+				<li class="nav-item dark-switch">
+					<div class="form-group">
+						<div class="checkbox checbox-switch darkswitchbox">
+							<label>
+								<input type="checkbox" id="darkSwitch" />Dark
+								<span></span>
+							</label>
+              			</div>
+              		</div>
+            	</li>
+            	<?xjs if (user.alias === settings.guest || user.number < 1) { ?>
                     <?xjs if (settings.user_registration) { ?>
                         <li>
                             <a href="./?page=000-register.xjs"><? write(locale.strings.main.menu_item_register); ?></a>
diff --git a/webv4/root/css/checkbox.css b/webv4/root/css/checkbox.css
new file mode 100644
index 0000000000..a19ff70842
--- /dev/null
+++ b/webv4/root/css/checkbox.css
@@ -0,0 +1,188 @@
+/* ---------------------------------------------------
+
+Project : CSS Checkbox Switch
+Author : Partha Kar (https://www.facebook.com/partha.creativemind)
+Version : 1.0
+Release Dtae : 15 November, 2017
+
+---------------------------------------------------- */
+
+
+.checkbox.checbox-switch {
+    padding-left: 0;
+}
+
+.checkbox.checbox-switch label,
+.checkbox-inline.checbox-switch {
+    display: inline-block;
+    position: relative;
+    padding-left: 0;
+}
+.checkbox.checbox-switch label input,
+.checkbox-inline.checbox-switch input {
+    display: none;
+}
+.checkbox.checbox-switch label span,
+.checkbox-inline.checbox-switch span {
+    width: 35px;
+    border-radius: 20px;
+    height: 18px;
+    border: 1px solid #dbdbdb;
+    background-color: rgb(255, 255, 255);
+    border-color: rgb(223, 223, 223);
+    box-shadow: rgb(223, 223, 223) 0px 0px 0px 0px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s;
+    display: inline-block;
+    vertical-align: middle;
+    margin-right: 5px;
+}
+.checkbox.checbox-switch label span:before,
+.checkbox-inline.checbox-switch span:before {
+    display: inline-block;
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    background: rgb(255,255,255);
+    content: " ";
+    top: 0;
+    position: relative;
+    left: 0;
+    transition: all 0.3s ease;
+    box-shadow: 0 1px 4px rgba(0,0,0,0.4);
+}
+.checkbox.checbox-switch label > input:checked + span:before,
+.checkbox-inline.checbox-switch > input:checked + span:before {
+    left: 17px;
+}
+
+
+/* Switch Default */
+.checkbox.checbox-switch label > input:checked + span,
+.checkbox-inline.checbox-switch > input:checked + span {
+    background-color: rgb(180, 182, 183);
+    border-color: rgb(180, 182, 183);
+    box-shadow: rgb(180, 182, 183) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+.checkbox.checbox-switch label > input:checked:disabled + span,
+.checkbox-inline.checbox-switch > input:checked:disabled + span {
+    background-color: rgb(220, 220, 220);
+    border-color: rgb(220, 220, 220);
+    box-shadow: rgb(220, 220, 220) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+.checkbox.checbox-switch label > input:disabled + span,
+.checkbox-inline.checbox-switch > input:disabled + span {
+    background-color: rgb(232,235,238);
+    border-color: rgb(255,255,255);
+}
+.checkbox.checbox-switch label > input:disabled + span:before,
+.checkbox-inline.checbox-switch > input:disabled + span:before {
+    background-color: rgb(248,249,250);
+    border-color: rgb(243, 243, 243);
+    box-shadow: 0 1px 4px rgba(0,0,0,0.1);
+}
+
+/* Switch Light */
+.checkbox.checbox-switch.switch-light label > input:checked + span,
+.checkbox-inline.checbox-switch.switch-light > input:checked + span {
+    background-color: rgb(248,249,250);
+    border-color: rgb(248,249,250);
+    box-shadow: rgb(248,249,250) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+
+/* Switch Dark */
+.checkbox.checbox-switch.switch-dark label > input:checked + span,
+.checkbox-inline.checbox-switch.switch-dark > input:checked + span {
+    background-color: rgb(52,58,64);
+    border-color: rgb(52,58,64);
+    box-shadow: rgb(52,58,64) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+.checkbox.checbox-switch.switch-dark label > input:checked:disabled + span,
+.checkbox-inline.checbox-switch.switch-dark > input:checked:disabled + span {
+    background-color: rgb(100, 102, 104);
+    border-color: rgb(100, 102, 104);
+    box-shadow: rgb(100, 102, 104) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+
+/* Switch Success */
+.checkbox.checbox-switch.switch-success label > input:checked + span,
+.checkbox-inline.checbox-switch.switch-success > input:checked + span {
+    background-color: rgb(40, 167, 69);
+    border-color: rgb(40, 167, 69);
+    box-shadow: rgb(40, 167, 69) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+.checkbox.checbox-switch.switch-success label > input:checked:disabled + span,
+.checkbox-inline.checbox-switch.switch-success > input:checked:disabled + span {
+    background-color: rgb(153, 217, 168);
+    border-color: rgb(153, 217, 168);
+    box-shadow: rgb(153, 217, 168) 0px 0px 0px 8px inset;
+}
+
+/* Switch Danger */
+.checkbox.checbox-switch.switch-danger label > input:checked + span,
+.checkbox-inline.checbox-switch.switch-danger > input:checked + span {
+    background-color: rgb(200, 35, 51);
+    border-color: rgb(200, 35, 51);
+    box-shadow: rgb(200, 35, 51) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+.checkbox.checbox-switch.switch-danger label > input:checked:disabled + span,
+.checkbox-inline.checbox-switch.switch-danger > input:checked:disabled + span {
+    background-color: rgb(216, 119, 129);
+    border-color: rgb(216, 119, 129);
+    box-shadow: rgb(216, 119, 129) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+
+/* Switch Primary */
+.checkbox.checbox-switch.switch-primary label > input:checked + span,
+.checkbox-inline.checbox-switch.switch-primary > input:checked + span {
+    background-color: rgb(0, 105, 217);
+    border-color: rgb(0, 105, 217);
+    box-shadow: rgb(0, 105, 217) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+.checkbox.checbox-switch.switch-primary label > input:checked:disabled + span,
+.checkbox-inline.checbox-switch.switch-primary > input:checked:disabled + span {
+    background-color: rgb(109, 163, 221);
+    border-color: rgb(109, 163, 221);
+    box-shadow: rgb(109, 163, 221) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+
+/* Switch Info */
+.checkbox.checbox-switch.switch-info label > input:checked + span,
+.checkbox-inline.checbox-switch.switch-info > input:checked + span {
+    background-color: rgb(23, 162, 184);
+    border-color: rgb(23, 162, 184);
+    box-shadow: rgb(23, 162, 184) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+.checkbox.checbox-switch.switch-info label > input:checked:disabled + span,
+.checkbox-inline.checbox-switch.switch-info > input:checked:disabled + span {
+    background-color: rgb(102, 192, 206);
+    border-color: rgb(102, 192, 206);
+    box-shadow: rgb(102, 192, 206) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+
+/* Switch Warning */
+.checkbox.checbox-switch.switch-warning label > input:checked + span,
+.checkbox-inline.checbox-switch.switch-warning > input:checked + span {
+    background-color: rgb(255, 193, 7);
+    border-color: rgb(255, 193, 7);
+    box-shadow: rgb(255, 193, 7) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
+.checkbox.checbox-switch.switch-warning label > input:checked:disabled + span,
+.checkbox-inline.checbox-switch.switch-warning > input:checked:disabled + span {
+    background-color: rgb(226, 195, 102);
+    border-color: rgb(226, 195, 102);
+    box-shadow: rgb(226, 195, 102) 0px 0px 0px 8px inset;
+    transition: border 0.4s ease 0s, box-shadow 0.4s ease 0s, background-color 1.2s ease 0s;
+}
diff --git a/webv4/root/css/style.css b/webv4/root/css/style.css
index 7e49bcf0b1..9e5b47ed76 100644
--- a/webv4/root/css/style.css
+++ b/webv4/root/css/style.css
@@ -53,7 +53,72 @@ span.message-header.unread {
 	background-color: #FCF8E3;
 }
 
-/*	You probably don't need to mess with rules below this line. */
+/*** Dark mode ***/
+
+/* default links, like the breadcrumbs */
+.dark a {
+	color: #75b8f1;
+}
+
+/* background of the top bar */
+.dark .navbar {
+	background-color: #333;
+}
+
+/* bbs name at top left */
+.dark .navbar-brand {
+	color: #ccc;
+}
+.dark .navbar-brand:hover {
+	color: #fff;
+}
+
+/* hover for the top nav buttons */
+.dark .navbar-default a:hover {
+	color: #8cc1ee !important;
+	color: #fff;
+	background-color: #444 !important;
+}
+
+/* the active top nav button when opened */
+.dark .navbar-default .navbar-nav>.open>a,
+.dark.navbar-default .navbar-nav>.open>a:focus,
+.dark.navbar-default .navbar-nav>.open>a:hover {
+	background-color: #555;
+	color: #EEE;
+}
+
+/* dropdown menus */
+.dark .dropdown-menu {
+	background-color: #333;
+}
+.dark .dropdown-menu li a {
+	color: #75b8f1;
+}
+
+/* background color of alternate rows in lists */
+.dark .striped:nth-of-type(even), .dark .table-striped > tbody > tr:nth-child(odd) > td, .dark  .table-striped > tbody > tr:nth-child(odd) > th {
+	background: #777;
+}
+
+/* this is the text and color for most items, including non-alternating rows */
+.dark .list-group-item {
+	background-color: #555;
+	color: #CCC;
+}
+
+/* A link in a list when the mouse is hovering over it (mostly applies to the Forum) */
+.dark a.list-group-item:hover, .dark  a.list-group-item:active, .dark  li.list-group-item.mail:hover {
+	background-color: #888;
+	color: #222;
+}
+
+/* background color for the breadcrumb box */
+.dark .breadcrumb {
+	background-color: #555;
+}
+
+/*** You probably don't need to mess with rules below this line. ***/
 
 blockquote {
 	margin: .5em;
@@ -180,3 +245,50 @@ animation: indicator-fade 3s ease 0s 1 alternate !important;
 .breadcrumb li {
 	display: inline;
 }
+
+.dark {
+	background-color: #222 !important;
+	color: #eee;
+}
+
+.dark span.badge.ignored {
+	background-color: #aaa;
+}
+
+.dark .text-danger {
+	color: #ef1c18;
+}
+
+.dark .text-success {
+	color: #3eef41;
+}
+
+.dark a.btn, .dark .icon {
+	color: #000;
+	background-color: #ddd !important;
+}
+
+.dark a.btn :hover, .dark .icon:hover {
+	color: #000;
+	background-color: #fff !important;
+}
+
+@media (max-width: 767px) {
+	.dark-switch {
+		padding: 10px 15px;
+	}
+}
+
+@media (min-width: 768px) {
+	.dark-switch {
+		padding: 0px;
+	}
+}
+
+.darkswitchbox {
+	margin-block-start: 1em;
+	margin-block-end: 1em;
+	margin-inline-start: 0px;
+	margin-inline-end: 0px;
+	padding-inline-start: 40px;
+}
diff --git a/webv4/root/index.xjs b/webv4/root/index.xjs
index 477b77f418..08fe3fa1bc 100644
--- a/webv4/root/index.xjs
+++ b/webv4/root/index.xjs
@@ -49,6 +49,7 @@
 		<link href="./bootstrap/css/bootstrap.min.css" rel="stylesheet">
 		<link href="./css/offcanvas.css" rel="stylesheet">
 		<link href="./css/style.css" rel="stylesheet">
+		<link href="./css/checkbox.css" rel="stylesheet">
 		<? if (file_exists(settings.web_root + 'css/custom.css')) { ?>
 			<link href="./css/custom.css" rel="stylesheet">
 		<? } ?>
@@ -101,7 +102,6 @@
     			return false;
 			});
 		</script>
-
 	</body>
 
 </html>
diff --git a/webv4/root/js/common.js b/webv4/root/js/common.js
index b922962687..dbe189a38f 100644
--- a/webv4/root/js/common.js
+++ b/webv4/root/js/common.js
@@ -139,4 +139,32 @@ window.onload =	function () {
         es.addEventListener(e, _sbbs_events[e].callback);
     });
 
+	// originally based on dark-mode-switch by Christian Oliff
+	var darkSwitch = document.getElementById("darkSwitch");
+	if (darkSwitch) {
+		initTheme();
+		darkSwitch.addEventListener("change", function(event) {
+			resetTheme();
+		});
+		function initTheme() {
+			var darkThemeSelected =
+				localStorage.getItem("darkSwitch") !== null &&
+				localStorage.getItem("darkSwitch") === "dark";
+			darkSwitch.checked = darkThemeSelected;
+			if (darkThemeSelected) {
+				jQuery("body").addClass("dark")
+			} else {
+				jQuery("body").removeClass("dark");
+			}
+		}
+		function resetTheme() {
+			if (darkSwitch.checked) {
+				jQuery("body").addClass("dark");
+				localStorage.setItem("darkSwitch", "dark");
+			} else {
+				jQuery("body").removeClass("dark");
+				localStorage.removeItem("darkSwitch");
+			}
+		}
+	}
 }
-- 
GitLab