diff --git a/DESCRIPTION b/DESCRIPTION
index fde27780..42c7da31 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -32,7 +32,8 @@ URL: http://rmarkdown.rstudio.com/flexdashboard
BugReports: https://github.com/rstudio/flexdashboard/issues
Encoding: UTF-8
Depends: R (>= 3.0.2)
-Imports:
+Imports:
+ grDevices,
tools,
utils,
jsonlite,
@@ -43,9 +44,12 @@ Imports:
shiny (>= 0.13),
scales,
sass,
- bslib
+ bslib (>= 0.2.4.9002)
Suggests: testthat
LazyData: TRUE
License: MIT + file LICENSE
RoxygenNote: 7.1.1
Config/testthat/edition: 3
+Remotes:
+ rstudio/bslib,
+ rstudio/rmarkdown#2049
diff --git a/NAMESPACE b/NAMESPACE
index 6cb184a6..be2f741f 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -12,6 +12,7 @@ import(bslib)
import(htmltools)
import(rmarkdown)
import(sass)
+importFrom(grDevices,col2rgb)
importFrom(jsonlite,toJSON)
importFrom(tools,file_path_sans_ext)
importFrom(utils,packageVersion)
diff --git a/NEWS.md b/NEWS.md
index c4332d63..41b23f4d 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,9 +1,51 @@
flexdashboard 0.5.2.9000
===========
+This release adds integration with the new [`{bslib}` package](https://rstudio.github.io/bslib/index.html), making the customization of main colors and fonts much easier via `flex_dashboard`'s `theme` parameter. For example, here's a custom dark mode with custom Google Fonts:
+
+````yaml
+---
+output:
+ flexdashboard::flex_dashboard:
+ theme:
+ bg: "#101010"
+ fg: "#FDF7F7"
+ primary: "#ED79F9"
+ base_font: !expr bslib::font_google("Prompt")
+ code_font: !expr bslib::font_google("JetBrains Mono")
+---
+````
+
+Furthermore, all of `{flexdashboard}` now also works sensible with `{bslib}`'s real-time theming widget (`bs_themer()`). To use it, add a `runtime: shiny` to the top of the yaml matter and call `bslib::bs_themer()` in a server context. Also, if your dashboard contains static plots, you can add `thematic::thematic_shiny(font = "auto")` to theme plots in real-time too (just make sure the plots are generated through `renderPlot()`).
+
+````yaml
+---
+output:
+ flexdashboard::flex_dashboard:
+ theme:
+ version: 4
+---
+
+```{r, include = FALSE}
+bslib::bs_themer()
+thematic::thematic_shiny(font = "auto")
+```
+
+## Row
+
+### My plot
+
+```{r}
+renderPlot(plot(1:10))
+```
+````
+
+By default, using this `{bslib}` integration will also upgrade your dashboard from Bootstrap 3 to 4. If you run into any issues with custom widgets rendering not quite right, note that you can add `version: 3` to the `theme` in order to use Bootstrap 3 instead of 4. To learn more about `{bslib}`[See here](https://github.com/rstudio/bslib#basic-theming-options) to learn more about the theming options that `{bslib}` provides.
+
### Possibly breaking changes
* The `smart` argument was removed from `flexdashboard::flex_dashboard` since it was removed in rmarkdown 2.2 (relatedly, we now require rmarkdown 2.2 or higher). (#301)
+* The `window.FlexDashboard.themeColor` JavaScript object property is no longer available. Resolving of theming accent colors should now be done server-side via `{bslib}`'s [dynamic theming tools](https://rstudio.github.io/bslib/articles/theming.html#custom-components-1). (#305)
### Improvements & fixes
diff --git a/R/bslib.R b/R/bslib.R
index e50ebf59..3da975f3 100644
--- a/R/bslib.R
+++ b/R/bslib.R
@@ -1,8 +1,5 @@
resolve_theme <- function(theme) {
if (is.list(theme)) {
- if (!is_available("rmarkdown", "2.6.6")) {
- stop("Providing a list to `theme` requires the rmarkdown verion 2.6.6 or higher.", call. = FALSE)
- }
return(as_bs_theme(theme))
}
if (identical(theme, "default")) {
diff --git a/R/dependencies.R b/R/dependencies.R
index a0dea7f4..bf44bf2a 100644
--- a/R/dependencies.R
+++ b/R/dependencies.R
@@ -12,6 +12,8 @@ flexdashboard_dependency <- function(name) {
system.file("www", name, package = "flexdashboard")
}
+# Might have an issue with jQuery 3?
+# https://github.com/jmosbech/StickyTableHeaders/pull/157
html_dependency_stickytableheaders <- function() {
htmlDependency(
"stickytableheaders",
diff --git a/R/flex_dashboard.R b/R/flex_dashboard.R
index 68840da0..3b894e28 100644
--- a/R/flex_dashboard.R
+++ b/R/flex_dashboard.R
@@ -297,54 +297,22 @@ flex_dashboard <- function(fig_width = 6.0,
add_graphic("logo", logo)
add_graphic("favicon", favicon)
- # include flexdashboard.css and flexdashboard.js (but not in devel
- # mode, in that case relative filesystem references to
- # them are included in the template along with live reload)
+ # Include flexdashboard.js unless we're in devel mode.
+ # In that case, relative filesystem references to
+ # them are included in the template, along with live reload
if (devel) {
args <- c(args, pandoc_variable_arg("devel", "1"))
- dashboardCss <- NULL
- dashboardScript <- NULL
} else {
- if (fill_page) {
- fillPageCss <- readLines(resource("fillpage.css"))
- } else {
- fillPageCss <- NULL
- }
-
- theme <- ifelse(identical(theme, "default"), "bootstrap", theme)
- dashboardCss <- c(
- ''
- )
-
- dashboardScript <- c(
- ''
- )
+ dashboardScriptFile <- tempfile(fileext = ".html")
+ dashboardScript <- c('')
+ writeLines(dashboardScript, dashboardScriptFile)
+ includes$before_body <- c(includes$before_body, dashboardScriptFile)
}
# if there is no fig_mobile height and width then pass the default
if (is.null(fig_mobile))
fig_mobile <- default_fig_mobile
- # css
- if (!is.null(dashboardCss)) {
- dashboardCssFile <- tempfile(fileext = "html")
- writeLines(dashboardCss, dashboardCssFile)
- args <- c(args, pandoc_include_args(in_header = dashboardCssFile))
- }
-
- # script
- if (!is.null(dashboardScript)) {
- dashboardScriptFile <- tempfile(fileext = ".html")
- writeLines(dashboardScript, dashboardScriptFile)
- includes$before_body <- c(includes$before_body, dashboardScriptFile)
- }
-
# dashboard init script
dashboardInitScript <- c(
''
)
@@ -420,6 +400,33 @@ flex_dashboard <- function(fig_width = 6.0,
html_dependency_prism()))
}
+ if (fill_page) {
+ extra_dependencies <- append(extra_dependencies, html_dependencies_fillpage())
+ }
+
+ if (is_bs_theme(theme)) {
+ if (!is_available("rmarkdown", "2.7.1")) {
+ stop("Using a {bslib} theme requires rmarkdown v2.7.1 or higher")
+ }
+
+ # Attach the dynamic CSS dependency to the theme so that the dependency
+ # is restyled if and when `session$setCurrentTheme()` gets called
+ flexdb_css <- bslib::bs_dependency_defer(html_dependencies_flexdb)
+ theme <- bslib::bs_bundle(theme, sass::sass_layer(html_deps = flexdb_css))
+
+ # If $navbar-bg wasn't specified by user, default it to $primary
+ # (instead of $dark, since the template has .navbar-inverse)
+ navbar_bg <- bslib::bs_get_variables(theme, "navbar-bg")
+ if (is.na(navbar_bg)) {
+ theme <- bslib::bs_add_variables(
+ theme, primary = getSassAccentColors(theme, "primary"),
+ "navbar-bg" = "$primary"
+ )
+ }
+ } else {
+ extra_dependencies <- append(extra_dependencies, html_dependencies_flexdb(theme))
+ }
+
# return format
output_format(
knitr = knitr_options,
@@ -616,6 +623,45 @@ storyboard_dependencies <- function(source = NULL) {
}
+html_dependencies_fillpage <- function() {
+ list(htmlDependency(
+ name = "flexdashboard-fillpage",
+ version = packageVersion("flexdashboard"),
+ src = "rmarkdown/templates/flex_dashboard/resources",
+ package = "flexdashboard",
+ stylesheet = "fillpage.css"
+ ))
+}
+
+html_dependencies_flexdb <- function(theme) {
+ name <- "flexdashboard-css"
+ version <- packageVersion("flexdashboard")
+
+ if (is.character(theme)) {
+ dep <- htmlDependency(
+ name = name, version = version,
+ src = "rmarkdown/templates/flex_dashboard/resources",
+ package = "flexdashboard",
+ stylesheet = c(
+ "flexdashboard.css",
+ paste0("theme-", theme, ".css")
+ )
+ )
+ return(list(dep))
+ }
+
+ if (bslib::is_bs_theme(theme)) {
+ dep <- bslib::bs_dependency(
+ sass::sass_file(resource("flexdashboard.scss")),
+ theme = theme, name = name, version = version,
+ cache_key_extra = version
+ )
+ return(list(dep))
+ }
+
+ stop("Didn't recognize a theme object with class: ", class(theme))
+}
+
# function for resolving resources
resource <- function(name) {
system.file("rmarkdown/templates/flex_dashboard/resources", name,
diff --git a/R/gauge.R b/R/gauge.R
index e778b518..a14e227d 100644
--- a/R/gauge.R
+++ b/R/gauge.R
@@ -133,11 +133,11 @@ resolveAccentColors <- function(colors, theme) {
if (!length(colors)) return(colors)
idx <- vapply(colors, is_accent_color, logical(1))
- if (is.character(theme)) {
- colors[idx] <- themeColors[[theme]][colors[idx]]
- } else if (bslib::is_bs_theme(theme)) {
+ if (bslib::is_bs_theme(theme)) {
accentMap <- getSassAccentColors(theme, unique(colors[idx]))
colors[idx] <- accentMap[colors[idx]]
+ } else if (is.character(theme)) {
+ colors[idx] <- themeColors[[theme]][colors[idx]]
}
as.character(colors)
}
@@ -146,10 +146,9 @@ getSassAccentColors <- function(theme, accents = accent_colors()) {
if ("3" %in% bslib::theme_version(theme)) {
accents <- paste0("brand-", accents)
}
- setNames(
- bslib::bs_get_variables(theme, accents),
- sub("^brand-", "", accents)
- )
+ vals <- bslib::bs_get_variables(theme, accents)
+ names(vals) <- sub("^brand-", "", accents)
+ vals
}
diff --git a/R/package.R b/R/package.R
index f5ae43fc..b8ea1e9f 100644
--- a/R/package.R
+++ b/R/package.R
@@ -21,6 +21,7 @@
#' @importFrom jsonlite toJSON
#' @importFrom tools file_path_sans_ext
#' @importFrom utils packageVersion
+#' @importFrom grDevices col2rgb
#'
#' @docType package
#' @name flexdashboard
diff --git a/R/valuebox.R b/R/valuebox.R
index e5c09021..bcf00c17 100644
--- a/R/valuebox.R
+++ b/R/valuebox.R
@@ -111,11 +111,8 @@ valueBoxDynamicAccentCSS <- function(theme) {
getColorContrast <- function(color) {
sass_func <- system.file("sass-utils", "color-contrast.scss", package = "bslib")
sassValue(
- sprintf("color-contrast(%s)", color),
- defaults = list(
- "color-contrast-dark" = "#1a1a1a", # TODO: better way to get a muted contrast?
- sass::sass_file(sass_func)
- )
+ sprintf("color-contrast(%s, #1a1a1a)", color),
+ defaults = sass::sass_file(sass_func)
)
}
@@ -125,7 +122,9 @@ sassValue <- function(expr, defaults = "") {
list(defaults, sprintf("foo{bar:%s}", expr)),
options = sass::sass_options(output_style = "compressed")
)
- sub("}", "", sub("foo{bar:", "", out, fixed = TRUE), fixed = TRUE)
+ out <- sub("foo{bar:", "", out, fixed = TRUE)
+ out <- sub("}", "", out, fixed = TRUE)
+ gsub("\n", "", out, fixed = TRUE)
}
diff --git a/inst/rmarkdown/templates/flex_dashboard/resources/default.html b/inst/rmarkdown/templates/flex_dashboard/resources/default.html
index 062b5fb3..6e2f47e9 100644
--- a/inst/rmarkdown/templates/flex_dashboard/resources/default.html
+++ b/inst/rmarkdown/templates/flex_dashboard/resources/default.html
@@ -99,11 +99,9 @@