diff --git a/R/mod_navbar.R b/R/mod_navbar.R index 39cd7c0..fbfbd7c 100644 --- a/R/mod_navbar.R +++ b/R/mod_navbar.R @@ -18,7 +18,7 @@ mod_navbar_ui <- function(id) { a( class = "navbar-brand", href = "/", - "Signature.r" + "Signature.gomart" ), input_dark_mode() ) diff --git a/site/app.json b/site/app.json index a43037b..43191a2 100644 --- a/site/app.json +++ b/site/app.json @@ -1 +1 @@ -[{"name":"app.R","content":"# Launch the ShinyApp (Do not remove this comment)\n# To deploy, run: rsconnect::deployApp()\n# Or use the blue button on top of this file\n\npkgload::load_all(export_all = FALSE, helpers = FALSE, attach_testthat = FALSE)\noptions(\"golem.app.prod\" = TRUE)\nsignature.r::run_app() # add parameters here (if any)\n","type":"text"},{"name":"CODE_OF_CONDUCT.md","content":"# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at arthur@thinkr.fr. \nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n.\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][https://github.com/mozilla/inclusion].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n. Translations are available at .\n\n[homepage]: https://www.contributor-covenant.org\n","type":"text"},{"name":"DESCRIPTION","content":"Package: signature.r\nTitle: Fill your email signature\nVersion: 0.0.0.9000\nAuthors@R: \n person(\"Arthur\", \"Bréant\", , \"arthur@thinkr.fr\", role = c(\"cre\", \"aut\"))\nDescription: Fill in your email signature from Thinkr template.\nLicense: MIT + file LICENSE\nURL: https://github.com/ThinkR-open/signature.r\nBugReports: https://github.com/ThinkR-open/signature.r/issues\nImports: \n bslib,\n config (>= 0.3.2),\n golem (>= 0.4.1),\n shiny (>= 1.9.1),\n whereami\nSuggests: \n spelling,\n testthat (>= 3.0.0)\nConfig/testthat/edition: 3\nEncoding: UTF-8\nLanguage: en-US\nLazyData: true\nRoxygenNote: 7.3.2\n","type":"text"},{"name":"LICENSE","content":"YEAR: 2024\nCOPYRIGHT HOLDER: signature.r authors\n","type":"text"},{"name":"LICENSE.md","content":"# MIT License\n\nCopyright (c) 2024 signature.r authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","type":"text"},{"name":"NAMESPACE","content":"# Generated by roxygen2: do not edit by hand\n\nexport(run_app)\nimport(shiny)\nimportFrom(bslib,accordion)\nimportFrom(bslib,accordion_panel)\nimportFrom(bslib,input_dark_mode)\nimportFrom(bslib,input_task_button)\nimportFrom(golem,activate_js)\nimportFrom(golem,add_resource_path)\nimportFrom(golem,bundle_resources)\nimportFrom(golem,favicon)\nimportFrom(golem,with_golem_options)\nimportFrom(shiny,HTML)\nimportFrom(shiny,NS)\nimportFrom(shiny,column)\nimportFrom(shiny,shinyApp)\nimportFrom(shiny,tagAppendAttributes)\nimportFrom(shiny,tagList)\nimportFrom(shiny,tags)\nimportFrom(whereami,cat_where)\nimportFrom(whereami,whereami)\n","type":"text"},{"name":"NEWS.md","content":"# signature.r 0.0.0.9000\n\n- Rebuild signature with R\n","type":"text"},{"name":"R/_disable_autoload.R","content":"# Disabling shiny autoload\n\n# See ?shiny::loadSupport for more information\n","type":"text"},{"name":"R/app_config.R","content":"#' Access files in the current app\n#'\n#' NOTE: If you manually change your package name in the DESCRIPTION,\n#' don't forget to change it here too, and in the config file.\n#' For a safer name change mechanism, use the `golem::set_golem_name()` function.\n#'\n#' @param ... character vectors, specifying subdirectory and file(s)\n#' within your package. The default, none, returns the root of the app.\n#'\n#' @noRd\napp_sys <- function(...) {\n system.file(..., package = \"signature.r\")\n}\n\n\n#' Read App Config\n#'\n#' @param value Value to retrieve from the config file.\n#' @param config GOLEM_CONFIG_ACTIVE value. If unset, R_CONFIG_ACTIVE.\n#' If unset, \"default\".\n#' @param use_parent Logical, scan the parent directory for config file.\n#' @param file Location of the config file\n#'\n#' @noRd\nget_golem_config <- function(\n value,\n config = Sys.getenv(\n \"GOLEM_CONFIG_ACTIVE\",\n Sys.getenv(\n \"R_CONFIG_ACTIVE\",\n \"default\"\n )\n ),\n use_parent = TRUE,\n # Modify this if your config file is somewhere else\n file = app_sys(\"golem-config.yml\")\n) {\n config::get(\n value = value,\n config = config,\n file = file,\n use_parent = use_parent\n )\n}\n","type":"text"},{"name":"R/app_server.R","content":"#' The application server-side\n#'\n#' @param input,output,session Internal parameters for {shiny}.\n#' DO NOT REMOVE.\n#' @import shiny\n#' @noRd\napp_server <- function(input, output, session) {\n global <- reactiveValues()\n\n mod_navbar_server(\"navbar\")\n mod_form_server(\"form\", global = global)\n mod_preview_server(\"preview\", global = global)\n}\n","type":"text"},{"name":"R/app_ui.R","content":"#' The application User-Interface\n#'\n#' @param request Internal parameter for `{shiny}`.\n#' DO NOT REMOVE.\n#' @import shiny\n#' @noRd\napp_ui <- function(request) {\n tagList(\n # Leave this function for adding external resources\n golem_add_external_resources(),\n # Your application UI logic\n tagList(\n useBusyIndicators(\n spinners = FALSE\n ),\n div(\n class = \"container\",\n mod_navbar_ui(\"navbar\"),\n div(\n class = \"container\",\n div(\n class = \"row\",\n mod_form_ui(\"form\"),\n mod_preview_ui(\"preview\")\n )\n )\n )\n )\n )\n}\n\n#' Add external Resources to the Application\n#'\n#' This function is internally used to add external\n#' resources inside the Shiny application.\n#'\n#' @import shiny\n#' @importFrom golem add_resource_path activate_js favicon bundle_resources\n#' @noRd\ngolem_add_external_resources <- function() {\n add_resource_path(\n \"www\",\n app_sys(\"app/www\")\n )\n\n tags$head(\n favicon(ext = \"png\"),\n bundle_resources(\n path = app_sys(\"app/www\"),\n app_title = \"signature.r\"\n ),\n tags$script(\n src = \"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js\",\n integrity = \"sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz\",\n crossorigin = \"anonymous\"\n ),\n tags$script(\n src = \"https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.5.10/clipboard.min.js\"\n ),\n includeHTML(\n app_sys(\"app\", \"www\", \"gtag.html\")\n )\n )\n}\n","type":"text"},{"name":"R/golem_utils_server.R","content":"#' Inverted versions of in, is.null and is.na\n#'\n#' @noRd\n#'\n#' @examples\n#' 1 %not_in% 1:10\n#' not_null(NULL)\n`%not_in%` <- Negate(`%in%`)\n\nnot_null <- Negate(is.null)\n\nnot_na <- Negate(is.na)\n\n#' Removes the null from a vector\n#'\n#' @noRd\n#'\n#' @example\n#' drop_nulls(list(1, NULL, 2))\ndrop_nulls <- function(x) {\n x[!sapply(x, is.null)]\n}\n\n#' If x is `NULL`, return y, otherwise return x\n#'\n#' @param x,y Two elements to test, one potentially `NULL`\n#'\n#' @noRd\n#'\n#' @examples\n#' NULL %||% 1\n\"%||%\" <- function(x, y) {\n if (is.null(x)) {\n y\n } else {\n x\n }\n}\n\n#' If x is `NA`, return y, otherwise return x\n#'\n#' @param x,y Two elements to test, one potentially `NA`\n#'\n#' @noRd\n#'\n#' @examples\n#' NA %|NA|% 1\n\"%|NA|%\" <- function(x, y) {\n if (is.na(x)) {\n y\n } else {\n x\n }\n}\n\n#' Typing reactiveValues is too long\n#'\n#' @inheritParams reactiveValues\n#' @inheritParams reactiveValuesToList\n#'\n#' @noRd\nrv <- function(...) shiny::reactiveValues(...)\nrvtl <- function(...) shiny::reactiveValuesToList(...)\n","type":"text"},{"name":"R/golem_utils_ui.R","content":"#' Turn an R list into an HTML list\n#'\n#' @param list An R list\n#' @param class a class for the list\n#'\n#' @return an HTML list\n#' @noRd\n#'\n#' @examples\n#' list_to_li(c(\"a\", \"b\"))\n#' @importFrom shiny tags tagAppendAttributes tagList\nlist_to_li <- function(list, class = NULL) {\n if (is.null(class)) {\n tagList(\n lapply(\n list,\n tags$li\n )\n )\n } else {\n res <- lapply(\n list,\n tags$li\n )\n res <- lapply(\n res,\n function(x) {\n tagAppendAttributes(\n x,\n class = class\n )\n }\n )\n tagList(res)\n }\n}\n#' Turn an R list into corresponding HTML paragraph tags\n#'\n#' @param list an R list\n#' @param class a class for the paragraph tags\n#'\n#' @return An HTML tag\n#' @noRd\n#'\n#' @examples\n#' list_to_p(c(\"This is the first paragraph\", \"this is the second paragraph\"))\n#' @importFrom shiny tags tagAppendAttributes tagList\n#'\nlist_to_p <- function(list, class = NULL) {\n if (is.null(class)) {\n tagList(\n lapply(\n list,\n tags$p\n )\n )\n } else {\n res <- lapply(\n list,\n tags$p\n )\n res <- lapply(\n res,\n function(x) {\n tagAppendAttributes(\n x,\n class = class\n )\n }\n )\n tagList(res)\n }\n}\n\n#' @importFrom shiny tags tagAppendAttributes tagList\nnamed_to_li <- function(list, class = NULL) {\n if (is.null(class)) {\n res <- mapply(\n function(x, y) {\n tags$li(\n HTML(\n sprintf(\"%s:<\/b> %s\", y, x)\n )\n )\n },\n list,\n names(list),\n SIMPLIFY = FALSE\n )\n tagList(res)\n } else {\n res <- mapply(\n function(x, y) {\n tags$li(\n HTML(\n sprintf(\"%s:<\/b> %s\", y, x)\n )\n )\n },\n list,\n names(list),\n SIMPLIFY = FALSE\n )\n res <- lapply(\n res,\n function(x) {\n tagAppendAttributes(\n x,\n class = class\n )\n }\n )\n tagList(res)\n }\n}\n\n#' Remove a tag attribute\n#'\n#' @param tag the tag\n#' @param ... the attributes to remove\n#'\n#' @return a new tag\n#' @noRd\n#'\n#' @examples\n#' a <- shiny::tags$p(src = \"plop\", \"pouet\")\n#' tagRemoveAttributes(a, \"src\")\ntagRemoveAttributes <- function(tag, ...) {\n attrs <- as.character(list(...))\n for (i in seq_along(attrs)) {\n tag$attribs[[attrs[i]]] <- NULL\n }\n tag\n}\n\n#' Hide or display a tag\n#'\n#' @param tag the tag\n#'\n#' @return a tag\n#' @noRd\n#'\n#' @examples\n#' ## Hide\n#' a <- shiny::tags$p(src = \"plop\", \"pouet\")\n#' undisplay(a)\n#' b <- shiny::actionButton(\"go_filter\", \"go\")\n#' undisplay(b)\n#' @importFrom shiny tagList\nundisplay <- function(tag) {\n # if not already hidden\n if (\n !is.null(tag$attribs$style) &&\n !grepl(\"display:\\\\s+none\", tag$attribs$style)\n ) {\n tag$attribs$style <- paste(\n \"display: none;\",\n tag$attribs$style\n )\n } else {\n tag$attribs$style <- \"display: none;\"\n }\n tag\n}\n\n#' @importFrom shiny tagList\ndisplay <- function(tag) {\n if (\n !is.null(tag$attribs$style) &&\n grepl(\"display:\\\\s+none\", tag$attribs$style)\n ) {\n tag$attribs$style <- gsub(\n \"(\\\\s)*display:(\\\\s)*none(\\\\s)*(;)*(\\\\s)*\",\n \"\",\n tag$attribs$style\n )\n }\n tag\n}\n\n#' Hide an elements by calling jquery hide on it\n#'\n#' @param id the id of the element to hide\n#'\n#' @noRd\n#'\n#' @importFrom shiny tags\njq_hide <- function(id) {\n tags$script(sprintf(\"$('#%s').hide()\", id))\n}\n\n#' Add a red star at the end of the text\n#'\n#' Adds a red star at the end of the text\n#' (for example for indicating mandatory fields).\n#'\n#' @param text the HTLM text to put before the red star\n#'\n#' @return an html element\n#' @noRd\n#'\n#' @examples\n#' with_red_star(\"Enter your name here\")\n#' @importFrom shiny tags HTML\nwith_red_star <- function(text) {\n shiny::tags$span(\n HTML(\n paste0(\n text,\n shiny::tags$span(\n style = \"color:red\",\n \"*\"\n )\n )\n )\n )\n}\n\n\n\n#' Repeat tags$br\n#'\n#' @param times the number of br to return\n#'\n#' @return the number of br specified in times\n#' @noRd\n#'\n#' @examples\n#' rep_br(5)\n#' @importFrom shiny HTML\nrep_br <- function(times = 1) {\n HTML(rep(\"
\", times = times))\n}\n\n#' Create an url\n#'\n#' @param url the URL\n#' @param text the text to display\n#'\n#' @return an a tag\n#' @noRd\n#'\n#' @examples\n#' enurl(\"https://www.thinkr.fr\", \"ThinkR\")\n#' @importFrom shiny tags\nenurl <- function(url, text) {\n tags$a(href = url, text)\n}\n\n#' Columns wrappers\n#'\n#' These are convenient wrappers around\n#' `column(12, ...)`, `column(6, ...)`, `column(4, ...)`...\n#'\n#' @noRd\n#'\n#' @importFrom shiny column\ncol_12 <- function(...) {\n column(12, ...)\n}\n\n#' @importFrom shiny column\ncol_10 <- function(...) {\n column(10, ...)\n}\n\n#' @importFrom shiny column\ncol_8 <- function(...) {\n column(8, ...)\n}\n\n#' @importFrom shiny column\ncol_6 <- function(...) {\n column(6, ...)\n}\n\n\n#' @importFrom shiny column\ncol_4 <- function(...) {\n column(4, ...)\n}\n\n\n#' @importFrom shiny column\ncol_3 <- function(...) {\n column(3, ...)\n}\n\n\n#' @importFrom shiny column\ncol_2 <- function(...) {\n column(2, ...)\n}\n\n\n#' @importFrom shiny column\ncol_1 <- function(...) {\n column(1, ...)\n}\n\n\n\n#' Make the current tag behave like an action button\n#'\n#' Only works with compatible tags like button or links\n#'\n#' @param tag Any compatible tag.\n#' @param inputId Unique id. This will host the input value to be used\n#' on the server side.\n#'\n#' @return The modified tag with an extra id and the action button class.\n#' @noRd\n#'\n#' @examples\n#' if (interactive()) {\n#' library(shiny)\n#'\n#' link <- a(href = \"#\", \"My super link\", style = \"color: lightblue;\")\n#'\n#' ui <- fluidPage(\n#' make_action_button(link, inputId = \"mylink\")\n#' )\n#'\n#' server <- function(input, output, session) {\n#' observeEvent(input$mylink, {\n#' showNotification(\"Pouic!\")\n#' })\n#' }\n#'\n#' shinyApp(ui, server)\n#' }\nmake_action_button <- function(tag, inputId = NULL) {\n # some obvious checks\n if (!inherits(tag, \"shiny.tag\")) stop(\"Must provide a shiny tag.\")\n if (!is.null(tag$attribs$class)) {\n if (grep(\"action-button\", tag$attribs$class)) {\n stop(\"tag is already an action button\")\n }\n }\n if (is.null(inputId) && is.null(tag$attribs$id)) {\n stop(\"tag does not have any id. Please use inputId to be able to\n access it on the server side.\")\n }\n\n # handle id\n if (!is.null(inputId)) {\n if (!is.null(tag$attribs$id)) {\n warning(\n paste(\n \"tag already has an id. Please use input$\",\n tag$attribs$id,\n \"to access it from the server side. inputId will be ignored.\"\n )\n )\n } else {\n tag$attribs$id <- inputId\n }\n }\n\n # handle class\n if (is.null(tag$attribs$class)) {\n tag$attribs$class <- \"action-button\"\n } else {\n tag$attribs$class <- paste(tag$attribs$class, \"action-button\")\n }\n # return tag\n tag\n}\n\n\n# UNCOMMENT AND USE\n#\n# attachment::att_amend_desc()\n#\n# To use this part of the UI\n#\n#' #' Include Content From a File\n#' #'\n#' #' Load rendered RMarkdown from a file and turn into HTML.\n#' #'\n#' #' @rdname includeRMarkdown\n#' #' @export\n#' #'\n#' #' @importFrom rmarkdown render\n#' #' @importFrom markdown markdownToHTML\n#' #' @importFrom shiny HTML\n#' includeRMarkdown <- function(path){\n#'\n#' md <- tempfile(fileext = '.md')\n#'\n#' on.exit(unlink(md),add = TRUE)\n#'\n#' rmarkdown::render(\n#' path,\n#' output_format = 'md_document',\n#' output_dir = tempdir(),\n#' output_file = md,quiet = TRUE\n#' )\n#'\n#' html <- markdown::markdownToHTML(md, fragment.only = TRUE)\n#'\n#' Encoding(html) <- \"UTF-8\"\n#'\n#' return(HTML(html))\n#' }\n","type":"text"},{"name":"R/mod_form.R","content":"#' form UI Function\n#'\n#' @description A shiny Module.\n#'\n#' @importFrom bslib accordion accordion_panel\n#'\n#' @param id,input,output,session Internal parameters for {shiny}.\n#'\n#' @noRd\n#'\n#' @importFrom shiny NS tagList\nmod_form_ui <- function(id) {\n ns <- NS(id)\n tagList(\n div(\n class = \"col-lg-5 col-md-12 p-3\",\n div(\n class = \"row\",\n accordion(\n id = \"form-accordion\",\n multiple = FALSE,\n accordion_panel(\n title = \"Personal information\",\n tagList(\n textInput(\n inputId = ns(\"firstname\"),\n label = \"First name\",\n placeholder = \"John\",\n width = \"100%\"\n ),\n textInput(\n inputId = ns(\"lastname\"),\n label = \"Last name\",\n placeholder = \"Doe\",\n width = \"100%\"\n )\n )\n ),\n accordion_panel(\n title = \"Business information\",\n tagList(\n textInput(\n inputId = ns(\"job_title\"),\n label = \"Job title\",\n placeholder = \"Data Scientist\",\n width = \"100%\"\n ),\n textInput(\n inputId = ns(\"email\"),\n label = \"Email\",\n placeholder = \"you@thinkr.fr\",\n width = \"100%\"\n ),\n textInput(\n inputId = ns(\"phone\"),\n label = \"Phone number\",\n value = NULL,\n placeholder = \"+33(0) xx xx xx xx\",\n width = \"100%\"\n )\n )\n ),\n accordion_panel(\n title = \"Details about this application\",\n tagList(\n p(\n \"This application is a demonstration of the use of the shiny library with R.\"\n ),\n p(\n \"You can enter your personal and professional information in the form on the left. Then you can preview the rendering of your signature on the right.\"\n ),\n p(\"Then you can copy the signature to your clipboard.\"),\n p(\"You love this application and you would like to reuse it?\"),\n p(\"Discover how to do it on the GitHub repository.\"),\n a(\n \"Explore the code of this application on GitHub.\",\n href = \"https://github.com/ThinkR-open/signature.r/\",\n target = \"_blank\",\n )\n )\n )\n )\n )\n )\n )\n}\n\n#' form Server Functions\n#'\n#' @importFrom whereami whereami cat_where\n#'\n#' @noRd\nmod_form_server <- function(id, global) {\n moduleServer(id, function(input, output, session) {\n ns <- session$ns\n\n observeEvent(\n c(\n input$firstname,\n input$lastname,\n input$job_title,\n input$email,\n input$phone\n ),\n ignoreInit = FALSE,\n {\n cat_where(whereami())\n\n lapply(\n c(\"firstname\", \"lastname\", \"job_title\", \"email\", \"phone\"),\n function(x) {\n global[[x]] <- if (is.null(input[[x]]) | input[[x]] == \"\") {\n sprintf(\"{{%s}}\", x)\n } else {\n input[[x]]\n }\n }\n )\n\n global$phone_url <- sprintf(\"tel:%s\", global$phone)\n global$email_url <- sprintf(\"mailto:%s\", global$email)\n }\n )\n })\n}\n\n## To be copied in the UI\n# mod_form_ui(\"form\")\n\n## To be copied in the server\n# mod_form_server(\"form\")\n","type":"text"},{"name":"R/mod_navbar.R","content":"#' navbar UI Function\n#'\n#' @description A shiny Module.\n#'\n#' @param id,input,output,session Internal parameters for {shiny}.\n#'\n#' @noRd\n#'\n#' @importFrom shiny NS tagList\n#' @importFrom bslib input_dark_mode\nmod_navbar_ui <- function(id) {\n ns <- NS(id)\n tagList(\n tags$nav(\n class = \"navbar navbar-light bg-transparent\",\n div(\n class = \"container-fluid\",\n a(\n class = \"navbar-brand\",\n href = \"/\",\n \"Signature.r\"\n ),\n input_dark_mode()\n )\n )\n )\n}\n\n#' navbar Server Functions\n#'\n#' @noRd\nmod_navbar_server <- function(id) {\n moduleServer(id, function(input, output, session) {\n ns <- session$ns\n })\n}\n\n## To be copied in the UI\n# mod_navbar_ui(\"navbar\")\n\n## To be copied in the server\n# mod_navbar_server(\"navbar)\n","type":"text"},{"name":"R/mod_preview.R","content":"#' preview UI Function\n#'\n#' @description A shiny Module.\n#'\n#' @param id,input,output,session Internal parameters for {shiny}.\n#'\n#' @importFrom bslib input_task_button\n#'\n#' @noRd\n#'\n#' @importFrom shiny NS tagList\nmod_preview_ui <- function(id) {\n ns <- NS(id)\n tagList(\n div(\n class = \"col-lg-7 col-md-12 p-3\",\n div(\n class = \"card\",\n div(\n class = \"card-header bg-ligth\",\n div(\n class = \"buttons\",\n div(class = \"close\"),\n div(class = \"minimize\"),\n div(class = \"zoom\"),\n )\n ),\n div(\n class = \"card-body row gy-4\",\n div(\n id = \"intro\",\n p(\"Hello the team!\"),\n p(\"You can edit your signature from this interface.\"),\n p(\"Then you'll just have to insert it as your signature.\"),\n HTML(\"Thank you 😁\")\n ),\n div(\n id = \"signature\",\n uiOutput(ns(\"preview\"))\n )\n ),\n div(\n class = \"card-footer bg-transparent border-top-0\",\n input_task_button(\n id = ns(\"copy\"),\n label = \" Copy to clipboard\",\n icon = icon(\"copy fa-solid\"),\n label_busy = \"Copied!\",\n icon_busy = icon(\"check\"),\n `data-clipboard-target` = \"#signature\",\n class = \"btn-info btn-md\",\n style = \"width: 100%;\"\n )\n )\n )\n )\n )\n}\n\n#' preview Server Functions\n#'\n#' @noRd\nmod_preview_server <- function(id, global) {\n moduleServer(id, function(input, output, session) {\n ns <- session$ns\n\n output$preview <- renderUI({\n htmlTemplate(\n filename = app_sys(\n \"app\", \"www\", \"template\", \"template.html\"\n ),\n firstname = global$firstname,\n lastname = global$lastname,\n job_title = global$job_title,\n email = global$email,\n email_url = global$email_url,\n phone = global$phone,\n phone_url = global$phone_url\n )\n })\n\n observeEvent(input$copy, {\n Sys.sleep(0.75)\n showNotification(\n \"Paste the signature in your email client\",\n type = \"default\",\n duration = 5\n )\n })\n })\n}\n\n## To be copied in the UI\n# mod_preview_ui(\"preview\")\n\n## To be copied in the server\n# mod_preview_server(\"preview\")\n","type":"text"},{"name":"R/run_app.R","content":"#' Run the Shiny Application\n#'\n#' @param ... arguments to pass to golem_opts.\n#' See `?golem::get_golem_options` for more details.\n#' @inheritParams shiny::shinyApp\n#'\n#' @export\n#' @importFrom shiny shinyApp\n#' @importFrom golem with_golem_options\nrun_app <- function(\n onStart = NULL,\n options = list(),\n enableBookmarking = NULL,\n uiPattern = \"/\",\n ...\n) {\n with_golem_options(\n app = shinyApp(\n ui = app_ui,\n server = app_server,\n onStart = onStart,\n options = options,\n enableBookmarking = enableBookmarking,\n uiPattern = uiPattern\n ),\n golem_opts = list(...)\n )\n}\n","type":"text"},{"name":"README.Rmd","content":"---\noutput: github_document\n---\n\n\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n collapse = TRUE,\n comment = \"#>\",\n fig.path = \"man/figures/README-\",\n out.width = \"100%\"\n)\n```\n\n# signature.r \"Signature.r<\/a>\n\n![R](https://img.shields.io/badge/r-%23276DC3.svg?style=for-the-badge&logo=r&logoColor=white)\n![Bootstrap](https://img.shields.io/badge/bootstrap-%238511FA.svg?style=for-the-badge&logo=bootstrap&logoColor=white)\n[![Figma](https://img.shields.io/badge/figma-%23F24E1E.svg?style=for-the-badge&logo=figma&logoColor=white)](https://www.figma.com/proto/u95KvEqgWLB8arxt7saZcJ/%7Bsignature%7D?node-id=705-5&t=xevegkmzONTrRyR3-8&scaling=contain&content-scaling=fixed&page-id=0%3A1&starting-point-node-id=705%3A5&hide-ui=1)\n\n\n[![R-CMD-check](https://github.com/ThinkR-open/signature.r/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/ThinkR-open/signature.r/actions/workflows/R-CMD-check.yaml)\n\n\nThis is the R version of the [`{signature.py}`](https://github.com/ThinkR-open/signature.py) and [`{signature.js}`](https://github.com/ThinkR-open/signature.js) application.\n\nThis application provides a graphical interface to streamline the creation and maintenance of your email signature.\n\nNo more wrestling with images or getting tangled up in HTML code; the application offers a set of fields to update your signature easily.\n\nSimply enter your name, first name, email, and other necessary information to populate your signature.\n\nAdditionally, the application allows you to copy the HTML code with a single button click, making it easy to paste into your email client settings.\n\nLastly, updating the banner (the image at the bottom of the signature) and the associated link for redirection is straightforward. You no longer need to request everyone to update their signature individually for these changes.\n\n## Demo\n\n🕹️ Try the app at:\n[https://connect.thinkr.fr/signature-r/](https://connect.thinkr.fr/signature-r/)\n\n\n## Try locally\n\n1. Install the package from GitHub:\n\n```{r eval=FALSE}\nremotes::install_github(\"ThinkR-open/signature.r\")\n```\n\n2. Run the app:\n\n```{r eval=FALSE}\nsignature.r::run_app()\n```\n\nor clone the repository and run the app:\n\n1. Clone the repository\n\n2. Run the app:\n\n```{r eval=FALSE}\nrenv::restore()\npkgload::load_all()\ngolem::run_dev()\n```\n\n## Modify the theme\n\nThis app uses Bootstrap `5.3.3`.\n\nTo modify the theme, edit the `inst/app/signature.scss` file.\n\nEvery time you run `golem::run_dev()`, the `signature.scss` file is compiled into `inst/app/www/signature.css`.\n\n## How the redirection banner works?\n\nThe redirection banner is a JavaScript function that redirects the user to the specified URL.\n\nTo modify the redirection URL, creeate a `index.html` file at the root of the project.\n\nSee : [signature](https://github.com/ThinkR-open/signature/)\n\n## Deployment\n\nThis application is deployed on Connect. \n\nBut also serverless directly with ShinyLive : \n\n```{r eval=FALSE}\nshinylive::export(\".\", \"site\")\nhttpuv::runStaticServer(\"site/\")\n```\n\nor with Github Actions. [More details here](https://posit-dev.github.io/r-shinylive/#github-pages) : \n\n```{r eval=FALSE}\nusethis::use_github_action(url = \"https://github.com/posit-dev/r-shinylive/blob/actions-v1/examples/deploy-app.yaml\")\n```\n\n## You love this project?\n\nYou love this project and would like to reuse it for your own needs?\n\nYou can fork this repository and adapt it to your needs.\n\nWhat you can do:\n\n- fork this repository\n\n- adapt the signature template to your needs. \n\n- modify the app to add or remove fields from the signature form to edit the signature.\n\n- modify the redirection banner to redirect to your own URL.\n\n- modify the theme by editing the `inst/app/signature.scss` file.\n\n- Remove google analytics from tag script in the `app.py` file.\n\n- deploy the app on your own server.\n\n- share the app with your colleagues.\n\n- enjoy the app!\n\n\n## Code of Conduct\n\nPlease note that the signature.py project is released with a [Contributor Code of Conduct](https://contributor-covenant.org/version/2/1/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms.\n","type":"text"},{"name":"README.html","content":"\n\n\n\n\n\n\n\n\n\n\n\n