Skip to content

Commit

Permalink
Merge commit '69f7e6b8db1b9d13234b3ac28bb779bebc332610'
Browse files Browse the repository at this point in the history
  • Loading branch information
hadley committed May 24, 2024
2 parents 27f6b3c + 69f7e6b commit 0ddb6e8
Show file tree
Hide file tree
Showing 14 changed files with 355 additions and 80 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# pkgdown (development version)

* `build_articles()` now recognises a new `external-articles` top-level field that allows you to define articles that live in other packages (#2028).
* 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).
* `vignette("search")` has been removed since BS3 is deprecated and all the BS5 docs are also included in `build_search()` (#2564).
* 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).
Expand Down
12 changes: 9 additions & 3 deletions R/build-articles.R
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,7 @@ build_article <- function(name,
output_options = options,
seed = seed,
new_process = new_process,
quiet = quiet,
call = quote(build_article())
quiet = quiet
)
}

Expand Down Expand Up @@ -390,6 +389,7 @@ build_articles_index <- function(pkg = ".") {
data = data_articles_index(pkg),
path = path("articles", "index.html")
)
invisible()
}

data_articles_index <- function(pkg = ".", call = caller_env()) {
Expand Down Expand Up @@ -539,7 +539,13 @@ data_articles_index_section <- function(section, index, articles, pkg, call = ca
error_pkg = pkg,
error_call = call
)
check_contents(section$contents, index, pkg, prefix = "articles", call = call)
check_contents(
section$contents,
index,
pkg,
prefix = "articles",
call = call
)

# Match topics against any aliases
contents <- articles[select_topics(section$contents, articles), ]
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) {
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
10 changes: 9 additions & 1 deletion R/rmarkdown.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
#' Render RMarkdown document in a fresh session
#'
#' @noRd
render_rmarkdown <- function(pkg, input, output, ..., seed = NULL, copy_images = TRUE, new_process = TRUE, quiet = TRUE, call = caller_env()) {
render_rmarkdown <- function(pkg,
input,
output,
...,
seed = NULL,
copy_images = TRUE,
new_process = TRUE,
quiet = TRUE,
call = caller_env()) {

input_path <- path_abs(input, pkg$src_path)
output_path <- path_abs(output, pkg$dst_path)
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
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 () {
'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

0 comments on commit 0ddb6e8

Please sign in to comment.