Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement dark mode #2338

Merged
merged 38 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
4e1278b
Implement dark mode
jayhesselberth Sep 3, 2023
e6a3dba
Merge branch 'main' into dark-mode
jayhesselberth Nov 28, 2023
ce1885d
Merge branch 'main' into dark-mode
jayhesselberth Nov 30, 2023
dfe878d
Merge branch 'main' into dark-mode
jayhesselberth Apr 20, 2024
75c73e4
Merge branch 'main' into dark-mode
jayhesselberth Apr 24, 2024
56a5f31
port over some tweaks from rstudio/bslib
Apr 28, 2024
02e13ff
include search in navbar right
jayhesselberth Apr 28, 2024
907c8df
document and news bullet
jayhesselberth Apr 28, 2024
00576bf
acknowledge @gadenbuie
jayhesselberth Apr 28, 2024
1d320dc
add bootstrap icons css
jayhesselberth Apr 28, 2024
401be6b
Merge commit '6757fe4f8270db56cb098838b8610c2adb2569d6'
hadley May 21, 2024
8a5bf60
Static lightswitcher menu made with navbar menu
hadley May 21, 2024
cd17170
Simplify css
hadley May 21, 2024
27eb176
Re-do scss with eye to #2573
hadley May 22, 2024
393e164
Merge commit '36db6570616631aabae3f9c4cc71588489519f7f'
hadley May 22, 2024
cb18b29
Conditionally set navbar bg
hadley May 22, 2024
d70081f
Explanatory comment
hadley May 22, 2024
cd55c5f
Revert menu changes
hadley May 22, 2024
0bce689
Only add lilghtswitch if needed
hadley May 22, 2024
d5f14e4
Test (and fix) theme errors
hadley May 22, 2024
0775200
Use a variable
hadley May 22, 2024
9ad1d30
Remove dark mode content for now
hadley May 22, 2024
dc1b802
Make an explicit switch for light switch and document
hadley May 22, 2024
b63cfd8
Update test
hadley May 22, 2024
57e82f0
Generate buttons instead of broken links
hadley May 22, 2024
2ca8a11
WS
hadley May 22, 2024
38092ef
Use opacity for foreground colours
hadley May 22, 2024
e30adb6
Better approach for navbar colour
hadley May 22, 2024
2d0a7b9
Revert unrelated change
hadley May 22, 2024
dd0602b
Make search styling more like navbars
hadley May 22, 2024
87aabeb
Better strategy for TOC highlights
hadley May 23, 2024
78cc4dd
More search polishing
hadley May 23, 2024
d57f700
More news polishing
hadley May 23, 2024
83341f2
More polishing
hadley May 23, 2024
cb2dee8
Merge commit '98d30d834b33ce896310ee7a9ae89de11809d8e2'
hadley May 23, 2024
d06820d
Use same technique for TOC and nav bar
hadley May 23, 2024
e196064
Polish navbar colouring
hadley May 23, 2024
a02e726
Hopefully last search tweak
hadley May 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# pkgdown (development version)

* The dark mode introduced in Bootstrap 5.3 can now be used in pkgdown sites based on work in bslib by @gadenbuie. See the customization vignette for details.
* `as.pkgdown()` will no longer prompt you to install a missing template package from CRAN, since these are almost always found in GitHub (#2076).
* `init_site()` once again describes one copy per line, and now uses a better prefix when copying assets from pkgdown itself (#2445).
* Very wide words are now automatically broken across lines and hyphenated (when possible) when they'd otherwise create a horizontal scrollbar on mobile (#1888).
Expand Down
126 changes: 126 additions & 0 deletions inst/BS5/assets/pkgdown.js
jayhesselberth marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,130 @@ async function searchFuse(query, callback) {
});
})(window.jQuery || window.$)

/*!
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors
* Licensed under the Creative Commons Attribution 3.0 Unported License.
* Updates for {pkgdown} by the {bslib} authors, also licensed under CC-BY-3.0.
*/

const getStoredTheme = () => localStorage.getItem('theme')
const setStoredTheme = theme => localStorage.setItem('theme', theme)

const getPreferredTheme = () => {
const storedTheme = getStoredTheme()
if (storedTheme) {
return storedTheme
}

return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}

const setTheme = theme => {
if (theme === 'auto') {
document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'))
} else {
document.documentElement.setAttribute('data-bs-theme', theme)
}
}

setTheme(getPreferredTheme())

function bsSetupThemeToggle () {
hadley marked this conversation as resolved.
Show resolved Hide resolved
'use strict'

const showActiveTheme = (theme, focus = false) => {
const themeSwitcher = document.querySelector('#bd-theme')

if (!themeSwitcher) {
return
}

const themeSwitcherText = document.querySelector('#bd-theme-text')
const activeThemeIcon = document.querySelector('.theme-icon-active')
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
const svgOfActiveBtn = btnToActive.querySelector('.theme-icon').innerHTML

document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
element.classList.remove('active')
element.setAttribute('aria-pressed', 'false')
})

btnToActive.classList.add('active')
btnToActive.setAttribute('aria-pressed', 'true')
activeThemeIcon.innerHTML = svgOfActiveBtn
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)

if (focus) {
themeSwitcher.focus()
}
}

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = getStoredTheme()
if (storedTheme !== 'light' && storedTheme !== 'dark') {
setTheme(getPreferredTheme())
}
})

window.addEventListener('DOMContentLoaded', () => {
showActiveTheme(getPreferredTheme())

document.querySelectorAll('[data-bs-theme-value]')
.forEach(toggle => {
toggle.addEventListener('click', () => {
const theme = toggle.getAttribute('data-bs-theme-value')
setStoredTheme(theme)
setTheme(theme)
showActiveTheme(theme, true)
})
})
})
}

function colorPickerMarkup () {

const icons = {
"sun-fill": `<i class="bi bi-sun-fill"></i>`,
"moon-stars-fill": `<i class="bi bi-moon-stars-fill"></i>`,
"circle-half": `<i class="bi bi-circle-half"></i>`
}

return `<button class="btn btn-link nav-link py-2 px-0 px-lg-2 dropdown-toggle d-flex align-items-center" id="bd-theme" type="button" aria-expanded="false" data-bs-toggle="dropdown" data-bs-display="static" aria-label="Toggle theme (light)">
hadley marked this conversation as resolved.
Show resolved Hide resolved
<span class="theme-icon-active">${icons['sun-fill']}</span>
<span class="d-lg-none ms-2" id="bd-theme-text">Toggle theme</span>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-theme-text">
<li>
<button type="button" class="dropdown-item d-flex align-items-center active" data-bs-theme-value="light" aria-pressed="true">
<span class="me-2 opacity-50 theme-icon">${icons['sun-fill']}</span>
Light
<svg class="bi ms-auto d-none"><use href="#check2"></use></svg>
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="false">
<span class="me-2 opacity-50 theme-icon">${icons['moon-stars-fill']}</span>
Dark
<svg class="bi ms-auto d-none"><use href="#check2"></use></svg>
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto" aria-pressed="false">
<span class="me-2 opacity-50 theme-icon">${icons['circle-half']}</span>
Auto
<svg class="bi ms-auto d-none"><use href="#check2"></use></svg>
</button>
</li>
</ul>`
}

document.addEventListener('DOMContentLoaded', () => {
const switcher = document.querySelector('.navbar [href$="#dark-mode"]')
if (!switcher) return

switcher.parentElement.classList.add('dropdown')
switcher.parentElement.innerHTML = colorPickerMarkup()
bsSetupThemeToggle()
hadley marked this conversation as resolved.
Show resolved Hide resolved
})
247 changes: 246 additions & 1 deletion inst/BS5/assets/pkgdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
.row > main {
// Ensure contents never become unreadably wide
max-width: 50rem;

// And that we can break and hypenate very long words
overflow-wrap: break-word;
hyphens: auto;
Expand Down Expand Up @@ -507,3 +507,248 @@ mark {
.algolia-autocomplete .aa-dropdown-menu .aa-suggestion.aa-cursor {
background-color: mix($primary, $body-bg, 10%);
}

/* ---- Dark Mode ---- */

@include media-breakpoint-down(sm) {
aside {
background-color: var(--bs-tertiary-bg);
border-color: var(--bs-border-color);
}
}

@media (min-width: 800px) {
.usage {
display: flex;
* {
flex: 1;
}
}
}

p a {
text-decoration-skip-ink: none;
text-decoration-thickness: from-font;
}

a:focus, a:hover {
text-decoration: underline;
}

.navbar-light .navbar-nav .active>.nav-link {
background: #D0E5FC;
}

table.dataTable.table-bordered {
border-collapse: collapse !important;
}

main h2 {
margin-top: 1lh;
}

.html-widget {
margin-bottom: 0;
}

/* ---- Callouts ---- */
.callout {
position: relative;
border: 1px solid gray;
padding: 1rem;
margin: 1rem 0;
border-radius: var(--bs-border-radius);
}

.callout > :last-child {
margin-bottom: 0;
}

.callout > h3 {
position: relative;
margin: -1rem;
margin-bottom: 10px;
padding: 1rem;
font-size: 1.5rem;
border-top-left-radius: inherit;
border-top-right-radius: inherit;
}

.callout > h3 > .anchor {
display: none;
}

.callout.callout-warning {
--callout--border-color: #ffd700;
--callout--header-bg: #fffae0;
--callout--header-color: #473D00;

[data-bs-theme="dark"] & {
--callout--border-color: #473D00;
--callout--header-color: #fffae0;
--callout--header-bg: #473D00;
}

border-color: var(--callout--border-color);

> h3 {
color: var(--callout--header-color);
background-color: var(--callout--header-bg);

&:before {
content: "!";
font-weight: bold;
font-size: 1.25rem;
font-family: serif;
margin-right: 0.5rem;
border-radius: 50%;
background-color: #ffd70080;
width: 2rem;
height: 2rem;
display: inline-flex;
align-items: center;
justify-content: center;
}
}
}


.callout.callout-note {
--callout--header-color: #373a3c;
--callout--header-bg: #e9f2fc;
--callout--border-color: #bdccdc;

[data-bs-theme="dark"] & {
--callout--header-color: #e9f2fc;
--callout--header-bg: #1b425d;
--callout--border-color: #1b425d;
}

border-color: var(--callout--border-color);

> h3 {
color: var(--callout--header-color);
background-color: var(--callout--header-bg);

&:before {
content: "i";
font-weight: bold;
font-size: 1.25rem;
font-style: italic;
font-family: serif;
margin-right: 0.5rem;
border-radius: 50%;
background-color: #bdccdc80;
width: 2rem;
height: 2rem;
display: inline-flex;
align-items: center;
justify-content: center;
}
}
}


iframe, .bslib-page-fill {
height: 500px;
border: var(--bs-border-width) solid var(--bs-border-color);
}

iframe.resizable {
resize: vertical;
min-height: 200px;
}

aside .roles,
footer {
color: rgba(var(--bs-emphasis-color-rgb), 0.6);
}

/* pkgdown fixes for dark mode */
// these could probably end up in pkgdown?

.card-footer.bg-white {
--bs-bg-opacity: 0.1;
}

.navbar a {
text-decoration: none !important;
}

.navbar-nav .nav-item>.nav-link:hover,
#toc>.nav a.nav-link:hover,
#toc>.nav a.nav-link:focus {
color: var(--bs-body-color);
background-color: rgba(var(--bs-info-rgb), 0.45);
}

#toc>.nav a.nav-link.active {
[data-bs-theme="dark"] {
color: var(--bs-body-bg);
}
background-color: rgba(var(--bs-info-rgb), 0.75);
}

[data-bs-theme="dark"] {
.navbar.bg-info {
background-color: #333f48 !important;
}

::selection {
background: #344c5a;
}

input[type="search"] {
border-color: var(--bs-border-color);
}

pre {
background-color: #272b30;
}

// low-tech image softening in dark mode
img {
opacity: 0.66;
transition: opacity 250ms ease-in-out;
}

img:hover,
img:focus,
img:active {
opacity: 1;
}

// github-dark.css //
jayhesselberth marked this conversation as resolved.
Show resolved Hide resolved
pre code /* Normal */ {color:#e1e4e8}
pre code span.al /* Alert */ {color:#ff5555; font-weight: bold}
pre code span.an /* Annotation */ {color:#6a737d}
pre code span.at /* Attribute */ {color:#f97583}
pre code span.bn /* BaseN */ {color:#79b8ff}
pre code span.bu /* BuiltIn */ {color:#f97583}
pre code span.cf /* ControlFlow */ {color:#f97583}
pre code span.ch /* Char */ {color:#9ecbff}
pre code span.cn /* Constant */ {color:#79b8ff}
pre code span.co /* Comment */ {color:#6a737d}
pre code span.cv /* CommentVar */ {color:#6a737d}
pre code span.do /* Documentation */ {color:#6a737d}
pre code span.dt /* DataType */ {color:#f97583}
pre code span.dv /* DecVal */ {color:#79b8ff}
pre code span.er /* Error */ {color:#ff5555; text-decoration: underline}
pre code span.ex /* Extension */ {color:#f97583; font-weight: bold}
pre code span.fl /* Float */ {color:#79b8ff}
pre code span.fu /* Function */ {color:#b392f0}
pre code span.im /* Import */ {color:#9ecbff}
pre code span.in /* Information */ {color:#6a737d}
pre code span.kw /* Keyword */ {color:#f97583}
pre code span.op /* Operator */ {color:#e1e4e8}
pre code span.ot /* Others */ {color:#b392f0}
pre code span.pp /* Preprocessor */ {color:#f97583}
pre code span.re /* RegionMarker */ {color:#6a737d}
pre code span.sc /* SpecialChar */ {color:#79b8ff}
pre code span.ss /* SpecialString */ {color:#9ecbff}
pre code span.st /* String */ {color:#9ecbff}
pre code span.va /* Variable */ {color:#ffab70}
pre code span.vs /* VerbatimString */ {color:#9ecbff}
pre code span.wa /* Warning */ {color:#ff5555}

}
Loading
Loading