Skip to content

Commit

Permalink
Merge pull request #575 from Appsilon/530-versioned-pkgdown
Browse files Browse the repository at this point in the history
Add version switcher to the site
  • Loading branch information
kamilzyla committed Jun 12, 2024
2 parents dd901d0 + fd5a656 commit 7ae011f
Show file tree
Hide file tree
Showing 6 changed files with 290 additions and 41 deletions.
12 changes: 6 additions & 6 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,9 @@ It should be saved as the `APP_PUSH_TEST_PAT`

The [documentation site](https://appsilon.github.io/rhino/)
is built and deployed automatically by our [`pkgdown.yml`](workflows/pkgdown.yml) workflow.
This workflow is triggered when a
[release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository)
is published, or a pre-release is changed to a release.
It is also possible to manually run it for a selected tag/branch
from the [Actions](https://github.com/Appsilon/rhino/actions/workflows/pkgdown.yml) tab.
It is triggered on each push to the `main` branch.
It runs the `pkgdown/build.R` script which builds the documentation
for all Rhino versions listed in `pkgdown/versions.yml`.

## Release process

Expand Down Expand Up @@ -82,7 +80,9 @@ for the `main` branch should be green).
Do not add a link to GitHub releases yet - the link won't work and will fail CRAN checks.
* Edit the list of changes to make it useful and understandable for our users.
See [keep a changelog](https://keepachangelog.com/) for some guidelines.
5. Submit the changes in a pull request titled "Release X.Y.Z".
5. Update `pkgdown/versions.yml`.
* Add a new version corresponding to the release you are preparing.
6. Submit the changes in a pull request titled "Release X.Y.Z".
Get it approved and merged.

### Submitting to CRAN
Expand Down
38 changes: 20 additions & 18 deletions .github/workflows/pkgdown.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
name: pkgdown
on:
# Run when a release is published, or a pre-release is changed to a release. Reference:
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release
# https://docs.github.com/en/webhooks/webhook-events-and-payloads#release
release:
types: [released]
# It is also possible to manually trigger this workflow for a selected tag/branch
# from the "Actions" tab on GitHub.
workflow_dispatch:
push:
branches: [main]
permissions:
contents: write
jobs:
main:
pkgdown:
name: Build and publish website
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install R
uses: r-lib/actions/setup-r@v2
Expand All @@ -29,13 +25,19 @@ jobs:
with:
extra-packages: any::pkgdown, local::.

- name: Configure git
- name: Build site
shell: Rscript {0}
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
source("pkgdown/build.R")
build_versioned(
repo = ".",
versions = yaml::read_yaml("pkgdown/versions.yml"),
root_url = "https://appsilon.github.io/rhino",
destination = "docs"
)
- name: Build and deploy site
shell: Rscript {0}
run: pkgdown::deploy_to_branch(branch = "bot/github-pages")
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: docs
branch: bot/github-pages
111 changes: 111 additions & 0 deletions pkgdown/build.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#' @param repo The path to the git repository to build.
#' @param versions A list of lists. Each sublist should contain the following keys:
#' - `git_ref`: The git ref to build.
#' - `url`: The URL path for the version.
#' - `label`: The label to display in the navbar. To use the version from DESCRIPTION provide `TRUE`.
#' Additonally, exactly one version should have `url` set to "/".
#' @param root_url The root URL for all versions of the website.
#' @param destination The destination directory for the built website.
build_versioned <- function(repo, versions, root_url, destination) {
validate_versions(versions)

# Prepare a repo for building
temp_repo <- fs::dir_copy(repo, fs::file_temp("versioned-build-repo-"))
on.exit(fs::dir_delete(temp_repo))
# NOTE: detach to avoid git worktree complaining about the current ref being checked out
system2("git", c("-C", temp_repo, "switch", "--detach", "@"))
build_version <- build_version_factory(temp_repo, versions, root_url, destination)

# NOTE: building the root URL first, so pkgdown doesn't complain about a non-empty destination directory
root_index <- purrr::detect_index(versions, \(x) isTRUE(x$url == "/"))
purrr::walk(c(versions[root_index], versions[-root_index]), build_version)
}

validate_versions <- function(versions) {
expected_names <- c("git_ref", "url", "label")
n_root <- 0
purrr::walk(versions, function(version) {
diff <- setdiff(expected_names, names(version))
if (length(diff) > 0) {
stop("A version is missing the following keys: ", paste(diff, collapse = ", "))
}
if (isTRUE(version$url == "/")) {
n_root <<- n_root + 1
}
})
if (n_root != 1) {
stop("Exactly one version should have url set to '/'")
}
}

build_version_factory <- function(repo, versions, root_url, destination) {
navbar_template <- navbar_template_factory(versions, root_url)
destination <- fs::path_abs(destination)
extra_css_path <- fs::path_join(c(repo, "pkgdown", "extra.css"))

function(version) {
# Prepare a worktree for building
build_dir <- fs::file_temp("versioned-build-worktree-")
on.exit(system2("git", c("-C", repo, "worktree", "remove", "--force", build_dir))) # NOTE: --force because we add the navbar file
status <- system2("git", c("-C", repo, "worktree", "add", build_dir, version$git_ref))
if (status != 0) {
stop("Failed to create a worktree for ref ", version$git_ref)
}

# Write the navbar template and extra.css
template_dir <- fs::path_join(c(build_dir, "pkgdown", "templates"))
fs::dir_create(template_dir)
writeLines(navbar_template(version), fs::path_join(c(template_dir, "navbar.html")))
fs::file_copy(extra_css_path, fs::path_join(c(build_dir, "pkgdown", "extra.css")), overwrite = TRUE)

# NOTE: providing an absolute path to build_site won't work: https://github.com/r-lib/pkgdown/issues/2172
withr::with_dir(build_dir, {
pkgdown::build_site_github_pages(
override = list(
url = sub("/$", "", url_join(root_url, version$url)),
navbar = list(type = "light")
),
dest_dir = fs::path_join(c(destination, version$url))
)
})
}
}

url_join <- function(url, path) {
paste(
sub("/$", "", url),
sub("^/", "", path),
sep = "/"
)
}

navbar_template_factory <- function(versions, root_url) {
navbar_code <- readLines("pkgdown/navbar_template.html")
index_current <- grep("___CURRENT_PLACEHOLDER___", navbar_code)
index_options <- grep("___OPTIONS_PLACEHOLDER___", navbar_code)
stopifnot(index_current < index_options)
wrap_label <- function(label) {
if (isTRUE(label)) {
label <- paste(desc::desc_get_version(), "(dev)")
}
label
}
function(version) {
c(
navbar_code[1:(index_current - 1)],
wrap_label(version$label),
navbar_code[(index_current + 1):(index_options - 1)],
purrr::map_chr(
versions,
function(ver) {
sprintf(
'<li><a class="dropdown-item" href="%s">%s</a></li>',
url_join(root_url, ver$url),
wrap_label(ver$label)
)
}
),
navbar_code[(index_options + 1):length(navbar_code)]
)
}
}
69 changes: 52 additions & 17 deletions pkgdown/extra.css
Original file line number Diff line number Diff line change
@@ -1,36 +1,50 @@
:root {
--primary-color: #7B7CD2 ;
--primary-color: #7b7cd2;
}

.navbar {
background-color: var(--primary-color) !important;
--bs-primary-rgb: 123, 124, 210;
}

#navbar > ul.navbar-nav > li.nav-item a:hover {
background-color: var(--primary-color) !important;
.navbar a.dropdown-item:hover {
background-color: var(--primary-color);
}

#navbar > ul.navbar-nav > li.nav-item > a {
color: rgba(255, 255, 255, 0.8);
.navbar .navbar-nav .nav-item.active > .nav-link {
color: #fff;
background-color: var(--primary-color);
}

.navbar-light .navbar-nav .active > .nav-link {
background-color: var(--primary-color) !important;
color: #fff !important;
.navbar .navbar-nav .nav-item > .nav-link {
color: rgba(255, 255, 255, 0.8);

&:hover {
background-color: var(--primary-color);
color: #fff;
}
}

.navbar-brand {
color: #fff !important;
}
--bs-navbar-brand-color: #fff;

nav .text-muted {
color: #d8d8d8 !important;
&:hover {
--bs-navbar-brand-hover-color: rgba(255, 255, 255, 0.8);
}
}

a {
color: var(--primary-color);
}

a.nav-link,
.home {
color: hsl(0, 0%, 80%);

&:hover {
color: hsl(0, 0%, 100%);
}
}

a:hover {
color: #2c2b2b;
}
Expand All @@ -41,14 +55,34 @@ button.btn.btn-primary.btn-copy-ex {
}

.home {
display: none;
left: 0px;
position: absolute;
padding: 8px 30px;
color: rgba(255,255,255,0.55);

@media (min-width: 1250px) {
display: initial;
}
}

.home:hover {
color: rgba(255,255,255,0.9);
#version-switcher {
margin-inline-start: 0.5rem;
margin-inline-end: auto;

@media (min-width: 992px) {
margin-inline-end: 2rem;
}

& > a {
background-color: hsl(239.3, 40.2%, 55.3%);
color: rgba(255, 255, 255, 0.8);
padding: 0.25rem 1rem;
border-radius: 1rem;

&:hover {
color: white;
}
}
}

summary:has(h3#past) {
Expand All @@ -58,6 +92,7 @@ summary:has(h3#past) {

&::marker,
&::-webkit-details-marker {
font-size: calc(1.3rem + .6vw); /* an equivalent of Bootstrap's h3 that's within the summary */
/* an equivalent of Bootstrap's h3 that's within the summary */
font-size: calc(1.3rem + 0.6vw);
}
}
71 changes: 71 additions & 0 deletions pkgdown/navbar_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{{#navbar}}
<nav
class="navbar fixed-top navbar-{{{type}}} navbar-expand-lg bg-{{{bg}}}"
data-bs-theme="{{{type}}}"
>
<div class="container">
{{#includes}}{{{before_title}}}{{/includes}}
<a class="navbar-brand me-2" href="{{#site}}{{root}}{{/site}}index.html"
>{{#site}}{{title}}{{/site}}</a
>

<div id="version-switcher" class="dropdown">
<a
href="#"
class="nav-link dropdown-toggle"
data-bs-toggle="dropdown"
role="button"
aria-expanded="false"
aria-haspopup="true"
>
___CURRENT_PLACEHOLDER___
</a>
<ul class="dropdown-menu">
___OPTIONS_PLACEHOLDER___
</ul>
</div>

{{#includes}}{{{before_navbar}}}{{/includes}}
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbar"
aria-controls="navbar"
aria-expanded="false"
aria-label="{{#translate}}{{toggle_nav}}{{/translate}}"
>
<span class="navbar-toggler-icon"></span>
</button>

<div id="navbar" class="collapse navbar-collapse ms-3">
{{#left}}
<ul class="navbar-nav me-auto">
{{{.}}}
</ul>
{{/left}}

<form class="form-inline my-2 my-lg-0" role="search">
<input
type="search"
class="form-control me-sm-2"
aria-label="{{#translate}}{{toggle_nav}}{{/translate}}"
name="search-input"
data-search-index="{{#site}}{{root}}{{/site}}search.json"
id="search-input"
placeholder="{{#translate}}{{search_for}}{{/translate}}"
autocomplete="off"
/>
</form>

{{#right}}
<ul class="navbar-nav">
{{{.}}}
</ul>
{{/right}}
</div>

{{#includes}}{{{after_navbar}}}{{/includes}}
</div>
</nav>
{{/navbar}}
Loading

0 comments on commit 7ae011f

Please sign in to comment.