diff --git a/inst/emptystate.js b/inst/emptystate.js index 92a36d6..aceb406 100644 --- a/inst/emptystate.js +++ b/inst/emptystate.js @@ -75,6 +75,18 @@ function hideEmptyState(message) { resizeObserver.unobserve(elementToReplace); } +function shiny_emptystate_updatePosition(id){ + const elementWithEmptyState = findElementById(id); + const emptyStateContainer = elementWithEmptyState.querySelector(".empty-state-container"); + + const parentElement = emptyStateContainer.parentElement; + emptyStateContainer.style.height = parentElement.offsetHeight + "px"; + emptyStateContainer.style.width = parentElement.offsetWidth + "px"; + emptyStateContainer.style.left = parentElement.offsetLeft + "px"; + emptyStateContainer.style.top = parentElement.offsetTop + "px"; +} + + $(function() { Shiny.addCustomMessageHandler("showEmptyState", showEmptyState) Shiny.addCustomMessageHandler("hideEmptyState", hideEmptyState) diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index 6798028..84d0edb 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -31,25 +31,38 @@ url: https://appsilon.github.io/shiny.emptystate/ navbar: bg: primary - left: - - icon: fa-home - href: index.html + structure: + left: [home, tutorials, reference, changelog] + right: [search, github, twitter, mastodon] + components: + home: + icon: fa-home text: "Start" - - icon: fa-university - href: articles/use-undraw-drawkit-image.html - text: "Tutorial" - - icon: fa-file-code-o + href: index.html + tutorials: + text: Tutorials + icon: fa-university + menu: + - text: How to Use unDraw/Drawkit Illustrations + href: articles/use-undraw-drawkit-image.html + - text: How to use triggered animations + href: articles/use-toggle-animations.html + reference: + icon: fa-file-code-o text: "Reference" href: reference/index.html - - icon: fa-newspaper-o - text: Changelog + changelog: + icon: fa-newspaper-o + text: "Changelog" href: news/index.html - right: - - icon: fa-github fa-lg + github: + icon: fa-github fa-lg href: https://github.com/Appsilon/shiny.emptystate - - icon: fa-twitter fa-lg + twitter: + icon: fa-twitter fa-lg href: https://twitter.com/Appsilon - - icon: fab fa-mastodon fa-lg + mastodon: + icon: fab fa-mastodon fa-lg href: https://fosstodon.org/@appsilon home: diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index 3fc3db1..67ab194 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -26,3 +26,46 @@ test_app <- function() { } ) } + +test_slider_app <- function() { + shiny::shinyApp( + ui = shiny::fillPage( + use_empty_state(), + shiny::actionButton( + "toggle_pannel", + "Toggle panel", + class = "btn btn-primary", + onClick = "$('#container1').toggle(0, + function(){shiny_emptystate_updatePosition('container2')});" + ), + shiny::div( + style = "width: 300px", + class = "d-flex flex-column gap-5", + shiny::div( + id = "container1", + shiny::div( + shiny::h1("Card 1"), + "Card content" + ) + ), + shiny::div( + id = "container2", + shiny::div( + shiny::h1("Card 2"), + "Card content" + ) + ) + ) + ), + server = function(input, output) { + empty_state_content <- shiny::div( + "This is example empty state content" + ) + empty_state_manager <- EmptyStateManager$new( + id = "container2", + html_content = empty_state_content + ) + empty_state_manager$show() + } + ) +} diff --git a/tests/testthat/test-empty_state.R b/tests/testthat/test-empty_state.R index aa25bdd..b204f02 100644 --- a/tests/testthat/test-empty_state.R +++ b/tests/testthat/test-empty_state.R @@ -59,6 +59,15 @@ describe("EmptyStateManager", { expect_null(app$get_html(selector = ".empty-state-content")) app$stop() }) + + it("checks the empty state component follows slider from id", { + app <- shinytest2::AppDriver$new(test_slider_app(), name = "slide_tag") + position_1 <- app$get_html(selector = "#container2") + app$click("toggle_pannel") + position_2 <- app$get_html(selector = "#container2") + expect_false(position_1 == position_2) + app$stop() + }) }) describe("use_empty_state()", { diff --git a/vignettes/files/dynamic_emptystate.gif b/vignettes/files/dynamic_emptystate.gif new file mode 100644 index 0000000..2927ffe Binary files /dev/null and b/vignettes/files/dynamic_emptystate.gif differ diff --git a/vignettes/use-toggle-animations.rmd b/vignettes/use-toggle-animations.rmd new file mode 100644 index 0000000..71c9a82 --- /dev/null +++ b/vignettes/use-toggle-animations.rmd @@ -0,0 +1,69 @@ +--- +title: "How to use triggered animations" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{How to use triggered animations} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +# Introduction + +`shiny.emptystate` is capable of being used for dynamic positioning trigger animations. This is specially interesting when we have UIs that change position and we want to keep the `emptystate` in the appropriate tag + +**Note:** This solution is only available for instant positioning animation. + +# Animation example + +The example below showcases the example of using a dynamic trigger slider that changes. + +The function `shiny_emptystate_updatePosition` updates the position of the #container1 after being re-positioned + +``` r +library(shiny) +library(shiny.emptystate) + +ui <- shiny::fillPage( + use_empty_state(), + shiny::actionButton( + "toggle_pannel", + "Toggle panel", + class = "btn btn-primary", + onClick = "$('#container1').toggle(0, + function(){shiny_emptystate_updatePosition('container2')});" + ), + shiny::div( + style = "width: 300px", + class = "d-flex flex-column gap-5", + shiny::div( + id = "container1", + shiny::div( + shiny::h1("Card 1"), + "Card content" + ) + ), + shiny::div( + id = "container2", + shiny::div( + shiny::h1("Card 2"), + "Card content" + ) + ) + ) +) + +server = function(input, output) { + empty_state_content <- shiny::div( + "This is example empty state content" + ) + empty_state_manager <- EmptyStateManager$new( + id = "container2", + html_content = empty_state_content + ) + empty_state_manager$show() +} + +shinyApp(ui, server) +``` + +![](files/dynamic_emptystate.gif)