diff --git a/site/assets/js/application.js b/site/assets/js/application.js index 0cf4199c9659..c5000bb6b3cc 100644 --- a/site/assets/js/application.js +++ b/site/assets/js/application.js @@ -29,6 +29,56 @@ checkbox.indeterminate = true })() + var btnToggleDarkMode = document.querySelector('.bd-toggle-dark-mode') + var darkModeEnabledStorage = localStorage.getItem('bs-docs-dark-mode') + var isDarkModeEnabledOnLoad = darkModeEnabledStorage === '1' || + (window.matchMedia('(prefers-color-scheme: dark)').matches && + (darkModeEnabledStorage === null || + darkModeEnabledStorage === 0 + )) + + if (isDarkModeEnabledOnLoad) { + document.documentElement.classList.add('bs-docs-dark-mode') + btnToggleDarkMode.classList.add('active') + } + + function debounce(func, wait, immediate) { + var timeout + + return function () { + var callNow = immediate && !timeout + var context = this + var args = arguments + var later = function () { + timeout = null + + if (!immediate) { + func.apply(context, args) + } + } + + clearTimeout(timeout) + timeout = setTimeout(later, wait) + + if (callNow) { + func.apply(context, args) + } + } + } + + btnToggleDarkMode + .addEventListener('click', debounce(function () { + if (document.documentElement.classList.contains('bs-docs-dark-mode')) { + localStorage.setItem('bs-docs-dark-mode', '0') + document.documentElement.classList.remove('bs-docs-dark-mode') + btnToggleDarkMode.classList.remove('active') + } else { + localStorage.setItem('bs-docs-dark-mode', '1') + document.documentElement.classList.add('bs-docs-dark-mode') + btnToggleDarkMode.classList.add('active') + } + }, 10)) + makeArray(document.querySelectorAll('.js-sidenav-group')) .forEach(function (sidenavGroup) { var groupHasLinks = Boolean(sidenavGroup.querySelector('li')) diff --git a/site/assets/scss/_dark-mode.scss b/site/assets/scss/_dark-mode.scss new file mode 100644 index 000000000000..b87e109a5d3b --- /dev/null +++ b/site/assets/scss/_dark-mode.scss @@ -0,0 +1,191 @@ +// stylelint-disable declaration-no-important, selector-max-compound-selectors, selector-max-id, selector-max-type + +.bd-toggle-dark-mode.active svg { + fill: #ff0; +} + +.bs-docs-dark-mode { + // Globals + body { + color: rgba(255, 255, 255, .75); + background-color: darken(desaturate($bd-purple, 25%), 25%); + } + + h1, + h2, + h3, + h4, + h5, + h6, + a { + color: $white; + } + + code { + color: lighten($code-color, 15%); + } + + // Navbar + .bd-navbar { + background-color: darken($bd-purple, 15%); + } + + // Sidebar + .bd-sidebar { + background-color: rgba(0, 0, 0, .1); + border-color: rgba(255, 255, 255, .05); + } + .bd-toc-link, + .bd-toc nav li a, + .bd-sidebar .nav > li > a { + color: rgba(255, 255, 255, .75); + } + .bd-toc-link:hover, + .bd-toc nav li a:hover, + .bd-sidebar .nav > li > a:hover, + .bd-sidebar .nav > .active > a, + .bd-sidebar .nav > .active:hover > a, + .bd-toc-item.active > .bd-toc-link { + color: $white; + } + .ds-input { + background-color: rgba(0, 0, 0, .25); + border-color: rgba(255, 255, 255, .1); + + &:focus { + background-color: rgba(0, 0, 0, .5); + } + } + + // Footer + .bd-footer { + color: rgba(255, 255, 255, .5) !important; + background-color: rgba(0, 0, 0, .15) !important; + border-top: 1px solid $gray-900; + + a { + color: rgba(255, 255, 255, .75); + + &:hover { + color: $white; + } + } + } + + // Content + .bd-content { + a:not(.btn):not(.anchorjs-link):not(.carbon-img):not(.carbon-text):not(.carbon-poweredby) { + border-bottom: 1px solid rgba(255, 255, 255, .375); + + &:hover { + color: $white; + text-decoration: none; + border-bottom-color: rgba(255, 255, 255, .75); + } + } + + > table { + color: rgba(255, 255, 255, .5); + + td, + th { + border-color: $gray-800 !important; + } + th, + thead td:first-child { + color: rgba(255, 255, 255, .75); + background-color: rgba(255, 255, 255, .05); + } + .bg-light { + background-color: rgba(255, 255, 255, .05) !important; + } + } + } + + .bd-callout { + border-width: 0 0 0 .25rem; + @include border-radius(0); + } + + // Ads + .bd-content, + .bd-masthead { + #carbonads { + background-color: rgba(0, 0, 0, .15); + border: 1px solid rgba(255, 255, 255, .1); + } + .anchorjs-link, + .carbon-img, + .carbon-poweredby { + color: rgba(255, 255, 255, .5) !important; + } + .carbon-text { + color: rgba(255, 255, 255, .75) !important; + + &:hover { + color: $white !important; + } + } + } + + // Code snippets + .highlight { + color: rgba(255, 255, 255, .5); + background-color: rgba(0, 0, 0, .5); + + pre code { + color: rgba(255, 255, 255, .5); + } + } + .chroma { + .language-sh::before, + .language-bash::before, + .language-powershell::before { + color: $bd-info; + } + } + + // Examples + .bd-example { + // color: rgba(255, 255, 255, .5); + // background-color: rgba(0, 0, 0, .5); + color: $body-color; + border-color: rgba(0, 0, 0, .5); + + h1, + h2, + h3, + h4, + h5, + h6 { + color: inherit; + } + } + .bd-example-row .col, + .bd-example-row [class^="col-"] { + color: rgba(255, 255, 255, .5); + } + + // ToC + .section-nav { + border-left-color: rgba(255, 255, 255, .1); + + a { + color: rgba(255, 255, 255, .5); + + &:hover { + color: $white; + } + } + } + + // Homepage + .masthead-followup { + border-color: $gray-900 !important; + + .bg-light { + background-color: rgba(0, 0, 0, .15) !important; + border-color: $gray-900 !important; + } + } +} diff --git a/site/assets/scss/docs.scss b/site/assets/scss/docs.scss index 53622b9c2c83..df7142f349ad 100644 --- a/site/assets/scss/docs.scss +++ b/site/assets/scss/docs.scss @@ -46,6 +46,7 @@ @import "colors"; @import "clipboard-js"; @import "placeholder-img"; +@import "dark-mode"; // Load docs dependencies @import "syntax"; diff --git a/site/layouts/partials/docs-navbar.html b/site/layouts/partials/docs-navbar.html index 3b07cba9d13d..068c4c632eba 100644 --- a/site/layouts/partials/docs-navbar.html +++ b/site/layouts/partials/docs-navbar.html @@ -31,6 +31,11 @@