From 4430469cdcd23a930fef60279602d5150184117d Mon Sep 17 00:00:00 2001 From: Andrew Rioux Date: Sun, 19 Oct 2025 21:59:42 -0400 Subject: [PATCH] feat: add build commands to distribute over HTTP --- .gitignore | 5 + build/build-article.sh | 29 ++++ default.nix | 25 ++++ resources/basestyles.css | 297 +++++++++++++++++++++++++++++++++++++++ resources/html-setup.el | 55 ++++++++ 5 files changed, 411 insertions(+) create mode 100644 .gitignore create mode 100755 build/build-article.sh create mode 100644 default.nix create mode 100644 resources/basestyles.css create mode 100644 resources/html-setup.el diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ebb5a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +articles/*.html +articles/*.pdf +articles/*.tex + +/result* diff --git a/build/build-article.sh b/build/build-article.sh new file mode 100755 index 0000000..8952aa2 --- /dev/null +++ b/build/build-article.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -eux + +export FILE_NAME="$1" +LAST_COMMIT="$(git rev-list -1 HEAD -- "$FILE_NAME")" +FIRST_COMMIT_DATE="$(git log --diff-filter=A --no-patch --no-notes --pretty='%as' -- "$FILE_NAME")" +FIRST_COMMIT_DATE_PRETTY="$(git log --diff-filter=A --no-patch --no-notes '--date=format:%B, %e %Y' --pretty='%ad' -- "$FILE_NAME")" +LAST_COMMIT_DATE="$(git show --no-patch --no-notes --pretty='%as' "$LAST_COMMIT")" + +export LAST_COMMIT +export FIRST_COMMIT_DATE +export FIRST_COMMIT_DATE_PRETTY +export LAST_COMMIT_DATE + +emacs --batch --load resources/html-setup.el "$1" --funcall org-html-export-to-html + +emacs --batch "$1" --funcall org-latex-export-to-latex +TEX_FILE="${FILE_NAME%.org}.tex" +sed -i -e "s/\\\\date{\\\\today}/\\\\date{$FIRST_COMMIT_DATE_PRETTY}/" "$TEX_FILE" +TEX_BUILD="$(mktemp -d)" +cp "$TEX_FILE" "$TEX_BUILD" +pushd "${TEX_BUILD}" +pdflatex "$(basename "$TEX_FILE")" > /dev/null +popd +ls -al "$TEX_BUILD" +ls -al "$TEX_BUILD/$(basename "${TEX_FILE%.tex}.pdf")" +cp "$TEX_BUILD/$(basename "${TEX_FILE%.tex}.pdf")" "$(dirname "$TEX_FILE")" +rm "$TEX_FILE" diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..d93a1ee --- /dev/null +++ b/default.nix @@ -0,0 +1,25 @@ +{ pkgs ? import { system = "x86_64-linux"; } }: +let + build-article = pkgs.writeShellApplication { + name = "build-article"; + runtimeInputs = with pkgs; [ which texliveFull emacs git ]; + text = builtins.readFile ./build/build-article.sh; + }; + + articles = pkgs.stdenv.mkDerivation { + name = "articles"; + src = builtins.filterSource + (path: type: !(pkgs.lib.strings.hasPrefix "result" (baseNameOf path))) + ./.; + buildInputs = with pkgs; [ emacs git build-article ]; + + buildPhase = '' + cp -a . $out + cd $out + find . -name '*.org' -exec build-article {} \; + ''; + }; +in { + inherit build-article articles; + default = articles; +} diff --git a/resources/basestyles.css b/resources/basestyles.css new file mode 100644 index 0000000..4d17b7f --- /dev/null +++ b/resources/basestyles.css @@ -0,0 +1,297 @@ +/* === Dark Theme Org-Mode Style === */ + +:root { + --bg: #1e1e2e; + --bg-alt: #2a2a3a; + --bg-alt-2: #4a4a5a; + --fg: #e0e0e0; + --accent: #8aadf4; + --muted: #a0a0a0; + --border: #3a3a4a; + --code-bg: #2d2d3d; + --code-border: #444; + --tag-bg: #3a3a50; + --tag-fg: #cdd6f4; + --todo: #f38ba8; + --done: #a6e3a1; + --priority: #f9e2af; + --timestamp: #7f849c; + --timestamp-kwd: #89b4fa; +} + +body { + background-color: var(--bg); + color: var(--fg); + font-family: "Inter", "Segoe UI", system-ui, sans-serif; + line-height: 1.6; + margin: 0; + padding: 0; + display: grid; + grid-template-columns: 1fr min(40%, 30em) min(40%, 30em) 1fr; + grid-template-rows: 2em auto auto 2em; + grid-template-areas: + "tr tr tr tr" + "lb preamble postamble rb" + "lb content content rb" + "br br br br"; +} + +#content { + max-width: 60em; + padding: 1.5em; + background-color: var(--bg-alt); + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + box-shadow: + 0 6px 12px -4px #0006, + 6px 0 12px -6px #0005, + -6px 0 12px -6px #0005; + grid-area: content; +} + +#preamble { + border-top-left-radius: 10px; + grid-area: preamble; + z-index: 2; +} + +#postamble { + grid-area: postamble; + text-align: right; + border-top-right-radius: 10px; + z-index: 2; +} + +#preamble, #postamble { + background: var(--bg-alt-2); + padding: 1em 1.5em; +} + +/* Titles */ +.title { + text-align: center; + font-size: 2em; + color: var(--accent); + font-weight: 600; + margin-bottom: 0.2em; +} + +.subtitle { + text-align: center; + font-size: 1.1em; + font-weight: 500; + color: var(--muted); + margin-top: 0; +} + +/* Org States */ +.todo { + font-family: monospace; + color: var(--todo); +} + +.done { + font-family: monospace; + color: var(--done); +} + +.priority { + font-family: monospace; + color: var(--priority); +} + +/* Tags */ +.tag { + background-color: var(--tag-bg); + color: var(--tag-fg); + font-family: monospace; + padding: 3px 6px; + border-radius: 4px; + font-size: 80%; + font-weight: 500; +} + +/* Timestamps */ +.timestamp { + color: var(--timestamp); +} + +.timestamp-kwd { + color: var(--timestamp-kwd); +} + +/* Alignment helpers */ +.org-right { text-align: right; } +.org-left { text-align: left; } +.org-center { text-align: center; } + +/* Text */ +.underline { + text-decoration: underline dotted var(--accent); +} + +/* Footnotes & Verse */ +#postamble p, #preamble p { + font-size: 90%; + margin: .2em; + color: var(--muted); +} + +p.verse { + margin-left: 3%; + font-style: italic; +} + +/* Code Blocks */ +pre { + border: 1px solid var(--code-border); + border-radius: 6px; + background-color: var(--code-bg); + padding: 12pt; + font-family: "Fira Code", monospace; + overflow: auto; + margin: 1.2em 0; + color: #f8f8f2; +} + +pre.src { + position: relative; + overflow: auto; +} + +pre.src:before { + display: none; + position: absolute; + top: 6px; + right: 12px; + padding: 3px 6px; + border-radius: 4px; + font-size: 0.75em; + color: #cdd6f4; + background-color: #45475a; + opacity: 0.85; +} + +pre.src:hover:before { + display: inline-block; +} + +/* Language labels (examples) */ +pre.src-python:before { content: 'Python'; } +pre.src-js:before { content: 'JavaScript'; } +pre.src-sh:before { content: 'Shell'; } +pre.src-html:before { content: 'HTML'; } +pre.src-css:before { content: 'CSS'; } +pre.src-rust:before { content: 'Rust'; } +pre.src-cpp:before { content: 'C++'; } + +/* Tables */ +table { + border-collapse: collapse; + width: 100%; + margin: 1em 0; + font-size: 0.95em; +} + +th, td { + border: 1px solid var(--border); + padding: 0.5em 1em; + vertical-align: top; +} + +th { + background-color: #2e2e3e; + color: var(--accent); + font-weight: 600; + text-align: center; +} + +td { + background-color: #252534; +} + +/* Figures, Equations */ +.figure { + padding: 1em; + text-align: center; +} + +.equation-container { + display: table; + width: 100%; + text-align: center; +} + +.equation-label { + display: table-cell; + text-align: right; + color: var(--muted); +} + +/* Inline Tasks */ +.inlinetask { + padding: 10px; + border: 1px solid var(--border); + border-left: 4px solid var(--accent); + margin: 10px 0; + background: #2b2b3b; + border-radius: 6px; +} + +/* Highlights */ +.code-highlighted { + background-color: #45475a; + border-radius: 4px; +} + +/* Misc */ +textarea { + background-color: var(--bg); + color: var(--fg); + border: 1px solid var(--border); + padding: 0.5em; + font-family: monospace; + border-radius: 4px; +} + +#org-div-home-and-up { + text-align: right; + font-size: 70%; + white-space: nowrap; + color: var(--muted); +} + +.org-info-js_search-highlight { + background-color: var(--accent); + color: #000; + font-weight: bold; +} + +a, a:visited { + color: var(--accent); + text-decoration: none; + font-weight: 500; + transition: color 0.2s ease, background-color 0.2s ease; + border-bottom: 1px dashed var(--accent); +} + +a:visited { + color: #a5adcb; +} + +a:hover { + color: #b4c9ff; + background-color: #2b2b3b; + border-bottom-style: solid; +} + +/* Anchors (links within same page) */ +a[href^="#"] { + color: var(--priority); + border-bottom: 1px dotted var(--priority); +} + +a[href^="#"]:hover { + color: #ffeabf; + border-bottom-style: solid; +} diff --git a/resources/html-setup.el b/resources/html-setup.el new file mode 100644 index 0000000..0a012ec --- /dev/null +++ b/resources/html-setup.el @@ -0,0 +1,55 @@ +(require 'org) + +(setq org-html-style-default "") + +(setq org-html-postamble + (let ((article-name (getenv "FILE_NAME")) + (last-commit (getenv "LAST_COMMIT"))) + + (concat + (format + "

View source

" + last-commit + (substring article-name 2)) + (format + "

View PDF

" + (string-replace "org" "pdf" (substring article-name 2)))))) + +(setq org-html-head-extra + (let ((last-commit-date (getenv "LAST_COMMIT_DATE")) + (first-commit-date (getenv "FIRST_COMMIT_DATE")) + (article-name (getenv "FILE_NAME"))) + + (concat + "" + (format "" first-commit-date) + (format "" last-commit-date) + "" + "" + (format + "" + (string-replace "org" "pdf" (substring article-name 2)))))) + +(setq org-html-preamble + (let ((last-commit-date (getenv "LAST_COMMIT_DATE")) + (first-commit-date (getenv "FIRST_COMMIT_DATE"))) + + (if (string= last-commit-date first-commit-date) + (concat + "

Author: Andrew Rioux

" + ; "" + "" + "

Publish date: " + last-commit-date + "

") + + (concat + "

Author: Andrew Rioux

" + ; "" + "" + "

Initial publish date: " + first-commit-date + "

Last modify date: " + last-commit-date + "

") + )))