Every function that writes into a site now requires the site
directory: dir has no default any more in
build_site(), serve_site(),
stop_server(), bundle_install(),
new_post(), use_pages_workflow(),
add_feed(), use_r_bloggers(),
add_footer_credit(), remove_footer_credit(),
set_theme_color(), set_theme_style(),
set_theme_skin(), set_theme_font(),
set_element_style(), add_css() and
add_mathjax(). CRAN policy does not allow writing to a
default location such as the working directory. Pass
dir = "." from a session running inside the site, or the
site’s path from outside; the functions still climb to the site root
from any directory inside it. Calling one without dir
aborts with a message saying so. check() only reads and
keeps its default.
The examples of install_ruby(),
install_git(), install_quarto() and
bundle_install() are gone (CRAN asks that examples never
install software, not even inside \dontrun{}); their help
pages describe the calls instead.
New add_feed(): renders the site’s Atom feeds from a
site-level copy of jekyll-feed’s template
(_includes/atom-feed.xml), patched so that al-folio’s
title: blank convention yields the author’s full name as
the feed title. The plugin alone printed the literal word “blank”.
Optional per-category feeds (feed/<category>.xml,
full text, only the posts carrying that category) on any theme. The
template is taken from the jekyll-feed gem installed for the site (the
version pinned in Gemfile.lock), falling back to that
version’s tag on GitHub and then to a copy shipped with the package. The
include records its provenance so a later gem upgrade regenerates it. In
the feeds, root-relative image and link paths in the post body are made
absolute from url: in _config.yml, as
aggregators such as R-Bloggers ask. The title patch targets one anchor
line and aborts with a clear message if upstream moves it.
New use_r_bloggers(): the site side of an R-Bloggers
submission in one call: an R-only feed via
add_feed(category = "R"), the link back to R-Bloggers under
the blog header on al-folio (a snippet to place on other themes), and
the feed URL to submit.
new_site(theme = "al-folio") and, through it,
migrate_hugo() call add_feed() so fresh
al-folio sites never publish a feed titled “blank”.
use_r_bloggers() leaves _pages/blog.md
alone when it already links to R-Bloggers outside the jekylldown
markers, instead of adding a second line.
[x](u){target="_blank"}) are now rewritten as kramdown
inline attribute lists during migration, as image attributes already
were. Before, the braces were printed as literal text after the link in
migrated posts.*.Rproj from the
Jekyll build – RStudio project files were being copied into the
published site.use_pages_workflow()‘s.
The README and vignette also note that a history-replacing first push
does not match the workflows’ paths filters (trigger the first run by
hand).{{< blogdown/postref >}} prefix is stripped before
the bundle path rewrites (it was hiding raw
<img src="index_files/..."> tags from them, leaving
broken figures); raw HTML img tags with bundle-relative
paths are rewritten like Markdown links; and plain non-page files under
Hugo’s content/ tree (old blogdown sites keep figures in
content/figs/) are published to the site root exactly like
static/, honoring only_referenced.{{< vimeo >}} shortcodes convert to an embedded
player, like {{< youtube >}} already did._source file fails to knit (typical on migrated sites whose
posts need packages from the original author’s setup),
build_site() skips it with a prominent warning listing the
affected files, removes any partial output, and builds everything else.
Surfaced by a six-site migration battery (this package’s own test sites
plus the three real sites from the migration gallery) run against this
release.migrate_hugo() (template pages
protect some files until your content replaces them), prunes the
preview/cover folders file by file (the bibliography references them by
bare file name), and drops the placeholder portrait once the profile
picture is yours. The demo jekyll_get_json resume feed goes
from _config.yml along with its data file. Net effect on a
real migration: the site keeps only what came from the original site
plus what Jekyll and the theme need (~62 MB of demo media gone).add_footer_credit() inserts “Built from
R with jekylldown X.Y.Z.” (linked) into the theme’s own footer line –
right after the “Powered by Jekyll …” sentence on al-folio (via
footer_text: in _config.yml), and as a managed
block in a local _includes/footer.html on minima, Chirpy
and Minimal Mistakes. new_site() adds it to fresh sites,
build_site() keeps the version number current on every
build, and remove_footer_credit() takes it out. Hosting
claims (“Hosted by GitHub Pages”) are the theme’s own
footer_text defaults and stay untouched.serve_site() rebuilds content-only
edits (posts, pages) with jekyll’s incremental mode, regenerating just
the changed pages; edits that incremental mode does not track (sass
partials, _config.yml, data files) still get a full build.
The .jekyll-metadata cache joins the serve artifacts in
.gitignore.?serve_site and the README.new_site from the template, bundle_install
with its git-sourced gem, build_site), so the theme that
exercises the most toolchain now runs on a real Windows on every
push.install_git() (Windows): downloads MinGit – the
portable build Git for Windows publishes for embedding – into the
isolated toolchain, with the same API-then-github.com-then-pinned
release ladder, file = for offline installs and toolchain
reuse as install_ruby(). Bundler and
new_site()’s template fetch find it automatically, so
al-folio’s git-sourced gem installs without a system git;
bundle_install()’s missing-git message and
check() now point at it..gitignore and .nojekyll) is dropped
from the scaffolded site, on every platform and fetch path.bundle_install(), and bundle_install() on a
Gemfile with git-sourced gems (al-folio’s has one) checks for git
upfront and points at git-scm.com – the one step of the workflow that
genuinely needs git.new_site() no longer requires git for the GitHub-hosted
themes (al-folio and the Chirpy starter): when git is missing – common
on Windows – the template is downloaded as a plain archive of the
default branch instead, and a failed clone falls back to the same
download.?new_site and the vignettes.serve_site() works on Windows: the build command was
assembled as a shell string with a POSIX-only VAR=value
environment prefix and a /dev/null-style redirect, which
Windows cannot run (” ‘JEKYLL_NO_BUNDLER_REQUIRE=true’ not found”).
Rebuilds now go through processx with the environment passed properly,
the output silenced without a shell redirect, and
.bat/.cmd wrappers routed through
cmd.exe – on every platform.serve_site(), so the serving path is exercised on a real
Windows from here on.install_ruby() is now cheap: a working
provisioned Ruby is reused (no re-download; force = TRUE
starts over) and already-installed gems are skipped
(gem install --conservative), so the function doubles as
“complete whatever is missing”.install_ruby() also installs the minima gem: the second
Windows CI run got all the way through Ruby, MSYS2 and Jekyll, then
failed building the scaffolded default site because the theme gem was
missing. The README’s Linux/macOS gem install one-liners
gained minima too – a fresh toolchain set up from those instructions had
the same gap on every platform.api.github.com is unreachable, the latest release
is now discovered from the releases/latest page on
github.com itself (the same host the archive downloads
from) before resorting to the pinned fallback, and the DNS warning noise
is suppressed.install_ruby() now sets up the MSYS2 build tools by default
(devkit = TRUE) – Jekyll depends on the eventmachine gem,
which has no precompiled binary for current Rubies and failed to compile
without a proper toolchain; two test expectations compare normalized
paths (Windows mixes separators and 8.3 short names); the tilde
expansion test is skipped on Windows, where R_USER is fixed
at startup and the fixture’s HOME override cannot take
effect.install_ruby() no longer depends on
api.github.com being reachable: when the release lookup
fails (that host is blocked on some networks even where
github.com works), a known-good pinned RubyInstaller
release is downloaded directly from github.com, with a new
version argument to pick a specific release; download
failures now explain the proxy/offline escape hatches.devkit = TRUE fixed before it ever worked: upstream
publishes no portable .7z of the devkit variant, so the
MSYS2 toolchain is now added by running RubyInstaller’s own
ridk install after unpacking.install_ruby(),
scaffolds a site and builds it.install_ruby() downloads the portable RubyInstaller archive
(a .7z; needs the archive package to unpack)
into tools::R_user_dir("jekylldown", "data") and installs
the jekyll and bundler gems there – no admin rights, no graphical
installer, nothing system-wide. install_ruby(devkit = TRUE)
adds the MSYS2 build tools for gems that compile C extensions..bat/.cmd/.exe wrappers Ruby uses
there, those wrappers are run through cmd.exe /c (processx
cannot exec batch files directly), the quiet serve rebuild redirects to
NUL instead of /dev/null, and
check()’s advice for a missing Ruby points at
install_ruby() on Windows.set_element_style("socials", size = ...) now actually
resizes the icons. The mapped selectors were losing to the themes’ own,
more specific rules (al-folio nests .contact-icons under
.social; Chirpy nests .sidebar-bottom under
#sidebar) – the maps now match the themes’ specificity. On
top of the font-size, the sizing writes companion rules for
what a font size cannot reach: al-folio’s image icons, minima’s fixed
16px SVG icons, and Chirpy’s fixed-size circular buttons all track the
requested size now.set_element_style("socials", size = "3rem") and
set_theme_color("red") work directly from inside the site’s
project. New signatures: set_theme_color(color, dir = "."),
set_theme_style(..., dir = "."),
set_theme_skin(skin, dir = "."),
set_theme_font(family, size, headings, code, google, dir = "."),
set_element_style(element, ..., dir = "."),
add_css(css, id, dir = "."). From outside a site, pass the
location by name:
set_theme_color("red", dir = "my-site").dir argument.set_theme_color(dir, NULL)
removes the override and returns to the theme default. Deleting the
site-local stylesheet (assets/css/main.scss) remains the
documented way to drop every customization at once."socials" element in
set_element_style()‘s per-theme maps (al-folio’s about-page
icon row, Chirpy’s sidebar icons, Minimal Mistakes’ author links,
minima’s footer icons) – e.g.
set_element_style(site, "socials", size = "2rem").build_site()) from outside a
site now aborts with a message that tells you to pass the site’s path
via dir, instead of a bare “no _config.yml” error.set_theme_color(),
set_theme_style(), set_theme_skin(),
set_theme_font(), set_element_style(),
add_css(), add_mathjax()) now find the site
root from any subdirectory, exactly like build_site() –
running them from inside the site’s RStudio project just works with the
default dir = ".".serve_site() now waits for a real HTTP response
– which also warms the server up before the Viewer’s own request – plus
a short settle before opening the preview.serve_site() again for a site that is already
being served now reuses the running server and just reopens the preview,
instead of silently piling up background workers (the pid file records
the port too).serve_site(): the
preview was opened while the background worker was still doing the
initial build, before anything listened on the port (the Viewer does not
retry). serve_site() now waits for the server to answer
before opening the preview – and if the worker dies during the initial
build, the last log lines are surfaced as the error instead of a silent
blank page.serve_site() itself now keeps
.jekylldown-serve.* (its log and pid files) in the site’s
.gitignore – covering sites created by older versions or
not created by jekylldown at all; users never need to know the line
exists.serve_site() opens the preview in RStudio’s Viewer pane
again when running inside RStudio (background mode was sending it to the
system browser); elsewhere the default browser keeps being used.new_site() adds .jekylldown-serve.* (the
background server’s log and pid files) to the site’s
.gitignore on every theme.serve_site() bug: since the
servr::httw() rewrite, source edits never triggered a
rebuild – servr evaluates its file watcher lazily from inside the served
_site/ directory, so the watcher was silently watching the
wrong tree. The watch path is now absolute, and the live loop truly
works: save a watched file with the preview tab open and the site
re-knits, rebuilds and reloads.serve_site() now runs in a separate background R
process by default (background = TRUE in interactive
sessions): the console stays free, nothing spams it, and rebuild output
goes to .jekylldown-serve.log in the site (one status line
per rebuild instead of the full jekyll echo).
stop_server("site") stops it via the recorded PID.
background = FALSE keeps the old in-session daemon.knit_all() gained quiet =, used by the
serve loop to silence the per-poll “all posts up to date” chatter.Topic|Length over
----|----) and/or glued to the previous paragraph with no
blank line – were not recognized by kramdown on any theme, and rendered
as prose full of pipe characters. tag_tables() (applied
both when knitting and when migrating) now normalizes them: leading
pipes added, a blank line inserted before the table, and the
{: .table} styling tag applied. Fenced code and
{% highlight %} blocks remain untouched.Theme-parity pass: everything that worked on al-folio now works on the other three themes.
post layout – it uses single),
which looked like “nothing renders”, tables included. The scaffold now
ships a _layouts/post.html alias, so every jekylldown post
works unchanged.<a>, so img.pkg matched nothing and
logos rendered full-size. Ported rules now target both shapes
(img.pkg, .pkg img)../-relative paths in plain posts (e.g.
<img src='./img/logo.png'>, which Hugo’s
relativeURLs used to paper over) resolved against the post
URL and 404’d; they are now rooted to the site during migration.Gemfile but no
Gemfile.lock (that is, before
bundle_install()), build_site() and
serve_site() crashed – Jekyll insisted on
Bundler.setup and died on any version skew
(You have already activated bigdecimal ...). Plain-jekyll
runs now set JEKYLL_NO_BUNDLER_REQUIRE, Jekyll’s own escape
hatch; once a lockfile exists, bundle exec takes over as
before.publications = "bib" now produces a decent page on
every theme: on al-folio it keeps feeding jekyll-scholar, and on themes
without it (minima, Chirpy, Minimal Mistakes) the page is rebuilt as a
clean Markdown list of formatted citations (APA, fetched from doi.org –
the same authoritative source), each ending in a single DOI link.
Raw-HTML publication pages, which kramdown mangles, are no longer the
fallback when the DOIs are fetchable.new_site(theme = "al-folio") now sets
baseurl: "" (the template ships its own
/al-folio, which 404’d every asset on a fresh site served
at the root – the first build looked completely unstyled), and the scrub
comments out the placeholder profile picture (Einstein) so an empty site
starts with no photo; migrate_hugo() re-enables the line
when it finds a real avatar._data/socials.yml, Chirpy _data/contact.yml +
config usernames, Minimal Mistakes author.links, minima
footer keys)._config.yml changes apply without a server restart under
serve_site()), and the pages-are-not-Rmd limitation. The
README’s file map gained the pages row and points there.use_pages_workflow(): writes the standard GitHub
Actions workflow that builds and deploys the site to GitHub Pages
(checkout, cached Ruby/bundle, jekyll build, deploy) for
themes that do not ship one (minima, Minimal Mistakes, …); sites whose
theme already includes a deploy workflow (al-folio, Chirpy) are left
alone.gh-pages), plus Netlify/Cloudflare Pages, GitLab Pages
and plain static hosting – _site/ is static files, any host
works.First minor release: four themes with scaffolding, styling, migration and a real-world gallery – the package is feature-complete for its anchor use cases.
add_mathjax(): enables LaTeX math the way each
theme expects (al-folio’s native flag, Chirpy’s per-page
math default, Minimal Mistakes’ head_scripts,
or a configured MathJax script inserted into a site-local head include
on minima), with inline $...$ and display
$$...$$ both rendering. Demonstrated in the gallery on a
2007 post.migrate_hugo() against the real
world:
[[menu.header]],
[[menu.nav]] and theme-specific
[[params.mainMenu]] lists
(link/text keys);content/en/, custom section names) are detected as post
sections;{{% %}} form and with quoted
arguments convert like their {{< >}} cousins, and
blogdown’s {{< blogdown/postref >}} wrappers are
resolved away;{{/{% in migrated content (LaTeX
math, template snippets) are Liquid-escaped – previously a single such
post aborted the entire Jekyll build;rerender argument: rerender = FALSE
migrates the rendered Markdown blogdown committed next to each R source
instead of queueing years of old posts for re-knitting – the right mode
for archival migrations._pages in the Jekyll build – without it every migrated page
404’d.Title now says what has been true since
0.0.3: sites are written from ‘R Markdown’ and ‘Quarto’.migrate_hugo() target (with al-folio as its worked
example); and the package Description mentions the four
themes and the declarative customization.build.R is no longer described
as the hook behind serve_site() (it has not been since the
servr::httw() rewrite); the generated file documents itself
as a compatibility hook for users driving servr::jekyll()
directly.new_site(theme = "chirpy") clones the
Chirpy starter (stripped of the upstream repo tooling, Pages deploy
workflow kept, and the theme gem un-pinned so bundler can pick a release
the local Ruby runs); new_site(theme = "minimal-mistakes")
generates a gem-based Minimal Mistakes site locally. The knit/serve
pipeline, the styled tables and the customization layers know all four
themes: set_theme_style() speaks Chirpy’s CSS variables,
the new set_theme_skin() switches Minimal Mistakes’
compiled skins, set_element_style() carries per-theme
selector maps, and set_theme_color() delegates
sensibly.migrate_hugo() targets the new themes too: menu pages
become Chirpy _tabs/ entries (icon + order) or
Minimal Mistakes _pages/ plus
_data/navigation.yml; the Hugo home lands in Chirpy’s about
tab or above the Minimal Mistakes post list; the avatar becomes Chirpy’s
avatar: or Minimal Mistakes’ author.avatar;
social profiles are written to Chirpy’s social: config
block (plus its github/twitter buttons) or Minimal Mistakes’
author: sidebar links, with URLs rebuilt deterministically
from the extracted usernames. publications = "bib" falls
back to "html" on themes without
_bibliography/.set_theme_style() overrides al-folio’s own CSS
variables (background, text, dividers, code/card/footer colors, …) with
light/dark-aware values; set_theme_font() sets font
families (Google Fonts faces are fetched and inlined as
@font-face, valid anywhere in a stylesheet, unlike
@import) and the base size;
set_element_style() styles one semantic element
("navbar", "footer", "headings",
…) through a curated selector map – documented as the fragile layer,
with a warning when the installed theme no longer contains a mapped
selector; add_css() is the escape hatch: free-form CSS in a
managed, removable block..Rmd posts can opt into a pandoc pipeline with
knit_method: pandoc in the front matter (or site-wide with
options(jekylldown.knit_method = "pandoc")): the post is
rendered through rmarkdown’s md_document(variant = "gfm"),
which enables the pandoc-only features – citations
(bibliography:), footnotes, cross-references – while
figures and front matter get the same treatment as every other post. The
default remains plain knitr (fast, no pandoc needed).serve_site() was rebuilt on servr::httw():
it now watches the whole source tree (.Rmd,
.qmd, Markdown pages, _config.yml, data files,
styles) and re-knits/re-renders whatever is outdated before rebuilding –
Quarto posts included. Previously only .Rmd changes
triggered a rebuild.install_quarto() downloads the Quarto CLI into
jekylldown’s isolated toolchain directory
(tools::R_user_dir("jekylldown", "data")/quarto), where the
package finds it automatically – nothing system-wide, no shell
configuration, delete the directory to uninstall. check()
reports the Quarto found (toolchain, PATH, or the
quarto package’s discovery)._source/*.qmd posts are rendered by
build_site() through the Quarto CLI
(quarto render --to gfm) and adapted to the same
conventions as .Rmd posts: source front matter carried over
(minus Quarto-only keys), pandoc’s repeated title/date heading stripped,
figures moved to assets/img/posts/<post>/ behind
{{ site.baseurl }}. new_post() gained
format = c("Rmd", "qmd", "md").knitr::kable()) are tagged with a {: .table}
kramdown IAL when knitting and when migrating, so al-folio styles them
(a bare <table> gets almost no styling from the
theme); code blocks are left untouched.migrate_hugo() fills al-folio’s
_data/socials.yml from the Hugo pages: profile URLs
(GitHub, LinkedIn, ORCID, Google Scholar, ResearchGate, StackOverflow,
X, and friends), the first mailto: address, and a CV/resume
PDF link. Only profile-shaped URLs on non-post pages count, so
repository links and profiles mentioned in posts are not mistaken for
the site owner’s.publications = "bib" is now the default in
migrate_hugo() (it falls back to "html"
automatically without _bibliography/, DOIs or network),
after a real-world migration with the old "html" default
produced a broken publications page.exclude entries, the
upstream repo tooling is dropped (hidden files and directories except
.gitignore, the docs/ tree, demo data files,
and all of .github except the Pages deploy workflow), and
the jekyll-jupyter-notebook plugin is removed (the demo
posts were its only content, and without
jupyter/nbconvert on the PATH it aborts every
local build).First prototype. Do for Jekyll what blogdown does for Hugo:
new_site() scaffolds a Jekyll site with the jekylldown
conventions (_source/*.Rmd knitted to
_posts/*.md), with the minima theme generated
locally or al-folio cloned from GitHub.new_post() creates dated posts with Jekyll front
matter.build_site() / knit_post() knit outdated
posts (front matter preserved, kramdown/rouge fences, figures in
assets/img/posts/ via {{ site.baseurl }}) and
run jekyll build when available.serve_site() / stop_server() wrap
servr::jekyll() for live preview with automatic
re-knitting.bundle_install() installs a theme’s
Gemfile dependencies into the isolated gem environment;
sites with a Gemfile.lock are then built with
bundle exec jekyll automatically.migrate_hugo() converts a Hugo/blogdown site guided by
its config: post filenames, YAML and TOML front matter, page bundles,
figure/ youtube shortcodes, and Pandoc image
attributes. The Hugo menu ([[menu.main]]) drives page
migration (content/<slug>.md becomes a Jekyll page
with the same URL and nav_order),
content/_index.md becomes the landing page (with
avatar-to-profile-picture conversion on al-folio), and the site identity
(name, url, description, jekyll-scholar author names) is
written into _config.yml.
only_referenced = TRUE copies from static/
only the files the migrated content actually references.
publications = "bib" converts a hand-written publications
page deterministically: the DOIs are extracted, each reference is
fetched as authoritative BibTeX from doi.org (Crossref/DataCite content
negotiation), preview images are paired with their DOIs, and
_bibliography/papers.bib drives al-folio’s jekyll-scholar
page (badges and buttons included). theme_color = picks the
al-folio accent color. url/baseurl are derived
from the Hugo baseURL (empty baseurl for user
pages). A report lists everything that needs manual porting.{{< figure >}} conversion keeps
class/width/height as a kramdown
inline attribute list, and the CSS rules behind those classes (which is
where Hugo themes define figure display sizes) are ported from the Hugo
theme’s sass into the new site’s stylesheet, with sass variables
resolved and selectors rewritten for kramdown output – so images keep
the size they had on the old site.set_theme_color() changes al-folio’s accent color at
any time: named palette colors ("red", "blue",
…) resolved from the theme’s own variables, or any hex value;
implemented as a CSS-variable override appended to a site-local copy of
the theme’s main.scss.new_site(demo = FALSE) (implied by
migrate_hugo()) scrubs al-folio’s demo content: sample
posts, news, projects, books, teachings, the Einstein pages, the demo
bibliography and the external demo blog feeds
(external_sources).check() prints a situation report on the Ruby/Jekyll
toolchain, with support for a fully isolated toolchain under
tools::R_user_dir("jekylldown", "data").