Skip to content

Instantly share code, notes, and snippets.

Last active June 13, 2023 13:58
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save pdxmph/1d17833f910dbfd86068d94cfac585f9 to your computer and use it in GitHub Desktop.
Configuration to publish Denote directory to Web.

;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-

DenoteGeneral settings

(use-package denote
(setq denote-directory "/Users/mph/org/notes")
(setq denote-infer-keywords t)
(setq denote-sort-keywords t)
(setq denote-file-type 'org) ; Org is the default, set others here
(setq denote-prompts '(title keywords))
;; Pick dates, where relevant, with Org's advanced interface:
(setq denote-date-prompt-use-org-read-date t)
;; By default, we fontify backlinks in their bespoke buffer.
(setq denote-link-fontify-backlinks t))
(add-hook 'dired-mode-hook #'denote-dired-mode)

Denote publishing

Enable denote dblocks

(require 'denote-org-dblock)

Universal for all projects

Align org-html’s divs with SimpleCSS’s primary containers, pull in Fuse.js & SimpleCSS

(setq org-html-divs
    '((preamble "header" "preamble")
      (content "main" "content")
      (postamble "footer" "postamble")))

(setq org-html-validation-link nil            ;; Don't show validation link
      org-html-head-include-scripts nil       ;; Use our own scripts
      org-html-head-include-default-style nil ;; Use our own styles
      org-export-with-author nil              
      org-html-head "<link rel=\"stylesheet\" href=\"\" />
                     <link rel=\"stylesheet\" href=\"/local.css\" />
                     <script src=\"\"></script>")

Denote project specific

Set up specific params for the Denote publishing project:

(setq org-publish-project-alist
         :base-directory "~/org/notes"
         :base-extension "org"
         :publishing-directory "~/webnotes/"
         :publishing-function org-html-publish-to-html
         :recursive t
         :auto-sitemap t
         :with-tags t
         :html-validation-link t
         :section-numbers nil
         :sitemap-sort-files anti-chronologically
         :html-preamble "<nav><ul>
                           <li><a href=\"/\" class=\"home\">Home</a>
                           <li><a href=\"/sitemap.html\">All Notes</a>
         :sitemap-format-entry (lambda (entry style project)
                        (let ((title (org-publish-find-title entry project))
                              (date (format-time-string "%Y-%m-%d" (org-publish-find-date entry project))))
                          (if (not (equal entry ""))
                              (format "[[file:%s][%s]] (%s)" entry title date)

Automate the HTML generation and indexing

Add this as a post-save hook:

(defun mph/publish-and-update-index ()
  "Publish our projects then update the fuse index."
    (call-interactively 'org-publish-all)
    (shell-command "python3 ~/bin/ /Users/mph/webnotes")))

Sample .dir-locals.el:

((nil . ((before-save-hook . org-update-all-dblocks)
         (after-save-hook . mph/publish-and-update-index)
import os
import re
import json
from datetime import datetime
import sys
def generate_index(directory):
data = []
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(".html"):
file_path = os.path.join(root, file)
with open(file_path, "r") as html_file:
content =
# Extract the title from the <title> tag
title_match ="<title>(.*?)</title>", content, re.IGNORECASE)
if title_match:
title =
title = ""
# Extract tags from the file name
tags = re.findall(r"_(\w+)", file)
tags = [tag.lower() for tag in tags]
# Extract the creation time from the file name
timestamp_match ="(\d{8}T\d{6})", file)
if timestamp_match:
timestamp_str =
date = datetime.strptime(timestamp_str, "%Y%m%dT%H%M%S").strftime("%Y-%m-%d %H:%M")
date = ""
# Get the subdirectory relative to the top directory
subdirectory = os.path.relpath(root, directory)
# Construct the filename with subdirectory information
filename = os.path.join(subdirectory, file)
# Create a dictionary for each file
result = {
"title": title,
"filename": filename,
"tags": tags,
"date": date
# Add the dictionary to the data list
# Write the data to a JSON file
output_file = os.path.join(directory, "index.json")
with open(output_file, "w") as json_file:
json.dump(data, json_file, indent=4)
if __name__ == "__main__":
if len(sys.argv) > 1:
directory = sys.argv[1]
print("Please provide the directory path as an argument.")

In its current form this could just as easily be a plain HTML file. I originally included a few meta-lists and never bothered to change it. (View raw)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment