Configuration for this Website
This is the entire configuration for this website including the css styling and org-publish configuration. The features this website supports can be seen here. Ideas for features I’d like to implement in the future can be found here.
CSS
Doom One Dark Theme
https://github.com/doomemacs/themes
@media (prefers-color-scheme: dark) { :root { --bg : #282c34; --fg : #bbc2cf; --bg-alt : #21242b; --fg-alt : #5B6268; --base0 : #1B2229; --base1 : #1c1f24; --base2 : #202328; --base3 : #23272e; --base4 : #3f444a; --base5 : #5B6268; --base6 : #73797e; --base7 : #9ca0a4; --base8 : #DFDFDF; --grey : #3f444a; --red : #ff6c6b; --i-red : #ce537a; --orange : #da8548; --green : #98be65; --i-green : #2d9574; --teal : #4db5bd; --yellow : #ECBE7B; --blue : #51afef; --dark-blue : #2257A0; --magenta : #c678dd; --violet : #a9a1e1; --cyan : #46D9FF; --dark-cyan : #5699AF; } }
Doom One Light Theme
@media (prefers-color-scheme: light) { :root { --bg : #fafafa; --fg : #383a42; --bg-alt : #f0f0f0; --fg-alt : #c6c7c7; --base0 : #f0f0f0; --base1 : #e7e7e7; --base2 : #dfdfdf; --base3 : #c6c7c7; --base4 : #9ca0a4; --base5 : #383a42; --base6 : #202328; --base7 : #1c1f24; --base8 : #1b2229; --grey : #9ca0a4; --red : #e45649; --i-red : #e45649; --orange : #da8548; --green : #50a14f; --i-green : #50a14f; --teal : #4db5bd; --yellow : #986801; --blue : #4078f2; --dark-blue : #a0bcf8; --magenta : #a626a4; --violet : #b751b6; --cyan : #0184bc; --dark-cyan : #005478; } }
elements
Much of this is from org-html-style-default
body { font-family: "Helvetica Neue", Helvetica, sans-serif; color: var(--fg); background-color: var(--bg); max-width: 42em; margin: auto; } #preamble { text-align: center; } #postamble { text-align: center; margin: 2em; } .menu { display: inline-block; padding: 0.2em; position: relative; background-color: var(--base0); border-radius: 0.2em; } button { border: none; background-color: inherit; font-size: inherit; font: inherit; cursor: pointer; color: var(--blue); } button:hover { text-decoration: underline; } .menu-btn { display: inline-block; width: 6em; transition: all 0.2s ease; color: var(--fg); padding: 0.3em; margin: 0.2em; border-radius: 0.2em; border: 2px solid var(--magenta); fill: var(--fg); } .menu-btn:hover { background-color: var(--magenta); color: var(--base0); fill: var(--base0); } a { color: var(--blue); background-color: inherit; font: inherit; text-decoration: inherit; } a:hover { text-decoration: underline; } .title { text-align: center; margin-bottom: .2em; } .subtitle { text-align: center; font-size: medium; font-weight: bold; margin-top:0; } .todo { font-family: monospace; color: red; } .done { font-family: monospace; color: green; } .priority { font-family: monospace; color: orange; } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal; } .timestamp { color: var(--fg-alt); } .timestamp-kwd { color: var(--dark-cyan); } .org-right { margin-left: auto; margin-right: 0px; text-align: right; } .org-left { margin-left: 0px; margin-right: auto; text-align: left; } .org-center { margin-left: auto; margin-right: auto; text-align: center; } .underline { text-decoration: underline; } #postamble p, #preamble p { font-size: 90%; margin: .2em; } p.verse { margin-left: 3%; } table { border-collapse:collapse; } caption.t-above { caption-side: top; } caption.t-bottom { caption-side: bottom; } td, th { vertical-align:top; } th.org-right { text-align: center; } th.org-left { text-align: center; } th.org-center { text-align: center; } td.org-right { text-align: right; } td.org-left { text-align: left; } td.org-center { text-align: center; } dt { font-weight: bold; } .footpara { display: inline; } .footdef { margin-bottom: 1em; } .figure { padding: 1em; } .figure p { text-align: center; } .equation-container { display: table; text-align: center; width: 100%; } .equation { vertical-align: middle; } .equation-label { display: table-cell; text-align: right; vertical-align: middle; } .inlinetask { padding: 10px; border: 2px solid gray; margin: 10px; background: #ffffcc; } #org-div-home-and-up { text-align: right; font-size: 70%; white-space: nowrap; } textarea { overflow-x: auto; } .linenr { font-size: smaller } .code-highlighted { background-color: #ffff00; } .org-info-js_info-navigation { border-style: none; } #org-info-js_console-label { font-size: 10px; font-weight: bold; white-space: nowrap; } .org-info-js_search-highlight { background-color: #ffff00; color: #000000; font-weight: bold; } .org-svg { width: 90%; } .org-src-container { } .org-ul {}
org classes
.org-builtin {color: var(--magenta);} .org-comment {color: var(--fg-alt);} .org-comment-delimiter {color: var(--fg-alt);} .org-constant {color: var(--violet);} .org-css-property {color: var(--green);} .org-css-selector {color: var(--blue);} .org-doc {color: #83898d;} .org-font-latex-bold {font-weight: bold;} .org-font-latex-math {color: var(--green);} .org-font-latex-script-char {color: var(--dark-blue);} .org-font-latex-sedate {color: #d3d3d3;} .org-function-name {color: var(--magenta);} .org-keyword {color: var(--blue);} .org-operator {} .org-whitespace-line { color: var(--red); background-color: var(--base0); font-weight: bold; } .org-negation-char { color: var(--blue); font-weight: bold; } .org-org-block { background-color: var(--base3); } .org-org-block-begin-line { color: var(--fg-alt); background-color: var(--base3); } .org-org-block-end-line { color: var(--fg-alt); background-color: var(--base3); } .org-org-meta-line {color: #83898d;} .org-org-target {text-decoration: underline;} .org-rainbow-delimiters-depth-1 {color: var(--blue);} .org-rainbow-delimiters-depth-2 {color: var(--magenta);} .org-rainbow-delimiters-depth-3 {color: var(--green);} .org-rainbow-delimiters-depth-4 {color: var(--violet);} .org-rainbow-delimiters-depth-5 {color: var(--teal);} .org-rainbow-delimiters-depth-6 {color: var(--blue);} .org-rainbow-delimiters-depth-7 {color: var(--magenta);} .org-rainbow-delimiters-depth-8 {color: var(--green);} .org-rainbow-delimiters-depth-9 {color: var(--violet);} .org-regexp-grouping-backslash { color: var(--blue); font-weight: bold; } .org-regexp-grouping-construct { color: var(--blue); font-weight: bold; } .org-sh-heredoc {color: var(--green);} .org-sh-quoted-exec { color: var(--blue); font-weight: bold; } .org-string {color: var(--green);} .org-type {color: var(--yellow);} .org-variable-name {color: #dcaeea;} .org-warning {color: var(--yellow);} .org-diff-added { color: var(--green); background-color: var(--bg-alt); } .org-diff-changed { color: var(--violet); } .org-diff-changed-unspecified { color: var(--violet); background-color: #333333; } .org-diff-context {} .org-diff-error { color: #ff0000; background-color: #000000; font-weight: bold; } .org-diff-file-header {color: var(--blue);} .org-diff-function {color: var(--cyan);} .org-diff-header {color: var(--cyan);} .org-diff-hunk-header {color: var(--violet);} .org-diff-index {color: var(--blue);} .org-diff-indicator-added { color: #22aa22; background-color: var(--bg-alt); } .org-diff-indicator-changed {color: #aaaa22;} .org-diff-indicator-removed { color: #aa2222; background-color: var(--base3); } .org-diff-nonexistent {color: var(--blue);} .org-diff-refine-added { color: var(--green); background-color: var(--bg-alt); } .org-diff-refine-changed {color: var(--violet);} .org-diff-refine-removed { color: var(--red); background-color: var(--base3); } .org-diff-removed { color: var(--red); background-color: var(--base3); }
Source Code
pre { border: 1px solid #e6e6e6; border-radius: 3px; padding: 8pt; font-family: monospace; overflow: auto; margin: 1.2em; } pre.src { position: relative; overflow: auto; } pre.src:before { display: none; position: absolute; top: -8px; right: 12px; padding: 3px; color: #555; background-color: #f2f2f299; } pre.src:hover:before { display: inline; margin-top: 14px;} pre.src-C:before { content: 'C'; } pre.src-css:before { content: 'CSS'; } pre.src-dot:before { content: 'Graphviz'; } pre.src-calc:before { content: 'Emacs Calc'; } pre.src-emacs-lisp:before { content: 'Emacs Lisp'; } pre.src-elisp:before { content: 'Emacs Lisp'; } pre.src-fortran:before { content: 'Fortran'; } pre.src-haskell:before { content: 'Haskell'; } pre.src-js:before { content: 'Javascript'; } pre.src-latex:before { content: 'LaTeX'; } pre.src-lisp:before { content: 'Lisp'; } pre.src-lua:before { content: 'Lua'; } pre.src-org:before { content: 'Org mode'; } pre.src-python:before { content: 'Python'; } pre.src-jupyter-python:before { content: 'Jupyter Python'; } pre.src-jupyter-julia:before { content: 'Jupyter Julia'; } pre.src-ruby:before { content: 'Ruby'; } pre.src-scheme:before { content: 'Scheme'; } pre.src-sed:before { content: 'Sed'; } pre.src-sh:before { content: 'shell'; } pre.src-makefile:before { content: 'Makefile'; } pre.src-perl:before { content: 'Perl'; } pre.src-shell:before { content: 'Shell Script'; } pre.src-cpp:before { content: 'C++'; } pre.src-bash:before { content: 'bash'; } pre.src-html:before { content: 'HTML'; } pre.src-prolog:before { content: 'Prolog'; } pre.src-tex:before { content: 'TeX'; } pre.src-plain-tex:before { content: 'Plain TeX'; } pre.src-conf:before { content: 'Configuration File'; }
JS
/* @licstart The following is the entire license notice for the JavaScript code in this tag. Copyright (C) 2012-2019 Free Software Foundation, Inc. The JavaScript code in this tag is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License (GNU GPL) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The code is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. As additional permission under GNU GPL version 3 section 7, you may distribute non-source (e.g., minimized or compacted) forms of that code without the copy of the GNU GPL normally required by section 4, provided you include this license notice and a URL through which recipients can access the Corresponding Source. @licend The above is the entire license notice for the JavaScript code in this tag. */ function CodeHighlightOn(elem, id) { var target = document.getElementById(id); if(null != target) { elem.cacheClassElem = elem.className; elem.cacheClassTarget = target.className; target.className = "code-highlighted"; elem.className = "code-highlighted"; } } function CodeHighlightOff(elem, id) { var target = document.getElementById(id); if(elem.cacheClassElem) elem.className = elem.cacheClassElem; if(elem.cacheClassTarget) target.className = elem.cacheClassTarget; }
HTML
https://css-tricks.com/svg-favicons-and-all-the-fun-things-we-can-do-with-them/
<script src="/scripts.js" type="text/javascript"></script> <link href="/styles.css" rel="stylesheet" type="text/css"> <link href="/favicon.svg" rel="icon" type="image/svg+xml">
<div class="menu"> <a class="menu-btn" href="/">Akira Kyle</a> <span style="color: var(--func);">|</span> <a class="menu-btn" href="/blog">Blogoroam</a> </div>
<script> MathJax = { chtml: { displayAlign: "center", displayIndent: "0em", scale: 1 }, svg: { scale: 1 }, tex: { tags: "ams", multlineWidth: "85%", tagSide: "right", tagIndent: ".8em", autoload: { color: [], colorV2: ['color'] }, packages: {'[+]': ['physics']} }, options: { ignoreHtmlClass: 'tex2jax_ignore', processHtmlClass: 'tex2jax_process' }, loader: { load: ['[tex]/physics'] } }; </script> <script type="text/javascript" id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"> </script>
Emacs Lisp org-publish
See How I publish my wiki with org-publish for another take on exporting org-roam using org-publish.
(setq my-org-dir (file-name-as-directory "~/org")) (setq my-org-publish-dir (file-name-as-directory "~/www/org")) (setq my-website-publish-dir (file-name-as-directory "~/www/akirakyle.com"))
List of notes/pages
(defun my-org-get-env-key (post-filename key) "Extract the value of `#+title:`, `#+author:`, `#+date:`, or `#+filetags:` from post-filename." (with-temp-buffer (insert-file-contents post-filename) (cadar (org-collect-keywords (list key))))) (defun my-notes-filenames () "Returns a list of all files sorted approprately." (sort (mapcan (lambda (dir) (directory-files (file-name-as-directory (concat my-org-dir dir)) t ".*\\.org$" nil)) '("notes" "config")) (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 (post-filenames) (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")))) post-filenames) ""))
org roam export backlinks and reflinks and citations
insert-bibliography
eliminates the need for#+print_bibliography:
at the end of every filemy-filter-citations
makes 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 (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)))) (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))))))))))
publish config
(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
;; 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 <<blk-to-elisp-str("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 <<blk-to-elisp-str("html-header")>> ) (setq org-html-preamble 'my-org-html-build-preamble) (setq org-html-postamble nil) (setq org-html-mathjax-template <<blk-to-elisp-str("mathjax-script")>> ) ;; 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) (setq collab-url "collab/") (defun my-publish-dir-with-cite-filter (dir) `(,dir :base-directory ,(concat my-org-dir dir) :publishing-directory ,(concat my-website-publish-dir collab-url dir) :publishing-function my-org-html-publish-to-html-with-cite-filter)) (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-with-cite-filter "ref-notes") ,(my-publish-dir-with-cite-filter "notebook") ,(my-publish-dir-with-cite-filter "rough") ;("pub" ; :exclude "info/.*\\|rough/.*\\|notebook/.*\\|ref-notes/.*" ; :recursive t) ("resources" :base-directory ,my-org-dir :publishing-directory ,my-website-publish-dir :base-extension "svg" :publishing-function org-publish-attachment) ("website" :components ("top" "config" "notes" "resources")) )) (defun my-tangle-website-js-css () (org-babel-tangle-file (concat my-org-dir "config/website.org") (concat my-website-publish-dir "styles.css") "css") (org-babel-tangle-file (concat my-org-dir "config/website.org") (concat my-website-publish-dir "scripts.js") "js"))
<<org-dir-vars>> <<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”
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)