157 lines
6.6 KiB
EmacsLisp
Executable File
157 lines
6.6 KiB
EmacsLisp
Executable File
;;; build-html.el --- HTML export customisation -*- lexical-binding: t; -*-
|
|
|
|
;;; Code:
|
|
|
|
(require 'org)
|
|
(require 'ox-html)
|
|
(require 'subr-x)
|
|
(require 'tags)
|
|
(require 'sidenotes)
|
|
(require 'build-comments)
|
|
|
|
(setq org-export-global-macros
|
|
(append
|
|
org-export-global-macros
|
|
'(("sidenote"
|
|
. "@@html:<label for=\"sn$1\" class=\"margin-toggle sidenote-number\"></label>\
|
|
<input type=\"checkbox\" id=\"sn$1\" class=\"margin-toggle\"/>\
|
|
<span class=\"sidenote\">$2</span>@@")
|
|
("epigraph"
|
|
. "@@html:<div class=\"epigraph\"><blockquote>$1<footer>$2</footer></blockquote></div>@@")
|
|
("epigraph_single"
|
|
. "@@html:<div class=\"epigraph\"><blockquote>$1</blockquote></div>@@")
|
|
("epigraph3"
|
|
. "@@html:<div class=\"epigraph\"><blockquote>$1<footer>$2, <cite>$3</cite></footer></blockquote></div>@@")
|
|
("kbd"
|
|
. "@@html:<kbd>$1</kbd>@@@@latex:\\texttt{$1}@@")
|
|
("margimg"
|
|
. "@@html:<aside class=\"marginnote\"><figure class=\"mn-fig\">\
|
|
<img src=\"$1\" alt=\"$2\" class=\"mn-img\" loading=\"lazy\" decoding=\"async\"/>$3\
|
|
</figure></aside>@@")
|
|
("countdown"
|
|
. "@@html:<time class=\"countdown\" datetime=\"$1\" data-label=\"$2\"></time>@@"))))
|
|
|
|
(defvar z/preamble
|
|
"<div class=\"banner-header\" role=\"banner\">
|
|
<a class=\"site-brand\" href=\"/\" aria-label=\"Home\">
|
|
<img src=\"/assets/images/gr.png\" alt=\"\" class=\"banner-logo\" />
|
|
<span class=\"site-brand__text\">zxh</span>
|
|
</a>
|
|
<nav class=\"site-nav\" aria-label=\"Primary\">
|
|
<a href=\"/\">Home</a>
|
|
<a href=\"/blogs/blogs-list.html\">Blogs</a>
|
|
<a href=\"/posts/career/career-list.html\">Career</a>
|
|
<a href=\"/play/play.html\">Play</a>
|
|
<a href=\"https://zone.zainezq.com\">Dashboard</a>
|
|
</nav>
|
|
<div class=\"site-actions\">
|
|
<label class=\"site-search\" for=\"search-input\">
|
|
<span class=\"visually-hidden\">Search notes</span>
|
|
<input type=\"search\" id=\"search-input\" placeholder=\"Search notes\" aria-label=\"Search notes\" />
|
|
</label>
|
|
<button id=\"search-btn\" aria-label=\"Search\" type=\"button\">Search</button>
|
|
<button class=\"theme-toggle\" id=\"theme-toggle\" type=\"button\" aria-label=\"Switch theme\">Theme</button>
|
|
</div>
|
|
</div>
|
|
<div id=\"updated\">Updated: %C</div>
|
|
")
|
|
|
|
(defvar z/postamble
|
|
"<footer>
|
|
<div class=\"copyright-container\">
|
|
<div class=\"copyright\">
|
|
Copyright © 2022-2026 Zaine Qayyum. All rights reserved unless otherwise noted.</div></div>
|
|
<div class=\"generated\">
|
|
Created with %c on <a href=\"https://www.archlinux.org/\">Arch</a> \
|
|
<a href=\"https://www.gnu.org\">GNU</a>/<a href=\"https://www.kernel.org/\">Linux</a>
|
|
</div>
|
|
</footer>")
|
|
|
|
(defun z/org-html-src-block-mermaid (orig-fun src-block contents info)
|
|
"Export Mermaid source blocks as Mermaid divs."
|
|
(let ((lang (org-element-property :language src-block)))
|
|
(if (string= lang "mermaid")
|
|
(let ((code (org-remove-indentation
|
|
(org-element-property :value src-block))))
|
|
(format "<div class=\"mermaid\">\n%s\n</div>" code))
|
|
(funcall orig-fun src-block contents info))))
|
|
|
|
(advice-add 'org-html-src-block :around #'z/org-html-src-block-mermaid)
|
|
|
|
(defun z/org-html-add-body-classes (output backend info)
|
|
"Add layout-related classes to <body> based on file metadata."
|
|
(if (and (org-export-derived-backend-p backend 'html)
|
|
(not (and (fboundp 'z/rpg-standalone-file-p)
|
|
(z/rpg-standalone-file-p info))))
|
|
(let* ((input-file (plist-get info :input-file))
|
|
(classes
|
|
(delq nil
|
|
(list
|
|
(when (and input-file (z/no-sidenotes-file-p input-file))
|
|
"no-sidenotes")))))
|
|
(if classes
|
|
(replace-regexp-in-string
|
|
"<body\\([^>]*\\)>"
|
|
(format "<body\\1 class=\"%s\">"
|
|
(string-join classes " "))
|
|
output)
|
|
output))
|
|
output))
|
|
|
|
(add-to-list 'org-export-filter-final-output-functions
|
|
#'z/org-html-add-body-classes)
|
|
(add-to-list 'org-export-filter-body-functions
|
|
#'z/org-html-insert-comments-into-body)
|
|
|
|
(defconst z/rpg-standalone-start "<!-- RPG-STANDALONE-START -->")
|
|
(defconst z/rpg-standalone-end "<!-- RPG-STANDALONE-END -->")
|
|
|
|
(defun z/rpg-standalone-file-p (info)
|
|
"Return non-nil when INFO describes the dedicated RPG page."
|
|
(let ((input-file (plist-get info :input-file)))
|
|
(and input-file
|
|
(string= (file-truename input-file)
|
|
(file-truename (site-path "play/rpg.org"))))))
|
|
|
|
(defun z/render-rpg-standalone (output backend info)
|
|
"Replace normal site chrome with a dedicated game document for the RPG."
|
|
(if (and (org-export-derived-backend-p backend 'html)
|
|
(z/rpg-standalone-file-p info))
|
|
(let* ((start (string-match (regexp-quote z/rpg-standalone-start) output))
|
|
(end (and start (string-match (regexp-quote z/rpg-standalone-end) output start))))
|
|
(if (and start end)
|
|
(let* ((body-start (+ start (length z/rpg-standalone-start)))
|
|
(body (substring output body-start end))
|
|
(body (replace-regexp-in-string
|
|
"<link rel=\"stylesheet\" href=\"/assets/styles/pages/princess-lima-rpg.css[^\"]*\" />"
|
|
""
|
|
body)))
|
|
(concat
|
|
"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n"
|
|
"<meta charset=\"utf-8\" />\n"
|
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\" />\n"
|
|
"<meta name=\"theme-color\" content=\"#080a12\" />\n"
|
|
"<meta name=\"description\" content=\"A storybook pixel fantasy RPG about helping a wounded kingdom and rescuing Princess Lima.\" />\n"
|
|
"<title>Rescue Princess Lima</title>\n"
|
|
"<link rel=\"icon\" href=\"/assets/icons/icons8-film-tape-100.png\" />\n"
|
|
"<link rel=\"stylesheet\" href=\"/assets/styles/pages/princess-lima-rpg.css?v=princess-lima-2.0.0\" />\n"
|
|
"</head>\n<body class=\"princess-lima-page\">\n"
|
|
body
|
|
"\n</body>\n</html>\n"))
|
|
output))
|
|
output))
|
|
|
|
(add-to-list 'org-export-filter-final-output-functions
|
|
#'z/render-rpg-standalone)
|
|
|
|
(org-export-define-derived-backend 'z-html 'html
|
|
:filters-alist '((:filter-final-output . z/insert-filetags-after-title)))
|
|
|
|
(defun z/z-publish-to-html (plist filename pub-dir)
|
|
"Publish FILENAME to HTML using the z-html backend."
|
|
(org-publish-org-to 'z-html filename ".html" plist pub-dir))
|
|
|
|
(provide 'build-html)
|
|
|
|
;;; build-html.el ends here
|