Configuration for this website
This is the org-publish configuration for this website.
The css styling lives here.
The features this website supports can be viewed here.
See How I publish my wiki with org-publish for another take on exporting org-roam using org-publish.
HTML headers
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/font/fira.css" rel="stylesheet" type="text/css">
<link href="/styles.css" rel="stylesheet" type="text/css">
<script src="/mathjax-init.js" type="text/javascript" async></script>
<script src="/load-file.js" type="text/javascript" async></script>
<link href="/reveal.css" rel="stylesheet" type="text/css">
<script src="/revealjs/reveal.js" type="module" defer></script>
<script src="/revealjs/notes/plugin.js" type="module" defer></script>
<script src="/reveal-init.js" type="module" defer></script>
<div class="menu">
<a class="menu-btn" id="menu-home" href="/">Akira Kyle</a>
<span style="color: var(--func);">|</span>
<a class="menu-btn" id="menu-papers" href="/papers">papers</a>
<span style="color: var(--func);">|</span>
<a class="menu-btn" id="menu-talks" href="/talks">talks</a>
<span style="color: var(--func);">|</span>
<a class="menu-btn" id="menu-blog" href="/blog">interoam</a>
</div>
(let* ((named-element (org-element-map (org-element-parse-buffer) org-element-all-elements
(lambda (element)
(when (string= (org-element-property :name element) name)
element))
nil t))
(result (org-element-property :value named-element)))
(format "\"%s\"" (replace-regexp-in-string "\\\"" "\\\\\"" result))) ;; escape quote
(setq my-org-html-head
<<blk-to-elisp-str("html-head")>>
)
(setq my-org-html-head-reveal
<<blk-to-elisp-str("html-head-reveal")>>
)
(setq my-org-html-preamble
<<blk-to-elisp-str("html-preamble")>>
)
A bunch of emacs-lisp helper functions
List of notes/pages
(defun my-org-get-env-key (file key)
"Extract the value of keywords on beginning lines starting with `#+:` from `file`"
(with-temp-buffer (insert-file-contents file)
(org-mode)
(cadar (org-collect-keywords (list key)))))
(defun my-note-filenames ()
"Returns a list of all files sorted approprately."
(seq-filter
(lambda (fname)
(not (my-org-get-env-key fname "hide")))
(mapcan (lambda (dir)
(directory-files
(file-name-as-directory (concat my-org-dir dir)) t ".*\\.org$" nil))
'("notes" "config"))))
(defun my-sort-note-filenames (fnames)
"Returns a list of all files sorted approprately."
(sort fnames (lambda (a b)
(>
(org-time-string-to-seconds (my-org-get-env-key a "date"))
(org-time-string-to-seconds (my-org-get-env-key b "date"))))))
(defun my-filenames-to-org-list ()
(seq-reduce
(lambda (acc el) (concat acc "\n- " el))
(seq-map (lambda (fname)
(concat
(org-export-get-date
`(:date ,(org-element-parse-secondary-string
(my-org-get-env-key fname "date")
(org-element-restriction 'keyword))) "~%Y-%m-%d~")
": "
(org-link-make-string
(concat "file:" (file-relative-name fname))
(my-org-get-env-key fname "title"))))
(my-sort-note-filenames (my-note-filenames)))
""))
org roam export backlinks and reflinks and citations
insert-bibliographyeliminates the need for#+print_bibliography:at the end of every filemy-filter-citationsmakes org citations link to the corresponding org-roam nodes- I didn’t end up trying to use the csl formatter to get the nice, configurable inline style, but rather just make the org-roam title close to what the csl formatter would do (yeah this is hacky).
;; TODO: Still need to fix spacing also consider leaving in original citation, just add link to ref-notes only if it exists...
(defun my-filter-citations (data backend info)
(let* ((cite-to-id
(lambda (el)
(let* ((key (concat "@" (org-element-property :key el)))
(node (org-roam-node-from-ref key))
(_ (and (not node) (error "No org roam node for key %s" key)))
(id (org-roam-node-id node))
(title (org-roam-node-title node)))
(org-link-make-string (concat "id:" id) title))))
; (id (if node
; (concat "id:" (org-roam-node-id node))
; (message "No org roam node for key %s" key)
; "id:C2668D73-1846-4A59-82DC-76B911AAE86B"))
; (title (if node
; (org-roam-node-title node)
; key)))
; (org-link-make-string id title))))
(cites-to-ids
(lambda (elts)
(with-temp-buffer
(save-excursion
(insert (concat " (" (mapconcat cite-to-id elts "; ") ") "))
(car (org-element-map (org-element-parse-buffer) 'paragraph
'org-element-contents))))))
(map-citation
(lambda (el)
(unless (org-element-property :style el)
(mapc (lambda (l) (org-element-insert-before l el))
(funcall cites-to-ids (org-element-contents el)))
(org-element-extract-element el)))))
(org-element-map data 'citation map-citation info nil nil t)
data))
(defun insert-bibliography (backend)
"Insert reflinks into the end of the org file before parsing it."
(when (eq backend 'html)
(goto-char (point-min))
(when (re-search-forward "\\[cite:.*\\]" nil t)
(goto-char (point-max))
(insert "\n\n* references\n")
(insert "#+print_bibliography: :title \"references\""))))
;; https://org-roam.discourse.group/t/export-backlinks-on-org-export/1756/2?page=2
(defun collect-backlinks-string (backend)
"Insert backlinks into the end of the org file before parsing it."
(when (and (or (eq backend 'html) (eq backend 'html-with-cite-filter))
(org-roam-node-at-point))
(let* ((backlinks (org-roam-backlinks-get (org-roam-node-at-point))))
(when backlinks
(goto-char (point-max))
(insert "\n\n* backlinks\n")
(dolist (backlink backlinks)
(let* ((source-node (org-roam-backlink-source-node backlink))
(point (org-roam-backlink-point backlink)))
(insert
(format "- [[id:%s][%s]]\n"
(file-name-nondirectory (org-roam-node-id source-node))
(org-roam-node-title source-node)))))))))
(defun collect-reflinks-string (backend)
"Insert reflinks into the end of the org file before parsing it."
(when (and (or (eq backend 'html) (eq backend 'html-with-cite-filter))
(org-roam-node-at-point))
(let* ((reflinks (org-roam-reflinks-get (org-roam-node-at-point))))
(when reflinks
(goto-char (point-max))
(insert "\n\n* reflinks:\n")
(dolist (reflink reflinks)
(let* ((source-node (org-roam-reflink-source-node reflink))
(point (org-roam-reflink-point reflink)))
(unless (string= (org-roam-node-id source-node)
(org-roam-node-id (org-roam-node-at-point)))
(insert
(format "- [[id:%s][%s]]\n"
(file-name-nondirectory (org-roam-node-id source-node))
(org-roam-node-title source-node))))))))))
remove automatically generated ids
- Disable auto id generation in org-mode html export - Emacs Stack Exchange
- unpackaged/org-export-get-reference: Cache of previous export causes error · Issue #21 · alphapapa/unpackaged.el · GitHub
- Globally unique internal links exported by org mode – kozikow blog
- https://www.vidal-rosset.net/the_code_that_runs_this_blog.html
- Re: citeproc-org and org-ref 3
(defun unpackaged/org-export-new-title-reference (datum cache)
"Return new reference for DATUM that is unique in CACHE."
(cl-macrolet ((inc-suffixf (place)
`(progn
(string-match (rx bos
(minimal-match (group (1+ anything)))
(optional "--" (group (1+ digit)))
eos)
,place)
;; HACK: `s1' instead of a gensym.
(-let* (((s1 suffix) (list (match-string 1 ,place)
(match-string 2 ,place)))
(suffix (if suffix
(string-to-number suffix)
0)))
(setf ,place (format "%s--%s" s1 (cl-incf suffix)))))))
(let* ((title-raw (org-element-property :title datum))
(title (org-export-string-as (org-element-interpret-data title-raw) 'org t))
(ref (replace-regexp-in-string "[^a-zA-Z0-9]+" "" title))
(parent (org-element-property :title datum)))
(while (--any (equal ref (car it))
cache)
;; Title not unique: make it so.
(if parent
;; Append ancestor title.
(setf title (concat (org-element-property :title parent) "--" title)
;ref (url-hexify-string (substring-no-properties title))
ref (replace-regexp-in-string "[^a-zA-Z0-9]+" "-" (substring-no-properties title))
parent (org-element-property :parent parent))
;; No more ancestors: add and increment a number.
(inc-suffixf ref)))
ref)))
(defun unpackaged/org-export-get-reference (datum info)
"Like `org-export-get-reference', except uses heading titles instead of random numbers."
(let ((cache (plist-get info :internal-references)))
(or (car (rassq datum cache))
(let* ((crossrefs (plist-get info :crossrefs))
(cells (org-export-search-cells datum))
;; Preserve any pre-existing association between
;; a search cell and a reference, i.e., when some
;; previously published document referenced a location
;; within current file (see
;; `org-publish-resolve-external-link').
;;
;; However, there is no guarantee that search cells are
;; unique, e.g., there might be duplicate custom ID or
;; two headings with the same title in the file.
;;
;; As a consequence, before re-using any reference to
;; an element or object, we check that it doesn't refer
;; to a previous element or object.
(new (or (cl-some
(lambda (cell)
(let ((stored (cdr (assoc cell crossrefs))))
(when stored
(let ((old stored))
(and (not (assoc old cache)) stored)))))
cells)
(when (org-element-property :raw-value datum)
;; Heading with a title
(unpackaged/org-export-new-title-reference datum cache))
;; NOTE: This probably breaks some Org Export
;; feature, but if it does what I need, fine.
(org-export-format-reference
(org-export-new-reference cache))))
(reference-string new))
;; Cache contains both data already associated to
;; a reference and in-use internal references, so as to make
;; unique references.
(dolist (cell cells) (push (cons cell new) cache))
;; Retain a direct association between reference string and
;; DATUM since (1) not every object or element can be given
;; a search cell (2) it permits quick lookup.
(push (cons reference-string datum) cache)
(plist-put info :internal-references cache)
reference-string))))
(advice-add #'org-export-get-reference :override #'unpackaged/org-export-get-reference)
;(advice-remove #'org-export-get-reference #'unpackaged/org-export-get-reference)
org-publish setup
;; I use the ~#+modified:~ property rather than org's default of using the
;; file's modification time, since my org files are in git
(defun my-org-html-build-preamble (info)
(let* ((spec (org-html-format-spec info))
(date (cdr (assq ?d spec)))
(timestamp-format (plist-get info :html-metadata-timestamp-format))
(modified-str (cadar (org-collect-keywords '("modified"))))
(modified-parsed (org-element-parse-secondary-string
modified-str (org-element-restriction 'keyword)))
(modified (org-export-get-date `(:date ,modified-parsed)
timestamp-format)))
(concat
my-org-html-preamble
(and (plist-get info :with-date)
(org-string-nw-p date)
(format "<p class=\"date\">Created: %s</p>\n" date))
(and (plist-get info :with-date)
(org-string-nw-p modified)
(format "<p class=\"date\">Last modified: %s</p>\n" modified)))))
;;(setq org-export-async-init-file (expand-file-name "~/notebook/setup.el")
;; org-export-in-background t)
(setq org-html-metadata-timestamp-format "%B %e, %Y")
(setq org-html-htmlize-output-type 'css)
(setq org-html-html5-fancy t)
(setq org-html-doctype "html5")
(setq org-export-with-toc nil)
(setq org-export-with-section-numbers nil)
(setq org-export-time-stamp-file nil)
(setq org-html-head-include-default-style nil)
(setq org-html-head-include-scripts nil)
(setq org-html-head my-org-html-head)
(setq org-html-preamble 'my-org-html-build-preamble)
(setq org-html-postamble nil)
(setq org-html-mathjax-template "")
(setq org-html-self-link-headlines t)
(setq org-html-prefer-user-labels t)
;; for org-html-link to omit .html from a href links
(setq org-html-extension "")
(org-export-define-derived-backend 'html-with-cite-filter 'html)
(defun my-org-html-publish-to-html (plist filename pub-dir)
(org-publish-org-to 'html filename ".html" plist pub-dir))
(defun my-org-html-publish-to-html-with-cite-filter (plist filename pub-dir)
(let ((org-export-filter-parse-tree-functions '(my-filter-citations)))
(org-publish-org-to 'html-with-cite-filter filename ".html" plist pub-dir)))
(add-hook 'org-export-before-processing-functions 'insert-bibliography)
(add-hook 'org-export-before-processing-functions 'collect-backlinks-string)
(add-hook 'org-export-before-processing-functions 'collect-reflinks-string)
(defun my-publish-collab-dir (dir)
`(,dir
:base-directory ,(concat my-org-dir dir)
:publishing-directory ,(concat my-website-publish-dir dir my-collab-url)
:publishing-function my-org-html-publish-to-html-with-cite-filter))
;; :html-head-extra ,my-org-html-head-reveal
(defun my-publish-dir (dir)
`(,dir
:base-directory ,(concat my-org-dir dir)
:publishing-directory ,(concat my-website-publish-dir dir)
:publishing-function my-org-html-publish-to-html))
;;:html-postamble "Insert comments here..."))
(setq org-publish-project-alist
`(
,(cons "top" (cdr (my-publish-dir "")))
,(my-publish-dir "config")
,(my-publish-dir "notes")
,(my-publish-dir "talks")
,(my-publish-collab-dir "notebook")
,(my-publish-collab-dir "present")
,(my-publish-collab-dir "ref-notes")
("website" :components ("top" "config" "notes" "talks"))
))
<<org-html-strings>>
<<org-dir-vars>>
<<org-html-export-remove-auto-id>>
<<list-org-files>>
<<org-roam-export-helpers>>
<<org-publish-project>>
(org-publish "website" t)
Need to run org-id-update-id-locations and org-roam-update-org-id-locations when exporting and get “org-export-data: Unable to resolve link”
dir locals
((org-mode . (
(eval . (add-hook 'after-save-hook 'org-publish-current-file nil t))
(eval . (setq-local org-html-head-extra my-org-html-head-reveal))
;(org-html-head-extra . my-org-html-head-reveal)
;(org-html-preamble . nil)
;(org-export-with-title . nil)
)))
<<talk-dir-locals>>
<<talk-dir-locals>>
Mathjax JS
https://groups.google.com/g/mathjax-users/c/M6Uh4ANEdPU https://github.com/mathjax/MathJax/issues/3304 https://github.com/mathjax/MathJax/issues/3392
window.MathJax = {
options: {
menuOptions: {
settings: {
enrich: false,
}
},
},
loader: {
load: ['[tex]/physics', '[tex]/mathtools']
},
tex: {
packages: {'[+]': ['physics', 'mathtools']},
tags: "ams",
ams: {
multlineWidth: "85%"
},
mathtools: {
'use-unicode': true
}
},
output: {
font: 'mathjax-fira',
fontPath: '/mathjax/fira-font'
}
};
(function () {
var script = document.createElement('script');
script.src = '/mathjax/tex-chtml-nofont.js';
script.async = true;
document.head.appendChild(script);
})();
load-file js
Inspired by js from
- Interaction with SVG · Issue #1626 · hakimel/reveal.js · GitHub
- GitHub - ranr01/reveal-inline-svg: Automatically inlines SVG file in Reveal.js presentations. Allows the application of fragments, animations etc.to SVG DOM elements.
- 〈load-file〉Web Component, add external content to the DOM - DEV Community
customElements.define("load-file", class extends HTMLElement {
async connectedCallback() {
const shadowRoot = this.attachShadow({mode:"open"});
shadowRoot.innerHTML = await (await fetch(this.getAttribute("src"))).text();
this.querySelectorAll("param").forEach(function(p) {
var svg_elem = shadowRoot.querySelector("#".concat(p.getAttribute("id")));
for (const attr of p.attributes) {
svg_elem.setAttribute(attr.name, attr.value);
}
});
this.replaceWith(...shadowRoot.childNodes);
}
})
Reveal JS
import Reveal from './revealjs/index.js'
import RevealNotes from './revealjs/notes/plugin.js'
function replaceWithSection(el) {
let sec = document.createElement("section");
sec.innerHTML = el.innerHTML;
for (const name of el.getAttributeNames()) {
const value = el.getAttribute(name);
sec.setAttribute(name, value);
}
el.parentNode.replaceChild(sec, el);
}
let content = document.getElementById("content");
let parent = content.parentNode;
let wrapper = document.createElement("div");
for (const el of document.getElementsByTagName("header")) {
parent.insertBefore(el, content);
}
parent.insertBefore(wrapper, content);
wrapper.appendChild(content);
document.querySelectorAll("div.outline-3").forEach(replaceWithSection);
document.querySelectorAll("div.outline-2").forEach(replaceWithSection);
content.classList.add("slides");
wrapper.classList.add("reveal");
wrapper.style.height = "378px";
Reveal.initialize({
width: 1920,
height: 1080,
hash: true,
controls: false,
slideNumber: 'c',
transition: "none",
viewDistance: 4,
hideCursorTime: 1000,
embedded: true,
//disableLayout: true,
center: false,
margin: 0,
pdfMaxPagesPerSlide: 1,
//pdfSeparateFragments: false,
plugins: [ RevealNotes ]
});
Reveal.addEventListener("ready", function addFragmentToLists() {
for (const listItem of document.querySelectorAll(".fragmented-list li")) {
listItem.classList.add("fragment");
}
});
/*
Reveal.on('ready', event => {
Reveal.configure({ slideNumber: !(event.indexh === 0) });
});
Reveal.addEventListener('slidechanged', (event) => {
Reveal.configure({ slideNumber: !(event.indexh === 0) });
});
*/
svg favicon
<svg width="86pt" height="86pt" version="1.1" viewBox="0 0 86 86" xmlns="http://www.w3.org/2000/svg">
<style>
@media (prefers-color-scheme: dark) {
.grid {
stroke: white;
fill: none;
stroke-width: 2.1918;
stroke-miterlimit: 10;
clip-path: url(#clip);
}
.node {fill: white;}
.outl {
stroke: white;
fill: none;
stroke-width: .797;
stroke-miterlimit: 10;
}
.arro {
stroke: white;
fill: white;
stroke-width: .797;
stroke-miterlimit: 10;
}
}
@media (prefers-color-scheme: light) {
.grid {
stroke: black;
fill: none;
stroke-width: 2.1918;
stroke-miterlimit: 10;
clip-path: url(#clip);
}
.node {fill: black;}
.outl {
stroke: black;
fill: none;
stroke-width: .797;
stroke-miterlimit: 10;
}
.arro {
stroke: black;
fill: black;
stroke-width: .797;
stroke-miterlimit: 10;
}
}
</style>
<defs>
<clipPath id="clip">
<path d="m61.578 29.039-36.824-21.258-36.824 21.258v42.52l36.824 21.262 36.824-21.262z"/>
</clipPath>
</defs>
<g id="page" transform="translate(18.246 -7.3008)">
<path class="grid" d="m81.445 50.301h-56.691" clip-path="url(#clip)"/>
<path class="grid" d="m53.098 1.2031-28.344 49.098" clip-path="url(#clip)"/>
<path class="grid" d="m-3.5937 1.2031 28.348 49.098" clip-path="url(#clip)"/>
<path class="grid" d="m-31.941 50.301h56.695" clip-path="url(#clip)"/>
<path class="grid" d="m-3.5937 99.398 28.348-49.098" clip-path="url(#clip)"/>
<path class="grid" d="m53.098 99.398-28.344-49.098" clip-path="url(#clip)"/>
<path class="grid" d="m67.273 25.75h-85.039l42.52 73.648z" clip-path="url(#clip)"/>
<path class="grid" d="m24.754 1.2031-42.52 73.645h85.039z" clip-path="url(#clip)"/>
<path class="node" d="m57.066 50.301c0-2.1914-1.7734-3.9688-3.9687-3.9688-2.1914 0-3.9649 1.7773-3.9649 3.9688s1.7735 3.9688 3.9649 3.9688c2.1953 0 3.9687-1.7773 3.9687-3.9688z"/>
<path class="node" d="m42.894 25.75c0-2.1914-1.7773-3.9688-3.9687-3.9688s-3.9688 1.7774-3.9688 3.9688 1.7774 3.9687 3.9688 3.9687 3.9687-1.7773 3.9687-3.9687z"/>
<path class="node" d="m14.547 25.75c0-2.1914-1.7774-3.9688-3.9688-3.9688s-3.9687 1.7774-3.9687 3.9688 1.7773 3.9687 3.9687 3.9687 3.9688-1.7773 3.9688-3.9687z"/>
<path class="node" d="m0.375 50.301c0-2.1914-1.7773-3.9688-3.9687-3.9688-2.1915 0-3.9688 1.7773-3.9688 3.9688s1.7773 3.9688 3.9688 3.9688c2.1914 0 3.9687-1.7773 3.9687-3.9688z"/>
<path class="node" d="m14.547 74.848c0-2.1915-1.7774-3.9688-3.9688-3.9688s-3.9687 1.7773-3.9687 3.9688c0 2.1914 1.7773 3.9687 3.9687 3.9687s3.9688-1.7773 3.9688-3.9687z"/>
<path class="node" d="m42.894 74.848c0-2.1915-1.7773-3.9688-3.9687-3.9688s-3.9688 1.7773-3.9688 3.9688c0 2.1914 1.7774 3.9687 3.9688 3.9687s3.9687-1.7773 3.9687-3.9687z"/>
<path class="node" d="m28.723 50.301c0-2.1914-1.7774-3.9688-3.9688-3.9688-2.1914 0-3.9687 1.7773-3.9687 3.9688s1.7773 3.9688 3.9687 3.9688c2.1914 0 3.9688-1.7773 3.9688-3.9688z"/>
<path class="outl" d="m61.578 29.039-36.824-21.258-36.824 21.258v42.52l36.824 21.262 36.824-21.262z"/>
<path class="arro" d="m43.812 18.781 2.8086 3.4375-0.40625-2.0469 1.9766-0.67188z"/>
<path class="arro" d="m38.117 15.496 2.8125 3.4375-0.41016-2.0508 1.9805-0.67187z"/>
<path class="arro" d="m10.086 16.25 4.3828-0.71875-1.9805-0.67188 0.41015-2.0469z"/>
<path class="arro" d="m4.3906 19.535 4.3828-0.71485-1.9766-0.67187 0.40625-2.0508z"/>
<path class="arro" d="m-1.3047 22.824 4.3828-0.71875-1.9766-0.67188 0.40625-2.0469z"/>
<path class="arro" d="m-12.07 47.855 1.5703 4.1523-1.5703-1.3789-1.5703 1.3789z"/>
<path class="arro" d="m0.24218 78.668 4.3789 0.71485-1.9766 0.67187 0.40625 2.0508z"/>
<path class="arro" d="m5.9336 81.957 4.3828 0.71485-1.9766 0.67187 0.40625 2.0469z"/>
<path class="arro" d="m35.691 86.504 2.8125-3.4375-0.40625 2.0508 1.9766 0.67187z"/>
<path class="arro" d="m41.387 83.215 2.8125-3.4336-0.41015 2.0469 1.9805 0.67188z"/>
<path class="arro" d="m47.082 79.93 2.8086-3.4375-0.40625 2.0469 1.9805 0.67188z"/>
<path class="arro" d="m61.578 48.441-1.5703 4.1524 1.5703-1.3789 1.5703 1.3789z"/>
</g>
</svg>
Preview with simple-httpd
(require 'simple-httpd)
(defun httpd-gen-path (path &optional root)
"Translate GET to secure path in ROOT (`httpd-root')."
(let ((clean (expand-file-name (httpd-clean-path path) (or root httpd-root))))
(if (file-directory-p clean)
(let* ((dir (file-name-as-directory clean))
(indexes (cl-mapcar (apply-partially 'concat dir) httpd-indexes))
(existing (cl-remove-if-not 'file-exists-p indexes)))
(or (car existing) dir))
(if (file-exists-p clean)
clean
(concat clean ".html")))))
(setq httpd-root my-website-publish-dir)
(setq httpd-listings t)
(setq httpd-host "0.0.0.0")
(httpd-start)
find leaky links
wget -r localhost:8080