-
Notifications
You must be signed in to change notification settings - Fork 99
feat: Dynamic theming #1358
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
Merged
Merged
feat: Dynamic theming #1358
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Also use new sass file compilation method for bootstrap.min.css
a8a117e
to
93f8284
Compare
cpsievert
reviewed
Jun 25, 2024
cpsievert
reviewed
Jun 25, 2024
cpsievert
reviewed
Jun 26, 2024
cpsievert
reviewed
Jun 26, 2024
A slightly more involved suggestion to fix/simplify some of the |
Co-authored-by: Carson Sievert <carson@posit.co>
8f9e5d1
to
95cc53e
Compare
cpsievert
reviewed
Jun 26, 2024
cpsievert
reviewed
Jun 26, 2024
cpsievert
reviewed
Jun 26, 2024
105a8f8
to
5a3f84b
Compare
5a3f84b
to
a0eaf80
Compare
cpsievert
reviewed
Jun 27, 2024
cpsievert
reviewed
Jun 27, 2024
cpsievert
approved these changes
Jun 27, 2024
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
schloerke
added a commit
to machow/py-shiny
that referenced
this pull request
Jul 2, 2024
* main: fix(tests): dynamically determine the path to the shiny app (posit-dev#1485) tests(deploys): use a stable version of html tools instead of main branch (posit-dev#1483) feat(data frame): Support basic cell styling (posit-dev#1475) fix: support static files on pyodide / py.cafe under a prefix (posit-dev#1486) feat: Dynamic theming (posit-dev#1358) Add return type for `_task()` (posit-dev#1484) tests(controls): Change API from controls to controller (posit-dev#1481) fix(docs): Update path to reflect correct one (posit-dev#1478) docs(testing): Add quarto page for testing (posit-dev#1461) fix(test): Remove unused testrail reporting from nightly builds (posit-dev#1476)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Remaining tasks
shiny/api-examples/theme/app-core.py
includes a POC-level tests/example)scripts/_pkg-sources.R
shiny.ui.Theme
py-shinyswatch#39Introduction
This is a large PR; please read the PR description.
The primary goal of this PR is a low-level interface to customizable Shiny themes via
shiny.ui.Theme()
. In #1334, we introduced atheme
argument for all page functions, e.g.ui.page_sidebar()
andexpress.ui.page_opts()
. This can now be combined withshiny.ui.Theme()
to create a custom theme for your Shiny app:Note
Note that this API is aimed at advanced users who are comfortable with Bootstrap's Sass, as well as our own internal usage. With
brand.yml
, #1226, we intend to provide a higher-level API for theming that is more user-friendly.Internal Dependency Changes
The biggest internal changes is around how we handle page-level depenendencies. First I've renamed
bootstrap_theme_deps()
toshiny_page_theme_deps()
. This function now:Returns a complete bundle of dependencies for Bootstrap, and shiny/bslib components like selectize, ionRangeSlider, the datepicker and bslib's components.
Importantly, the styles for all of these base-Shiny components are now included in
bootstrap.min.css
, which can be thought of as a complete Shiny theme.The component dependencies are still attached directly to the components that use them, e.g. selectize still adds the selectize dependencies.
In these contexts, the component styles are rendered against a base Boostrap 5 theme. Within Shiny apps,
shiny_page_theme_deps()
are loaded by the page and appear first. Component dependencies are suppressed unless the component is used outside of a Shiny page, such as in an interactive Quarto document.This usage explains both the component-specific dependency as well as the use of default Bootstrap styles for these components.
Dependency Sourcing
The dependency sourcing in
scripts/htmlDependencies.R
has been completely refactored. There are two levels to the change:First, to bring in the component dependencies from shiny and bslib as before, but this time pre-rendering component-specific styles against a base Bootstrap 5 theme.
Second, to create
shiny/www/shared/sass
containing the complete set of Sass.scss
files to compile Bootstrap 5, as well as all component styles from shiny and bslib, into a single file.The end result is that we have a set of Sass files in
shiny/www/shared/sass/preset/{preset}/
that compile into a singlepreset.min.css
file and include all of the dependencies inshiny_page_theme_deps()
in a single stylesheet.These Sass files draw from source styles in
shiny/www/shared/sass/shiny
andshiny/www/shared/sass/bslib
. We only include Sass stylesheets that are needed, by recursively tracking imports.I did some very heavy refactoring of the existing
scripts/htmlDependencies.R
to make this work. The biggest refactor of existing code happened in e7c6189 and at every step I made sure that the existing functionality was preserved by running the script and ensuring that only the source code changed. In general, any commit usingrefactor:
in the commit message is a refactoring commit where only the source files changed.Initially in this PR, the Sass prep and compilation was a separate step, but it's now integrated into the
scripts/htmlDependencies.R
script. A big part of this refactoring included moving everything into smaller functions so that the script is easier to read as a workflow of steps.Getting the individual Sass files for all of the components required changes in shiny and bslib. In both packages, we had component dependency functions that took a
theme
object and returned a dependency passed throughbslib::bs_dependency()
orbslib::bs_dependency_defer()
, which rendered the Sass into minified CSS. The two PRs below refactored out the Sass rules or files so that we can call those directly to avoid the Sass compilation:Sass Compilation
For a
Theme
object, you can use the.to_sass()
method to get the Sass code for the theme. This reveals the structure of the Sass code that is generated by theTheme
object:We place user Sass code after the preset theme Sass code, except for defaults which are placed before theme defaults. This follows the logic of
sass::sass_layer_file()
and the layering order of Quarto. We only accept user Sass code in the theme, however, so we don't handle multiple Sass layers.To compile a custom theme to CSS, use the
.to_css()
method. This method caches the compiled CSS in the theme object, so that it only needs to be compiled once. If you use any of the.add_*()
methods after calling.to_css()
, or if you change{theme}.preset
, the CSS will be recompiled.The theme object is not a
Tagifiable
object but it does have a.tagify()
method so that we can throw an error if the theme is tagified. Tagifying the theme object is a signal that the theme was used in the UI. Instead, as the error recommends, users should pass the theme object to thetheme
argument of anypage_*()
function (orshiny.express.page_opts()
).We include pre-compiled versions of the
"shiny"
and"bootstrap"
themes, so no compilation or temporary folders are required forui.Theme("shiny")
orui.Theme("bootstrap")
until they have been customized.Before this PR, the shiny wheel was 3.38 MB (as reported by
make dist
); with the new Sass files and two pre-compiled themes it is now 3.75MB. If we included the pre-compiled Bootswatch themes, the wheel would be 4.91 MB.