From e7e55f4f71afd770ca49bf8479118e13ab30ba2f Mon Sep 17 00:00:00 2001 From: timelyportfolio Date: Mon, 3 Jan 2022 16:35:33 -0600 Subject: [PATCH 1/4] add experimental Vue 3 support #10 --- CRAN-RELEASE | 2 - DESCRIPTION | 4 +- NAMESPACE | 4 + R/dependencies.R | 62 + R/meta.R | 3 + R/vue.R | 81 + build/getvue.R | 5 +- cran-comments.md | 2 +- inst/examples/vue3_shiny_examples.R | 33 + inst/examples/vue3_widget_examples.R | 66 + inst/examples/vue_widget_examples.R | 2 +- inst/htmlwidgets/vue3.js | 48 + inst/htmlwidgets/vue3.yaml | 0 inst/www/vue3/LICENSE | 21 + inst/www/vue3/README.md | 54 + inst/www/vue3/dist/vue.global.js | 15704 ++++++++++++++++++++++++ inst/www/vue3/dist/vue.global.prod.js | 1 + inst/www/vue3/package.json | 75 + man/html_dependency_vue.Rd | 5 + man/html_dependency_vue3.Rd | 53 + man/vue-shiny.Rd | 44 + man/vue.Rd | 7 +- man/vue3.Rd | 104 + tests/testthat/test_deps.R | 18 + 24 files changed, 16389 insertions(+), 9 deletions(-) delete mode 100644 CRAN-RELEASE create mode 100644 inst/examples/vue3_shiny_examples.R create mode 100644 inst/examples/vue3_widget_examples.R create mode 100644 inst/htmlwidgets/vue3.js create mode 100644 inst/htmlwidgets/vue3.yaml create mode 100644 inst/www/vue3/LICENSE create mode 100644 inst/www/vue3/README.md create mode 100644 inst/www/vue3/dist/vue.global.js create mode 100644 inst/www/vue3/dist/vue.global.prod.js create mode 100644 inst/www/vue3/package.json create mode 100644 man/html_dependency_vue3.Rd create mode 100644 man/vue3.Rd diff --git a/CRAN-RELEASE b/CRAN-RELEASE deleted file mode 100644 index 56760fc..0000000 --- a/CRAN-RELEASE +++ /dev/null @@ -1,2 +0,0 @@ -This package was submitted to CRAN on 2021-11-25. -Once it is accepted, delete this file and tag the release (commit 7172950). diff --git a/DESCRIPTION b/DESCRIPTION index fabe5c2..cd22f16 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: vueR Type: Package Title: 'Vuejs' Helpers and 'Htmlwidget' -Version: 0.5.3 -Date: 2021-11-25 +Version: 0.6 +Date: 2022-01-03 Authors@R: c( person( "Evan","You" diff --git a/NAMESPACE b/NAMESPACE index 9189123..83aac11 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,8 +1,12 @@ # Generated by roxygen2: do not edit by hand export(html_dependency_vue) +export(html_dependency_vue3) export(renderVue) +export(renderVue3) export(vue) +export(vue3) +export(vue3Output) export(vueOutput) import(htmlwidgets) importFrom(htmltools,htmlDependency) diff --git a/R/dependencies.R b/R/dependencies.R index 97c9b43..2988b6d 100644 --- a/R/dependencies.R +++ b/R/dependencies.R @@ -7,6 +7,7 @@ #' #' @return \code{\link[htmltools]{htmlDependency}} #' @importFrom htmltools htmlDependency +#' @family dependencies #' @export #' #' @examples @@ -53,3 +54,64 @@ html_dependency_vue <- function(offline=TRUE, minified=TRUE){ hd } + + +#' Dependencies for 'Vue3' +#' +#' @param offline \code{logical} to use local file dependencies. If \code{FALSE}, +#' then the dependencies use cdn as its \code{src}. +#' @param minified \code{logical} to use minified (production) version. Use +#' \code{minified = FALSE} for debugging or working with Vue devtools. +#' +#' @return \code{\link[htmltools]{htmlDependency}} +#' @importFrom htmltools htmlDependency +#' @family dependencies +#' @export +#' +#' @examples +#' if(interactive()){ +#' +#' library(vueR) +#' library(htmltools) +#' +#' browsable( +#' tagList( +#' tags$div(id="app","{{message}}"), +#' tags$script( +#' " +#' var app = { +#' data: function() { +#' return { +#' message: 'Hello Vue!' +#' } +#' } +#' }; +#' +#' Vue.createApp(app).mount('#app'); +#' " +#' ), +#' html_dependency_vue3() +#' ) +#' ) +#' } +html_dependency_vue3 <- function(offline=TRUE, minified=TRUE){ + hd <- htmltools::htmlDependency( + name = "vue", + version = vue3_version(), + src = system.file("www/vue3/dist",package="vueR"), + script = "vue.global.prod.js" + ) + + if(!minified) { + hd$script <- "vue.global.js" + } + + if(!offline) { + hd$src <- list(href=sprintf( + "https://unpkg.com/vue@%s/dist/", + vue3_version() + )) + } + + hd +} diff --git a/R/meta.R b/R/meta.R index 0b55c51..8290c41 100644 --- a/R/meta.R +++ b/R/meta.R @@ -1,2 +1,5 @@ #'@keywords internal vue_version <- function(){'2.6.14'} + +#'@keywords internal +vue3_version <- function(){'3.2.26'} diff --git a/R/vue.R b/R/vue.R index 53cf3c1..1612817 100644 --- a/R/vue.R +++ b/R/vue.R @@ -15,6 +15,7 @@ #' #' @import htmlwidgets #' +#' @family htmlwidget #' @export #' @example ./inst/examples/vue_widget_examples.R #' @return vue htmlwidget @@ -45,6 +46,56 @@ vue <- function( hw } +#' 'Vue.js 3' 'htmlwidget' +#' +#' Use 'Vue.js 3' with the convenience and flexibility of 'htmlwidgets'. +#' \code{vue3} is a little different from other 'htmlwidgets' though +#' since it requires specification of the HTML tags/elements separately. +#' +#' @param app \code{list} with \code{el} and \code{data} and other pieces +#' of a 'Vue.js 3' app +#' @param width,height any valid \code{CSS} size unit, but in reality +#' this will not currently have any impact +#' @param elementId \code{character} id of the htmlwidget container +#' element +#' @param minified \code{logical} to indicate minified (\code{minified=TRUE}) or +#' non-minified (\code{minified=FALSE}) Vue.js +#' +#' @import htmlwidgets +#' +#' @family htmlwidget +#' @export +#' @example ./inst/examples/vue3_widget_examples.R +#' @return vue htmlwidget + +vue3 <- function( + app = list(), + width = NULL, height = NULL, elementId = NULL, + minified = TRUE +) { + + # forward options using x + x = app + + # will try to convert data that is not a function in widget JS + + # create widget + hw <- htmlwidgets::createWidget( + name = 'vue3', + x, + width = width, + height = height, + package = 'vueR', + elementId = elementId + ) + + hw$dependencies <- list( + html_dependency_vue3(offline=TRUE, minified=minified) + ) + + hw +} + #' Shiny bindings for vue #' #' Output and render functions for using vue within Shiny @@ -62,6 +113,7 @@ vue <- function( #' @name vue-shiny #' #' @export +#' @example ./inst/examples/vue3_shiny_examples.R vueOutput <- function(outputId, width = '100%', height = '400px'){ htmlwidgets::shinyWidgetOutput(outputId, 'vue', width, height, package = 'vueR') } @@ -72,3 +124,32 @@ renderVue <- function(expr, env = parent.frame(), quoted = FALSE) { if (!quoted) { expr <- substitute(expr) } # force quoted htmlwidgets::shinyRenderWidget(expr, vueOutput, env, quoted = TRUE) } + + +#' Shiny bindings for 'vue 3' +#' +#' Output and render functions for using 'vue 3' within Shiny +#' applications and interactive Rmd documents. +#' +#' @param outputId output variable to read from +#' @param width,height Must be a valid CSS unit (like \code{'100\%'}, +#' \code{'400px'}, \code{'auto'}) or a number, which will be coerced to a +#' string and have \code{'px'} appended. +#' @param expr An expression that generates a vue +#' @param env The environment in which to evaluate \code{expr}. +#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This +#' is useful if you want to save an expression in a variable. +#' +#' @name vue-shiny +#' +#' @export +vue3Output <- function(outputId, width = '100%', height = '400px'){ + htmlwidgets::shinyWidgetOutput(outputId, 'vue3', width, height, package = 'vueR') +} + +#' @rdname vue-shiny +#' @export +renderVue3 <- function(expr, env = parent.frame(), quoted = FALSE) { + if (!quoted) { expr <- substitute(expr) } # force quoted + htmlwidgets::shinyRenderWidget(expr, vueOutput, env, quoted = TRUE) +} diff --git a/build/getvue.R b/build/getvue.R index bd9a4c3..bf38faf 100644 --- a/build/getvue.R +++ b/build/getvue.R @@ -31,8 +31,9 @@ download.file( # for use when creating dependencies cat( sprintf( - "#'@keywords internal\nvue_version <- function(){'%s'}\n", - get_vue_latest() + "#'@keywords internal\nvue_version <- function(){'%s'}\n#'@keywords internal\nvue3_version <- function(){'%s'}\n", + get_vue_latest(), + "3.2.26" #hard coded for now ), file = "./R/meta.R" ) diff --git a/cran-comments.md b/cran-comments.md index 3c6a057..349e9bd 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,6 +1,6 @@ ## Comments -Second submission resolving license issue... +Second submission resolving license issue by using CRAN template. ``` Thanks, we see: diff --git a/inst/examples/vue3_shiny_examples.R b/inst/examples/vue3_shiny_examples.R new file mode 100644 index 0000000..cf0f3e2 --- /dev/null +++ b/inst/examples/vue3_shiny_examples.R @@ -0,0 +1,33 @@ +if(interactive()) { + + library(shiny) + library(vueR) + + ui <- tagList( + tags$div(id="app-3", + tags$p("v-if"="seen", "Now you see me") + ), + vue3Output('vue1') + ) + + server <- function(input, output, session) { + output$vue1 <- renderVue3({ + vue3( + list( + el = '#app-3', + data = list(seen = TRUE), + mounted = htmlwidgets::JS("function() {var that = this; setInterval(function(){that.seen=!that.seen},1000);}"), + watch = list( + seen = htmlwidgets::JS("function() {Shiny.setInputValue('seen',this.seen)}") + ) + ) + ) + }) + + # show that Shiny input value is being updated + observeEvent(input$seen, {print(input$seen)}) + } + + shinyApp(ui, server) + +} diff --git a/inst/examples/vue3_widget_examples.R b/inst/examples/vue3_widget_examples.R new file mode 100644 index 0000000..95a0166 --- /dev/null +++ b/inst/examples/vue3_widget_examples.R @@ -0,0 +1,66 @@ +if(interactive()) { + + library(vueR) + library(htmltools) + + # recreate Hello Vue! example + browsable( + tagList( + tags$div(id="app", "{{message}}"), + vue3( + list( + el = "#app", + # vue 3 is more burdensome but robust requiring data as function + # if data is not a function then widget will auto-convert + data = list(message = "Hello Vue3!") + # data = htmlwidgets::JS(" + # function() {return {message: 'Hello Vue3!'}} + # ") + ) + ) + ) + ) + + # app2 from Vue.js introduction + browsable( + tagList( + tags$div(id="app-2", + tags$span( + "v-bind:title" = "message", + "Hover your mouse over me for a few seconds to see my dynamically bound title!" + ) + ), + vue3( + list( + el = "#app-2", + # vue 3 is more burdensome but robust requiring data as function + # if data is not a function then widget will auto-convert + data = htmlwidgets::JS(" + function() { + return {message: 'You loaded this page on ' + new Date()} + } + ") + ) + ) + ) + ) + + # app3 from Vue.js introduction + # with a setInterval to toggle seen true and false + browsable( + tagList( + tags$div(id="app-3", + tags$p("v-if"="seen", "Now you see me") + ), + vue3( + list( + el = '#app-3', + data = list(seen = TRUE), + # data = htmlwidgets::JS("function() {return {seen: true}}"), + mounted = htmlwidgets::JS("function() {var that = this; setInterval(function(){that.seen=!that.seen},1000);}") + ) + ) + ) + ) + +} diff --git a/inst/examples/vue_widget_examples.R b/inst/examples/vue_widget_examples.R index f4e798c..9a40c59 100644 --- a/inst/examples/vue_widget_examples.R +++ b/inst/examples/vue_widget_examples.R @@ -7,7 +7,7 @@ if(interactive()) { browsable( tagList( tags$div(id="app", "{{message}}"), - vue( + vue3( list( el = "#app", data = list( diff --git a/inst/htmlwidgets/vue3.js b/inst/htmlwidgets/vue3.js new file mode 100644 index 0000000..38d14b6 --- /dev/null +++ b/inst/htmlwidgets/vue3.js @@ -0,0 +1,48 @@ +HTMLWidgets.widget({ + + name: 'vue3', + + type: 'output', + + factory: function(el, width, height) { + + var instance = {}; + + return { + + renderValue: function(x) { + // if x.el is specified then use it and + // hide our htmlwidget container + if(x.el) { + el.style.display = "none"; + } else { + // x.el not specified so use our htmlwidget el + // container for our Vue app but this will + // will probably not work as expected + // since the tag is just a div + x.el = "#" + el.id; + } + + // Vue 3 requires data to be a function + // so if not a function then we will auto-convert to a function + if(typeof(x.data) !== 'function') { + var dat = Object.assign({}, x.data); + x.data = function() {return dat}; + } + + this.instance = Vue.createApp(x).mount(x.el); + + }, + + resize: function(width, height) { + + // for now ignore resize hopefully without + // much consequence + + }, + + instance: instance + + }; + } +}); diff --git a/inst/htmlwidgets/vue3.yaml b/inst/htmlwidgets/vue3.yaml new file mode 100644 index 0000000..e69de29 diff --git a/inst/www/vue3/LICENSE b/inst/www/vue3/LICENSE new file mode 100644 index 0000000..15f1f7e --- /dev/null +++ b/inst/www/vue3/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018-present, Yuxi (Evan) You + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/inst/www/vue3/README.md b/inst/www/vue3/README.md new file mode 100644 index 0000000..a98bd99 --- /dev/null +++ b/inst/www/vue3/README.md @@ -0,0 +1,54 @@ +# vue + +## Which dist file to use? + +### From CDN or without a Bundler + +- **`vue(.runtime).global(.prod).js`**: + - For direct use via ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - -
-
- + +
+ + + - - -
+
+
-
- +
+ + - - diff --git a/docs/CONDUCT.html b/docs/CONDUCT.html index d03f032..dcf8773 100644 --- a/docs/CONDUCT.html +++ b/docs/CONDUCT.html @@ -1,66 +1,12 @@ - - - - - - - -Contributor Code of Conduct • vueR - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Contributor Code of Conduct • vueR - + + - - - -
-
- -
- -
+
+
-
- +
- - + + diff --git a/docs/LICENSE-text.html b/docs/LICENSE-text.html index 32ac4a1..57f0caf 100644 --- a/docs/LICENSE-text.html +++ b/docs/LICENSE-text.html @@ -1,66 +1,12 @@ - - - - - - - -License • vueR - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -License • vueR - + + - - - -
-
- -
- -
+
+
-
- +
- - + + diff --git a/docs/LICENSE.html b/docs/LICENSE.html index da195f0..2588e90 100644 --- a/docs/LICENSE.html +++ b/docs/LICENSE.html @@ -1,66 +1,12 @@ - - - - - - - -MIT License • vueR - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -MIT License • vueR - + + - - - -
-
- -
- -
+
+
-
- +
- - + + diff --git a/docs/authors.html b/docs/authors.html index f3e72d2..f63e049 100644 --- a/docs/authors.html +++ b/docs/authors.html @@ -1,66 +1,12 @@ - - - - - - - -Authors • vueR - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Authors and Citation • vueR + + - - - - - -
-
-
- -
+
- @@ -142,22 +93,20 @@

Authors

-
- +
- - + + diff --git a/docs/index.html b/docs/index.html index a952f8a..02d6480 100644 --- a/docs/index.html +++ b/docs/index.html @@ -20,6 +20,8 @@ + +
- - -
+
- - - - - - - - - - - + +
-

All functions

+ - - - - - - - - - - - - + + - - - - - -
+

All functions

+

html_dependency_vue()

Dependencies for Vue

-

vueOutput() renderVue()

+
+

html_dependency_vue3()

+

Dependencies for 'Vue3'

+

vueOutput() renderVue() vue3Output() renderVue3()

Shiny bindings for vue

+

vue()

'Vue.js' 'htmlwidget'

- +
+

vue3()

+

'Vue.js 3' 'htmlwidget'

+
-
- +
- - + + diff --git a/inst/examples/vue3_shiny_examples.R b/inst/examples/vue3_shiny_examples.R index cf0f3e2..fe760f0 100644 --- a/inst/examples/vue3_shiny_examples.R +++ b/inst/examples/vue3_shiny_examples.R @@ -16,7 +16,12 @@ if(interactive()) { list( el = '#app-3', data = list(seen = TRUE), - mounted = htmlwidgets::JS("function() {var that = this; setInterval(function(){that.seen=!that.seen},1000);}"), + mounted = htmlwidgets::JS(" + function() { + var that = this; + setInterval(function(){that.seen=!that.seen},1000); + } + "), watch = list( seen = htmlwidgets::JS("function() {Shiny.setInputValue('seen',this.seen)}") ) diff --git a/inst/examples/vue3_widget_examples.R b/inst/examples/vue3_widget_examples.R index 95a0166..73ddd71 100644 --- a/inst/examples/vue3_widget_examples.R +++ b/inst/examples/vue3_widget_examples.R @@ -57,7 +57,12 @@ if(interactive()) { el = '#app-3', data = list(seen = TRUE), # data = htmlwidgets::JS("function() {return {seen: true}}"), - mounted = htmlwidgets::JS("function() {var that = this; setInterval(function(){that.seen=!that.seen},1000);}") + mounted = htmlwidgets::JS(" + function() { + var that = this; + setInterval(function(){that.seen=!that.seen},1000); + } + ") ) ) ) diff --git a/man/vue-shiny.Rd b/man/vue-shiny.Rd index 4e78fa3..6c067b6 100644 --- a/man/vue-shiny.Rd +++ b/man/vue-shiny.Rd @@ -55,8 +55,13 @@ if(interactive()) { vue3( list( el = '#app-3', - data = htmlwidgets::JS("function() {return {seen: true}}"), - mounted = htmlwidgets::JS("function() {var that = this; setInterval(function(){that.seen=!that.seen},1000);}"), + data = list(seen = TRUE), + mounted = htmlwidgets::JS(" + function() { + var that = this; + setInterval(function(){that.seen=!that.seen},1000); + } + "), watch = list( seen = htmlwidgets::JS("function() {Shiny.setInputValue('seen',this.seen)}") ) diff --git a/man/vue3.Rd b/man/vue3.Rd index 89d34ea..2cdef51 100644 --- a/man/vue3.Rd +++ b/man/vue3.Rd @@ -47,9 +47,11 @@ if(interactive()) { list( el = "#app", # vue 3 is more burdensome but robust requiring data as function - data = htmlwidgets::JS(" - function() {return {message: 'Hello Vue3!'}} - ") + # if data is not a function then widget will auto-convert + data = list(message = "Hello Vue3!") + # data = htmlwidgets::JS(" + # function() {return {message: 'Hello Vue3!'}} + # ") ) ) ) @@ -68,6 +70,7 @@ if(interactive()) { list( el = "#app-2", # vue 3 is more burdensome but robust requiring data as function + # if data is not a function then widget will auto-convert data = htmlwidgets::JS(" function() { return {message: 'You loaded this page on ' + new Date()} @@ -88,8 +91,14 @@ if(interactive()) { vue3( list( el = '#app-3', - data = htmlwidgets::JS("function() {return {seen: true}}"), - mounted = htmlwidgets::JS("function() {var that = this; setInterval(function(){that.seen=!that.seen},1000);}") + data = list(seen = TRUE), + # data = htmlwidgets::JS("function() {return {seen: true}}"), + mounted = htmlwidgets::JS(" + function() { + var that = this; + setInterval(function(){that.seen=!that.seen},1000); + } + ") ) ) ) From 36dc8f18e6775fc7475c429451a4657a3b67502b Mon Sep 17 00:00:00 2001 From: timelyportfolio Date: Sun, 1 Oct 2023 11:12:12 -0500 Subject: [PATCH 4/4] update github actions --- .github/workflows/R-CMD-check.yaml | 29 ++++++++++------------------- README.Rmd | 1 + 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 0528262..a3ac618 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,4 +1,4 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: config: - - {os: macOS-latest, r: 'release'} + - {os: macos-latest, r: 'release'} - {os: windows-latest, r: 'release'} - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} - {os: ubuntu-latest, r: 'release'} @@ -29,30 +29,21 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-pandoc@v1 + - uses: r-lib/actions/setup-pandoc@v2 - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} http-user-agent: ${{ matrix.config.http-user-agent }} use-public-rspm: true - - uses: r-lib/actions/setup-r-dependencies@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: rcmdcheck + extra-packages: any::rcmdcheck + needs: check - - uses: r-lib/actions/check-r-package@v1 - - - name: Show testthat output - if: always() - run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true - shell: bash - - - name: Upload check results - if: failure() - uses: actions/upload-artifact@main + - uses: r-lib/actions/check-r-package@v2 with: - name: ${{ runner.os }}-r${{ matrix.config.r }}-results - path: check + upload-snapshots: true diff --git a/README.Rmd b/README.Rmd index 350a82d..46c10c8 100644 --- a/README.Rmd +++ b/README.Rmd @@ -15,6 +15,7 @@ knitr::opts_chunk$set( [![R-CMD-check](https://github.com/vue-r/vueR/workflows/R-CMD-check/badge.svg)](https://github.com/vue-r/vueR/actions) [![CRAN status](https://www.r-pkg.org/badges/version/vueR)](https://CRAN.R-project.org/package=vueR) +[![R-CMD-check](https://github.com/vue-r/vueR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/vue-r/vueR/actions/workflows/R-CMD-check.yaml) [Vue.js](https://vuejs.org) is a quiet, very popular JavaScript framework with an impressive set of features, a solid community, and MIT license. Don't tell anybody, but I think I might even like it better than React. With all this, Vue deserves its own set of helpers for `R`, just like [`d3r`](https://github.com/timelyportfolio/d3r) and [`reactR`](https://github.com/react-r/reactR).