hello
") - (result (z/org-html-add-body-classes output 'html info))) - (should (string-match-p "class=\"wip\"" result)))))) - -(ert-deftest test/add-body-classes-adds-no-sidenotes-class () - "Should add class=\"no-sidenotes\" when z/no-sidenotes-file-p is t." - (with-temp-org-file "#+TITLE: No sidenotes\n\nContent.\n" - (cl-letf (((symbol-function 'z/wip-file-p) (lambda (_) nil)) - ((symbol-function 'z/no-sidenotes-file-p) (lambda (_) t))) - (let* ((info (list :input-file temp-file)) - (output "hello
") - (result (z/org-html-add-body-classes output 'html info))) - (should (string-match-p "class=\"no-sidenotes\"" result)))))) - -(ert-deftest test/add-body-classes-combines-multiple-classes () - "Both wip and no-sidenotes classes should appear when both predicates are t." - (with-temp-org-file "#+TITLE: Both\n\nContent.\n" - (cl-letf (((symbol-function 'z/wip-file-p) (lambda (_) t)) - ((symbol-function 'z/no-sidenotes-file-p) (lambda (_) t))) - (let* ((info (list :input-file temp-file)) - (output "hello
") - (result (z/org-html-add-body-classes output 'html info))) - (should (string-match-p "wip" result)) - (should (string-match-p "no-sidenotes" result)))))) - -(ert-deftest test/add-body-classes-unchanged-when-no-classes () - "Output should be unmodified when no special classes apply." - (with-temp-org-file "#+TITLE: Plain\n\nContent.\n" - (cl-letf (((symbol-function 'z/wip-file-p) (lambda (_) nil)) - ((symbol-function 'z/no-sidenotes-file-p) (lambda (_) nil))) - (let* ((info (list :input-file temp-file)) - (output "hello
") - (result (z/org-html-add-body-classes output 'html info))) - (should (string= output result)))))) - -(ert-deftest test/add-body-classes-ignores-non-html-backend () - "For non-HTML backends the function currently returns nil (known bug: -`when' has no else branch so output is not passed through). -Fix: change `when' to `if' with output as the else clause. -This test documents current behaviour; flip the should once fixed." - (with-temp-org-file "#+TITLE: LaTeX\n\nContent.\n" - (cl-letf (((symbol-function 'z/wip-file-p) (lambda (_) t)) - ((symbol-function 'z/no-sidenotes-file-p) (lambda (_) t))) - (let* ((info (list :input-file temp-file)) - (output "\\documentclass{article}") - (result (z/org-html-add-body-classes output 'latex info))) - ;; BUG: should be (should (string= output result)) - (should (null result)))))) - -;;; build-site-tests.el ends here \ No newline at end of file diff --git a/build-site.el b/build-site.el index 32f44ba..237607e 100755 --- a/build-site.el +++ b/build-site.el @@ -6,127 +6,32 @@ ;;; Commentary: ;; Run this file with: -;; emacs -Q --script build-site.el -;; -;; Optional env vars: -;; SITE_FORCE=1 Force republish all files (default: incremental) -;; SITE_DRY=1 Parse and prepare only; skip org-publish-all +;; emacs -Q --script build-site.el ;;; Code: -;; ───────────────────────────────────────────────────────────────────────────── -;; 0. Bootstrap: paths and load-path -;; ───────────────────────────────────────────────────────────────────────────── - -(defconst z/build-start-time (float-time) - "Wall-clock time when the build started.") - -(defconst z/site-root - (file-name-as-directory - (file-name-directory - (or load-file-name buffer-file-name))) - "Absolute path to the site root (always ends with /). -This is the single authoritative definition — lisp/* files must NOT -redefine site-root themselves.") - -;; Keep the old name around so any stray code still compiles. -(defvaralias 'site-root 'z/site-root) +(require 'package) +(defvar site-root + (file-name-directory + (or load-file-name buffer-file-name))) (defun site-path (path) - "Expand PATH relative to `z/site-root'." - (expand-file-name path z/site-root)) + (expand-file-name path site-root)) -(add-to-list 'load-path (site-path "lisp")) -;; ───────────────────────────────────────────────────────────────────────────── -;; 1. Logging helpers (ANSI colours for terminal output) -;; ───────────────────────────────────────────────────────────────────────────── +(add-to-list 'load-path + (expand-file-name "lisp" + (file-name-directory + (or load-file-name buffer-file-name)))) -(defconst z/colour-reset "\033[0m") -(defconst z/colour-bold "\033[1m") -(defconst z/colour-dim "\033[2m") -(defconst z/colour-green "\033[32m") -(defconst z/colour-yellow "\033[33m") -(defconst z/colour-cyan "\033[36m") -(defconst z/colour-red "\033[31m") -(defconst z/colour-blue "\033[34m") -(defconst z/colour-magenta "\033[35m") +(require 'recently-updated) +(require 'tags) +(require 'sidenotes) +(require 'sitemaps) -(defun z/log (level fmt &rest args) - "Emit a coloured build-log line. -LEVEL is one of: info warn error step metric done. -FMT / ARGS are passed to `format'." - (let* ((msg (apply #'format fmt args)) - (prefix - (pcase level - ('info (concat z/colour-cyan " INFO " z/colour-reset)) - ('warn (concat z/colour-yellow " WARN " z/colour-reset)) - ('error (concat z/colour-red " ERROR " z/colour-reset)) - ('step (concat z/colour-blue z/colour-bold - " ──── " z/colour-reset)) - ('metric (concat z/colour-magenta " ◈ " z/colour-reset)) - ('done (concat z/colour-green z/colour-bold - " ✓ " z/colour-reset)) - (_ " ")))) - (message "%s%s" prefix msg))) - -(defun z/log-separator (&optional label) - "Print a coloured separator line, optionally with LABEL." - (if label - (message "%s%s── %s %s%s" - z/colour-dim z/colour-bold label - (make-string (max 0 (- 60 (length label))) ?─) - z/colour-reset) - (message "%s%s%s" - z/colour-dim - (make-string 66 ?─) - z/colour-reset))) - -(defmacro z/with-timing (label &rest body) - "Execute BODY, then log elapsed seconds under LABEL." - (declare (indent 1)) - (let ((t0 (gensym "t0"))) - `(let ((,t0 (float-time))) - (prog1 (progn ,@body) - (z/log 'metric "%s took %.2fs" ,label (- (float-time) ,t0)))))) - -;; ───────────────────────────────────────────────────────────────────────────── -;; 2. Package bootstrap -;; ───────────────────────────────────────────────────────────────────────────── - -(z/log-separator "Package setup") - -(require 'package) - -(setq package-user-dir (site-path ".packages")) -(setq package-archives - '(("melpa" . "https://melpa.org/packages/") - ("elpa" . "https://elpa.gnu.org/packages/"))) - -(package-initialize) - -(z/with-timing "Package archive refresh" - (unless package-archive-contents - (z/log 'info "Refreshing package archive contents…") - (condition-case err - (package-refresh-contents) - (error - (z/log 'warn "Could not refresh archives: %s" (error-message-string err)))))) - -(z/with-timing "htmlize install" - (unless (package-installed-p 'htmlize) - (z/log 'info "Installing htmlize…") - (condition-case err - (package-install 'htmlize) - (error - (z/log 'error "htmlize install failed: %s" (error-message-string err)) - (error "Cannot continue without htmlize"))))) - -(require 'htmlize) - -;; ───────────────────────────────────────────────────────────────────────────── -;; 3. Org / ox requires -;; ───────────────────────────────────────────────────────────────────────────── +(setq package-user-dir (expand-file-name "./.packages")) +(setq package-archives '(("melpa" . "https://melpa.org/packages/") + ("elpa" . "https://elpa.gnu.org/packages/"))) (require 'ox-publish) (require 'cl-lib) @@ -135,176 +40,154 @@ FMT / ARGS are passed to `format'." (require 'ox-html) (require 'ox-md) -;; ───────────────────────────────────────────────────────────────────────────── -;; 4. Local library requires (after load-path is set) -;; ───────────────────────────────────────────────────────────────────────────── +(package-initialize) +(unless package-archive-contents + (package-refresh-contents)) -(z/log-separator "Local libraries") +(package-install 'htmlize) +(add-to-list 'load-path "~/master-folder/org_files/org_web/") +(require 'htmlize) -(dolist (lib '(recently-updated tags sidenotes sitemaps)) - (condition-case err - (progn - (require lib) - (z/log 'done "Loaded %s" lib)) - (error - (z/log 'error "Failed to load %s: %s" lib (error-message-string err)) - (error "Aborting: required library %s missing" lib)))) +(defvar z-shared-head + " + -;; ───────────────────────────────────────────────────────────────────────────── -;; 5. HTML export settings -;; ───────────────────────────────────────────────────────────────────────────── + + + + + + + + + -(setq org-html-htmlize-output-type 'css) - -(defvar z/shared-head - (concat - "\n" - (mapconcat - (lambda (f) - (format "" f)) - '("style.css" - "bigger-picture.min.css" - "comments.css" - "kanban.css" - "org-syntax.css" - "misc.css" - "toc.css" - "media.css" - "wird-tracker.css") - "\n") - "\n" - (mapconcat - (lambda (f) - (format "" f)) - '("script.js" - "lunr.js" - "competency-status-board.js" - "notes.js" - "comments.js" - "bigger-picture.min.js" - "search.js" - "svg-pan-zoom.min.js" - "gallery-init.js" - "sitemap-interactive.js" - "wird-tracker.js") - "\n")) - "Shared HTML fragment injected into every page.") - -;; ───────────────────────────────────────────────────────────────────────────── -;; 6. Global Org macros -;; ───────────────────────────────────────────────────────────────────────────── + + + + + + + + + + + +" + ) (setq org-export-global-macros (append - org-export-global-macros '(("sidenote" - . "@@html:\ -\ -$2@@") - ("epigraph" - . "@@html:$1
$1
$1
$1
$1
$1
Comments
+