diff --git a/README.md b/README.md index b3ddeb5..e843395 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ code. The website is built using the Rust-powered static site generator, framework - **[basecoat-css](https://basecoatui.com/)** — a lightweight shadcn/ui components library built with Tailwind CSS -- **[just](https://github.com/casey/just)** — a Rust-powered command runner, - similar to `make` - **[Quarto](https://quarto.org/)** — currently used to execute code chunks and render to commonmark, though this is likely to change - **[Node.js](https://nodejs.org/en)** — `npm` and `npx` are also used to @@ -23,18 +21,13 @@ code. The website is built using the Rust-powered static site generator, Tailwind extension for icons (currently limited to fa7-brands, lucide, and mdi icons) -## Pipeline - -Running `just build` will do the following: +The build pipeline: 1. **Tailwind** compiles `css/*.css` to `static/style.css`. -2. **Quarto** executes code in `content/**/*.qmd` and compiles to CommonMark in +2. **Quarto** executes code in `content/**/*.qmd` and compiles to commonmark in `content/**/*.md`. 3. **Zola** compiles commonmark to HTML and builds site in public/. -For development, the same is achieved with `just dev`, which will serve the site -and open it in the default browser with live reload. - ## Structure ``` @@ -60,9 +53,13 @@ and open it in the default browser with live reload. **Prerequisites** In addition to the stack software listed above, you will need R installed and -the most recent release version of the rextendr package. The -[`just`](https://github.com/casey/just) command line runner will also be very -beneficial to you. +the most recent release version of the rextendr package. The `just` command line +runner will also be very beneficial to you. + +- **[just](https://github.com/casey/just)** v1.55.0 or higher +- **Node.js** v24.15.0 or higher +- **Quarto** +- **Zola** v0.22.1 or higher **Installation** @@ -85,24 +82,21 @@ just dev just build ``` -**Available commands** - -Run `just` with no arguments to list all recipes. - -| Recipe | Description | -|---------------------|------------------------------------------------------------------------------------| -| `basecoat` | Move basecoat component js files from node_modules to static/js | -| `build` | Compile Tailwind css, then build the site with Zola | -| `check` | Try to build site without rendering (checks links) | -| `default` | List all available recipes | -| `dev` | Run Tailwind watch and Zola live serve in parallel | -| `install` | Install Node.js dependencies | -| `new-page` path | Create a new documentation page at content/{{path}} | -| `new-post` title | Create a new blog post at content/blog/{{date}}-{{title}}/index.qmd | -| `new-section` path | Create a new documentation section at content/{{path}}/ | -| `render` path | Render a single qmd file at content/{{path}} | -| `render-all` | Render all qmd files in content/ (except those in "blog/") | -| `render-dir` path | Render all qmd files in content/{{path}}/ non-recursively (fails if path="blog/") | -| `render-post` title | Render a blog post at content/blog/{{date}}-{{title}}/index.qmd | -| `reset` | Clear public directory generated by Zola | -| `tailwind-build` | Generate Tailwind static/style.css from css/style.css | +**Available recipes** + +Run `just` without arguments to list available recipes. + +``` +Available recipes: + build # Compile Tailwind css, then build the site with Zola + build-tailwind # Generate Tailwind static/style.css from css/style.css + check # Try to build site without rendering (checks links) + dev # Run Tailwind watch and Zola live serve in parallel + install # Install Node.js dependencies + page path # Create a new documentation page at content/{{path}}.qmd + post title # Create a new blog post at content/blog/{{title}}/index.qmd + render # Render all pages in content/ recursively (ignores blog/) + render-page path # Render a documentation page at content/{{path}}.qmd + render-post title # Render a blog post at content/blog/{{title}}/index.qmd + reset # Clear public directory generated by Zola +``` \ No newline at end of file diff --git a/justfile b/justfile index c735fc9..0e2ca00 100644 --- a/justfile +++ b/justfile @@ -1,194 +1,105 @@ -# List all available recipes -default: - @just --list +set default-list # Compile Tailwind css, then build the site with Zola -build: tailwind-build +build: build-tailwind zola build +# Generate Tailwind static/style.css from css/style.css +build-tailwind: + npm run tailwind:build + # Try to build site without rendering (checks links) check: zola check +# Run Tailwind watch and Zola live serve in parallel +dev: + npm run dev + # Clear public directory generated by Zola reset: rm -rf public # Install Node.js dependencies -install: +install: npm basecoat + echo "Successfully installed dependencies and copied basecoat files to static." + +[private] +npm: npm install -# Move basecoat component js files from node_modules to static/js +[private] basecoat: - #!/usr/bin/env bash - cp node_modules/basecoat-css/dist/js/*.js static/js/ - echo "Successfully copied basecoat component js to static/js" - -# Render a single qmd file at content/{{path}} -render path: - #!/usr/bin/env bash - set -euo pipefail - src='{{path}}' - src="${src#content/}" - if [[ "$src" == blog/* ]]; then - echo "render: found 'blog/' path, use 'just render-post'" >&2 - exit 1 - fi - # move to content folder so _quarto.yml is invoked - cd content - # clear .md file to prevent quarto from writing to another file - rm -f "${src%.qmd}.md" - quarto render "$src" -M engine:knitr - - -# Render all qmd files in content/{{path}}/ non-recursively (fails if path="blog/") -render-dir path: - #!/usr/bin/env bash - set -euo pipefail - target='{{path}}' - target="${target#content/}" - target="${target%/}" - if [ "$target" = "blog" ]; then - echo "render-dir: found 'blog/' path, use 'just render-post' instead" >&2 - exit 1 - fi - cd content - shopt -s nullglob - files=( "$target"/*.qmd ) - if [ ${#files[@]} -eq 0 ]; then - echo "No .qmd files found under content/$target" >&2 - exit 1 - fi - for src in "${files[@]}"; do - rm -f "${src%.qmd}.md" - base=$(basename "$src") - dir=$(dirname "$src") - tmp_src="$dir/x${base}" - mv "$src" "$tmp_src" - trap 'mv "$tmp_src" "$src" 2>/dev/null' EXIT - quarto render "$tmp_src" -M engine:knitr - mv "${tmp_src%.qmd}.md" "${src%.qmd}.md" - mv "$tmp_src" "$src" - trap - EXIT - done - -# Render all qmd files in content/ (except those in "blog/") -render-all: - #!/usr/bin/env bash - set -euo pipefail - cd content - shopt -s globstar nullglob - files=() - for f in **/*.qmd; do - [[ "$f" == blog/* ]] && continue - files+=( "$f" ) - done - if [ ${#files[@]} -eq 0 ]; then - echo "No .qmd files to render" >&2 - exit 1 - fi - for src in "${files[@]}"; do - rm -f "${src%.qmd}.md" - base=$(basename "$src") - dir=$(dirname "$src") - tmp_src="$dir/x${base}" - mv "$src" "$tmp_src" - trap 'mv "$tmp_src" "$src" 2>/dev/null' EXIT - quarto render "$tmp_src" -M engine:knitr - mv "${tmp_src%.qmd}.md" "${src%.qmd}.md" - mv "$tmp_src" "$src" - trap - EXIT - done + cp node_modules/basecoate-css/dist/js/*.js static/js/ -# Generate Tailwind static/style.css from css/style.css -tailwind-build: - npm run tailwind:build +# Create a new documentation page at content/{{path}}.qmd +page path: + #!/usr/bin/env bash + set -euo pipefail + if [ -f "content/{{ path }}.qmd" ]; then + echo "Error: content/{{ path }}.qmd already exists." + exit 1 + fi + cat > "content/{{ path }}.qmd" <<-EOF + --- + title: + description: "" + weight: 0 + extra: + short_title: + --- + EOF + echo "Created content/{{ path }}.qmd" -# Create a new documentation page at content/{{path}} -new-page path: - #!/usr/bin/env bash - set -euo pipefail - rel='{{path}}' - rel="${rel#content/}" - if [[ "$rel" == blog/* ]]; then - echo "new-page: found 'blog/' path, use 'just new-post' instead" >&2 - exit 1 - fi - file="content/$rel" - parent=$(dirname "$file") - if [ ! -d "$parent" ]; then - echo "new-page: section $parent does not exist, use 'just new-section' first" >&2 - exit 1 - fi - if [ -e "$file" ]; then - echo "File exists: $file" >&2 - exit 1 - fi - cat > "$file" <<-EOF - --- - title: - description: "" - weight: 0 - extra: - short_title: - --- - EOF - echo "Created $file" +# Create a new blog post at content/blog/{{title}}/index.qmd +post title: + #!/usr/bin/env bash + set -euo pipefail + date=$(date +%Y-%m-%d) + dir="content/blog/${date}-{{ title }}" + mkdir -p "$dir" + cat > "$dir/index.qmd" <<-EOF + --- + title: {{ title }} + date: "$date" + authors: [] + taxonomies: + tags: [] + --- + EOF + echo "Created $dir/index.qmd" -# Create a new documentation section at content/{{path}}/ -new-section path: - #!/usr/bin/env bash - set -euo pipefail - dir="content/{{path}}" - dir="${dir%/}" - file="$dir/_index.qmd" - if [ -e "$file" ]; then - echo "File exists: $file" >&2 - exit 1 - fi - mkdir -p "$dir" - cat > "$file" <<-EOF - --- - title: - description: "" - weight: 0 - extra: - section_title: - --- - EOF - echo "Created $file" +# Render a documentation page at content/{{path}}.qmd +render-page path: (render-one path) -# Create a new blog post at content/blog/{{date}}-{{title}}/index.qmd -new-post title: - #!/usr/bin/env bash - set -euo pipefail - date=$(date +%Y-%m-%d) - dir="content/posts/${date}-{{title}}" - mkdir -p "$dir" - cat > "$dir/index.qmd" <<-EOF - --- - title: {{title}} - date: "$date" - authors: [] - taxonomies: - tags: [] - --- - EOF - echo "Created $dir/index.qmd" +# Render a blog post at content/blog/{{title}}/index.qmd +render-post title: (render-one ("blog" / title / "index")) -# Render a blog post at content/blog/{{date}}-{{title}}/index.qmd -render-post title: +[private] +render-one path: #!/usr/bin/env bash set -euo pipefail - shopt -s nullglob - matches=( content/blog/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-{{title}} ) - if [ ${#matches[@]} -eq 0 ]; then - echo "No post found matching *-{{title}}" >&2; exit 1 - elif [ ${#matches[@]} -gt 1 ]; then - echo "Ambiguous title, matched: ${matches[*]}" >&2; exit 1 + cd content + if [ -f "{{ path }}.qmd" ]; then + rm -f "{{ path }}.md" + quarto render "{{ path }}.qmd" {{ quarto_out + " " + quarto_flags }} + else + echo "Error: Could not find content/{{ path }}.qmd." + exit 1 fi - quarto render "${matches[0]}/index.qmd" -M engine:knitr -# Run Tailwind watch and Zola live serve in parallel -dev: - npm run dev +# Render all pages in content/ recursively (ignores blog/) +render: + #!/usr/bin/env bash + set -euo pipefail + shopt -s globstar nullglob + cd content + for page in **/*.qmd; do + [[ "$page" == blog/* ]] && continue + rm -f "${page%.qmd}.md" + quarto render "$page" {{ quarto_out + " " + quarto_flags }} + done + echo "Successfully rendered all documentation pages." + +quarto_out := "--to commonmark+yaml_metadata_block" +quarto_flags := "-M engine:knitr -M wrap:preserve -M from:markdown-smart" \ No newline at end of file