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").