Support via Liberapay

Colophon for the Org site

1. Org all the things

The website is created from org-mode documents. Just change the .html extension of a page to .org.html to see the org source 😃.

2. Creating the features screenshots

To produce the screenshots/screencasts in features, I did the following:

  • Use the doom-one-light theme
  • Use 24pt Source Code Pro
  • Use a frame 50 columns wide, and 10–20 lines tall
  • No org-superstar
  • (prettify-symbols-mode -1)
  • (setq org-pretty-entities nil)
  • (setq org-hide-leading-stars nil)
  • (setq org-link-descriptive nil)
  • (org-restart-font-lock)

From here, I either use emacs-gif-screencast or the following function:

(defun org-screenshot-svg ()
  "Save a screenshot of the current frame as an SVG image.
Saves to a file in ~/Pictures/Org and puts the filename in the kill ring."
  (let* ((filename (expand-file-name (format-time-string "~/Pictures/Org/%H:%M.svg")))
         (data (x-export-frames nil 'svg)))
    (with-temp-file filename
      (insert data))
    (kill-new filename)
    (message filename)))

3. Development

For easy development, there are some little snippets which make SASS recompilation, HTML exporting, and rsync all happen automatically. The "DESTINATION" needs customising for your particular environment.

(defvar bulk-save nil)
(defvar batch-export nil)
(defvar org-website-folder (file-name-directory (buffer-file-name)))
(defun org-website-sync ()
  (let ((file-name (buffer-file-name)))
    (when (and (s-contains-p "orgweb" file-name)
               (not (and (s-contains-p "html" file-name)
                         (file-exists-p (s-replace ".html" ".org" file-name))))
               (not (s-contains-p ".git" file-name))
               (not batch-export))
      (when (s-contains-p ".scss" file-name)
        (setq sassc-output (shell-command-to-string
                            (format "sassc %s %s"
                                    (concat (file-name-sans-extension file-name) ".css"))))
        (unless (string-empty-p sassc-output)
          (message "Sassc error: %s" sassc-output)))

      (when (s-contains-p ".org" file-name)
        (unless (string= (file-name-base file-name) "setup")
          (let ((org-html-style-default "")
                (org-html-scripts ""))
        (htmlize-file file-name (concat file-name ".html")))

      (unless bulk-save
        (message "= Performing bulk save (triggerd by %s." file-name)
        (let ((bulk-save t))
          (save-some-buffers t)

           (get-buffer-create "*orgweb rsync*"))
            (get-buffer "*orgweb rsync*")
            "-avz" "--delete" org-website-folder "DESTINATION")
           (lambda (p e)
             (when (= 0 (process-exit-status p))
               (delete-window (get-buffer-window "*orgweb rsync*"))))))))))

(add-hook 'after-save-hook #'org-website-sync)
(defun org-website-batch-export ()
  (let ((batch-export t)
        (files (directory-files org-website-folder t "\\.org$"))
        (errors nil))
    (dolist (file files)
      (message "exporting: %s" file)
      (with-current-buffer (find-file-noselect file)
        (condition-case nil
          (error (setq errors (append errors file))))))
    (message "finished exporting. Experienced errors with:%s" (if errors (concat "\n - " (s-join "\n - " errors)) ""))))

4. Local deployment

We use a little shell hack to immediately call Emacs on the file

#!/usr/bin/env sh
":"; exec emacs --quick --script "$0" -- "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*-

Then we can execute some Elisp. This requires the htmlize package, and ignore-headlines from ox-extra.

(require 'ox)
(require 'ox-html)
(load "~/.emacs.d/.local/straight/repos/emacs-htmlize/htmlize.el" t t) ; system-dependant
(require 'htmlize)

(load "~/.emacs.d/.local/straight/repos/org-mode/contrib/lisp/ox-extra.el" t t)
(require 'ox-extra)
(ox-extras-activate '(ignore-headlines))

 org-html-style-default ""
 org-html-scripts ""
 org-html-htmlize-output-type 'css
 org-html-doctype "html5"
 org-html-html5-fancy t
 org-html-validation-link nil
 org-html-postamble t
 '(("en" "<p class=\"author\">Made with <a href=\"\">🤎</a> by <a href=\"\" style=\"font-weight: bold; font-size: 0.9em; letter-spacing: 1px\">TEC</a></p>
<p xmlns:dct=\"\" xmlns:cc=\"\" class=\"license-text\" style=\"color: #aaa\">licensed under <a rel=\"license\" href=\"\"><img class=\"inline\" src=\"/resources/img/external/cc-by-sa.svg\" title=\"CC-BY-SA 4.0\" alt=\"CC-BY-SA\"/></a></p>"))
 make-backup-files nil
 debug-on-error t)

(let ((scss-files (directory-files-recursively default-directory "\\.scss$"))
      (org-files (directory-files-recursively default-directory "\\.org$")))
  (if (executable-find "sassc")
      (dolist (scss-file scss-files)
        (let ((sassc-out
                (format "sassc %s %s"
                        scss-file (concat (file-name-sans-extension scss-file) ".css")))))
          (message "\033[0;35m• %s%s\033[0m" (file-relative-name scss-file default-directory)
                   (if (string= "" sassc-out) "" (concat ":\033[31m\n" sassc-out)))))
    (message "No sassc executable found"))
  (dolist (org-file org-files)
    (message "\033[0;34m• %s\033[90m" (file-relative-name org-file default-directory))
    (with-current-buffer (find-file-literally org-file)
      (condition-case err
          (progn (org-html-export-to-html)
                 (htmlize-file org-file (concat org-file ".html")))
        (error (message "  \033[0;31m%s\033[90m"  (error-message-string err)))))))
(message "\033[0m")
(kill-emacs 0)

Documentation from the website (either in its HTML format or in its Org format) is licensed under the GNU Free Documentation License version 1.3 or later. The code examples and css stylesheets are licensed under the GNU General Public License v3 or later.