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 34 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
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# pkgdown (development version)

* New light switch makes it easy for users to switch between light and dark themes for the website (based on work in bslib by @gadenbuie). For now this behaviour is opt-in with `template.light-switch: true` but in the future we may turn it on automatically. See the customization vignette for details (#1696).
* The search dropdown has been tweaked to look more like the other navbar menu items (#2338).
* YAML validation has been substantially improved so you should get much clearer errors if you have made a mistake (#1927). Please file an issue if you find a case where the error message is not helpful.
* `template_reference()` and `template_article()` now only add backticks to function names if needed (#2561).
* Custom navbars that specify `icon` but not `aria-label` will now generate a message reminding you to provide one for to improve accessibility (#2533).
Expand Down
33 changes: 28 additions & 5 deletions R/navbar-menu.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

# Helpers for use within pkgdown itself - these must stay the same as the
# yaml structure defined in vignette("customise")
menu_submenu <- function(text, menu) {
menu_submenu <- function(text, menu, icon = NULL, label = NULL, id = NULL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed these files so that it's possible to generate the lightswitch menu using our internal code. The primary advantage is simplicity, but it also ensures that if the lightswitch is placed on the right, the menu is automatically right aligned.

if (length(menu) == 0) {
return()
} else {
list(text = text, menu = menu)
purrr::compact(list(
text = text,
icon = icon,
"aria-label" = label,
id = id,
menu = menu
))
}
}
menu_link <- function(text, href, target = NULL) {
Expand All @@ -15,6 +21,10 @@ menu_link <- function(text, href, target = NULL) {
menu_links <- function(text, href) {
purrr::map2(text, href, menu_link)
}
menu_theme <- function(text, icon, theme) {
purrr::compact(list(text = text, theme = theme, icon = icon))
}

menu_heading <- function(text, ...) list(text = text, ...)
menu_separator <- function() list(text = "---------")
menu_search <- function() list(search = list())
Expand All @@ -36,6 +46,8 @@ menu_type <- function(x, menu_depth = 0L) {
"menu"
} else if (!is.null(x$text) && grepl("^\\s*-{3,}\\s*$", x$text)) {
"separator"
} else if (!is.null(x$theme)) {
"theme"
} else if (!is.null(x$text) && is.null(x$href)) {
"heading"
} else if ((!is.null(x$text) || !is.null(x$icon)) && !is.null(x$href)) {
Expand Down Expand Up @@ -64,7 +76,8 @@ navbar_html <- function(x, path_depth = 0L, menu_depth = 0L, side = c("left", "r
heading = navbar_html_heading(x),
link = navbar_html_link(x, menu_depth = menu_depth),
separator = navbar_html_separator(),
search = navbar_html_search(x, path_depth = path_depth)
search = navbar_html_search(x, path_depth = path_depth),
theme = navbar_html_theme(x)
)

class <- c(
Expand All @@ -86,7 +99,7 @@ navbar_html_list <- function(x, path_depth = 0L, menu_depth = 0L, side = "left")
}

navbar_html_menu <- function(x, path_depth = 0L, menu_depth = 0L, side = "left") {
id <- paste0("dropdown-", make_slug(x$text))
id <- paste0("dropdown-", x$id %||% make_slug(x$text))

button <- html_tag("button",
type = "button",
Expand Down Expand Up @@ -126,6 +139,16 @@ navbar_html_link <- function(x, menu_depth = 0) {
)
}

navbar_html_theme <- function(x) {
html_tag(
"button",
class = "dropdown-item",
"aria-label" = x$`aria-label`,
"data-bs-theme-value" = x$theme,
navbar_html_text(x)
)
}

navbar_html_heading <- function(x) {
html_tag(
"h6",
Expand Down Expand Up @@ -198,7 +221,7 @@ navbar_html_text <- function(x) {

icon <- html_tag("span", class = unique(c(iconset, classes)))

if (is.null(x$`aria-label`)) {
if (is.null(x$`aria-label`) && is.null(x$text)) {
cli::cli_inform(
c(
x = "Icon {.str {x$icon}} lacks an {.var aria-label}.",
Expand Down
38 changes: 30 additions & 8 deletions R/navbar.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,26 @@ data_navbar <- function(pkg = ".", depth = 0L) {
pkg <- as_pkgdown(pkg)

navbar <- config_pluck(pkg, "navbar")

style <- navbar_style(
navbar = navbar,
theme = get_bslib_theme(pkg),
bs_version = pkg$bs_version
)


if (uses_lightswitch(pkg)) {
style <- NULL
} else {
style <- navbar_style(
navbar = navbar,
theme = get_bslib_theme(pkg),
bs_version = pkg$bs_version
)
}

links <- navbar_links(pkg, depth = depth)

c(style, links)
}

uses_lightswitch <- function(pkg) {
config_pluck_bool(pkg, "template.light-switch", default = FALSE)
}

# Default navbar ----------------------------------------------------------

navbar_style <- function(navbar = list(), theme = "_default", bs_version = 3) {
Expand All @@ -31,7 +39,7 @@ navbar_style <- function(navbar = list(), theme = "_default", bs_version = 3) {
navbar_structure <- function() {
print_yaml(list(
left = c("intro", "reference", "articles", "tutorials", "news"),
right = c("search", "github")
right = c("search", "github", "lightswitch")
))
}

Expand Down Expand Up @@ -125,6 +133,20 @@ navbar_components <- function(pkg = ".") {
menu$search <- menu_search()
}

if (uses_lightswitch(pkg)) {
menu$lightswitch <- menu_submenu(
text = NULL,
icon = "fa-sun",
label = tr_("Light switch"),
id = "lightswitch",
list(
menu_theme(tr_("Light"), icon = "fa-sun", theme = "light"),
menu_theme(tr_("Dark"), icon = "fa-moon", theme = "dark"),
menu_theme(tr_("Auto"), icon = "fa-adjust", theme = "auto")
)
)
}

if (!is.null(pkg$tutorials)) {
menu$tutorials <- menu_submenu(
tr_("Tutorials"),
Expand Down
60 changes: 46 additions & 14 deletions R/theme.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
build_bslib <- function(pkg = ".") {
build_bslib <- function(pkg = ".", call = caller_env()) {
pkg <- as_pkgdown(pkg)
bs_theme <- bs_theme(pkg)
bs_theme <- bs_theme(pkg, call = call)

cur_deps <- find_deps(pkg)
cur_digest <- purrr::map_chr(cur_deps, file_digest)
Expand Down Expand Up @@ -56,7 +56,7 @@ find_deps <- function(pkg) {
}
}

bs_theme <- function(pkg = ".") {
bs_theme <- function(pkg = ".", call = caller_env()) {
pkg <- as_pkgdown(pkg)

bs_theme_args <- pkg$meta$template$bslib %||% list()
Expand All @@ -71,26 +71,39 @@ bs_theme <- function(pkg = ".") {
bs_theme <- bslib::bs_remove(bs_theme, "bs3compat")

# Add additional pkgdown rules
rules <- bs_theme_rules(pkg)
rules <- bs_theme_rules(pkg, call = call)
files <- lapply(rules, sass::sass_file)
bs_theme <- bslib::bs_add_rules(bs_theme, files)

# Add dark theme if needed
if (uses_lightswitch(pkg)) {
dark_theme <- config_pluck_string(pkg, "template.theme-dark", default = "arrow-dark")
check_theme(
dark_theme,
error_pkg = pkg,
error_path = "template.theme-dark",
error_call = call
)
path <- highlight_path(dark_theme)
css <- c('[data-bs-theme="dark"] {', read_lines(path), '}')
bs_theme <- bslib::bs_add_rules(bs_theme, css)
}

bs_theme
}

bs_theme_rules <- function(pkg) {
bs_theme_rules <- function(pkg, call = caller_env()) {
paths <- path_pkgdown("BS5", "assets", "pkgdown.scss")

theme <- config_pluck_string(pkg, "template.theme", default = "arrow-light")
theme_path <- path_pkgdown("highlight-styles", paste0(theme, ".scss"))
if (!file_exists(theme_path)) {
cli::cli_abort(c(
"Unknown theme: {.val {theme}}",
i = "Valid themes are: {.val highlight_styles()}"
), call = caller_env())
}
paths <- c(paths, theme_path)

check_theme(
theme,
error_pkg = pkg,
error_path = "template.theme",
error_call = call
)
paths <- c(paths, highlight_path(theme))

package <- config_pluck_string(pkg, "template.package")
if (!is.null(package)) {
package_extra <- path_package_pkgdown("extra.scss", package, pkg$bs_version)
Expand All @@ -108,6 +121,25 @@ bs_theme_rules <- function(pkg) {
paths
}

check_theme <- function(theme,
error_pkg,
error_path,
error_call = caller_env()) {

if (theme %in% highlight_styles()) {
return()
}
config_abort(
error_pkg,
"{.field {error_path}} uses theme {.val {theme}}",
call = error_call
)
}

highlight_path <- function(theme) {
path_pkgdown("highlight-styles", paste0(theme, ".scss"))
}

highlight_styles <- function() {
paths <- dir_ls(path_pkgdown("highlight-styles"), glob = "*.scss")
path_ext_remove(path_file(paths))
Expand Down
83 changes: 83 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,87 @@ 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)
}
}

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

const showActiveTheme = (theme, focus = false) => {
var activeLabel, activeIcon;

document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
const buttonTheme = element.getAttribute('data-bs-theme-value')
const isActive = buttonTheme == theme

element.classList.toggle('active', isActive)
element.setAttribute('aria-pressed', isActive)

if (isActive) {
activeLabel = element.textContent;
activeIcon = element.querySelector('span').classList.value;
}
})

const themeSwitcher = document.querySelector('#dropdown-lightswitch')
if (!themeSwitcher) {
return
}

themeSwitcher.setAttribute('aria-label', activeLabel)
themeSwitcher.querySelector('span').classList.value = activeIcon;

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')
setTheme(theme)
setStoredTheme(theme)
showActiveTheme(theme, true)
})
})
})
}

setTheme(getPreferredTheme());
bsSetupThemeToggle();
Loading
Loading