mirror of
https://github.com/tenrok/bootstrap.git
synced 2026-06-08 17:22:31 +03:00
Add dark mode support
Heavily WIP still, but this begins the process of implementing dark mode for our docs and across the project itself. - Color modes are toggled in the docs navbar with a custom toggler, which stores the select color mode in local storage. - Color modes can also be set via data attribute thanks to `data-theme` (with light or dark options available currently). - Docs are heavily WIP for demonstrating the dark mode. - In order to best implement color modes, I've spiked out a number of new Sass and CSS variables (e.g., `--bs-secondary-bg` and `--bs-tertiary-bg`). In addition, I've added new global CSS variables like `--bs-border-color` and more. So, in addition to general color modes and theming support, we get greater real-time customization, too. Todos and open questions: - [ ] Do we refer to these as themes or color modes? - [ ] Do we provide a color mode toggler JS plugin? - [ ] Update all components to better utilize global CSS variables so they can be more easily themed (e.g., see `$dropdown-*` Sass variable changes in the diff).
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
}
|
||||
|
||||
// Tooltip and popover demos
|
||||
document.querySelectorAll('.tooltip-demo')
|
||||
document.querySelectorAll('.tooltip-demo, .bd-navbar')
|
||||
.forEach(function (tooltip) {
|
||||
new bootstrap.Tooltip(tooltip, {
|
||||
selector: '[data-bs-toggle="tooltip"]'
|
||||
@@ -132,6 +132,59 @@
|
||||
})
|
||||
}
|
||||
|
||||
// Toggle color modes
|
||||
|
||||
var currentTheme = localStorage.getItem('theme')
|
||||
var currentThemeIcon = document.querySelector('#bd-theme > .bi use')
|
||||
|
||||
function checkMatchMedia() {
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches && !currentTheme) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark')
|
||||
} else {
|
||||
document.documentElement.removeAttribute('data-theme')
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('.bd-theme-toggles .dropdown-item')
|
||||
.forEach(function (toggle) {
|
||||
toggle.addEventListener('click', function () {
|
||||
var theme = this.getAttribute('data-theme-value')
|
||||
|
||||
document.querySelector('.bd-theme-toggles .current').removeAttribute('class')
|
||||
toggle.parentElement.setAttribute('class', 'current')
|
||||
|
||||
var svg = toggle.querySelector('.theme-icon use').getAttribute('href')
|
||||
currentThemeIcon.setAttribute('href', svg)
|
||||
|
||||
console.log(theme)
|
||||
|
||||
// in OS darkmode, going from light to auto doesn't make it dark
|
||||
|
||||
if (theme === 'auto') {
|
||||
document.documentElement.removeAttribute('data-theme')
|
||||
localStorage.removeItem('theme')
|
||||
checkMatchMedia()
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-theme', theme)
|
||||
localStorage.setItem('theme', theme)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (currentTheme) {
|
||||
var currentThemeButton = document.querySelector('.dropdown-item[data-theme-value="' + currentTheme + '"]')
|
||||
document.documentElement.setAttribute('data-theme', currentTheme)
|
||||
document.querySelector('.bd-theme-toggles .current').removeAttribute('class')
|
||||
currentThemeButton.parentElement.setAttribute('class', 'current')
|
||||
var svg = currentThemeButton.querySelector('.theme-icon use').getAttribute('href')
|
||||
currentThemeIcon.setAttribute('href', svg)
|
||||
} else {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function () {
|
||||
checkMatchMedia()
|
||||
})
|
||||
checkMatchMedia()
|
||||
}
|
||||
|
||||
// Insert copy to clipboard button before .highlight
|
||||
var btnTitle = 'Copy to clipboard'
|
||||
var btnHtml = '<div class="bd-clipboard"><button type="button" class="btn-clipboard"><svg class="bi" width="1em" height="1em" fill="currentColor" role="img" aria-label="Copy"><use xlink:href="#clipboard"/></svg></button></div>'
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
@include font-size(.8125rem);
|
||||
line-height: 1.4;
|
||||
text-align: left;
|
||||
background-color: $gray-100;
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
|
||||
a {
|
||||
color: $gray-800;
|
||||
color: var(--bs-body-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -34,5 +34,5 @@
|
||||
.carbon-poweredby {
|
||||
display: block;
|
||||
margin-top: .75rem;
|
||||
color: $gray-700 !important;
|
||||
color: var(--bs-body-color) !important;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
.btn-bd-light {
|
||||
--bs-btn-color: var(--bs-gray-600);
|
||||
--bs-btn-border-color: var(--bs-gray-400);
|
||||
--bs-btn-border-color: var(--bs-border-color);
|
||||
--bs-btn-hover-color: var(--bd-violet);
|
||||
--bs-btn-hover-border-color: var(--bd-violet);
|
||||
--bs-btn-active-color: var(--bd-violet);
|
||||
@@ -43,3 +43,7 @@
|
||||
--bs-btn-focus-border-color: var(--bd-violet);
|
||||
--bs-btn-focus-shadow-rgb: var(--bd-violet-rgb);
|
||||
}
|
||||
|
||||
.btn-bd-lg {
|
||||
padding: .8rem 2rem;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
margin-bottom: .25rem;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
display: block;
|
||||
padding: .5em .75em .625em;
|
||||
line-height: 1;
|
||||
color: $gray-900;
|
||||
background-color: $gray-100;
|
||||
color: var(--bs-body-color);
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
border: 0;
|
||||
@include border-radius(.25rem);
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
position: relative;
|
||||
padding: 1rem;
|
||||
margin: 1rem ($bd-gutter-x * -.5) 0;
|
||||
border: solid $gray-300;
|
||||
border: solid var(--bs-border-color);
|
||||
border-width: 1px 0 0;
|
||||
@include clearfix();
|
||||
|
||||
@@ -317,7 +317,7 @@
|
||||
.highlight {
|
||||
padding: .75rem ($bd-gutter-x * .5);
|
||||
margin-bottom: 1rem;
|
||||
background-color: var(--bs-gray-100);
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
padding: .75rem 1.5rem;
|
||||
@@ -339,7 +339,7 @@
|
||||
|
||||
pre code {
|
||||
@include font-size(inherit);
|
||||
color: $gray-900; // Effectively the base text color
|
||||
color: var(--bs-body-color); // Effectively the base text color
|
||||
word-wrap: normal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
// Override Bootstrap defaults
|
||||
> .table {
|
||||
--bs-table-border-color: var(--bs-border-color);
|
||||
|
||||
max-width: 100%;
|
||||
margin-bottom: 1.5rem;
|
||||
@include font-size(.875rem);
|
||||
@@ -74,6 +76,11 @@
|
||||
min-width: 280px;
|
||||
}
|
||||
|
||||
.table-swatches {
|
||||
td:first-child { width: 340px; }
|
||||
td:nth-child(2) { width: 200px; }
|
||||
}
|
||||
|
||||
.bd-title {
|
||||
@include font-size(3rem);
|
||||
}
|
||||
@@ -83,8 +90,8 @@
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.bd-text-purple-bright {
|
||||
color: $bd-violet;
|
||||
.bd-text-violet {
|
||||
color: var(--bd-violet);
|
||||
}
|
||||
|
||||
.bd-bg-purple-bright {
|
||||
@@ -94,6 +101,7 @@
|
||||
.bi {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -.125em;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
.bd-footer {
|
||||
a {
|
||||
color: $gray-700;
|
||||
color: var(--bs-body-color);
|
||||
text-decoration: none;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $link-color;
|
||||
color: var(--bs-primary);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
.bd-masthead {
|
||||
padding: 3rem 0;
|
||||
background: linear-gradient(165deg, tint-color($bd-purple-light, 85%) 50%, $white 50%);
|
||||
background: linear-gradient(165deg, rgba(var(--bd-violet-rgb), .05) 50%, var(--bs-body-bg) 50%);
|
||||
|
||||
h1 {
|
||||
@include font-size(4rem);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.lead {
|
||||
@include font-size(1rem);
|
||||
font-weight: 400;
|
||||
color: $gray-700;
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.highlight {
|
||||
@@ -24,8 +23,7 @@
|
||||
}
|
||||
|
||||
#carbonads { // stylelint-disable-line selector-max-id
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
@@ -35,7 +33,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.masthead-followup {
|
||||
.bd-masthead-followup {
|
||||
.lead {
|
||||
@include font-size(1rem);
|
||||
}
|
||||
@@ -71,5 +69,6 @@
|
||||
}
|
||||
|
||||
.masthead-notice {
|
||||
background-color: #d2f4ea;
|
||||
--bg: #{to-rgb($teal)};
|
||||
background-color: rgba(var(--bg), .2);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
padding: .75rem 0;
|
||||
background-color: transparent;
|
||||
background-image: linear-gradient(to bottom, rgba(var(--bd-violet-rgb), 1), rgba(var(--bd-violet-rgb), .95));
|
||||
box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15), inset 0 -1px 0 rgba(0, 0, 0, .15);
|
||||
box-shadow: 0 .5rem 1rem rgba($black, .15), inset 0 -1px 0 rgba($white, .15);
|
||||
|
||||
[data-theme="dark"] & {
|
||||
backdrop-filter: blur(.25rem);
|
||||
background-image: linear-gradient(to bottom, rgba(var(--bd-violet-rgb), 1), rgba(var(--bd-violet-rgb), .75));
|
||||
box-shadow: 0 .5rem 1rem rgba($black, .15), inset 0 -1px 0 rgba($white, .15);
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
padding: 0;
|
||||
@@ -64,17 +70,63 @@
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
--#{$variable-prefix}dropdown-min-width: 12rem;
|
||||
--#{$variable-prefix}dropdown-link-hover-bg: rgba(var(--bd-violet-rgb), .1);
|
||||
@include rfs(.875rem, --#{$variable-prefix}dropdown-font-size);
|
||||
--bs-dropdown-min-width: 12rem;
|
||||
--bs-dropdown-padding: .25rem;
|
||||
--bs-dropdown-link-hover-bg: rgba(var(--bd-violet-rgb), .1);
|
||||
--bs-dropdown-link-active-bg: rgba(var(--bd-violet-rgb), 1);
|
||||
@include rfs(.875rem, --bs-dropdown-font-size);
|
||||
@include border-radius(.5rem);
|
||||
box-shadow: $dropdown-box-shadow;
|
||||
}
|
||||
|
||||
.dropdown-item.current {
|
||||
font-weight: 600;
|
||||
background-image: escape-svg($dropdown-active-icon);
|
||||
background-repeat: no-repeat;
|
||||
background-position: right $dropdown-item-padding-x top .6rem;
|
||||
background-size: .75rem .75rem;
|
||||
.current {
|
||||
font-weight: 600;
|
||||
|
||||
.bi {
|
||||
display: block !important; // stylelint-disable-line declaration-no-important
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
@include border-radius(.25rem);
|
||||
|
||||
&:active {
|
||||
.bi {
|
||||
color: inherit !important; // stylelint-disable-line declaration-no-important
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd-theme-toggle {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bd-theme-toggle-checkbox {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0 0 0 0);
|
||||
clip-path: inset(100%);
|
||||
white-space: nowrap;
|
||||
|
||||
~ .bd-theme-toggle-light { display: none; }
|
||||
~ .bd-theme-toggle-dark { display: block; }
|
||||
|
||||
&:checked {
|
||||
~ .bd-theme-toggle-light { display: block; }
|
||||
~ .bd-theme-toggle-dark { display: none; }
|
||||
}
|
||||
}
|
||||
|
||||
.bd-theme-toggle-light {
|
||||
color: var(--bs-warning);
|
||||
}
|
||||
|
||||
.bd-theme-toggle-dark {
|
||||
color: var(--bs-navbar-brand-color);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
margin-left: -.25rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(lg) {
|
||||
.offcanvas-lg {
|
||||
border-right-color: var(--bs-border-color);
|
||||
box-shadow: $box-shadow-lg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd-links-nav {
|
||||
@@ -35,16 +42,16 @@
|
||||
.bd-links-link {
|
||||
padding: .1875rem .5rem;
|
||||
margin-top: .125rem;
|
||||
margin-left: 1rem;
|
||||
color: rgba($black, .65);
|
||||
margin-left: 1.125rem;
|
||||
color: var(--bs-body-color);
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&.active {
|
||||
color: rgba($black, .85);
|
||||
color: var(--bs-heading-color);
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
background-color: rgba(var(--bd-violet-rgb), .1);
|
||||
background-color: var(--bd-sidebar-link-bg);
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
:root {
|
||||
:root,
|
||||
[data-theme="light"] {
|
||||
--base00: #fff;
|
||||
--base01: #f5f5f5;
|
||||
--base02: #c8c8fa;
|
||||
@@ -17,6 +18,25 @@
|
||||
--base0F: #333;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--base00: #282c34;
|
||||
--base01: #353b45;
|
||||
--base02: #3e4451;
|
||||
--base03: #545862;
|
||||
--base04: #565c64;
|
||||
--base05: #abb2bf;
|
||||
--base06: #b6bdca;
|
||||
--base07: #d19a66;
|
||||
--base08: #e06c75;
|
||||
--base09: #d19a66;
|
||||
--base0A: #e5c07b;
|
||||
--base0B: #98c379;
|
||||
--base0C: #56b6c2;
|
||||
--base0D: #61afef;
|
||||
--base0E: #c678dd;
|
||||
--base0F: #be5046;
|
||||
}
|
||||
|
||||
.hll { background-color: #fff; }
|
||||
.c { color: var(--base03); }
|
||||
.err { color: var(--base08); }
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
border: 1px solid $border-color;
|
||||
border: 1px solid var(--bs-border-color);
|
||||
@include border-radius(.4rem);
|
||||
|
||||
&:hover,
|
||||
|
||||
@@ -5,7 +5,6 @@ $bd-purple: #4c0bce;
|
||||
$bd-violet: lighten(saturate($bd-purple, 5%), 15%); // stylelint-disable-line function-disallowed-list
|
||||
$bd-purple-light: lighten(saturate($bd-purple, 5%), 45%); // stylelint-disable-line function-disallowed-list
|
||||
$bd-accent: #ffe484;
|
||||
$dropdown-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#292b2c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/></svg>");
|
||||
|
||||
$bd-gutter-x: 2rem;
|
||||
$bd-callout-variants: info, warning, danger !default;
|
||||
@@ -16,4 +15,11 @@ $bd-callout-variants: info, warning, danger !default;
|
||||
--bd-accent: #{$bd-accent};
|
||||
--bd-violet-rgb: #{to-rgb($bd-violet)};
|
||||
--bd-accent-rgb: #{to-rgb($bd-accent)};
|
||||
--bd-sidebar-link-bg: rgba(var(--bd-violet-rgb), .1);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bd-violet: #{mix($bd-violet, $black, 75%)};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user