diff --git a/DESCRIPTION b/DESCRIPTION index 61e3f2742..5cd7f4944 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -17,10 +17,10 @@ Description: Generate an attractive and useful website from a source License: MIT + file LICENSE URL: https://pkgdown.r-lib.org, https://github.com/r-lib/pkgdown BugReports: https://github.com/r-lib/pkgdown/issues -Depends: +Depends: R (>= 3.6) -Imports: - bslib (>= 0.3.1), +Imports: + bslib (>= 0.5.1), callr (>= 3.7.3), cli (>= 3.6.1), desc (>= 1.4.0), @@ -40,7 +40,7 @@ Imports: withr (>= 2.4.3), xml2 (>= 1.3.1), yaml -Suggests: +Suggests: covr, diffviewer, evaluate, @@ -59,7 +59,7 @@ Suggests: sass, testthat (>= 3.1.3), tools -VignetteBuilder: +VignetteBuilder: knitr Config/Needs/website: usethis, servr Config/potools/style: explicit diff --git a/NEWS.md b/NEWS.md index 4ad061cfa..19f03ab42 100644 --- a/NEWS.md +++ b/NEWS.md @@ -20,6 +20,7 @@ * Fix setting `seed` in `build_reference()`. The seed was reset too early, before. (@salim-b, #2355) * Translates citation sections (@eliocamp, #2410). * Topic names that conflict with selector functions can now be listed as references in `_pkgdown.yml` (@dmurdoch, #2397). +* pkgdown is now compatible with (and requires) bslib >= 0.5.1 (@gadenbuie, #2395). # pkgdown 2.0.7 diff --git a/R/navbar.R b/R/navbar.R index 4b67ed012..e5d670332 100644 --- a/R/navbar.R +++ b/R/navbar.R @@ -5,7 +5,7 @@ data_navbar <- function(pkg = ".", depth = 0L) { style <- navbar_style( navbar = navbar, - theme = get_bootswatch_theme(pkg), + theme = get_bslib_theme(pkg), bs_version = pkg$bs_version ) @@ -21,7 +21,7 @@ navbar_style <- function(navbar = list(), theme = "_default", bs_version = 3) { list(type = navbar$type %||% "default") } else { # bg is usually light, dark, or primary, but can use any .bg-* - bg <- navbar$bg %||% bootswatch_bg[[theme]] + bg <- navbar$bg %||% purrr::pluck(bootswatch_bg, theme, .default = "light") type <- navbar$type %||% if (bg == "light") "light" else "dark" list(bg = bg, type = type) diff --git a/R/package.R b/R/package.R index dc7b5396a..95a978143 100644 --- a/R/package.R +++ b/R/package.R @@ -24,9 +24,11 @@ as_pkgdown <- function(pkg = ".", override = list()) { meta <- read_meta(pkg) meta <- modify_list(meta, override) + bs_version <- get_bootstrap_version(list(meta = meta)) + template_config <- find_template_config( package = meta$template$package, - bs_version = meta$template$bootstrap + bs_version = bs_version ) meta <- modify_list(template_config, meta) @@ -38,8 +40,6 @@ as_pkgdown <- function(pkg = ".", override = list()) { package <- desc$get_field("Package") version <- desc$get_field("Version") - bs_version <- check_bootstrap_version(meta$template$bootstrap, pkg) - development <- meta_development(meta, version, bs_version) if (is.null(meta$destination)) { @@ -98,6 +98,28 @@ read_desc <- function(path = ".") { desc::description$new(path) } +get_bootstrap_version <- function(pkg) { + template_bootstrap <- pkg$meta[["template"]]$bootstrap + template_bslib <- pkg$meta[["template"]]$bslib$version + + if (!is.null(template_bootstrap) && !is.null(template_bslib)) { + cli::cli_abort( + c( + sprintf( + "Both {.field %s} and {.field %s} are set.", + pkgdown_field(pkg, c("template", "bootstrap")), + pkgdown_field(pkg, c("template", "bslib", "version")) + ), + x = "Remove one of them from {.file {pkgdown_config_relpath(pkg)}}" + ), + call = caller_env() + ) + } + + version <- template_bootstrap %||% template_bslib + check_bootstrap_version(version, pkg) +} + check_bootstrap_version <- function(version, pkg) { if (is.null(version)) { 3 diff --git a/R/theme.R b/R/theme.R index 4d0c780c4..67fc1743b 100644 --- a/R/theme.R +++ b/R/theme.R @@ -34,14 +34,12 @@ data_deps_path <- function(pkg) { bs_theme <- function(pkg = ".") { pkg <- as_pkgdown(pkg) - theme <- get_bootswatch_theme(pkg) - theme <- check_bootswatch_theme(theme, pkg$bs_version, pkg) + bs_theme_args <- pkg$meta$template$bslib %||% list() + bs_theme_args[["version"]] <- pkg$bs_version + bs_theme_args[["preset"]] <- get_bslib_theme(pkg) + + bs_theme <- exec(bslib::bs_theme, !!!bs_theme_args) - bs_theme <- exec(bslib::bs_theme, - version = pkg$bs_version, - bootswatch = theme, - !!!pkg$meta$template$bslib - ) # Drop bs3 compat files added for shiny/RMarkdown bs_theme <- bslib::bs_remove(bs_theme, "bs3compat") @@ -92,30 +90,54 @@ highlight_styles <- function() { path_ext_remove(path_file(paths)) } -get_bootswatch_theme <- function(pkg) { - pkg$meta[["template"]]$bootswatch %||% - pkg$meta[["template"]]$params$bootswatch %||% - "_default" +get_bslib_theme <- function(pkg) { + preset <- pkg$meta[["template"]]$bslib$preset + + if (!is.null(preset)) { + check_bslib_theme(preset, pkg, c("template", "bslib", "preset")) + return(preset) + } + + bootswatch <- + pkg$meta[["template"]]$bootswatch %||% + # Historically (< 0.2.0), bootswatch wasn't a top-level template field + pkg$meta[["template"]]$params$bootswatch + + if (!is.null(bootswatch)) { + check_bslib_theme(bootswatch, pkg, c("template", "bootswatch")) + return(bootswatch) + } + + "default" } -check_bootswatch_theme <- function(bootswatch_theme, bs_version, pkg) { - if (bootswatch_theme == "_default") { - NULL - } else if (bootswatch_theme %in% bslib::bootswatch_themes(bs_version)) { - bootswatch_theme - } else { - cli::cli_abort(c( - sprintf( - "Can't find Bootswatch theme {.val %s} ({.field %s}) for Bootstrap version {.val %s} ({.field %s}).", - bootswatch_theme, - pkgdown_field(pkg, c("template", "bootswatch")), - bs_version, - pkgdown_field(pkg, c("template", "bootstrap")) - ), - x = "Edit settings in {pkgdown_config_href({pkg$src_path})}" - ), call = caller_env()) +check_bslib_theme <- function(theme, pkg, field = c("template", "bootswatch"), bs_version = pkg$bs_version) { + if (theme %in% c("_default", "default")) { + return("default") + } + + bslib_themes <- c( + bslib::bootswatch_themes(bs_version), + bslib::builtin_themes(bs_version), + # bs_theme() recognizes both below as bare bootstrap + "default", + "bootstrap" + ) + + if (theme %in% bslib_themes) { + return(theme) } + cli::cli_abort(c( + sprintf( + "Can't find Bootswatch or bslib theme preset {.val %s} ({.field %s}) for Bootstrap version {.val %s} ({.field %s}).", + theme, + pkgdown_field(pkg, field), + bs_version, + pkgdown_field(pkg, c("template", "bootstrap")) + ), + x = "Edit settings in {pkgdown_config_href({pkg$src_path})}" + ), call = caller_env()) } bs_theme_deps_suppress <- function(deps = list()) { diff --git a/tests/testthat/_snaps/render.md b/tests/testthat/_snaps/render.md index d9ddfc5f3..3fe6c6d9a 100644 --- a/tests/testthat/_snaps/render.md +++ b/tests/testthat/_snaps/render.md @@ -1,6 +1,11 @@ -# check_bootswatch_theme() works +# check_bslib_theme() works - Can't find Bootswatch theme "paper" (template.bootswatch) for Bootstrap version "4" (template.bootstrap). + Can't find Bootswatch or bslib theme preset "paper" (template.bootswatch) for Bootstrap version "4" (template.bootstrap). + x Edit settings in _pkgdown.yml + +--- + + Can't find Bootswatch or bslib theme preset "paper" (template.preset) for Bootstrap version "4" (template.bootstrap). x Edit settings in _pkgdown.yml # capture data_template() diff --git a/tests/testthat/test-render.R b/tests/testthat/test-render.R index fe6d98043..e77fe6c28 100644 --- a/tests/testthat/test-render.R +++ b/tests/testthat/test-render.R @@ -1,8 +1,33 @@ -test_that("check_bootswatch_theme() works", { +test_that("check_bslib_theme() works", { pkg <- as_pkgdown(test_path("assets/reference")) - expect_equal(check_bootswatch_theme("_default", 4, pkg), NULL) - expect_equal(check_bootswatch_theme("lux", 4, pkg), "lux") - expect_snapshot_error(check_bootswatch_theme("paper", 4, pkg)) + expect_equal(check_bslib_theme("_default", pkg, bs_version = 4), "default") + expect_equal(check_bslib_theme("lux", pkg, bs_version = 4), "lux") + expect_snapshot_error(check_bslib_theme("paper", pkg, bs_version = 4)) + expect_snapshot_error(check_bslib_theme("paper", pkg, bs_version = 4, field = c("template", "preset"))) +}) + +test_that("get_bslib_theme() works with template.bslib.preset", { + pkg <- local_pkgdown_site(test_path("assets/site-empty"), ' + template: + bootstrap: 5 + bslib: + preset: shiny + enable-shadows: true + ') + + expect_equal(get_bslib_theme(pkg), "shiny") + expect_no_error(bs_theme(pkg)) + + pkg <- local_pkgdown_site(test_path("assets/site-empty"), ' + template: + bootstrap: 5 + bslib: + preset: lux + enable-shadows: true + ') + + expect_equal(get_bslib_theme(pkg), "lux") + expect_no_error(bs_theme(pkg)) }) test_that("capture data_template()", { diff --git a/vignettes/customise.Rmd b/vignettes/customise.Rmd index c192bb50e..48b56c484 100644 --- a/vignettes/customise.Rmd +++ b/vignettes/customise.Rmd @@ -40,7 +40,7 @@ Upgrading to Bootstrap 5 has a low chance of breaking your site unless you were ## Theming -There are two ways to change the visual style of your site from `_pkgdown.yml`: using a pre-packaged bootswatch theme or customising theme variables with bslib. +There are two ways to change the visual style of your site from `_pkgdown.yml`: using a pre-packaged bootswatch theme or customising theme variables with [bslib](https://rstudio.github.io/bslib/). The following sections show you how. ### Bootswatch themes @@ -56,13 +56,14 @@ template: Changing the bootswatch theme affects both the HTML (via the navbar, more on that below) and the CSS, so you'll need to re-build your complete site with `build_site()` to fully appreciate the changes. While you're experimenting, you can speed things up by just rebuilding the home page and the CSS by running `build_home_index(); init_site()` (and then refreshing the browser). -Bootswatch templates with tall navbars (e.g. lux, pulse) also require that you set the `pkgdown-nav-height` bslib variable: +Bootswatch templates with tall navbars (e.g. lux, pulse) also require that you set the `pkgdown-nav-height` bslib variable. +Because Bootswatch themes are provided by the [bslib](https://rstudio.github.io/bslib/) R package, you can also nest the `bootswatch` field under the `bslib` field. ``` yaml template: bootstrap: 5 - bootswatch: lux bslib: + bootswatch: lux pkgdown-nav-height: 100px ``` @@ -108,6 +109,19 @@ template: While iterating on colours and other variables you only need to rerun `init_site()` and refresh your browser; when iterating on fonts, you'll need to run `build_home_index(); init_site()`. +Theming with bslib is powered by `bslib::bs_theme()` and the `bslib` field is a direct translation of the arguments to that function. +As a result, you can fully specify a bslib theme using the `template.bslib` field, making it easy to share YAML with the `output.html_document.theme` field [of an R Markdown document](https://rstudio.github.io/bslib/articles/theming/index.html). + +``` yaml +template: + bslib: + version: 5 + bootswatch: lux + base_font: {google: "Roboto"} + heading_font: {google: "Roboto Slab"} + code_font: {google: "JetBrains Mono"} +``` + ### Syntax highlighting The colours used for syntax highlighting in code blocks are controlled by the `theme` setting: