├── .github ├── .gitignore └── workflows │ ├── pr-commands.yaml │ └── R-CMD-check.yaml ├── vignettes ├── .gitignore └── truelle.Rmd ├── LICENSE ├── inst ├── WORDLIST ├── app │ └── www │ │ ├── favicon.ico │ │ ├── shiny-fluent.png │ │ ├── shiny-semantic.png │ │ ├── semantic-dashboard.png │ │ └── shinyMobile.svg ├── golem-config.yml ├── templates_server │ ├── shinyMobile_tabs.R │ ├── shinydashboard.R │ ├── semantic.dashboard.R │ ├── shiny.fluent.R │ ├── shinyMobile_simple.R │ ├── shinyMobile_split.R │ ├── shiny.semantic.R │ ├── shinymaterial.R │ └── bs4Dash.R └── templates_ui │ ├── shiny.semantic.R │ ├── shiny.fluent.R │ ├── shinydashboard.R │ ├── semantic.dashboard.R │ ├── shinymaterial.R │ ├── shinyMobile_simple.R │ ├── shinyMobile_split.R │ ├── shinyMobile_tabs.R │ └── bs4Dash.R ├── tests ├── testthat.R ├── testthat │ ├── test-app.R │ └── test-golem-recommended.R └── spelling.R ├── NEWS.md ├── .gitignore ├── man ├── figures │ ├── truelle-output.png │ ├── truelle-project-type.png │ ├── truelle-ui-template.png │ ├── golem-package-structure.png │ ├── truelle-package-options.png │ └── truelle-project-engine.png ├── createRadioOptions.Rd ├── radio.Rd └── run_app.Rd ├── .Rbuildignore ├── dev ├── run_dev.R ├── 03_deploy.R ├── 01_start.R └── 02_dev.R ├── truelle.Rproj ├── NAMESPACE ├── R ├── run_app.R ├── golem_utils_server.R ├── app_config.R ├── utils_helpers.R ├── golem_utils_ui.R ├── app_ui.R └── app_server.R ├── DESCRIPTION ├── LICENSE.md ├── README.md ├── README.Rmd └── CODE_OF_CONDUCT.md /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2021 2 | COPYRIGHT HOLDER: David Granjon 3 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | Lifecycle 2 | github 3 | golem 4 | https 5 | reactR 6 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(truelle) 3 | 4 | test_check("truelle") 5 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # truelle 0.0.0.9000 2 | 3 | * Added a `NEWS.md` file to track changes to the package. 4 | -------------------------------------------------------------------------------- /inst/app/www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/inst/app/www/favicon.ico -------------------------------------------------------------------------------- /tests/testthat/test-app.R: -------------------------------------------------------------------------------- 1 | test_that("multiplication works", { 2 | expect_equal(2 * 2, 4) 3 | }) 4 | -------------------------------------------------------------------------------- /inst/app/www/shiny-fluent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/inst/app/www/shiny-fluent.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .Rdata 4 | .httr-oauth 5 | .DS_Store 6 | inst/doc 7 | /doc/ 8 | /Meta/ 9 | -------------------------------------------------------------------------------- /inst/app/www/shiny-semantic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/inst/app/www/shiny-semantic.png -------------------------------------------------------------------------------- /man/figures/truelle-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/man/figures/truelle-output.png -------------------------------------------------------------------------------- /inst/app/www/semantic-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/inst/app/www/semantic-dashboard.png -------------------------------------------------------------------------------- /man/figures/truelle-project-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/man/figures/truelle-project-type.png -------------------------------------------------------------------------------- /man/figures/truelle-ui-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/man/figures/truelle-ui-template.png -------------------------------------------------------------------------------- /man/figures/golem-package-structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/man/figures/golem-package-structure.png -------------------------------------------------------------------------------- /man/figures/truelle-package-options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/man/figures/truelle-package-options.png -------------------------------------------------------------------------------- /man/figures/truelle-project-engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinteRface/truelle/HEAD/man/figures/truelle-project-engine.png -------------------------------------------------------------------------------- /inst/golem-config.yml: -------------------------------------------------------------------------------- 1 | default: 2 | golem_name: truelle 3 | golem_version: 0.0.0.9000 4 | app_prod: no 5 | production: 6 | app_prod: yes 7 | dev: 8 | golem_wd: !expr here::here() 9 | -------------------------------------------------------------------------------- /tests/spelling.R: -------------------------------------------------------------------------------- 1 | if(requireNamespace('spelling', quietly = TRUE)) 2 | spelling::spell_check_test(vignettes = TRUE, error = FALSE, 3 | skip_on_cran = TRUE) 4 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^data-raw$ 4 | dev_history.R 5 | ^dev$ 6 | $run_dev.* 7 | ^LICENSE\.md$ 8 | ^README\.Rmd$ 9 | ^CODE_OF_CONDUCT\.md$ 10 | ^doc$ 11 | ^Meta$ 12 | ^\.github$ 13 | -------------------------------------------------------------------------------- /inst/templates_server/shinyMobile_tabs.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import shinyMobile 7 | #' @noRd 8 | app_server <- function( input, output, session ) { 9 | output$val <- renderPrint(input$stepper) 10 | } -------------------------------------------------------------------------------- /dev/run_dev.R: -------------------------------------------------------------------------------- 1 | # Set options here 2 | options(golem.app.prod = FALSE) # TRUE = production mode, FALSE = development mode 3 | 4 | # Detach all loaded packages and clean your environment 5 | golem::detach_all_attached() 6 | # rm(list=ls(all.names = TRUE)) 7 | 8 | # Document and reload your package 9 | golem::document_and_reload() 10 | 11 | # Run the application 12 | run_app() 13 | -------------------------------------------------------------------------------- /inst/templates_server/shinydashboard.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import shinydashboard 7 | #' @noRd 8 | app_server <- function( input, output, session ) { 9 | output$plot1 <- renderPlot( 10 | hist(rnorm(input$slider)) 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /inst/templates_server/semantic.dashboard.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import semantic.dashboard 7 | #' @noRd 8 | app_server <- function( input, output, session ) { 9 | output$plot1 <- renderPlot( 10 | hist(rnorm(input$slider)) 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /inst/templates_server/shiny.fluent.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import shiny.fluent 7 | #' @noRd 8 | app_server <- function( input, output, session ) { 9 | output$sliderValue <- renderText({ 10 | sprintf("Value: %s", input$slider) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /vignettes/truelle.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "truelle" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{truelle} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(truelle) 19 | ``` 20 | -------------------------------------------------------------------------------- /inst/templates_server/shinyMobile_simple.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import shinyMobile 7 | #' @noRd 8 | app_server <- function( input, output, session ) { 9 | output$data <- renderTable({ 10 | mtcars[, c("mpg", input$variable), drop = FALSE] 11 | }, rownames = TRUE) 12 | } -------------------------------------------------------------------------------- /truelle.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: XeLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | PackageRoxygenize: rd,collate,namespace 19 | -------------------------------------------------------------------------------- /inst/templates_server/shinyMobile_split.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import shinyMobile 7 | #' @noRd 8 | app_server <- function( input, output, session ) { 9 | output$selected_tab <- renderUI({ 10 | HTML(paste0("Selected tab: ", strong(input$menu))) 11 | }) 12 | 13 | output$distPlot <- renderPlot({ 14 | dist <- rnorm(input$obs) 15 | hist(dist) 16 | }) 17 | } -------------------------------------------------------------------------------- /man/createRadioOptions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils_helpers.R 3 | \name{createRadioOptions} 4 | \alias{createRadioOptions} 5 | \title{Generates a list of option for \link{f7Radio}} 6 | \usage{ 7 | createRadioOptions(choices, selected, inputId) 8 | } 9 | \arguments{ 10 | \item{choices}{List of choices.} 11 | 12 | \item{selected}{Selected value} 13 | 14 | \item{inputId}{Radio input id.} 15 | } 16 | \description{ 17 | Generates a list of option for \link{f7Radio} 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /man/radio.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils_helpers.R 3 | \name{f7Radio} 4 | \alias{f7Radio} 5 | \title{Modified Framework7 radio input} 6 | \usage{ 7 | f7Radio(inputId, label, choices = NULL, selected = NULL) 8 | } 9 | \arguments{ 10 | \item{inputId}{Radio input id.} 11 | 12 | \item{label}{Radio label} 13 | 14 | \item{choices}{List of choices. Must be a nested list.} 15 | 16 | \item{selected}{Selected element. NULL by default.} 17 | } 18 | \description{ 19 | \code{f7Radio} creates a radio button input. 20 | } 21 | -------------------------------------------------------------------------------- /inst/templates_server/shiny.semantic.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import shiny.semantic 7 | #' @noRd 8 | app_server <- function( input, output, session ) { 9 | observeEvent(input$button, { 10 | modal <- create_modal( 11 | modal( 12 | id = "simple-modal", 13 | header = h2("Important message"), 14 | "This is an important message!" 15 | ), 16 | show = TRUE, 17 | session = getDefaultReactiveDomain() 18 | ) 19 | showModal(modal, session = getDefaultReactiveDomain()) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(f7Radio) 4 | export(run_app) 5 | import(shiny) 6 | import(shinyMobile) 7 | importFrom(callr,r_bg) 8 | importFrom(golem,activate_js) 9 | importFrom(golem,add_resource_path) 10 | importFrom(golem,bundle_resources) 11 | importFrom(golem,favicon) 12 | importFrom(golem,with_golem_options) 13 | importFrom(jsonlite,toJSON) 14 | importFrom(rclipboard,rclipboardSetup) 15 | importFrom(shiny,HTML) 16 | importFrom(shiny,column) 17 | importFrom(shiny,shinyApp) 18 | importFrom(shiny,tagAppendAttributes) 19 | importFrom(shiny,tagList) 20 | importFrom(shiny,tags) 21 | importFrom(shinyAce,aceEditor) 22 | importFrom(shinyAce,updateAceEditor) 23 | -------------------------------------------------------------------------------- /tests/testthat/test-golem-recommended.R: -------------------------------------------------------------------------------- 1 | test_that("app ui", { 2 | ui <- app_ui() 3 | golem::expect_shinytaglist(ui) 4 | # Check that formals have not been removed 5 | fmls <- formals(app_ui) 6 | for (i in c("request")){ 7 | expect_true(i %in% names(fmls)) 8 | } 9 | }) 10 | 11 | test_that("app server", { 12 | server <- app_server 13 | expect_is(server, "function") 14 | # Check that formals have not been removed 15 | fmls <- formals(app_server) 16 | for (i in c("input", "output", "session")){ 17 | expect_true(i %in% names(fmls)) 18 | } 19 | }) 20 | 21 | # Configure this test to fit your need 22 | test_that( 23 | "app launches",{ 24 | golem::expect_running(sleep = 5) 25 | } 26 | ) 27 | -------------------------------------------------------------------------------- /R/run_app.R: -------------------------------------------------------------------------------- 1 | #' Run the Shiny Application 2 | #' 3 | #' @param ... arguments to pass to golem_opts. 4 | #' See `?golem::get_golem_options` for more details. 5 | #' @inheritParams shiny::shinyApp 6 | #' 7 | #' @export 8 | #' @importFrom shiny shinyApp 9 | #' @importFrom golem with_golem_options 10 | run_app <- function( 11 | onStart = NULL, 12 | options = list(), 13 | enableBookmarking = NULL, 14 | uiPattern = "/", 15 | ... 16 | ) { 17 | with_golem_options( 18 | app = runGadget(shinyApp( 19 | ui = app_ui, 20 | server = app_server, 21 | onStart = onStart, 22 | options = options, 23 | enableBookmarking = enableBookmarking, 24 | uiPattern = uiPattern 25 | )), 26 | golem_opts = list(...) 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: truelle 2 | Title: Build tools for {golem}, {packer}, {reactR} and {shiny} 3 | Version: 0.0.0.9000 4 | Authors@R: person('David', 'Granjon', email = 'dgranjon@ymail.com', role = c('cre', 'aut')) 5 | Description: Easily setup a {golem}, {packer}, {reactR} and {shiny} project 6 | with an intuitive Gadget. Perfect if you don't have good memory. 7 | License: MIT + file LICENSE 8 | Imports: 9 | callr, 10 | config (>= 0.3.1), 11 | golem (>= 0.3.1), 12 | jsonlite, 13 | processx, 14 | rclipboard, 15 | rlang, 16 | shiny (>= 1.6.0), 17 | shinyAce, 18 | shinyMobile 19 | Encoding: UTF-8 20 | LazyData: true 21 | RoxygenNote: 7.1.1 22 | Suggests: 23 | rmarkdown, 24 | knitr, 25 | spelling, 26 | testthat (>= 3.0.0) 27 | Config/testthat/edition: 3 28 | Language: en-US 29 | VignetteBuilder: knitr 30 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2021 David Granjon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R/golem_utils_server.R: -------------------------------------------------------------------------------- 1 | #' Inverted versions of in, is.null and is.na 2 | #' 3 | #' @noRd 4 | #' 5 | #' @examples 6 | #' 1 %not_in% 1:10 7 | #' not_null(NULL) 8 | `%not_in%` <- Negate(`%in%`) 9 | 10 | not_null <- Negate(is.null) 11 | 12 | not_na <- Negate(is.na) 13 | 14 | #' Removes the null from a vector 15 | #' 16 | #' @noRd 17 | #' 18 | #' @example 19 | #' drop_nulls(list(1, NULL, 2)) 20 | drop_nulls <- function(x){ 21 | x[!sapply(x, is.null)] 22 | } 23 | 24 | #' If x is `NULL`, return y, otherwise return x 25 | #' 26 | #' @param x,y Two elements to test, one potentially `NULL` 27 | #' 28 | #' @noRd 29 | #' 30 | #' @examples 31 | #' NULL %||% 1 32 | "%||%" <- function(x, y){ 33 | if (is.null(x)) { 34 | y 35 | } else { 36 | x 37 | } 38 | } 39 | 40 | #' If x is `NA`, return y, otherwise return x 41 | #' 42 | #' @param x,y Two elements to test, one potentially `NA` 43 | #' 44 | #' @noRd 45 | #' 46 | #' @examples 47 | #' NA %||% 1 48 | "%|NA|%" <- function(x, y){ 49 | if (is.na(x)) { 50 | y 51 | } else { 52 | x 53 | } 54 | } 55 | 56 | #' Typing reactiveValues is too long 57 | #' 58 | #' @inheritParams reactiveValues 59 | #' @inheritParams reactiveValuesToList 60 | #' 61 | #' @noRd 62 | rv <- shiny::reactiveValues 63 | rvtl <- shiny::reactiveValuesToList 64 | 65 | -------------------------------------------------------------------------------- /R/app_config.R: -------------------------------------------------------------------------------- 1 | #' Access files in the current app 2 | #' 3 | #' NOTE: If you manually change your package name in the DESCRIPTION, 4 | #' don't forget to change it here too, and in the config file. 5 | #' For a safer name change mechanism, use the `golem::set_golem_name()` function. 6 | #' 7 | #' @param ... character vectors, specifying subdirectory and file(s) 8 | #' within your package. The default, none, returns the root of the app. 9 | #' 10 | #' @noRd 11 | app_sys <- function(...){ 12 | system.file(..., package = "truelle") 13 | } 14 | 15 | 16 | #' Read App Config 17 | #' 18 | #' @param value Value to retrieve from the config file. 19 | #' @param config GOLEM_CONFIG_ACTIVE value. If unset, R_CONFIG_ACTIVE. 20 | #' If unset, "default". 21 | #' @param use_parent Logical, scan the parent directory for config file. 22 | #' 23 | #' @noRd 24 | get_golem_config <- function( 25 | value, 26 | config = Sys.getenv( 27 | "GOLEM_CONFIG_ACTIVE", 28 | Sys.getenv( 29 | "R_CONFIG_ACTIVE", 30 | "default" 31 | ) 32 | ), 33 | use_parent = TRUE 34 | ){ 35 | config::get( 36 | value = value, 37 | config = config, 38 | # Modify this if your config file is somewhere else: 39 | file = app_sys("golem-config.yml"), 40 | use_parent = use_parent 41 | ) 42 | } 43 | 44 | -------------------------------------------------------------------------------- /dev/03_deploy.R: -------------------------------------------------------------------------------- 1 | # Building a Prod-Ready, Robust Shiny Application. 2 | # 3 | # README: each step of the dev files is optional, and you don't have to 4 | # fill every dev scripts before getting started. 5 | # 01_start.R should be filled at start. 6 | # 02_dev.R should be used to keep track of your development during the project. 7 | # 03_deploy.R should be used once you need to deploy your app. 8 | # 9 | # 10 | ###################################### 11 | #### CURRENT FILE: DEPLOY SCRIPT ##### 12 | ###################################### 13 | 14 | # Test your app 15 | 16 | ## Run checks ---- 17 | ## Check the package before sending to prod 18 | devtools::check() 19 | rhub::check_for_cran() 20 | 21 | # Deploy 22 | 23 | ## Local, CRAN or Package Manager ---- 24 | ## This will build a tar.gz that can be installed locally, 25 | ## sent to CRAN, or to a package manager 26 | devtools::build() 27 | 28 | ## RStudio ---- 29 | ## If you want to deploy on RStudio related platforms 30 | golem::add_rstudioconnect_file() 31 | golem::add_shinyappsio_file() 32 | golem::add_shinyserver_file() 33 | 34 | ## Docker ---- 35 | ## If you want to deploy via a generic Dockerfile 36 | golem::add_dockerfile() 37 | 38 | ## If you want to deploy to ShinyProxy 39 | golem::add_dockerfile_shinyproxy() 40 | 41 | ## If you want to deploy to Heroku 42 | golem::add_dockerfile_heroku() 43 | -------------------------------------------------------------------------------- /inst/templates_server/shinymaterial.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import shinymaterial 7 | #' @import ggplot2 8 | #' @noRd 9 | app_server <- function( input, output, session ) { 10 | output$mtcars_plot <- renderPlot({ 11 | plot_output <- 12 | ggplot( 13 | mtcars, 14 | aes( 15 | x = hp, 16 | y = mpg 17 | ) 18 | ) + 19 | xlab("Horse Power") + 20 | ylab("Miles Per Gallon") + 21 | geom_point() + 22 | theme( 23 | text = element_text(size = 16) 24 | ) 25 | 26 | if(input$facet_cyl){ 27 | plot_output <- 28 | plot_output + 29 | facet_wrap( 30 | "cyl" 31 | ) 32 | } 33 | 34 | if(input$trend_line){ 35 | plot_output <- 36 | plot_output + 37 | stat_smooth( 38 | method = "lm", 39 | se = FALSE 40 | ) 41 | } 42 | 43 | if(input$plot_theme == "light"){ 44 | plot_output <- 45 | plot_output + 46 | theme_light(base_size = 20) 47 | } else if(input$plot_theme == "dark"){ 48 | plot_output <- 49 | plot_output + 50 | theme_dark(base_size = 20) 51 | } 52 | 53 | plot_output 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /inst/templates_ui/shiny.semantic.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' Semantic UI template 4 | #' 5 | #' @param request Internal parameter for `{shiny}`. 6 | #' DO NOT REMOVE. 7 | #' @import shiny 8 | #' @import shiny.semantic 9 | #' @noRd 10 | app_ui <- function(request) { 11 | tagList( 12 | # Leave this function for adding external resources 13 | golem_add_external_resources(), 14 | semanticPage( 15 | div( 16 | class = "ui raised segment", 17 | div( 18 | a(class="ui green ribbon label", "Link"), 19 | p("Lorem ipsum, lorem ipsum, lorem ipsum"), 20 | progress("progress", percent = 24, label = "{percent}% complete"), 21 | actionButton("button", "Click me!") 22 | ) 23 | ) 24 | ) 25 | ) 26 | } 27 | 28 | 29 | #' Add external Resources to the Application 30 | #' 31 | #' This function is internally used to add external 32 | #' resources inside the Shiny application. 33 | #' 34 | #' @import shiny 35 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 36 | #' @noRd 37 | golem_add_external_resources <- function(){ 38 | 39 | add_resource_path( 40 | 'www', app_sys('app/www') 41 | ) 42 | 43 | tags$head( 44 | favicon(), 45 | bundle_resources( 46 | path = app_sys('app/www'), 47 | app_title = 'My app' 48 | ) 49 | # Add here other external resources 50 | # for example, you can add shinyalert::useShinyalert() 51 | ) 52 | } 53 | 54 | -------------------------------------------------------------------------------- /inst/templates_server/bs4Dash.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import bs4Dash 7 | #' @noRd 8 | app_server <- function( input, output, session ) { 9 | output$plot <- renderPlot({ 10 | req(!input$mybox$collapsed) 11 | plot(rnorm(200)) 12 | }) 13 | 14 | output$box_state <- renderText({ 15 | state <- if (input$mybox$collapsed) "collapsed" else "uncollapsed" 16 | paste("My box is", state) 17 | }) 18 | 19 | observeEvent(input$toggle_box, { 20 | updateBox("mybox", action = "toggle") 21 | }) 22 | 23 | observeEvent(input$remove_box, { 24 | updateBox("mybox", action = "remove") 25 | }) 26 | 27 | observeEvent(input$restore_box, { 28 | updateBox("mybox", action = "restore") 29 | }) 30 | 31 | observeEvent(input$update_box, { 32 | updateBox( 33 | "mybox", 34 | action = "update", 35 | options = list( 36 | title = h2("New title", dashboardBadge(1, color = "primary")), 37 | status = "danger", 38 | solidHeader = TRUE, 39 | width = 4 40 | ) 41 | ) 42 | }) 43 | 44 | observeEvent(input$mybox$visible, { 45 | collapsed <- if (input$mybox$collapsed) "collapsed" else "uncollapsed" 46 | visible <- if (input$mybox$visible) "visible" else "hidden" 47 | message <- paste("My box is", collapsed, "and", visible) 48 | toast( 49 | title = message, 50 | options = list( 51 | autohide = TRUE, 52 | class = "bg-pink", 53 | position = "topRight" 54 | ) 55 | ) 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /man/run_app.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/run_app.R 3 | \name{run_app} 4 | \alias{run_app} 5 | \title{Run the Shiny Application} 6 | \usage{ 7 | run_app( 8 | onStart = NULL, 9 | options = list(), 10 | enableBookmarking = NULL, 11 | uiPattern = "/", 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{onStart}{A function that will be called before the app is actually run. 17 | This is only needed for \code{shinyAppObj}, since in the \code{shinyAppDir} 18 | case, a \code{global.R} file can be used for this purpose.} 19 | 20 | \item{options}{Named options that should be passed to the \code{runApp} call 21 | (these can be any of the following: "port", "launch.browser", "host", "quiet", 22 | "display.mode" and "test.mode"). You can also specify \code{width} and 23 | \code{height} parameters which provide a hint to the embedding environment 24 | about the ideal height/width for the app.} 25 | 26 | \item{enableBookmarking}{Can be one of \code{"url"}, \code{"server"}, or 27 | \code{"disable"}. The default value, \code{NULL}, will respect the setting from 28 | any previous calls to \code{\link[shiny:enableBookmarking]{enableBookmarking()}}. See \code{\link[shiny:enableBookmarking]{enableBookmarking()}} 29 | for more information on bookmarking your app.} 30 | 31 | \item{uiPattern}{A regular expression that will be applied to each \code{GET} 32 | request to determine whether the \code{ui} should be used to handle the 33 | request. Note that the entire request path must match the regular 34 | expression in order for the match to be considered successful.} 35 | 36 | \item{...}{arguments to pass to golem_opts. 37 | See `?golem::get_golem_options` for more details.} 38 | } 39 | \description{ 40 | Run the Shiny Application 41 | } 42 | -------------------------------------------------------------------------------- /inst/templates_ui/shiny.fluent.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' Fluent React UI template 4 | #' 5 | #' @param request Internal parameter for `{shiny}`. 6 | #' DO NOT REMOVE. 7 | #' @import shiny 8 | #' @import shiny.fluent 9 | #' @importFrom glue glue 10 | #' @noRd 11 | app_ui <- function(request) { 12 | tagList( 13 | # Leave this function for adding external resources 14 | golem_add_external_resources(), 15 | fluentPage( 16 | tags$style(".card { padding: 28px; margin-bottom: 28px; }"), 17 | makeCard( 18 | title = Text(variant = "xxLarge", "Hello world!"), 19 | content = tagList( 20 | Slider.shinyInput("slider", value = 42, min = -100, max = 100), 21 | textOutput("sliderValue") 22 | ), 23 | size = 4, 24 | style = "max-height: 320px;" 25 | ) 26 | 27 | ) 28 | ) 29 | } 30 | 31 | 32 | makeCard <- function(title, content, size = 12, style = "") { 33 | div( 34 | class = glue("card ms-depth-8 ms-sm{size} ms-xl{size}"), 35 | style = style, 36 | Stack( 37 | tokens = list(childrenGap = 5), 38 | Text(variant = "large", title, block = TRUE), 39 | content 40 | ) 41 | ) 42 | } 43 | 44 | 45 | #' Add external Resources to the Application 46 | #' 47 | #' This function is internally used to add external 48 | #' resources inside the Shiny application. 49 | #' 50 | #' @import shiny 51 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 52 | #' @noRd 53 | golem_add_external_resources <- function(){ 54 | 55 | add_resource_path( 56 | 'www', app_sys('app/www') 57 | ) 58 | 59 | tags$head( 60 | favicon(), 61 | bundle_resources( 62 | path = app_sys('app/www'), 63 | app_title = 'My app' 64 | ) 65 | # Add here other external resources 66 | # for example, you can add shinyalert::useShinyalert() 67 | ) 68 | } 69 | 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # truelle 5 | 6 | 10 | 11 | The goal of `{truelle}` is to provide a GUI to the `{golem}` package and 12 | many more. 13 | 14 | ## Installation 15 | 16 | You can install the released version of truelle from 17 | [CRAN](https://CRAN.R-project.org) with: 18 | 19 | ``` r 20 | remotes::install_github("RinteRface/truelle") 21 | ``` 22 | 23 | ## Workflow example 24 | 25 | This is a basic example which shows you how to start the `{truelle}` 26 | GUI: 27 | 28 | ``` r 29 | library(truelle) 30 | run_app() 31 | ``` 32 | 33 | ### Step 1: project type 34 | 35 | Select **Package** and choose the `{golem}` engine. 36 | 37 | 38 | 39 | ### Step 2: options 40 | 41 | Provide a valid package path and review project options. 42 | 43 | 44 | 45 | ### Step 3: UI layout 46 | 47 | Select the Shiny layout of your choice. 48 | 49 | 50 | 51 | ### Step 4: code output 52 | 53 | Click on the 🎮 button or copy/paste 📸 the code to your terminal… 54 | 55 | 56 | 57 | ### Step 5: develop 58 | 59 | - Open the new project. 60 | - Run `devtools::load_all()`. 61 | - Enjoy … 62 | 63 | ## Disclaimer 64 | 65 | For now, only the `{golem}` workflow is supported. 66 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | issue_comment: 3 | types: [created] 4 | name: Commands 5 | jobs: 6 | document: 7 | if: startsWith(github.event.comment.body, '/document') 8 | name: document 9 | runs-on: macOS-latest 10 | env: 11 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: r-lib/actions/pr-fetch@v1 15 | with: 16 | repo-token: ${{ secrets.GITHUB_TOKEN }} 17 | - uses: r-lib/actions/setup-r@v1 18 | - name: Install dependencies 19 | run: Rscript -e 'install.packages(c("remotes", "roxygen2"))' -e 'remotes::install_deps(dependencies = TRUE)' 20 | - name: Document 21 | run: Rscript -e 'roxygen2::roxygenise()' 22 | - name: commit 23 | run: | 24 | git config --local user.email "actions@github.com" 25 | git config --local user.name "GitHub Actions" 26 | git add man/\* NAMESPACE 27 | git commit -m 'Document' 28 | - uses: r-lib/actions/pr-push@v1 29 | with: 30 | repo-token: ${{ secrets.GITHUB_TOKEN }} 31 | style: 32 | if: startsWith(github.event.comment.body, '/style') 33 | name: style 34 | runs-on: macOS-latest 35 | env: 36 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 37 | steps: 38 | - uses: actions/checkout@v2 39 | - uses: r-lib/actions/pr-fetch@v1 40 | with: 41 | repo-token: ${{ secrets.GITHUB_TOKEN }} 42 | - uses: r-lib/actions/setup-r@v1 43 | - name: Install dependencies 44 | run: Rscript -e 'install.packages("styler")' 45 | - name: Style 46 | run: Rscript -e 'styler::style_pkg()' 47 | - name: commit 48 | run: | 49 | git config --local user.email "actions@github.com" 50 | git config --local user.name "GitHub Actions" 51 | git add \*.R 52 | git commit -m 'Style' 53 | - uses: r-lib/actions/pr-push@v1 54 | with: 55 | repo-token: ${{ secrets.GITHUB_TOKEN }} 56 | -------------------------------------------------------------------------------- /inst/templates_ui/shinydashboard.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' Bootstrap 3 dashboard template 4 | #' 5 | #' @param request Internal parameter for `{shiny}`. 6 | #' DO NOT REMOVE. 7 | #' @import shiny 8 | #' @import shinydashboard 9 | #' @noRd 10 | app_ui <- function(request) { 11 | tagList( 12 | # Leave this function for adding external resources 13 | golem_add_external_resources(), 14 | dashboardPage( 15 | dashboardHeader(), 16 | dashboardSidebar( 17 | sidebarMenu( 18 | menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")), 19 | menuItem("Widgets", tabName = "widgets", icon = icon("th")) 20 | ) 21 | ), 22 | dashboardBody( 23 | tabItems( 24 | # First tab content 25 | tabItem( 26 | tabName = "dashboard", 27 | fluidRow( 28 | box(plotOutput("plot1", height = 250)), 29 | box( 30 | title = "Controls", 31 | sliderInput("slider", "Number of observations:", 1, 100, 50) 32 | ) 33 | ) 34 | ), 35 | 36 | # Second tab content 37 | tabItem(tabName = "widgets", h2("Widgets tab content") 38 | ) 39 | ) 40 | ) 41 | ) 42 | ) 43 | } 44 | 45 | 46 | 47 | 48 | 49 | #' Add external Resources to the Application 50 | #' 51 | #' This function is internally used to add external 52 | #' resources inside the Shiny application. 53 | #' 54 | #' @import shiny 55 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 56 | #' @noRd 57 | golem_add_external_resources <- function(){ 58 | 59 | add_resource_path( 60 | 'www', app_sys('app/www') 61 | ) 62 | 63 | tags$head( 64 | favicon(), 65 | bundle_resources( 66 | path = app_sys('app/www'), 67 | app_title = 'My app' 68 | ) 69 | # Add here other external resources 70 | # for example, you can add shinyalert::useShinyalert() 71 | ) 72 | } 73 | 74 | -------------------------------------------------------------------------------- /inst/templates_ui/semantic.dashboard.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' Semantic dashboard template 4 | #' 5 | #' @param request Internal parameter for `{shiny}`. 6 | #' DO NOT REMOVE. 7 | #' @import shiny 8 | #' @import semantic.dashboard 9 | #' @noRd 10 | app_ui <- function(request) { 11 | tagList( 12 | # Leave this function for adding external resources 13 | golem_add_external_resources(), 14 | dashboardPage( 15 | dashboardHeader(), 16 | dashboardSidebar( 17 | sidebarMenu( 18 | menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")), 19 | menuItem("Widgets", tabName = "widgets", icon = icon("th")) 20 | ) 21 | ), 22 | dashboardBody( 23 | tabItems( 24 | # First tab content 25 | tabItem( 26 | tabName = "dashboard", 27 | fluidRow( 28 | box(plotOutput("plot1", height = 250)), 29 | box( 30 | title = "Controls", 31 | sliderInput("slider", "Number of observations:", 1, 100, 50) 32 | ) 33 | ) 34 | ), 35 | 36 | # Second tab content 37 | tabItem(tabName = "widgets", h2("Widgets tab content") 38 | ) 39 | ) 40 | ) 41 | ) 42 | ) 43 | } 44 | 45 | 46 | 47 | 48 | 49 | #' Add external Resources to the Application 50 | #' 51 | #' This function is internally used to add external 52 | #' resources inside the Shiny application. 53 | #' 54 | #' @import shiny 55 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 56 | #' @noRd 57 | golem_add_external_resources <- function(){ 58 | 59 | add_resource_path( 60 | 'www', app_sys('app/www') 61 | ) 62 | 63 | tags$head( 64 | favicon(), 65 | bundle_resources( 66 | path = app_sys('app/www'), 67 | app_title = 'My app' 68 | ) 69 | # Add here other external resources 70 | # for example, you can add shinyalert::useShinyalert() 71 | ) 72 | } 73 | 74 | -------------------------------------------------------------------------------- /inst/templates_ui/shinymaterial.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' Materialize CSS template 4 | #' 5 | #' @param request Internal parameter for `{shiny}`. 6 | #' DO NOT REMOVE. 7 | #' @import shiny 8 | #' @import shinymaterial 9 | #' @noRd 10 | app_ui <- function(request) { 11 | tagList( 12 | # Leave this function for adding external resources 13 | golem_add_external_resources(), 14 | material_page( 15 | title = "shinymaterial", 16 | tags$br(), 17 | material_row( 18 | material_column( 19 | width = 2, 20 | material_card( 21 | title = "", 22 | depth = 4, 23 | tags$p("By Cylinder"), 24 | material_switch( 25 | input_id = "facet_cyl", 26 | off_label = "No", 27 | on_label = "Yes", 28 | initial_value = TRUE 29 | ), 30 | tags$p("Include Trend Line"), 31 | material_switch( 32 | input_id = "trend_line", 33 | off_label = "No", 34 | on_label = "Yes" 35 | ), 36 | material_radio_button( 37 | input_id = "plot_theme", 38 | label = "Theme", 39 | choices = 40 | c("Light" = "light", 41 | "Dark" = "dark") 42 | ) 43 | ) 44 | ), 45 | material_column( 46 | width = 9, 47 | material_card( 48 | title = "Power vs Efficiency", 49 | depth = 4, 50 | plotOutput("mtcars_plot") 51 | ) 52 | ) 53 | ) 54 | ) 55 | ) 56 | } 57 | 58 | 59 | #' Add external Resources to the Application 60 | #' 61 | #' This function is internally used to add external 62 | #' resources inside the Shiny application. 63 | #' 64 | #' @import shiny 65 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 66 | #' @noRd 67 | golem_add_external_resources <- function(){ 68 | 69 | add_resource_path( 70 | 'www', app_sys('app/www') 71 | ) 72 | 73 | tags$head( 74 | favicon(), 75 | bundle_resources( 76 | path = app_sys('app/www'), 77 | app_title = 'My app' 78 | ) 79 | # Add here other external resources 80 | # for example, you can add shinyalert::useShinyalert() 81 | ) 82 | } 83 | 84 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | #fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | 16 | # truelle 17 | 18 | 22 | 23 | The goal of `{truelle}` is to provide a GUI to the `{golem}` package and many more. 24 | 25 | ## Installation 26 | 27 | You can install the released version of truelle from [CRAN](https://CRAN.R-project.org) with: 28 | 29 | ``` r 30 | remotes::install_github("RinteRface/truelle") 31 | ``` 32 | 33 | ## Workflow example 34 | 35 | This is a basic example which shows you how to start the `{truelle}` GUI: 36 | 37 | ```{r, eval=FALSE, example} 38 | library(truelle) 39 | run_app() 40 | ``` 41 | 42 | ### Step 1: project type 43 | 44 | Select __Package__ and choose the `{golem}` engine. 45 | 46 | ```{r, echo = FALSE, fig.show="hold", out.width="50%"} 47 | knitr::include_graphics("man/figures/truelle-project-type.png") 48 | knitr::include_graphics("man/figures/truelle-project-engine.png") 49 | ``` 50 | 51 | ### Step 2: options 52 | 53 | Provide a valid package path and review project options. 54 | 55 | ```{r, echo = FALSE, out.width='50%', fig.align='center'} 56 | knitr::include_graphics("man/figures/truelle-package-options.png") 57 | ``` 58 | 59 | 60 | ### Step 3: UI layout 61 | 62 | Select the Shiny layout of your choice. 63 | 64 | ```{r, echo = FALSE, out.width='50%', fig.align='center'} 65 | knitr::include_graphics("man/figures/truelle-ui-template.png") 66 | ``` 67 | 68 | 69 | ### Step 4: code output 70 | 71 | Click on the `r emo::ji("play")` button or copy/paste `r emo::ji("photo")` the code to your terminal... 72 | 73 | ```{r, echo = FALSE, fig.show="hold", out.width="50%"} 74 | knitr::include_graphics("man/figures/truelle-output.png") 75 | knitr::include_graphics("man/figures/golem-package-structure.png") 76 | ``` 77 | 78 | 79 | ### Step 5: develop 80 | 81 | - Open the new project. 82 | - Run `devtools::load_all()`. 83 | - Enjoy ... 84 | 85 | ## Disclaimer 86 | 87 | For now, only the `{golem}` workflow is supported. -------------------------------------------------------------------------------- /dev/01_start.R: -------------------------------------------------------------------------------- 1 | # Building a Prod-Ready, Robust Shiny Application. 2 | # 3 | # README: each step of the dev files is optional, and you don't have to 4 | # fill every dev scripts before getting started. 5 | # 01_start.R should be filled at start. 6 | # 02_dev.R should be used to keep track of your development during the project. 7 | # 03_deploy.R should be used once you need to deploy your app. 8 | # 9 | # 10 | ######################################## 11 | #### CURRENT FILE: ON START SCRIPT ##### 12 | ######################################## 13 | 14 | ## Fill the DESCRIPTION ---- 15 | ## Add meta data about your application 16 | ## 17 | ## /!\ Note: if you want to change the name of your app during development, 18 | ## either re-run this function, call golem::set_golem_name(), or don't forget 19 | ## to change the name in the app_sys() function in app_config.R /!\ 20 | ## 21 | golem::fill_desc( 22 | pkg_name = "truelle", # The Name of the package containing the App 23 | pkg_title = "Build tools for {golem}, {packer}, {reactR} and {shiny}", # The Title of the package containing the App 24 | pkg_description = "Easily setup a {golem}, {packer}, {reactR} and {shiny} project 25 | with an intuitive Gadget. Perfect if you don't have good memory.", # The Description of the package containing the App 26 | author_first_name = "David", # Your First Name 27 | author_last_name = "Granjon", # Your Last Name 28 | author_email = "dgranjon@ymail.com", # Your Email 29 | repo_url = NULL # The URL of the GitHub Repo (optional) 30 | ) 31 | 32 | ## Set {golem} options ---- 33 | golem::set_golem_options() 34 | 35 | ## Create Common Files ---- 36 | ## See ?usethis for more information 37 | usethis::use_mit_license( "David Granjon" ) # You can set another license here 38 | usethis::use_readme_rmd( open = FALSE ) 39 | usethis::use_code_of_conduct() 40 | usethis::use_lifecycle_badge( "Experimental" ) 41 | usethis::use_news_md( open = FALSE ) 42 | 43 | ## Use git ---- 44 | usethis::use_git() 45 | 46 | ## Init Testing Infrastructure ---- 47 | ## Create a template for tests 48 | golem::use_recommended_tests() 49 | 50 | ## Use Recommended Packages ---- 51 | golem::use_recommended_deps() 52 | 53 | ## Favicon ---- 54 | # If you want to change the favicon (default is golem's one) 55 | golem::use_favicon() # path = "path/to/ico". Can be an online file. 56 | golem::remove_favicon() 57 | 58 | ## Add helper functions ---- 59 | golem::use_utils_ui() 60 | golem::use_utils_server() 61 | 62 | # You're now set! ---- 63 | 64 | # go to dev/02_dev.R 65 | rstudioapi::navigateToFile( "dev/02_dev.R" ) 66 | 67 | -------------------------------------------------------------------------------- /inst/templates_ui/shinyMobile_simple.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' shinyMobile single layout template 4 | #' 5 | #' @param request Internal parameter for `{shiny}`. 6 | #' DO NOT REMOVE. 7 | #' @import shiny 8 | #' @import shinyMobile 9 | #' @noRd 10 | app_ui <- function(request) { 11 | tagList( 12 | # Leave this function for adding external resources 13 | golem_add_external_resources(), 14 | f7Page( 15 | allowPWA = FALSE, 16 | options = list( 17 | theme = c("ios", "md", "auto", "aurora"), 18 | dark = TRUE, 19 | filled = FALSE, 20 | color = "#007aff", 21 | touch = list( 22 | tapHold = TRUE, 23 | tapHoldDelay = 750, 24 | iosTouchRipple = FALSE 25 | ), 26 | iosTranslucentBars = FALSE, 27 | navbar = list( 28 | iosCenterTitle = TRUE, 29 | hideOnPageScroll = TRUE 30 | ), 31 | toolbar = list(hideOnPageScroll = FALSE), 32 | pullToRefresh = FALSE 33 | ), 34 | title = "My app", 35 | f7SingleLayout( 36 | navbar = f7Navbar( 37 | title = "Single Layout", 38 | hairline = TRUE, 39 | shadow = TRUE 40 | ), 41 | toolbar = f7Toolbar( 42 | position = "bottom", 43 | f7Link(label = "Link 1", href = "https://www.google.com"), 44 | f7Link(label = "Link 2", href = "https://www.google.com") 45 | ), 46 | # main content 47 | f7Shadow( 48 | intensity = 16, 49 | hover = TRUE, 50 | f7Card( 51 | title = "Card header", 52 | f7CheckboxGroup( 53 | inputId = "variable", 54 | label = "Choose a variable:", 55 | choices = colnames(mtcars)[-1], 56 | selected = NULL 57 | ), 58 | tableOutput("data") 59 | ) 60 | ) 61 | ) 62 | ) 63 | ) 64 | } 65 | 66 | 67 | 68 | 69 | 70 | #' Add external Resources to the Application 71 | #' 72 | #' This function is internally used to add external 73 | #' resources inside the Shiny application. 74 | #' 75 | #' @import shiny 76 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 77 | #' @noRd 78 | golem_add_external_resources <- function(){ 79 | 80 | add_resource_path( 81 | 'www', app_sys('app/www') 82 | ) 83 | 84 | tags$head( 85 | favicon(), 86 | bundle_resources( 87 | path = app_sys('app/www'), 88 | app_title = 'My app' 89 | ) 90 | # Add here other external resources 91 | # for example, you can add shinyalert::useShinyalert() 92 | ) 93 | } 94 | -------------------------------------------------------------------------------- /dev/02_dev.R: -------------------------------------------------------------------------------- 1 | # Building a Prod-Ready, Robust Shiny Application. 2 | # 3 | # README: each step of the dev files is optional, and you don't have to 4 | # fill every dev scripts before getting started. 5 | # 01_start.R should be filled at start. 6 | # 02_dev.R should be used to keep track of your development during the project. 7 | # 03_deploy.R should be used once you need to deploy your app. 8 | # 9 | # 10 | ################################### 11 | #### CURRENT FILE: DEV SCRIPT ##### 12 | ################################### 13 | 14 | # Engineering 15 | 16 | ## Dependencies ---- 17 | ## Add one line by package you want to add as dependency 18 | usethis::use_package( "thinkr" ) 19 | 20 | ## Add modules ---- 21 | ## Create a module infrastructure in R/ 22 | golem::add_module( name = "name_of_module1" ) # Name of the module 23 | golem::add_module( name = "name_of_module2" ) # Name of the module 24 | 25 | ## Add helper functions ---- 26 | ## Creates fct_* and utils_* 27 | golem::add_fct( "helpers" ) 28 | golem::add_utils( "helpers" ) 29 | 30 | ## External resources 31 | ## Creates .js and .css files at inst/app/www 32 | golem::add_js_file( "script" ) 33 | golem::add_js_handler( "handlers" ) 34 | golem::add_css_file( "custom" ) 35 | 36 | ## Add internal datasets ---- 37 | ## If you have data in your package 38 | usethis::use_data_raw( name = "my_dataset", open = FALSE ) 39 | 40 | ## Tests ---- 41 | ## Add one line by test you want to create 42 | usethis::use_test( "app" ) 43 | 44 | # Documentation 45 | 46 | ## Vignette ---- 47 | usethis::use_vignette("truelle") 48 | devtools::build_vignettes() 49 | 50 | ## Code Coverage---- 51 | ## Set the code coverage service ("codecov" or "coveralls") 52 | usethis::use_coverage() 53 | 54 | # Create a summary readme for the testthat subdirectory 55 | covrpage::covrpage() 56 | 57 | ## CI ---- 58 | ## Use this part of the script if you need to set up a CI 59 | ## service for your application 60 | ## 61 | ## (You'll need GitHub there) 62 | usethis::use_github() 63 | 64 | # GitHub Actions 65 | usethis::use_github_action() 66 | # Chose one of the three 67 | # See https://usethis.r-lib.org/reference/use_github_action.html 68 | usethis::use_github_action_check_release() 69 | usethis::use_github_action_check_standard() 70 | usethis::use_github_action_check_full() 71 | # Add action for PR 72 | usethis::use_github_action_pr_commands() 73 | 74 | # Travis CI 75 | usethis::use_travis() 76 | usethis::use_travis_badge() 77 | 78 | # AppVeyor 79 | usethis::use_appveyor() 80 | usethis::use_appveyor_badge() 81 | 82 | # Circle CI 83 | usethis::use_circleci() 84 | usethis::use_circleci_badge() 85 | 86 | # Jenkins 87 | usethis::use_jenkins() 88 | 89 | # GitLab CI 90 | usethis::use_gitlab_ci() 91 | 92 | # You're now set! ---- 93 | # go to dev/03_deploy.R 94 | rstudioapi::navigateToFile("dev/03_deploy.R") 95 | 96 | -------------------------------------------------------------------------------- /inst/templates_ui/shinyMobile_split.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' shinyMobile split layout template 4 | #' 5 | #' @param request Internal parameter for `{shiny}`. 6 | #' DO NOT REMOVE. 7 | #' @import shiny 8 | #' @import shinyMobile 9 | #' @noRd 10 | app_ui <- function(request) { 11 | tagList( 12 | # Leave this function for adding external resources 13 | golem_add_external_resources(), 14 | f7Page( 15 | allowPWA = FALSE, 16 | options = list( 17 | theme = c("ios", "md", "auto", "aurora"), 18 | dark = TRUE, 19 | filled = FALSE, 20 | color = "#007aff", 21 | touch = list( 22 | tapHold = TRUE, 23 | tapHoldDelay = 750, 24 | iosTouchRipple = FALSE 25 | ), 26 | iosTranslucentBars = FALSE, 27 | navbar = list( 28 | iosCenterTitle = TRUE, 29 | hideOnPageScroll = TRUE 30 | ), 31 | toolbar = list(hideOnPageScroll = FALSE), 32 | pullToRefresh = FALSE 33 | ), 34 | title = "My app", 35 | f7SplitLayout( 36 | sidebar = f7Panel( 37 | id = "sidebar", 38 | title = "Sidebar", 39 | side = "left", 40 | theme = "dark", 41 | f7PanelMenu( 42 | id = "menu", 43 | f7PanelItem( 44 | tabName = "tab1", 45 | title = "Tab 1", 46 | icon = f7Icon("envelope"), 47 | active = TRUE 48 | ), 49 | f7PanelItem( 50 | tabName = "tab2", 51 | title = "Tab 2", 52 | icon = f7Icon("house") 53 | ) 54 | ), 55 | uiOutput("selected_tab") 56 | ), 57 | navbar = f7Navbar( 58 | title = "Split Layout", 59 | hairline = FALSE, 60 | shadow = TRUE 61 | ), 62 | toolbar = f7Toolbar( 63 | position = "bottom", 64 | f7Link(label = "Link 1", href = "https://www.google.com"), 65 | f7Link(label = "Link 2", href = "https://www.google.com") 66 | ), 67 | # main content 68 | f7Items( 69 | f7Item( 70 | tabName = "tab1", 71 | f7Slider("obs", "Number of observations:", 72 | min = 0, max = 1000, value = 500 73 | ), 74 | plotOutput("distPlot") 75 | ), 76 | f7Item(tabName = "tab2", "Tab 2 content") 77 | ) 78 | ) 79 | ) 80 | ) 81 | } 82 | 83 | 84 | 85 | 86 | 87 | #' Add external Resources to the Application 88 | #' 89 | #' This function is internally used to add external 90 | #' resources inside the Shiny application. 91 | #' 92 | #' @import shiny 93 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 94 | #' @noRd 95 | golem_add_external_resources <- function(){ 96 | 97 | add_resource_path( 98 | 'www', app_sys('app/www') 99 | ) 100 | 101 | tags$head( 102 | favicon(), 103 | bundle_resources( 104 | path = app_sys('app/www'), 105 | app_title = 'My app' 106 | ) 107 | # Add here other external resources 108 | # for example, you can add shinyalert::useShinyalert() 109 | ) 110 | } 111 | -------------------------------------------------------------------------------- /inst/templates_ui/shinyMobile_tabs.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' shinyMobile tabs layout template 4 | #' 5 | #' @param request Internal parameter for `{shiny}`. 6 | #' DO NOT REMOVE. 7 | #' @import shiny 8 | #' @import shinyMobile 9 | #' @noRd 10 | app_ui <- function(request) { 11 | tagList( 12 | # Leave this function for adding external resources 13 | golem_add_external_resources(), 14 | f7Page( 15 | allowPWA = FALSE, 16 | options = list( 17 | theme = c("ios", "md", "auto", "aurora"), 18 | dark = TRUE, 19 | filled = FALSE, 20 | color = "#007aff", 21 | touch = list( 22 | tapHold = TRUE, 23 | tapHoldDelay = 750, 24 | iosTouchRipple = FALSE 25 | ), 26 | iosTranslucentBars = FALSE, 27 | navbar = list( 28 | iosCenterTitle = TRUE, 29 | hideOnPageScroll = TRUE 30 | ), 31 | toolbar = list(hideOnPageScroll = FALSE), 32 | pullToRefresh = FALSE 33 | ), 34 | title = "My app", 35 | f7TabLayout( 36 | panels = tagList( 37 | f7Panel( 38 | title = "Left Panel", 39 | side = "left", 40 | theme = "light", 41 | "Blabla", 42 | effect = "cover" 43 | ), 44 | f7Panel( 45 | title = "Right Panel", 46 | side = "right", 47 | theme = "dark", 48 | "Blabla", 49 | effect = "reveal" 50 | ) 51 | ), 52 | navbar = f7Navbar( 53 | title = "Tabs", 54 | hairline = TRUE, 55 | shadow = TRUE, 56 | leftPanel = TRUE, 57 | rightPanel = TRUE 58 | ), 59 | f7Tabs( 60 | animated = TRUE, 61 | f7Tab( 62 | tabName = "Tab 1", 63 | icon = f7Icon("folder"), 64 | active = TRUE, 65 | f7Stepper( 66 | inputId = "stepper", 67 | label = "My stepper", 68 | min = 0, 69 | max = 10, 70 | size = "small", 71 | value = 4, 72 | wraps = TRUE, 73 | autorepeat = TRUE, 74 | rounded = FALSE, 75 | raised = FALSE, 76 | manual = FALSE 77 | ), 78 | verbatimTextOutput("val") 79 | ), 80 | f7Tab( 81 | tabName = "Tab 2", 82 | icon = f7Icon("keyboard"), 83 | active = FALSE, 84 | "Tab 2" 85 | ), 86 | f7Tab( 87 | tabName = "Tab 3", 88 | icon = f7Icon("layers_alt"), 89 | active = FALSE, 90 | "Tab 3" 91 | ) 92 | ) 93 | ) 94 | ) 95 | ) 96 | } 97 | 98 | 99 | 100 | 101 | 102 | #' Add external Resources to the Application 103 | #' 104 | #' This function is internally used to add external 105 | #' resources inside the Shiny application. 106 | #' 107 | #' @import shiny 108 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 109 | #' @noRd 110 | golem_add_external_resources <- function(){ 111 | 112 | add_resource_path( 113 | 'www', app_sys('app/www') 114 | ) 115 | 116 | tags$head( 117 | favicon(), 118 | bundle_resources( 119 | path = app_sys('app/www'), 120 | app_title = 'My app' 121 | ) 122 | # Add here other external resources 123 | # for example, you can add shinyalert::useShinyalert() 124 | ) 125 | } 126 | -------------------------------------------------------------------------------- /inst/templates_ui/bs4Dash.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' Bootstrap 4 dashboard template 4 | #' 5 | #' @param request Internal parameter for `{shiny}`. 6 | #' DO NOT REMOVE. 7 | #' @import shiny 8 | #' @import bs4Dash 9 | #' @noRd 10 | app_ui <- function(request) { 11 | tagList( 12 | # Leave this function for adding external resources 13 | golem_add_external_resources(), 14 | dashboardPage( 15 | title = "Basic Dashboard", 16 | fullscreen = TRUE, 17 | header = dashboardHeader( 18 | title = dashboardBrand( 19 | title = "bs4Dash", 20 | color = "primary", 21 | href = "https://www.google.fr", 22 | image = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg", 23 | ), 24 | skin = "light", 25 | status = "white", 26 | border = TRUE, 27 | sidebarIcon = icon("bars"), 28 | controlbarIcon = icon("th"), 29 | fixed = FALSE 30 | ), 31 | sidebar = dashboardSidebar( 32 | skin = "light", 33 | status = "primary", 34 | elevation = 3, 35 | sidebarUserPanel( 36 | image = "https://image.flaticon.com/icons/svg/1149/1149168.svg", 37 | name = "Welcome Onboard!" 38 | ), 39 | sidebarMenu( 40 | sidebarHeader("Header 1"), 41 | menuItem( 42 | "Item 1", 43 | tabName = "item1", 44 | icon = icon("sliders") 45 | ), 46 | menuItem( 47 | "Item 2", 48 | tabName = "item2", 49 | icon = icon("id-card") 50 | ) 51 | ) 52 | ), 53 | controlbar = dashboardControlbar( 54 | skin = "light", 55 | pinned = TRUE, 56 | collapsed = FALSE, 57 | overlay = FALSE, 58 | controlbarMenu( 59 | id = "controlbarmenu", 60 | controlbarItem( 61 | title = "Item 1", 62 | "Item 1" 63 | ), 64 | controlbarItem( 65 | "Item 2", 66 | "Simple text" 67 | ) 68 | ) 69 | ), 70 | footer = dashboardFooter( 71 | left = a( 72 | href = "https://twitter.com/divadnojnarg", 73 | target = "_blank", "@DivadNojnarg" 74 | ), 75 | right = "2021" 76 | ), 77 | body = dashboardBody( 78 | tabItems( 79 | tabItem( 80 | tabName = "item1", 81 | tags$style("body { background-color: ghostwhite}"), 82 | fluidRow( 83 | actionButton("toggle_box", "Toggle Box"), 84 | actionButton("remove_box", "Remove Box", class = "bg-danger"), 85 | actionButton("restore_box", "Restore Box", class = "bg-success"), 86 | actionButton("update_box", "Update Box", class = "bg-primary") 87 | ), 88 | br(), 89 | box( 90 | title = textOutput("box_state"), 91 | "Box body", 92 | id = "mybox", 93 | collapsible = TRUE, 94 | closable = TRUE, 95 | plotOutput("plot") 96 | ) 97 | ), 98 | tabItem( 99 | tabName = "item2", 100 | "Body content 2" 101 | ) 102 | ) 103 | ) 104 | ) 105 | ) 106 | } 107 | 108 | 109 | 110 | 111 | 112 | #' Add external Resources to the Application 113 | #' 114 | #' This function is internally used to add external 115 | #' resources inside the Shiny application. 116 | #' 117 | #' @import shiny 118 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 119 | #' @noRd 120 | golem_add_external_resources <- function(){ 121 | 122 | add_resource_path( 123 | 'www', app_sys('app/www') 124 | ) 125 | 126 | tags$head( 127 | favicon(), 128 | bundle_resources( 129 | path = app_sys('app/www'), 130 | app_title = 'My app' 131 | ) 132 | # Add here other external resources 133 | # for example, you can add shinyalert::useShinyalert() 134 | ) 135 | } 136 | 137 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # NOTE: This workflow is overkill for most R packages 2 | # check-standard.yaml is likely a better choice 3 | # usethis::use_github_action("check-standard") will install it. 4 | # 5 | # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. 6 | # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions 7 | on: 8 | push: 9 | branches: 10 | - main 11 | - master 12 | pull_request: 13 | branches: 14 | - main 15 | - master 16 | 17 | name: R-CMD-check 18 | 19 | jobs: 20 | R-CMD-check: 21 | runs-on: ${{ matrix.config.os }} 22 | 23 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 24 | 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | config: 29 | - {os: macOS-latest, r: 'release'} 30 | - {os: windows-latest, r: 'release'} 31 | - {os: windows-latest, r: '3.6', rspm: "https://packagemanager.rstudio.com/cran/latest"} 32 | - {os: ubuntu-18.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", http-user-agent: "R/4.0.0 (ubuntu-18.04) R (4.0.0 x86_64-pc-linux-gnu x86_64 linux-gnu) on GitHub Actions" } 33 | - {os: ubuntu-18.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} 34 | - {os: ubuntu-18.04, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} 35 | - {os: ubuntu-18.04, r: '3.6', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} 36 | - {os: ubuntu-18.04, r: '3.5', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} 37 | - {os: ubuntu-18.04, r: '3.4', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} 38 | 39 | env: 40 | RSPM: ${{ matrix.config.rspm }} 41 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 42 | 43 | steps: 44 | - uses: actions/checkout@v2 45 | 46 | - uses: r-lib/actions/setup-r@v1 47 | id: install-r 48 | with: 49 | r-version: ${{ matrix.config.r }} 50 | http-user-agent: ${{ matrix.config.http-user-agent }} 51 | 52 | - uses: r-lib/actions/setup-pandoc@v1 53 | 54 | - name: Install pak and query dependencies 55 | run: | 56 | install.packages("pak", repos = "https://r-lib.github.io/p/pak/dev/") 57 | saveRDS(pak::pkg_deps("local::.", dependencies = TRUE), ".github/r-depends.rds") 58 | shell: Rscript {0} 59 | 60 | - name: Restore R package cache 61 | uses: actions/cache@v2 62 | with: 63 | path: | 64 | ${{ env.R_LIBS_USER }}/* 65 | !${{ env.R_LIBS_USER }}/pak 66 | key: ${{ matrix.config.os }}-${{ steps.install-r.outputs.installed-r-version }}-1-${{ hashFiles('.github/r-depends.rds') }} 67 | restore-keys: ${{ matrix.config.os }}-${{ steps.install-r.outputs.installed-r-version }}-1- 68 | 69 | - name: Install system dependencies 70 | if: runner.os == 'Linux' 71 | run: | 72 | pak::local_system_requirements(execute = TRUE) 73 | pak::pkg_system_requirements("rcmdcheck", execute = TRUE) 74 | shell: Rscript {0} 75 | 76 | - name: Install dependencies 77 | run: | 78 | pak::local_install_dev_deps(upgrade = TRUE) 79 | pak::pkg_install("rcmdcheck") 80 | shell: Rscript {0} 81 | 82 | - name: Session info 83 | run: | 84 | options(width = 100) 85 | pkgs <- installed.packages()[, "Package"] 86 | sessioninfo::session_info(pkgs, include_base = TRUE) 87 | shell: Rscript {0} 88 | 89 | - name: Check 90 | env: 91 | _R_CHECK_CRAN_INCOMING_: false 92 | run: | 93 | options(crayon.enabled = TRUE) 94 | rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check") 95 | shell: Rscript {0} 96 | 97 | - name: Show testthat output 98 | if: always() 99 | run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true 100 | shell: bash 101 | 102 | - name: Upload check results 103 | if: failure() 104 | uses: actions/upload-artifact@main 105 | with: 106 | name: ${{ matrix.config.os }}-r${{ matrix.config.r }}-results 107 | path: check 108 | 109 | - name: Don't use tar from old Rtools to store the cache 110 | if: ${{ runner.os == 'Windows' && startsWith(steps.install-r.outputs.installed-r-version, '3.6' ) }} 111 | shell: bash 112 | run: echo "C:/Program Files/Git/usr/bin" >> $GITHUB_PATH 113 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards 42 | of acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies 54 | when an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail 56 | address, posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at [INSERT CONTACT 63 | METHOD]. All complaints will be reviewed and investigated promptly and fairly. 64 | 65 | All community leaders are obligated to respect the privacy and security of the 66 | reporter of any incident. 67 | 68 | ## Enforcement Guidelines 69 | 70 | Community leaders will follow these Community Impact Guidelines in determining 71 | the consequences for any action they deem in violation of this Code of Conduct: 72 | 73 | ### 1. Correction 74 | 75 | **Community Impact**: Use of inappropriate language or other behavior deemed 76 | unprofessional or unwelcome in the community. 77 | 78 | **Consequence**: A private, written warning from community leaders, providing 79 | clarity around the nature of the violation and an explanation of why the 80 | behavior was inappropriate. A public apology may be requested. 81 | 82 | ### 2. Warning 83 | 84 | **Community Impact**: A violation through a single incident or series of 85 | actions. 86 | 87 | **Consequence**: A warning with consequences for continued behavior. No 88 | interaction with the people involved, including unsolicited interaction with 89 | those enforcing the Code of Conduct, for a specified period of time. This 90 | includes avoiding interactions in community spaces as well as external channels 91 | like social media. Violating these terms may lead to a temporary or permanent 92 | ban. 93 | 94 | ### 3. Temporary Ban 95 | 96 | **Community Impact**: A serious violation of community standards, including 97 | sustained inappropriate behavior. 98 | 99 | **Consequence**: A temporary ban from any sort of interaction or public 100 | communication with the community for a specified period of time. No public or 101 | private interaction with the people involved, including unsolicited interaction 102 | with those enforcing the Code of Conduct, is allowed during this period. 103 | Violating these terms may lead to a permanent ban. 104 | 105 | ### 4. Permanent Ban 106 | 107 | **Community Impact**: Demonstrating a pattern of violation of community 108 | standards, including sustained inappropriate behavior, harassment of an 109 | individual, or aggression toward or disparagement of classes of individuals. 110 | 111 | **Consequence**: A permanent ban from any sort of public interaction within the 112 | community. 113 | 114 | ## Attribution 115 | 116 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 117 | version 2.0, 118 | available at https://www.contributor-covenant.org/version/2/0/ 119 | code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at https:// 128 | www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /R/utils_helpers.R: -------------------------------------------------------------------------------- 1 | pkg_description_fields <- list( 2 | pkg_name = "shinyexample", # The Name of the package containing the App 3 | pkg_title = "PKG_TITLE", # The Title of the package containing the App 4 | pkg_description = "PKG_DESC.", # The Description of the package containing the App 5 | author_first_name = "AUTHOR_FIRST", # Your First Name 6 | author_last_name = "AUTHOR_LAST", # Your Last Name 7 | author_email = "AUTHOR@MAIL.COM", # Your Email 8 | repo_url = NULL 9 | ) 10 | 11 | usethis_commons <- list( 12 | project = " usethis::use_rstudio()", 13 | license = ' usethis::use_mit_license( "Golem User" )', 14 | readme = " usethis::use_readme_rmd( open = FALSE )", 15 | coc = " usethis::use_code_of_conduct()", 16 | lifecycle = ' usethis::use_lifecycle_badge( "Experimental" )', 17 | news = " usethis::use_news_md( open = FALSE )", 18 | data = " usethis::use_data_raw()", 19 | git = " usethis::use_git()" 20 | ) 21 | 22 | 23 | webdev_commons <- list( 24 | input_binding = paste0( 25 | " golem::add_js_input_binding( \n", 26 | ' "myInputBinding", \n', 27 | " initialize = FALSE, \n", 28 | " dev = FALSE, \n", 29 | ' events = list(name = "click", rate_policy = FALSE) \n', 30 | " )", 31 | collapse = "\n" 32 | ), 33 | output_binding = ' golem::add_js_output_binding("myOutputBinding")', 34 | js_handler = ' golem::add_js_handler("script")', 35 | simple_js = ' golem::add_js_file("script")', 36 | simple_css = ' golem::add_css_file("custom")' 37 | ) 38 | 39 | jobs <- list() 40 | 41 | run_text <- function(code) eval(parse(text = code)) 42 | 43 | 44 | # dropNulls 45 | dropNulls <- function(x) { 46 | x[!vapply(x, is.null, FUN.VALUE = logical(1))] 47 | } 48 | 49 | # transform list to char 50 | list_2_char <- function(l, prefix, input) { 51 | temp <- lapply(seq_along(l), function(i) { 52 | if (input[[paste0(prefix, names(l)[[i]])]]) { 53 | l[[i]] 54 | } 55 | }) %>% 56 | dropNulls() %>% 57 | paste0(collapse = "\n") 58 | 59 | if (nchar(temp) > 0) temp <- paste0(temp, "\n \n", collapse = "\n") 60 | temp 61 | } 62 | 63 | 64 | # Copy a file template to the R folder to 65 | # replace the default app_ui.R provided by {golem} 66 | add_ui_template <- function(template) { 67 | 68 | pkg_to_import <- strsplit(template, "_")[[1]][1] 69 | 70 | paste0( 71 | ' unlink("R/app_ui.R", TRUE, TRUE) \n', 72 | ' file.copy( \n', 73 | ' system.file( \n', 74 | ' "templates_ui/', template, '.R", \n', 75 | ' package = "truelle" \n', 76 | ' ), \n', 77 | ' "R/app_ui.R" \n', 78 | ' ) \n', 79 | ' unlink("R/app_server.R", TRUE, TRUE) \n', 80 | ' file.copy( \n', 81 | ' system.file( \n', 82 | ' "templates_server/', template, '.R", \n', 83 | ' package = "truelle" \n', 84 | ' ), \n', 85 | ' "R/app_server.R" \n', 86 | ' ) \n', 87 | if (pkg_to_import != "golem") ' usethis::use_package("', pkg_to_import, '") \n', 88 | ' devtools::document() \n', 89 | collapse = "\n" 90 | ) 91 | } 92 | 93 | 94 | #' Modified Framework7 radio input 95 | #' 96 | #' \code{f7Radio} creates a radio button input. 97 | #' 98 | #' @param inputId Radio input id. 99 | #' @param label Radio label 100 | #' @param choices List of choices. Must be a nested list. 101 | #' @param selected Selected element. NULL by default. 102 | #' 103 | #' @export 104 | #' @rdname radio 105 | f7Radio <- function(inputId, label, choices = NULL, selected = NULL) { 106 | 107 | shiny::tagList( 108 | shiny::tags$div( 109 | class = "block-title", 110 | label 111 | ), 112 | shiny::tags$div( 113 | class = "list media-list shiny-input-radiogroup", 114 | id = inputId, 115 | createRadioOptions(choices, selected, inputId) 116 | ) 117 | ) 118 | 119 | } 120 | 121 | 122 | #' Generates a list of option for \link{f7Radio} 123 | #' 124 | #' @param choices List of choices. 125 | #' @param selected Selected value 126 | #' @param inputId Radio input id. 127 | #' 128 | #' @keywords internal 129 | createRadioOptions <- function(choices, selected, inputId) { 130 | titles <- unlist(lapply(seq_along(choices), function (c) choices[[c]]$title)) 131 | selectedPosition <- if (!is.null(selected)) match(selected, titles) else NULL 132 | 133 | choicesTag <- lapply(X = seq_along(choices), function(i) { 134 | shiny::tags$li( 135 | shiny::tags$label( 136 | class = "item-radio item-radio-icon-start item-content", 137 | shiny::tags$input( 138 | type = "radio", 139 | name = inputId, 140 | value = choices[[i]]$title 141 | ), 142 | shiny::tags$i(class = "icon icon-radio"), 143 | shiny::tags$div( 144 | class = "item-inner", 145 | shiny::tags$div( 146 | class = "item-title-row", 147 | shiny::tags$div(class="item-title", choices[[i]]$title), 148 | shiny::tags$div( 149 | class = "item-after item-media", 150 | choices[[i]]$image 151 | ) 152 | ), 153 | shiny::tags$div(class = "item-subtitle", choices[[i]]$subtitle), 154 | shiny::tags$div(class = "item-text", choices[[i]]$text) 155 | ) 156 | ) 157 | ) 158 | }) 159 | 160 | if (!is.null(selected)) choicesTag[[selectedPosition]]$children[[1]]$children[[1]]$attribs[["checked"]] <- NA 161 | 162 | shiny::tags$ul(choicesTag) 163 | } 164 | 165 | 166 | # Custom clipboard button 167 | rclipButton <- function (inputId, label, clipText, icon = NULL, modal = FALSE) 168 | { 169 | 170 | el <- a( 171 | id = inputId, 172 | class = "button button-small action-button display-flex margin-left-half", 173 | tagList(label, icon) 174 | ) 175 | el$attribs$`data-clipboard-text` <- clipText 176 | tagList( 177 | el, 178 | if (modal) { 179 | tags$script( 180 | sprintf( 181 | "new ClipboardJS(\".button\", { container: document.getElementById(\"%s\") } ); ", 182 | inputId 183 | ) 184 | ) 185 | } 186 | else { 187 | tags$script( 188 | sprintf( 189 | "new ClipboardJS(\".button\", document.getElementById(\"%s\") );", 190 | inputId 191 | ) 192 | ) 193 | } 194 | ) 195 | } -------------------------------------------------------------------------------- /R/golem_utils_ui.R: -------------------------------------------------------------------------------- 1 | #' Turn an R list into an HTML list 2 | #' 3 | #' @param list An R list 4 | #' @param class a class for the list 5 | #' 6 | #' @return an HTML list 7 | #' @noRd 8 | #' 9 | #' @examples 10 | #' list_to_li(c("a","b")) 11 | #' 12 | #' @importFrom shiny tags tagAppendAttributes tagList 13 | list_to_li <- function(list, class = NULL){ 14 | if (is.null(class)){ 15 | tagList( 16 | lapply( 17 | list, 18 | tags$li 19 | ) 20 | ) 21 | } else { 22 | res <- lapply( 23 | list, 24 | tags$li 25 | ) 26 | res <- lapply( 27 | res, 28 | function(x) { 29 | tagAppendAttributes( 30 | x, 31 | class = class 32 | ) 33 | } 34 | ) 35 | tagList(res) 36 | } 37 | 38 | } 39 | #' Turn an R list into corresponding HTML paragraph tags 40 | #' 41 | #' @param list an R list 42 | #' @param class a class for the paragraph tags 43 | #' 44 | #' @return An HTML tag 45 | #' @noRd 46 | #' 47 | #' @examples 48 | #' list_to_p(c("This is the first paragraph", "this is the second paragraph")) 49 | #' 50 | #' @importFrom shiny tags tagAppendAttributes tagList 51 | #' 52 | list_to_p <- function(list, class = NULL){ 53 | if (is.null(class)){ 54 | tagList( 55 | lapply( 56 | list, 57 | tags$p 58 | ) 59 | ) 60 | } else { 61 | res <- lapply( 62 | list, 63 | tags$p 64 | ) 65 | res <- lapply( 66 | res, 67 | function(x) { 68 | tagAppendAttributes( 69 | x, 70 | class = class 71 | ) 72 | } 73 | ) 74 | tagList(res) 75 | } 76 | 77 | } 78 | 79 | #' @importFrom shiny tags tagAppendAttributes tagList 80 | named_to_li <- function(list, class = NULL){ 81 | if(is.null(class)){ 82 | res <- mapply( 83 | function(x, y){ 84 | tags$li( 85 | HTML( 86 | sprintf("%s: %s", y, x) 87 | ) 88 | ) 89 | }, 90 | list, 91 | names(list), 92 | SIMPLIFY = FALSE 93 | ) 94 | tagList(res) 95 | } else { 96 | res <- mapply( 97 | function(x, y){ 98 | tags$li( 99 | HTML( 100 | sprintf("%s: %s", y, x) 101 | ) 102 | ) 103 | }, 104 | list, 105 | names(list), 106 | SIMPLIFY = FALSE 107 | ) 108 | res <- lapply( 109 | res, 110 | function(x) { 111 | tagAppendAttributes( 112 | x, 113 | class = class 114 | ) 115 | } 116 | ) 117 | tagList(res) 118 | } 119 | } 120 | 121 | #' Remove a tag attribute 122 | #' 123 | #' @param tag the tag 124 | #' @param ... the attributes to remove 125 | #' 126 | #' @return a new tag 127 | #' @noRd 128 | #' 129 | #' @examples 130 | #' a <- shiny::tags$p(src = "plop", "pouet") 131 | #' tagRemoveAttributes(a, "src") 132 | tagRemoveAttributes <- function(tag, ...) { 133 | attrs <- as.character(list(...)) 134 | for (i in seq_along(attrs)) { 135 | tag$attribs[[ attrs[i] ]] <- NULL 136 | } 137 | tag 138 | } 139 | 140 | #' Hide or display a tag 141 | #' 142 | #' @param tag the tag 143 | #' 144 | #' @return a tag 145 | #' @noRd 146 | #' 147 | #' @examples 148 | #' ## Hide 149 | #' a <- shiny::tags$p(src = "plop", "pouet") 150 | #' undisplay(a) 151 | #' b <- shiny::actionButton("go_filter", "go") 152 | #' undisplay(b) 153 | #' 154 | #' @importFrom shiny tagList 155 | undisplay <- function(tag) { 156 | # if not already hidden 157 | if ( 158 | !is.null(tag$attribs$style) && 159 | !grepl("display:\\s+none", tag$attribs$style) 160 | ) { 161 | tag$attribs$style <- paste( 162 | "display: none;", 163 | tag$attribs$style 164 | ) 165 | } else { 166 | tag$attribs$style <- "display: none;" 167 | } 168 | tag 169 | } 170 | 171 | #' @importFrom shiny tagList 172 | display <- function(tag) { 173 | if ( 174 | !is.null(tag$attribs$style) && 175 | grepl("display:\\s+none", tag$attribs$style) 176 | ) { 177 | tag$attribs$style <- gsub( 178 | "(\\s)*display:(\\s)*none(\\s)*(;)*(\\s)*", 179 | "", 180 | tag$attribs$style 181 | ) 182 | } 183 | tag 184 | } 185 | 186 | #' Hide an elements by calling jquery hide on it 187 | #' 188 | #' @param id the id of the element to hide 189 | #' 190 | #' @noRd 191 | #' 192 | #' @importFrom shiny tags 193 | jq_hide <- function(id) { 194 | tags$script(sprintf("$('#%s').hide()", id)) 195 | } 196 | 197 | #' Add a red star at the end of the text 198 | #' 199 | #' Adds a red star at the end of the text 200 | #' (for example for indicating mandatory fields). 201 | #' 202 | #' @param text the HTLM text to put before the red star 203 | #' 204 | #' @return an html element 205 | #' @noRd 206 | #' 207 | #' @examples 208 | #' with_red_star("Enter your name here") 209 | #' 210 | #' @importFrom shiny tags HTML 211 | with_red_star <- function(text) { 212 | shiny::tags$span( 213 | HTML( 214 | paste0( 215 | text, 216 | shiny::tags$span( 217 | style = "color:red", "*" 218 | ) 219 | ) 220 | ) 221 | ) 222 | } 223 | 224 | 225 | 226 | #' Repeat tags$br 227 | #' 228 | #' @param times the number of br to return 229 | #' 230 | #' @return the number of br specified in times 231 | #' @noRd 232 | #' 233 | #' @examples 234 | #' rep_br(5) 235 | #' 236 | #' @importFrom shiny HTML 237 | rep_br <- function(times = 1) { 238 | HTML(rep("
", times = times)) 239 | } 240 | 241 | #' Create an url 242 | #' 243 | #' @param url the URL 244 | #' @param text the text to display 245 | #' 246 | #' @return an a tag 247 | #' @noRd 248 | #' 249 | #' @examples 250 | #' enurl("https://www.thinkr.fr", "ThinkR") 251 | #' 252 | #' @importFrom shiny tags 253 | enurl <- function(url, text){ 254 | tags$a(href = url, text) 255 | } 256 | 257 | #' Columns wrappers 258 | #' 259 | #' These are convenient wrappers around 260 | #' `column(12, ...)`, `column(6, ...)`, `column(4, ...)`... 261 | #' 262 | #' @noRd 263 | #' 264 | #' @importFrom shiny column 265 | col_12 <- function(...){ 266 | column(12, ...) 267 | } 268 | 269 | #' @importFrom shiny column 270 | col_10 <- function(...){ 271 | column(10, ...) 272 | } 273 | 274 | #' @importFrom shiny column 275 | col_8 <- function(...){ 276 | column(8, ...) 277 | } 278 | 279 | #' @importFrom shiny column 280 | col_6 <- function(...){ 281 | column(6, ...) 282 | } 283 | 284 | 285 | #' @importFrom shiny column 286 | col_4 <- function(...){ 287 | column(4, ...) 288 | } 289 | 290 | 291 | #' @importFrom shiny column 292 | col_3 <- function(...){ 293 | column(3, ...) 294 | } 295 | 296 | 297 | #' @importFrom shiny column 298 | col_2 <- function(...){ 299 | column(2, ...) 300 | } 301 | 302 | 303 | #' @importFrom shiny column 304 | col_1 <- function(...){ 305 | column(1, ...) 306 | } 307 | 308 | 309 | 310 | #' Make the current tag behave like an action button 311 | #' 312 | #' Only works with compatible tags like button or links 313 | #' 314 | #' @param tag Any compatible tag. 315 | #' @param inputId Unique id. This will host the input value to be used 316 | #' on the server side. 317 | #' 318 | #' @return The modified tag with an extra id and the action button class. 319 | #' @noRd 320 | #' 321 | #' @examples 322 | #' if (interactive()) { 323 | #' library(shiny) 324 | #' 325 | #' link <- a(href = "#", "My super link", style = "color: lightblue;") 326 | #' 327 | #' ui <- fluidPage( 328 | #' make_action_button(link, inputId = "mylink") 329 | #' ) 330 | #' 331 | #' server <- function(input, output, session) { 332 | #' observeEvent(input$mylink, { 333 | #' showNotification("Pouic!") 334 | #' }) 335 | #' } 336 | #' 337 | #' shinyApp(ui, server) 338 | #' 339 | #' } 340 | make_action_button <- function(tag, inputId = NULL) { 341 | # some obvious checks 342 | if (!inherits(tag, "shiny.tag")) stop("Must provide a shiny tag.") 343 | if (!is.null(tag$attribs$class)) { 344 | if (grep("action-button", tag$attribs$class)) { 345 | stop("tag is already an action button") 346 | } 347 | } 348 | if (is.null(inputId) && is.null(tag$attribs$id)) { 349 | stop("tag does not have any id. Please use inputId to be able to 350 | access it on the server side.") 351 | } 352 | 353 | # handle id 354 | if (!is.null(inputId)) { 355 | if (!is.null(tag$attribs$id)) { 356 | warning( 357 | paste( 358 | "tag already has an id. Please use input$", 359 | tag$attribs$id, 360 | "to access it from the server side. inputId will be ignored." 361 | ) 362 | ) 363 | } else { 364 | tag$attribs$id <- inputId 365 | } 366 | } 367 | 368 | # handle class 369 | if (is.null(tag$attribs$class)) { 370 | tag$attribs$class <- "action-button" 371 | } else { 372 | tag$attribs$class <- paste(tag$attribs$class, "action-button") 373 | } 374 | # return tag 375 | tag 376 | } 377 | 378 | 379 | # UNCOMMENT AND USE 380 | # 381 | # usethis::use_package("markdown") 382 | # usethis::use_package("rmarkdown") 383 | # 384 | # To use this part of the UI 385 | # 386 | #' #' Include Content From a File 387 | #' #' 388 | #' #' Load rendered RMarkdown from a file and turn into HTML. 389 | #' #' 390 | #' #' @rdname includeRMarkdown 391 | #' #' @export 392 | #' #' 393 | #' #' @importFrom rmarkdown render 394 | #' #' @importFrom markdown markdownToHTML 395 | #' #' @importFrom shiny HTML 396 | #' includeRMarkdown <- function(path){ 397 | #' 398 | #' md <- tempfile(fileext = '.md') 399 | #' 400 | #' on.exit(unlink(md),add = TRUE) 401 | #' 402 | #' rmarkdown::render( 403 | #' path, 404 | #' output_format = 'md_document', 405 | #' output_dir = tempdir(), 406 | #' output_file = md,quiet = TRUE 407 | #' ) 408 | #' 409 | #' html <- markdown::markdownToHTML(md, fragment.only = TRUE) 410 | #' 411 | #' Encoding(html) <- "UTF-8" 412 | #' 413 | #' return(HTML(html)) 414 | #' } 415 | -------------------------------------------------------------------------------- /R/app_ui.R: -------------------------------------------------------------------------------- 1 | #' The application User-Interface 2 | #' 3 | #' @param request Internal parameter for `{shiny}`. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import shinyMobile 7 | #' @importFrom shinyAce aceEditor 8 | #' @importFrom rclipboard rclipboardSetup 9 | #' @noRd 10 | app_ui <- function(request) { 11 | tagList( 12 | # Leave this function for adding external resources 13 | golem_add_external_resources(), 14 | # Your application UI logic 15 | f7Page( 16 | options = list( 17 | theme = "md", 18 | dark = TRUE, 19 | filled = FALSE, 20 | color = "#007aff", 21 | touch = list( 22 | tapHold = TRUE, 23 | tapHoldDelay = 750, 24 | iosTouchRipple = FALSE 25 | ), 26 | iosTranslucentBars = FALSE, 27 | navbar = list( 28 | iosCenterTitle = TRUE, 29 | hideNavOnPageScroll = TRUE, 30 | mdCenterTitle = TRUE 31 | ), 32 | toolbar = list( 33 | hideNavOnPageScroll = FALSE 34 | ), 35 | pullToRefresh = FALSE 36 | ), 37 | title = "{truelle}", 38 | f7TabLayout( 39 | #panels = tagList( 40 | # f7Panel(title = "Left Panel", side = "left", theme = "light", "Blabla", effect = "cover"), 41 | # f7Panel(title = "Right Panel", side = "right", theme = "dark", "Blabla", effect = "cover") 42 | #), 43 | navbar = f7Navbar( 44 | title = "{truelle}", 45 | hairline = TRUE, 46 | shadow = TRUE, 47 | subNavbar = f7SubNavbar( 48 | f7Flex( 49 | f7Back(targetId = "widget_nav"), 50 | f7Next(targetId = "widget_nav"), 51 | a( 52 | href = "#", 53 | id = "close_app", 54 | class = "button button-small action-button display-flex margin-left-half", 55 | f7Icon("xmark_circle") 56 | ), 57 | a( 58 | class = "button button-small action-button display-flex margin-left-half", 59 | id = "run_code_output", 60 | f7Icon("play") 61 | ), 62 | uiOutput("clip_button"), 63 | a( 64 | class = "button button-small display-flex margin-left-half", 65 | id = "theme_switch", 66 | f7Icon("sun_max") 67 | ) 68 | ) 69 | ) 70 | ), 71 | f7Tabs( 72 | id = "widget_nav", 73 | animated = TRUE, 74 | f7Tab( 75 | tabName = "Home", 76 | icon = f7Icon("house"), 77 | active = TRUE, 78 | rclipboardSetup(), 79 | tags$head( 80 | tags$script( 81 | "$(function() { 82 | Shiny.addCustomMessageHandler('toggle_project_type', function(message) { 83 | if (message === 'placeholder') { 84 | $('#engine_type').hide(); 85 | $('#engine_type').siblings().last().hide(); 86 | } else { 87 | $('#engine_type').show(); 88 | $('#engine_type').siblings().last().show(); 89 | } 90 | $() 91 | }); 92 | 93 | Shiny.addCustomMessageHandler('toggle_run_button', function(message) { 94 | if (message) { 95 | $('#run_code_output').children().show(); 96 | $('#clip_button').show(); 97 | } else { 98 | $('#run_code_output').children().hide(); 99 | $('#clip_button').hide(); 100 | } 101 | }); 102 | 103 | $(document).one('shiny:connected', function() { 104 | var isDark = $('html').hasClass('theme-dark'); 105 | Shiny.setInputValue('is_dark', isDark); 106 | }); 107 | 108 | $('#theme_switch').on('click', function() { 109 | var isDark = $('html').hasClass('theme-dark'); 110 | if (isDark) { 111 | $(this).find('.f7-icons').html('moon_fill'); 112 | $('html').removeClass('theme-dark'); 113 | } else { 114 | $(this).find('.f7-icons').html('sun_max'); 115 | $('html').addClass('theme-dark'); 116 | } 117 | Shiny.setInputValue('is_dark', !isDark, {priority: 'event'}); 118 | }) 119 | });" 120 | ) 121 | ), 122 | 123 | f7Select( 124 | inputId = "project_type", 125 | label = "Project Type", 126 | choices = c( 127 | "Select a project type" = "placeholder", 128 | "Package" = "package", 129 | "Simple app" = "simple", 130 | "Extension" = "extension" 131 | ), 132 | selected = NULL 133 | ), 134 | shinyMobile::f7Radio( 135 | inputId = "engine_type", 136 | label = "Select an engine", 137 | choices = NULL 138 | ) 139 | ), 140 | f7Tab( 141 | tabName = "Configuration", 142 | icon = f7Icon("gear"), 143 | uiOutput("config_steps") 144 | ), 145 | f7Tab( 146 | tabName = "Template", 147 | icon = f7Icon("paintbrush"), 148 | truelle::f7Radio( 149 | inputId = "selected_template", 150 | label = "Selected template", 151 | selected = "golem_default", 152 | choices = list( 153 | default = list( 154 | title = "golem_default", 155 | subtitle = "{golem} default template", 156 | text = "Best choice if you don't know where to start.", 157 | image = img( 158 | src = "www/golem.svg", 159 | width = "40px", 160 | height = "40px" 161 | ) 162 | ), 163 | shinyMobile_simple = list( 164 | title = "shinyMobile_simple", 165 | subtitle = "Simplest {shinyMobile} template", 166 | text = "Ideal for simple apps with one page content.", 167 | image = img( 168 | src = "www/shinyMobile.svg", 169 | width = "40px", 170 | height = "40px" 171 | ) 172 | ), 173 | shinyMobile_tabs = list( 174 | title = "shinyMobile_tabs", 175 | subtitle = "Tabs layout for {shinyMobile}", 176 | text = "Ideal for complex apps with multi tabs content. 177 | Perfect for mobile devices.", 178 | image = img( 179 | src = "www/shinyMobile.svg", 180 | width = "40px", 181 | height = "40px" 182 | ) 183 | ), 184 | shinyMobile_split = list( 185 | title = "shinyMobile_split", 186 | subtitle = "Split layout for {shinyMobile}", 187 | text = "Ideal for complex apps with multi tabs content. 188 | Perfect for larger mobile devices such as tablets.", 189 | image = img( 190 | src = "www/shinyMobile.svg", 191 | width = "40px", 192 | height = "40px" 193 | ) 194 | ), 195 | bs4Dash = list( 196 | title = "bs4Dash", 197 | subtitle = "Bootstrap 4 dashboard template", 198 | text = "Ideal to build modern apps without losing the {shinydashboard} spirit.", 199 | image = img( 200 | src = "www/bs4Dash.svg", 201 | width = "40px", 202 | height = "40px" 203 | ) 204 | ), 205 | shinydashboard = list( 206 | title = "shinydashboard", 207 | subtitle = "Bootstrap 3 dashboard template", 208 | text = "The well know {shinydashboard} template.", 209 | image = NULL 210 | ), 211 | shiny_fluent = list( 212 | title = "shiny.fluent", 213 | subtitle = "Microsoft Fluent UI for {shiny}", 214 | text = "React-based user interface kit for {shiny}.", 215 | image = img( 216 | src = "www/shiny-fluent.png", 217 | width = "40px", 218 | height = "40px" 219 | ) 220 | ), 221 | shiny_material = list( 222 | title = "shinymaterial", 223 | subtitle = "Materialize CSS for {shiny}", 224 | text = "Material design UI kit for {shiny}.", 225 | image = NULL 226 | ), 227 | shiny_semantic = list( 228 | title = "shiny.semantic", 229 | subtitle = "Formantic UI for {shiny}", 230 | text = "Formantic UI toolkit for {shiny}.", 231 | image = img( 232 | src = "www/shiny-semantic.png", 233 | width = "40px", 234 | height = "40px" 235 | ) 236 | ), 237 | semantic_dashboard = list( 238 | title = "semantic.dashboard", 239 | subtitle = "Formantic dashboard UI for {shiny}", 240 | text = "Dashboard template powered by the Formantic UI toolkit for {shiny}.", 241 | image = img( 242 | src = "www/semantic-dashboard.png", 243 | width = "40px", 244 | height = "40px" 245 | ) 246 | ) 247 | ) 248 | ) 249 | ), 250 | f7Tab( 251 | tabName = "Output", 252 | icon = f7Icon("document_text"), 253 | aceEditor( 254 | outputId = "code_output", 255 | value = "", 256 | mode = "r" 257 | ) 258 | ) 259 | ) 260 | ) 261 | ) 262 | ) 263 | } 264 | 265 | #' Add external Resources to the Application 266 | #' 267 | #' This function is internally used to add external 268 | #' resources inside the Shiny application. 269 | #' 270 | #' @import shiny 271 | #' @importFrom golem add_resource_path activate_js favicon bundle_resources 272 | #' @noRd 273 | golem_add_external_resources <- function(){ 274 | 275 | add_resource_path( 276 | 'www', app_sys('app/www') 277 | ) 278 | 279 | tags$head( 280 | favicon(), 281 | bundle_resources( 282 | path = app_sys('app/www'), 283 | app_title = '{truelle}' 284 | ) 285 | # Add here other external resources 286 | # for example, you can add shinyalert::useShinyalert() 287 | ) 288 | } 289 | 290 | -------------------------------------------------------------------------------- /R/app_server.R: -------------------------------------------------------------------------------- 1 | #' The application server-side 2 | #' 3 | #' @param input,output,session Internal parameters for {shiny}. 4 | #' DO NOT REMOVE. 5 | #' @import shiny 6 | #' @import shinyMobile 7 | #' @importFrom shinyAce updateAceEditor 8 | #' @importFrom callr r_bg 9 | #' @importFrom jsonlite toJSON 10 | #' @noRd 11 | app_server <- function( input, output, session ) { 12 | 13 | # Tooltip for golem option 14 | observeEvent({ 15 | req(input$engine_type) 16 | }, { 17 | addF7Tooltip( 18 | selector = "#engine_type > ul > li:nth-child(1) > label > div > div", 19 | options = list( 20 | text = "{golem} allows to develop production ready shiny apps ..." 21 | ) 22 | ) 23 | }) 24 | 25 | 26 | observeEvent(input$project_type, { 27 | session$sendCustomMessage("toggle_project_type", input$project_type) 28 | }) 29 | 30 | observeEvent(c(input$package_path, input$project_type), { 31 | cond <- (input$project_type != "placeholder" && nchar(input$package_path) > 0) 32 | session$sendCustomMessage( 33 | "toggle_run_button", 34 | toJSON(cond, auto_unbox = TRUE) 35 | ) 36 | }) 37 | 38 | observeEvent(input$widget_nav,{ 39 | if (input$project_type == "placeholder" && ( 40 | input$widget_nav == "Configuration" || 41 | input$widget_nav == "Output" 42 | )) { 43 | f7Toast( 44 | text = "You can't do this now.", 45 | position = "center" 46 | ) 47 | } 48 | }) 49 | 50 | observeEvent(input$project_type, { 51 | choices <- if (input$project_type == "package") { 52 | c( 53 | "{golem}" = "golem", 54 | "{packer}" = "packer", 55 | "{reactR}" = "reactr" 56 | ) 57 | } 58 | updateF7Radio("engine_type", choices = choices) 59 | }) 60 | 61 | #observeEvent(input$engine_type, { 62 | # updateF7Tabs("widget_nav", selected = "Configuration") 63 | #}) 64 | 65 | output$config_steps <- renderUI({ 66 | req(input$engine_type) 67 | steps <- if (input$engine_type == "golem") { 68 | f7Block( 69 | inset = TRUE, 70 | f7AccordionItem( 71 | title = div(class = "text-color-blue", "Package path"), 72 | open = TRUE, 73 | f7Text( 74 | inputId = "package_path", 75 | label = "", 76 | value = "", 77 | placeholder = "package path" 78 | ) 79 | ), 80 | f7AccordionItem( 81 | title = div(class = "text-color-blue", "Metadata"), 82 | f7Block( 83 | inset = TRUE, 84 | strong = TRUE, 85 | f7Toggle( 86 | inputId = "edit_description", 87 | label = "Edit description", 88 | checked = FALSE 89 | ) 90 | ) 91 | ), 92 | f7AccordionItem( 93 | title = div(class = "text-color-blue", "{usethis} commons"), 94 | # common usethis tasks 95 | lapply(seq_along(usethis_commons), function(i) { 96 | f7Block( 97 | inset = TRUE, 98 | strong = TRUE, 99 | f7Toggle( 100 | inputId = paste0("set_usethis_", names(usethis_commons)[[i]]), 101 | label = names(usethis_commons)[[i]], 102 | checked = TRUE 103 | ), 104 | br() 105 | ) 106 | }) 107 | 108 | ), 109 | # Bug with interactivity... check what we can do ... 110 | #f7AccordionItem( 111 | # title = "{testthat} commons", 112 | # f7Toggle( 113 | # inputId = "allow_recommended_tests", 114 | # label = "Recommanded tests", 115 | # checked = FALSE 116 | # ) 117 | #), 118 | f7AccordionItem( 119 | title = div(class = "text-color-blue", "Dependencies"), 120 | f7Block( 121 | inset = TRUE, 122 | strong = TRUE, 123 | f7Toggle( 124 | inputId = "use_recommended_deps", 125 | label = "Add recommended deps", 126 | checked = TRUE 127 | ) 128 | ) 129 | ), 130 | f7AccordionItem( 131 | title = div(class = "text-color-blue", "{golem} utils"), 132 | f7Block( 133 | inset = TRUE, 134 | strong = TRUE, 135 | f7Toggle( 136 | inputId = "use_golem_utils", 137 | label = "Allow utils", 138 | checked = TRUE 139 | ) 140 | ) 141 | ), 142 | f7AccordionItem( 143 | title = div(class = "text-color-blue", "Shiny modules"), 144 | f7Block( 145 | inset = TRUE, 146 | strong = TRUE, 147 | f7Toggle( 148 | inputId = "add_module_skeleton", 149 | label = "Add module", 150 | checked = TRUE 151 | ) 152 | ) 153 | ), 154 | f7AccordionItem( 155 | title = div(class = "text-color-blue", "Web dev tools"), 156 | lapply(seq_along(webdev_commons), function(i) { 157 | f7Block( 158 | inset = TRUE, 159 | strong = TRUE, 160 | f7Toggle( 161 | inputId = paste0("create_golem_", names(webdev_commons)[[i]]), 162 | label = names(webdev_commons)[[i]], 163 | checked = TRUE 164 | ), 165 | br() 166 | ) 167 | }), 168 | f7TextArea( 169 | inputId = "css_template", 170 | label = "CSS template", 171 | value = paste0( 172 | "function(path, ...){ \n", 173 | " # Define a CSS template \n", 174 | " write_there <- function(...){ \n", 175 | " write(..., file = path, append = TRUE) \n", 176 | " } \n", 177 | 178 | ' write_there("body {") \n', 179 | ' write_there(" background-color:white;") \n', 180 | ' write_there("}") \n', 181 | " }", 182 | collapse = "\n" 183 | ) 184 | ), 185 | f7TextArea( 186 | inputId = "js_template", 187 | label = "JS template", 188 | value = NULL 189 | ) 190 | ), 191 | f7AccordionItem( 192 | title = div(class = "text-color-blue", "Other options"), 193 | f7Block( 194 | inset = TRUE, 195 | strong = TRUE, 196 | f7Toggle( 197 | inputId = "set_golem_options", 198 | label = "Golem options", 199 | checked = FALSE 200 | ) 201 | ) 202 | ) 203 | ) 204 | } 205 | if (!is.null(steps)) { 206 | tagList( 207 | f7Accordion( 208 | id = "config_step", 209 | multiCollapse = TRUE, 210 | steps 211 | ), 212 | f7Card( 213 | title = "Customize {golem} hooks", 214 | p("Enter any extra configuration you want to have in your 215 | project", class = "text-color-blue"), 216 | br(), 217 | f7TextArea( 218 | inputId = "custom_golem_hook", 219 | label = "Custom hook", 220 | value = NULL 221 | ) 222 | ) 223 | ) 224 | } 225 | }) 226 | 227 | # End-user info for package path 228 | observeEvent({ 229 | input$package_path 230 | }, { 231 | 232 | is_golem <- file.exists(file.path(input$package_path, "inst/golem-config.yml")) 233 | if (is_golem) { 234 | f7Dialog( 235 | title = "Oupps", 236 | text = "Package already exists here! Please use another path", 237 | type = "alert" 238 | ) 239 | updateF7Text("package_path", value = "") 240 | } else { 241 | validateF7Input( 242 | inputId = "package_path", 243 | pattern = "*", 244 | info = "Package path like ~/Desktop/myPackage", 245 | error = "Path cannot be empty!" 246 | ) 247 | } 248 | }) 249 | 250 | observeEvent({ 251 | input$custom_golem_hook 252 | }, { 253 | validateF7Input( 254 | inputId = "custom_golem_hook", 255 | info = "A {golem} hook is a function run at package creation.", 256 | ) 257 | }) 258 | 259 | # Insert text description fields if enabled 260 | observeEvent(input$edit_description, { 261 | if (input$edit_description) { 262 | insertUI( 263 | selector = "#edit_description", 264 | where = "afterEnd", 265 | ui = div( 266 | id = "package_description_div", 267 | lapply(seq_along(pkg_description_fields), function(i) { 268 | f7Text( 269 | inputId = names(pkg_description_fields)[[i]], 270 | label = strsplit(names(pkg_description_fields)[[i]], "_")[[1]][2], 271 | value = pkg_description_fields[[i]] 272 | ) 273 | }) 274 | ) 275 | ) 276 | } else { 277 | removeUI("#package_description_div") 278 | } 279 | }) 280 | 281 | # Update custom hook based on many options 282 | observeEvent({ 283 | req(input$engine_type == "golem") 284 | req(input$package_path) 285 | c( 286 | input$package_path, 287 | input$edit_description, 288 | input$set_golem_options, 289 | #input$allow_recommended_tests, 290 | input$use_golem_utils, 291 | input$use_recommended_deps, 292 | input$add_module_skeleton, 293 | input$css_template, 294 | input$js_template, 295 | input$selected_template, 296 | eval(parse(text = paste0("input$create_golem_", names(webdev_commons)))), 297 | eval(parse(text = paste0("input$set_usethis_", names(usethis_commons)))), 298 | eval(parse(text = paste0("input$", names(pkg_description_fields)))) 299 | ) 300 | }, 301 | { 302 | if (nchar(input$css_template) > 0) { 303 | webdev_commons[["simple_css"]] <- paste0( 304 | ' golem::add_css_file( \n', 305 | ' "custom_css", \n', 306 | " template = ", input$css_template, "\n", 307 | ' )', 308 | collapse = "\n" 309 | ) 310 | } 311 | 312 | if (nchar(input$js_template) > 0) { 313 | webdev_commons[["simple_js"]] <- paste0( 314 | ' golem::add_js_file( \n', 315 | ' "custom_js", \n', 316 | " template = ", input$js_template, "\n", 317 | ' )', 318 | collapse = "\n" 319 | ) 320 | } 321 | 322 | web_dev_tasks <- list_2_char(webdev_commons, "create_golem_", input) 323 | usethis_tasks <- list_2_char(usethis_commons, "set_usethis_", input) 324 | 325 | temp_val <- paste0( 326 | "function(path, package_name, ...) { \n", 327 | if (input$edit_description) { 328 | paste0( 329 | ' golem::fill_desc( \n', 330 | ' pkg_name = "', input[[names(pkg_description_fields)[[1]]]], '", \n', 331 | ' pkg_title = "', input[[names(pkg_description_fields)[[2]]]], '", \n', 332 | ' pkg_description = "', input[[names(pkg_description_fields)[[3]]]], '", \n', 333 | ' author_first_name = "', input[[names(pkg_description_fields)[[4]]]], '", \n', 334 | ' author_last_name = "', input[[names(pkg_description_fields)[[5]]]],'", \n', 335 | ' author_email = "', input[[names(pkg_description_fields)[[6]]]], '", \n', 336 | ' repo_url = "', input[[names(pkg_description_fields)[[7]]]], '" \n', 337 | ' ) \n', 338 | '\n', 339 | collapse = "\n" 340 | ) 341 | }, 342 | if (input$set_golem_options) " golem::set_golem_options() \n", 343 | usethis_tasks, 344 | #if (input$allow_recommended_tests) " golem::use_recommended_tests() \n", 345 | if (input$use_recommended_deps) " golem::use_recommended_deps() \n", 346 | if (input$use_golem_utils) { 347 | paste0( 348 | " golem::use_utils_ui() \n", 349 | " golem::use_utils_server() \n", 350 | "\n", 351 | collapse = "\n" 352 | ) 353 | }, 354 | if (input$add_module_skeleton) { 355 | paste0( 356 | ' golem::add_module( name = "my_first_module" ) \n', 357 | ' golem::add_fct("my_first_module") \n', 358 | ' golem::add_utils("my_first_module") \n', 359 | '\n', 360 | collapse = "\n" 361 | ) 362 | }, 363 | web_dev_tasks, 364 | if (input$selected_template != "golem_default") { 365 | add_ui_template(input$selected_template) 366 | }, 367 | " }", 368 | collapse = "\n" 369 | ) 370 | 371 | updateF7TextArea( 372 | inputId = "custom_golem_hook", 373 | value = temp_val 374 | ) 375 | }) 376 | 377 | # Update aceEditor with golem commands 378 | observeEvent( 379 | c( 380 | input$package_path, 381 | input$custom_golem_hook 382 | ), { 383 | req(nchar(input$package_path) > 0) 384 | 385 | hook <- if (nchar(input$custom_golem_hook) > 0) { 386 | input$custom_golem_hook 387 | } else { 388 | "golem::project_hook" 389 | } 390 | 391 | new_val <- paste0( 392 | 'golem::create_golem( \n', 393 | ' path = "', input$package_path, '", \n', 394 | ' open = FALSE, \n', 395 | ' project_hook = ', hook,' \n', 396 | ')', 397 | collapse = "\n" 398 | ) 399 | 400 | updateAceEditor( 401 | session, 402 | "code_output", 403 | value = new_val 404 | ) 405 | }) 406 | 407 | # Update ace editor on dark mode but don't run at start 408 | observeEvent(input$is_dark, { 409 | updateAceEditor( 410 | session, 411 | "code_output", 412 | theme = if (input$is_dark) "chaos" else "eclipse" 413 | ) 414 | }) 415 | 416 | # Copy to clipboard 417 | output$clip_button <- renderUI({ 418 | rclipButton( 419 | "copy_code_output", 420 | div(style = "padding-right: 5px", "Copy code"), 421 | input$code_output, 422 | icon = f7Icon("camera") 423 | ) 424 | }) 425 | 426 | 427 | # Run the command in another process 428 | observeEvent(input$run_code_output, { 429 | jobs[[1]] <- r_bg(run_text, args = list(code = input$code_output)) 430 | jobs[[1]]$wait() 431 | 432 | f7Notif( 433 | title = "Hey!", 434 | paste("Package successfully created at", jobs[[1]]$get_result()), 435 | icon = f7Icon("info_round") 436 | ) 437 | }) 438 | 439 | # Close the app 440 | observeEvent(input$close_app, { 441 | f7Dialog( 442 | id = "close_app_confirm", 443 | title = "Oupps", 444 | text = "Do you really want to close?", 445 | type = "confirm" 446 | ) 447 | }) 448 | 449 | observeEvent(input$close_app_confirm, { 450 | req(input$close_app_confirm) 451 | stopApp() 452 | }) 453 | 454 | #observeEvent(input$project_type, once = TRUE, { 455 | # updateF7Accordion("config_step", selected = 2) 456 | #}) 457 | } 458 | -------------------------------------------------------------------------------- /inst/app/www/shinyMobile.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | shiny 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Mobile 34 | 35 | 36 | 37 | 38 | 39 | --------------------------------------------------------------------------------