diff --git a/DESCRIPTION b/DESCRIPTION index 053c646..327cc3f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -18,12 +18,12 @@ Authors@R: c( ) Imports: bookdown, knitr (>= 1.30), rmarkdown (>= 1.2), stats, utils, yaml, BiocManager -Suggests: BiocGenerics, RUnit, htmltools +Suggests: BiocGenerics, RUnit, htmltools, quarto biocViews: Software License: Artistic-2.0 VignetteBuilder: knitr +SystemRequirements: quarto Encoding: UTF-8 URL: https://github.com/Bioconductor/BiocStyle BugReports: https://github.com/Bioconductor/BiocStyle/issues -RoxygenNote: 6.1.0 -Date: 2025-08-01 +RoxygenNote: 7.3.2 diff --git a/R/utils-vignettes.R b/R/utils-vignettes.R new file mode 100644 index 0000000..6b8c34a --- /dev/null +++ b/R/utils-vignettes.R @@ -0,0 +1,139 @@ +## BiocStyle vignette engine registration +## Adapted from github.com/quarto-dev/quarto-r/blob/main/R/utils-vignettes.R +register_vignette_engines <- function(pkg) { + vig_engine("html", quarto_format = "html") +} + +vig_engine <- function(..., quarto_format) { + rmd_eng <- tools::vignetteEngine("rmarkdown", package = "knitr") + tools::vignetteEngine( + ..., + weave = vweave_quarto(quarto_format), + tangle = rmd_eng$tangle, + pattern = "[.]qmd$", + package = "BiocStyle", + aspell = rmd_eng$aspell + ) +} + +vweave_quarto <- function(format) { + meta <- get_meta(format) + function(file, driver, syntax, encoding, quiet = FALSE, ...) { + # protect if Quarto is not installed + if (is.null(quarto::quarto_path())) { + msg <- c( + paste( + "Quarto binary is required to build Quarto vignettes", + "but is not available.", + ), + i = paste( + "Please make sure it is installed and found", + "by {.code find_quarto()}." + ) + ) + if (is_R_CMD_check()) { + cli::cli_inform(msg) + } else { + cli::cli_abort(msg, call = NULL) + } + return(vweave_empty(file)) + } + + # Log debug information using the new configurable logging function + quarto:::quarto_log("R_LIBS: ", Sys.getenv("R_LIBS")) + quarto:::quarto_log( + ".libPaths(): ", + paste0(.libPaths(), collapse = ":") + ) + quarto:::quarto_log( + "Packages: ", + paste0(dir(.libPaths()[1]), collapse = ",") + ) + + quarto::quarto_render( + file, + ..., + output_format = format, + metadata = meta + ) + } +} + +get_meta <- function(format) { + if (is.null(format)) { + return(NULL) + } + if (format == "html") { + return(get_meta_for_html()) + } + if (format == "pdf") { + return(get_meta_for_pdf()) + } +} + +get_meta_for_pdf <- function() { + meta <- list() + meta$format$pdf <- list( + # don't try to install CTAN package on CRAN environment + `latex-auto-install` = !is_cran_check() + ) + meta +} + +get_meta_for_html <- function() { + css <- system.file( + "resources", + "html", + "biocstyle.css", + package = "BiocStyle" + ) + scss <- system.file( + "resources", + "html", + "biocstyle.scss", + package = "BiocStyle" + ) + meta <- list() + meta$format$html <- + list( + `embed-resources` = TRUE, + minimal = TRUE, + toc = TRUE, + `toc-float` = TRUE, + `toc-depth` = 3L, + `toc-location` = "left", + `number-sections` = TRUE, + theme = scss, + css = css + ) + meta +} + +is_R_CMD_check <- function() { + !is.na(Sys.getenv("_R_CHECK_PACKAGE_NAME_", NA)) || + tolower(Sys.getenv("_R_CHECK_LICENSE_")) == "true" +} + +# from knitr internal +is_cran_check <- function() { + is_cran() && is_R_CMD_check() +} + +is_cran <- function() { + !rlang::is_interactive() && + !isTRUE(as.logical(Sys.getenv("NOT_CRAN", "false"))) +} + +# trick from knitr to avoid problem on R CMD check (e.g. when no Quarto +# available) It will silently skip the vignette +vweave_empty <- function(file, ..., .reason = "Quarto") { + out <- sprintf("%s.html", tools::file_path_sans_ext(basename(file))) + writeLines( + sprintf( + "The vignette could not be built because %s is not available.", + .reason + ), + out + ) + out +} diff --git a/R/zzz.R b/R/zzz.R index 93235d7..5e2b02c 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,7 +1,8 @@ resources <- bioconductor.sty <- bioconductor.css <- NULL # resolve paths once during package load -.onLoad <- function(...) { +.onLoad <- function(lib, pkg) { + register_vignette_engines(pkg) resources <<- system.file(package = "BiocStyle", "resources") bioconductor.sty <<- file.path(resources, "tex", "Bioconductor.sty") bioconductor.css <<- file.path(resources, "html", "bioconductor.css") diff --git a/inst/resources/html/biocstyle.css b/inst/resources/html/biocstyle.css new file mode 100644 index 0000000..fb4f59a --- /dev/null +++ b/inst/resources/html/biocstyle.css @@ -0,0 +1,522 @@ +body { + background-color: #fff; + margin: 1em auto; + max-width: 1134px; + overflow: visible; + padding-left: 2em; + padding-right: 2em; + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 10pt; + line-height: 1.35; +} + +/* Table of contents style */ + +div#TOC ul { + padding: 0px 0px 0px 45px; + list-style: none; + background-image: none; + background-repeat: none; + background-position: 0; + font-size: 10pt; + font-family: Helvetica, Arial, sans-serif; +} + +div#TOC > ul { + padding: 0px 150px 0px 65px; + font-size: 12pt; +} + +div#TOC > ul > li { + padding: 5px 0px 0px 0px; +} + +div#TOC ul ul { + font-size: 11pt; +} + +div#TOC.tocify ul { + padding: 0px; + font-size: inherit; + font-family: inherit; +} + +div#TOC.tocify li { + padding: 5px; + font-size: inherit; + font-family: inherit; +} + +p, dl { + padding: 0px 150px 0px 65px; + text-align: justify; + margin: 0.5em 0; +} + +/* vertical content spacing */ +p, img, table { + margin-top: 10px; + margin-bottom: 10px; +} + +/* lists */ +ol, ul { + padding: 0px 150px 0px 100px; + list-style: square; +} +ul { + margin-top: 0; +} +ul li { + list-style: circle outside; +} +ul ul { + margin-bottom: 0; +} + +li ol, li ul { + padding: 0px 0px 0px 35px; +} + +li p { + padding: 0; +} + +pre { + margin: 0em 150px 0.5em 0em; + padding: 10px; + border: 0px none; + background-color: #f7f7f7; + white-space: pre-wrap; /* Wrap long lines */ + overflow-x: auto; + font-size: 90%; + border-radius: 3px; +} +pre:not([class]) { + background-color: #f7f7f7; +} + +li pre { + margin: 0em 0px 0.5em -65px; + padding: 0px 0px 0px 65px; +} +pre code { + background-color: inherit; + border-radius: 3px; + color: #333; + display: block; + padding: 10px 10px 10px 0px; + white-space: pre-wrap; /* Wrap long lines */ + overflow-x: inherit; + font-size: 100%; +} + +/* markdown v1 */ +pre code[class] { + background-color: inherit; +} + +/* markdown v2 */ +pre[class] code { + background-color: inherit; +} + +tt, code, pre { + font-family: 'DejaVu Sans Mono', 'Droid Sans Mono', 'Lucida Console', Consolas, Monaco, monospace; +} + +h1, h2, h3, h4, h5, h6 { + font-family: Helvetica, Arial, sans-serif; + margin: 1.2em 150px 0.6em 0em; +/* hanging headings */ + padding-left: 65px; + text-indent: -65px; +} + +h1.title { + color: #87b13f; + line-height: 1.1em; + margin-top: 25px; + border-bottom: 0px; +} + +h1 { + line-height: 1.4em; + border-bottom: 1px #1a81c2 solid; + font-size: 35px; +} + +h1, h2, h3 { + color: #1a81c2; +} + +h2 { + font-size: 145%; + border-bottom: 4px solid #f7f7f7; + padding-top: 10px; + padding-bottom: 2px; +} + +h3 { + font-size: 120%; + border-bottom: 2px solid #f7f7f7; + padding-top: 10px; +} + +h4 { + font-size: 105%; + border-bottom: 1px solid #f7f7f7; + margin-left: 8px; +} + +h5, h6 { + font-size: 105%; + border-bottom: 1px solid #ccc; +} + +span.header-section-number { + float: left; + width: 65px; +} + +/* document header */ + +p.author-name { + font-size: 14.5pt; + font-weight: bold; + font-style: italic; + text-align: left; +} + +.date { + text-indent: 0px; + font-weight: bold; +} + +.abstract, .package { + font-weight: bold; +} + +/* formatting of inline code */ +code { + background-color: #f0f0f0; + color: #404040; + font-size: 90%; +} +p > code, li > code { + padding: 2px 0px; +} + +/* figures */ + +.figure { + margin: 0em 0px 0.5em; + text-align: center; +} + +img { + background-color: #FFFFFF; + padding: 0px 150px 0px 130px; + border: 1px solid #DDDDDD; + border-radius: 3px; + border: 1px solid #CCCCCC; + margin: 0 5px; + max-width: 100%; + display: block; +} + +p > img { + padding-left: 65px; + padding-right: 0px; +} + +td > img { + padding: 0px; + max-width: 100%; + display: inline; +} + +img.smallfigure { + padding-left: 195px; + padding-right: 280px; +} + +p > img.smallfigure { + padding-left: 130px; + padding-right: 130px; +} + +img.widefigure { + padding-left: 65px; + padding-right: 85px; + margin-right: -65px; +} + +p > img.widefigure { + padding-left: 0px; + padding-right: 0px; + margin-right: -65px; +} + +p.caption, caption { + color: inherit; + font-size: 8pt; +} + +p.caption { + padding-left: 130px; + padding-right: 85px; + margin-bottom: 20px; +} + +caption { + padding: 0px; + margin-bottom: 10px; + min-width: 583; +} +span.caption-title { + color: #1a81c2; + font-weight: bold; +} + +span.caption-label { + font-weight: bold; +} + +/* tables */ + +table { + margin: 1em auto; + border-width: 1px; + border-color: #DDDDDD; + border-style: outset; + border-collapse: collapse; + margin-left: 130px; + margin-right: 85px; +} +table th { + border-width: 2px; + padding: 5px; + border-style: inset; +} +table td { + border-width: 1px; + border-style: inset; + line-height: 18px; + padding: 5px 5px; +} +table, table th, table td { + border-left-style: none; + border-right-style: none; +} +table thead, table tr.even { + background-color: #f7f7f7; +} + +.table { + max-width: 518px; +} + +/* definition lists */ + +dl { + margin-left: 0; +} +dl dd { + margin-bottom: 13px; + margin-left: 13px; +} +dl dt { + font-weight: bold; +} + +/* code folding buttons */ + +.code-folding-btn { + position: relative; + margin-top: -26px; + top: 26px; +} + +.col-md-12 { + min-height: 0px; +} + +/* footnotes as sidenotes */ + +.sidenote { + float: right; + clear: right; + margin-right: -150px; + width: 130px; + margin-top: 0; + margin-bottom: 1rem; + font-size: 8pt; + line-height: 1.3; + vertical-align: baseline; + position: relative; + text-align: left; +} + +.sidenote-number, .affil-mark { + position: relative; + vertical-align: super; + font-size: 7.5pt; + font-weight: normal; + font-style: normal; + line-height: normal; +} + +/* Class described in https://benjeffrey.com/posts/pandoc-syntax-highlighting-css + Colours from https://gist.github.com/robsimmons/1172277 */ + +code > span.kw { color: #E07020; } /* Function calls */ +code > span.dt { color: #404040; } /* Function args */ +code > span.dv { color: #D02070; } /* DecVal (decimal values) */ +code > span.bn { color: #d14; } /* BaseN */ +code > span.fl { color: #D02070; } /* Float */ +code > span.ch { color: #40A040; } /* Char */ +code > span.st { color: #40A040; } /* String */ +code > span.co { color: #808080; font-style: italic; } /* Comment */ +code > span.ot { color: #2020F0; } /* Keywords */ +code > span.al { color: #ff0000; font-weight: bold; } /* AlertToken */ +code > span.fu { color: #E07020; } /* Function calls */ +code > span.er { color: #FF0000; } /* ErrorTok */ + +code > span.identifier { color: #404040; } +code > span.number { color: #D02070; } +code > span.string { color: #40A040; } +code > span.comment { color: #808080; font-style: italic; } +code > span.keyword { color: #2020F0; } +code > span.literal { color: #2020F0; } +code > span.operator { color: #000000;} +code > span.paren { color: #000000;} + +/* proper positioning of ggplotly graphics, see https://support.bioconductor.org/p/97609/ */ + +.js-plotly-plot .plotly { + padding-left: 65px; +} + +/* styling references / bibliography */ + +.references { + padding-right: 150px; +} + +/* Styling specifically aimed at smaller screen on phones and tablets */ + +.margin-toggle { + display: none; +} + +@media screen and (max-width: 991px) { + body { + padding-left: 0; + margin-left: 0; + margin-right: 0; + width: auto; + } + p { + padding-left: 0; + padding-right: 0; + } + .references { + padding-right: 0; + } + h1, h2, h3, h4, h5, h6 { + width: 100%; + padding-left: 0; + text-indent: 0; + } + ul { + padding-left: 20px; + padding-right: 0; + } + li pre { + margin-left: -20px; + padding-left: 10px; + } + pre { + margin-right: 0; + padding-left: 10px; + } + pre code { + white-space: pre; + } + p img{ + padding-left: 0; + } + .horizontal-scroll { + overflow-x: auto; + } + .table { + min-width: 100%; + margin: 0 0 0 0; + } + div.figure img { + padding: 0 0 0 0; + } + div.figure p.caption { + padding-left: 0; + padding-right: 0; + } + .sidenote { + float: unset; + margin-top: 1rem; + margin-right: 0; + margin-left: 10%; + width: 80%; + font-size: 8pt; + line-height: 1.3; + text-align: left; + display: none; + } + .sidenote-number{ + display: none; + } + .margin-toggle { + display: inline; + position: relative; + vertical-align: super; + font-size: 7.5pt; + font-weight: normal; + font-style: normal; + line-height: normal; + color: #337ab7; + } +} + +/* hide the TOC on really small screens */ +@media screen and (max-width: 767px) { + #TOC { + display: none; + } +} + +a { + color: #0033dd; + text-decoration: none; +} +a:hover { + color: #6666ff; } +a:visited { + color: #800080; } +a:visited:hover { + color: #BB00BB; } +a[href^="http:"] { + text-decoration: underline; } +a[href^="https:"] { + text-decoration: underline; } + +blockquote { + background-color: #f6f6f6; + padding: 0.25em 0.75em; +} + +hr { + border-style: solid; + border: none; + border-top: 1px solid #777; + margin: 28px 0; +} diff --git a/inst/resources/html/biocstyle.scss b/inst/resources/html/biocstyle.scss new file mode 100644 index 0000000..67be94d --- /dev/null +++ b/inst/resources/html/biocstyle.scss @@ -0,0 +1,119 @@ +/*-- scss:defaults --*/ + +// Color Palette +$bioc-primary: #1a81c2; +$bioc-secondary: #005C7A; +$bioc-text-dark: #333333; +$bioc-text-light: #556B7F; +$bioc-background: #FFFFFF; +$bioc-sidebar-bg: #F0F4F8; +$bioc-border-light: #D9E6F0; +$bioc-title-color: #87b13f; +// $bioc-reference-hover: #666666; +$bioc-reference-hover: lighten($bioc-secondary, 20%); // Lighter tone of secondary color for reference hover + +// Typography +$font-stack-primary: "Helvetica Neue", Helvetica, Arial, sans-serif; + +/*-- scss:mixins --*/ +@mixin bioc-heading { + color: $bioc-primary; + font-weight: 500; + border-bottom: 1px solid $bioc-border-light; + padding-bottom: 0.3em; + margin-top: 1.5em; + margin-bottom: 0.8em; +} + +/*-- scss:rules --*/ +h1, h2, h3, h4, h5, h6 { + @include bioc-heading; +} + +h1 { + font-size: 2em; + border-bottom: 2px solid $bioc-primary; + &.title { //target h1 with class title. + color: $bioc-title-color; //apply custom color. + } +} + +h2 { + font-size: 1.5em; +} + +h3 { + font-size: 1.3em; +} + +h4 { + font-size: 1.2em; +} + +// Links +a { + color: $bioc-primary; + text-decoration: none; + + &:hover { + color: darken($bioc-primary, 10%); + text-decoration: underline; + } +} + +// Code blocks +pre, code { + border-color: lighten($bioc-primary, 40%); +} + +div.sourceCode { + background-color: #f0f0f0; + padding-left: 65px; + border: 0px none; +} + +li div.sourceCode { + margin-left: -35px; +} + +img { + padding: 0px 150px 0px 130px; +} + +p > img { + padding-left: 65px; + padding-right: 0px; +} + +div.cell-output pre { + padding-left: 0px; +} + +div.cell-output pre code { + padding-left: 65px; +} + +// References styling +.citation, .citation a { + &:hover { + color: $bioc-reference-hover !important; + } +} + +// Bibliography/References section +#refs .csl-entry a { + &:hover { + color: $bioc-reference-hover !important; + } +} + +// Cross-references (figures, tables, etc.) +.quarto-xref { + &:hover { + color: $bioc-reference-hover !important; + } +} + +/*-- scss:uses --*/ +// Additional customizations +