diff --git a/ctrl/modopts.ini b/ctrl/modopts.ini index e70b2a5f693eee9d2428faa6438a97750bedc628..efa0d44398c07b3c5d6f26d413ab4a3baec13836 100644 --- a/ctrl/modopts.ini +++ b/ctrl/modopts.ini @@ -177,3 +177,5 @@ forum_extended_ascii=false max_messages=0 nodelist_ibbs = true + darkmode_off=false + diff --git a/webv4/components/navbar.xjs b/webv4/components/navbar.xjs index 42bf5de0cb92fc5fc7017b46d7d364960f5728d2..63fc1bedbb306c82d9fba40bb343ca503c598671 100644 --- a/webv4/components/navbar.xjs +++ b/webv4/components/navbar.xjs @@ -47,8 +47,21 @@ <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) { ?> +<?xjs if (!settings.darkmode_off) { ?> + <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 } ?> + <?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/pages/000-home.xjs b/webv4/pages/000-home.xjs index 32b5353df82af16356ee2a36e23572ad651df34b..53b5280a04a8689c95a03eb1d49c4fff1d80604e 100644 --- a/webv4/pages/000-home.xjs +++ b/webv4/pages/000-home.xjs @@ -20,30 +20,32 @@ <script id="fTelnetScript" src="<?xjs write(get_url()); ?>"></script> <script> - var wsp = <?xjs write(settings.wsp || GetWebSocketServicePort()); ?>; - var wssp = <?xjs write(settings.wssp || GetWebSocketServicePort(true)); ?>; - var Options = new fTelnetOptions(); - Options.BareLFtoCRLF = false; - Options.BitsPerSecond = 57600; - Options.ButtonBarVisible = true; - Options.ConnectionType = 'telnet'; - Options.Emulation = 'ansi-bbs'; - Options.Enter = '\r'; - Options.Font = 'CP437'; - Options.ForceWss = false; - Options.Hostname = '<?xjs write(http_request.vhost); ?>'; - Options.LocalEcho = false; - Options.Port = location.protocol == 'https:' ? wssp : wsp; - Options.ScreenColumns = 80; - Options.ScreenRows = 25; - Options.SplashScreen = '<?xjs write(get_splash()); ?>'; - var fTelnet = new fTelnetClient('fTelnetContainer', Options); - fTelnet.ButtonBarVisible = true; - if ($('#ftelnet-connect').length) { - $('#ftelnet-connect').click(function() { - fTelnet.Connect(); - }); - } + window.addEventListener('load', (event) => { + var wsp = <?xjs write(settings.wsp || GetWebSocketServicePort()); ?>; + var wssp = <?xjs write(settings.wssp || GetWebSocketServicePort(true)); ?>; + var Options = new fTelnetOptions(); + Options.BareLFtoCRLF = false; + Options.BitsPerSecond = 57600; + Options.ButtonBarVisible = true; + Options.ConnectionType = 'telnet'; + Options.Emulation = 'ansi-bbs'; + Options.Enter = '\r'; + Options.Font = 'CP437'; + Options.ForceWss = false; + Options.Hostname = '<?xjs write(http_request.vhost); ?>'; + Options.LocalEcho = false; + Options.Port = location.protocol == 'https:' ? wssp : wsp; + Options.ScreenColumns = 80; + Options.ScreenRows = 25; + Options.SplashScreen = '<?xjs write(get_splash()); ?>'; + var fTelnet = new fTelnetClient('fTelnetContainer', Options); + fTelnet.ButtonBarVisible = true; + if ($('#ftelnet-connect').length) { + $('#ftelnet-connect').click(function() { + fTelnet.Connect(); + }); + } + }); </script> <?xjs } ?> diff --git a/webv4/pages/003-games.xjs b/webv4/pages/003-games.xjs index 7b7604d8bb2b03cb992b44b613676ba42b0569e2..749594a43c12c17585f5b730dda21f57c02765e6 100644 --- a/webv4/pages/003-games.xjs +++ b/webv4/pages/003-games.xjs @@ -43,29 +43,31 @@ <script id="fTelnetScript" src="<?xjs write(get_url()); ?>"></script> <script type="text/javascript"> - var wsp = <?xjs write(settings.wsp || GetWebSocketServicePort()); ?>; - var wssp = <?xjs write(settings.wssp || GetWebSocketServicePort(true)); ?>; - var Options = new fTelnetOptions(); - Options.BareLFtoCRLF = false; - Options.BitsPerSecond = 57600; - Options.ConnectionType = 'rlogin'; - Options.Emulation = 'ansi-bbs'; - Options.Enter = '\r'; - Options.Font = 'CP437'; - Options.ForceWss = false; - Options.Hostname = '<?xjs write(http_request.vhost); ?>'; - Options.LocalEcho = false; - Options.Port = location.protocol == 'https:' ? wssp : wsp; - Options.RLoginClientUsername = '<?xjs write(user.security.password); ?>'; - Options.RLoginServerUsername = '<?xjs write(user.alias); ?>'; - Options.ScreenColumns = 80; - Options.ScreenRows = 25; - Options.SplashScreen = Options.SplashScreen = '<?xjs write(get_splash()); ?>'; - Options.WebSocketUrlPath = '?Port=<?xjs write(GetRLoginPort()); ?>'; - var fTelnet = new fTelnetClient('fTelnetContainer', Options); - fTelnet.OnConnectionClose = function () { - window.location.reload(); - }; + window.addEventListener('load', (event) => { + var wsp = <?xjs write(settings.wsp || GetWebSocketServicePort()); ?>; + var wssp = <?xjs write(settings.wssp || GetWebSocketServicePort(true)); ?>; + var Options = new fTelnetOptions(); + Options.BareLFtoCRLF = false; + Options.BitsPerSecond = 57600; + Options.ConnectionType = 'rlogin'; + Options.Emulation = 'ansi-bbs'; + Options.Enter = '\r'; + Options.Font = 'CP437'; + Options.ForceWss = false; + Options.Hostname = '<?xjs write(http_request.vhost); ?>'; + Options.LocalEcho = false; + Options.Port = location.protocol == 'https:' ? wssp : wsp; + Options.RLoginClientUsername = '<?xjs write(user.security.password); ?>'; + Options.RLoginServerUsername = '<?xjs write(user.alias); ?>'; + Options.ScreenColumns = 80; + Options.ScreenRows = 25; + Options.SplashScreen = Options.SplashScreen = '<?xjs write(get_splash()); ?>'; + Options.WebSocketUrlPath = '?Port=<?xjs write(GetRLoginPort()); ?>'; + window.fTelnet = new fTelnetClient('fTelnetContainer', Options); + fTelnet.OnConnectionClose = function () { + window.location.reload(); + }; + }); async function launchXtrn(code) { await v4_get('./api/system.ssjs?call=set-xtrn-intent&code=' + code); diff --git a/webv4/root/css/checkbox.css b/webv4/root/css/checkbox.css new file mode 100644 index 0000000000000000000000000000000000000000..a19ff7084203dc200c0f131aba9b2118cc842304 --- /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 7e49bcf0b1719cc5ecaf0b244f814668234257bf..9aaeae40472f7c135551e8abff5a8b882d912dff 100644 --- a/webv4/root/css/style.css +++ b/webv4/root/css/style.css @@ -18,8 +18,8 @@ a.unread { } span.badge.new { - background: #2E9AFE; - color: #FFFFFF; + background: #2E9AFE; + color: #FFFFFF; } /* A read mail message in the list view. */ @@ -53,7 +53,77 @@ 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: #444; +} + +/* this is the text and color for most items, including non-alternating rows */ +.dark .list-group-item { + background-color: #555; + color: #EEE; +} + +/* 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 { + background-color: #888; + color: #222; +} + +.dark li.list-group-item.mail:hover { + background-color: #888; + color: #FFF; +} + +/* 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 +250,72 @@ 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 .btn { + color: #000; + background-color: #ddd ; +} + +.dark .btn-primary { + color: #FFF; + background-color: #337ab7; +} + +.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; + } +} + +.dark .modal-content { + background-color: #555 !important; + color: #FFF !important; +} + +.darkswitchbox { + margin-block-start: 1em; + margin-block-end: 1em; + margin-inline-start: 0px; + margin-inline-end: 0px; + padding-inline-start: 40px; +} + +.dark input,.dark select,.dark textarea { + color: #333; + background-color: #DDD; +} + + diff --git a/webv4/root/index.xjs b/webv4/root/index.xjs index 477b77f4189faa010e4ed6eebed7a4e7fbea5354..b6a1f93a4726b65da3b52e28cf0248de90140703 100644 --- a/webv4/root/index.xjs +++ b/webv4/root/index.xjs @@ -41,6 +41,13 @@ <!DOCTYPE html> <html lang="en"> <head> + <style type="text/css"> + .hidden { display:none; } + </style> + <script src="./js/jquery.min.js"></script> + <script type="text/javascript"> + jQuery('html').addClass('hidden'); + </script> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> @@ -49,6 +56,9 @@ <link href="./bootstrap/css/bootstrap.min.css" rel="stylesheet"> <link href="./css/offcanvas.css" rel="stylesheet"> <link href="./css/style.css" rel="stylesheet"> +<?xjs if (!settings.darkmode_off) { ?> + <link href="./css/checkbox.css" rel="stylesheet"> +<?xjs } ?> <? if (file_exists(settings.web_root + 'css/custom.css')) { ?> <link href="./css/custom.css" rel="stylesheet"> <? } ?> @@ -56,7 +66,6 @@ <body> - <script src="./js/jquery.min.js"></script> <script src="./bootstrap/js/bootstrap.min.js"></script> <script src="./js/common.js"></script> @@ -101,7 +110,6 @@ return false; }); </script> - </body> </html> diff --git a/webv4/root/js/common.js b/webv4/root/js/common.js index aa4ff8fa7d9de414bcf14b32b44480cf2b84525a..c6208c9e2476bd8050bfe88f3a394881971820a9 100644 --- a/webv4/root/js/common.js +++ b/webv4/root/js/common.js @@ -91,6 +91,44 @@ function registerEventListener(scope, callback, params) { }; } +document.addEventListener("DOMContentLoaded", function () { + // 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; + if (localStorage.getItem("darkSwitch") !== null) { + darkThemeSelected = localStorage.getItem("darkSwitch") === "dark"; + } else { + darkThemeSelected = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; + } + 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.setItem("darkSwitch", "light"); + } + } + } + + jQuery('html').removeClass('hidden'); +}); + window.onload = function () { $('#button-logout').click(logout);