diff --git a/README.org b/README.org
index a0360085..69608b1b 100644
--- a/README.org
+++ b/README.org
@@ -1537,7 +1537,7 @@ I might try switching to and using denote instead of Org Roam. Denote doesn't us
:general
(chris/leader-keys
- :states 'normal
+ :states '(normal visual)
:keymaps 'override
"nf" 'denote-open-or-create
"nb" 'denote-backlinks
diff --git a/init.el b/init.el
index 99e61f68..257b3c93 100644
--- a/init.el
+++ b/init.el
@@ -1067,7 +1067,7 @@ much faster. The hope is to also make this a faster version of imenu."
:general
(chris/leader-keys
- :states 'normal
+ :states '(normal visual)
:keymaps 'override
"nf" 'denote-open-or-create
"nb" 'denote-backlinks
diff --git a/org-publish.el b/org-publish.el
index 04f91ef3..e3bfd436 100644
--- a/org-publish.el
+++ b/org-publish.el
@@ -145,5 +145,109 @@
(mapcar #'async-get futures)
(message "Finished exporting all files"))))
+(setq org-publish-project-alist
+ `(("notes"
+ :base-directory "~/docs/site/content/notes"
+ :base-extension "org"
+ :recursive nil
+ :html-doctype "html5"
+ :html-html5-fancy t
+ :html-self-link-headlines t
+ :htmlized-source t
+ :html-head ""
+ :publishing-directory "~/docs/site/public/notes/"
+ :publishing-function org-html-publish-to-html)
+ ("teaching"
+ :base-directory "~/docs/site/content/teaching"
+ :base-extension "org"
+ :recursive nil
+ :html-doctype "html5"
+ :html-html5-fancy t
+ :html-self-link-headlines t
+ :htmlized-source t
+ :html-head ""
+ :publishing-directory "~/docs/site/public/teaching/"
+ :publishing-function org-html-publish-to-html)
+ ("static"
+ :base-directory "~/docs/site/assets/"
+ :base-extension "css\\|txt\\|jpg\\|gif\\|png"
+ :recursive t
+ :html-doctype "html5"
+ :html-html5-fancy t
+ :publishing-directory "~/docs/site/public/static/"
+ :publishing-function org-publish-attachment)
+ ("cochrun.xyz" :components ("notes" "static" "teaching"))))
+
+(defun quick/org-publish-projects (projects)
+ "Publish all files belonging to the PROJECTS alist.
+If `:auto-sitemap' is set, publish the sitemap too. If
+`:makeindex' is set, also produce a file \"theindex.org\"."
+ (dolist (project (org-publish-expand-projects projects))
+ (let ((plist (cdr project)))
+ (let ((fun (org-publish-property :preparation-function project)))
+ (cond
+ ((functionp fun) (funcall fun plist))
+ ((consp fun) (dolist (f fun) (funcall f plist)))))
+ ;; Each project uses its own cache file.
+ (org-publish-initialize-cache (car project))
+ (when (org-publish-property :auto-sitemap project)
+ (let ((sitemap-filename
+ (or (org-publish-property :sitemap-filename project)
+ "sitemap.org")))
+ (org-publish-sitemap project sitemap-filename)))
+ ;; Publish all files from PROJECT except "theindex.org". Its
+ ;; publishing will be deferred until "theindex.inc" is
+ ;; populated.
+ (let ((theindex
+ (expand-file-name "theindex.org"
+ (org-publish-property :base-directory project))))
+ (dolist (file (org-publish-get-base-files project))
+ (unless (file-equal-p file theindex)
+ (org-publish-file file project t)))
+ ;; Populate "theindex.inc", if needed, and publish
+ ;; "theindex.org".
+ (when (org-publish-property :makeindex project)
+ (org-publish-index-generate-theindex
+ project (org-publish-property :base-directory project))
+ (org-publish-file theindex project t)))
+ (let ((fun (org-publish-property :completion-function project)))
+ (cond
+ ((functionp fun) (funcall fun plist))
+ ((consp fun) (dolist (f fun) (funcall f plist))))))
+ (org-publish-write-cache-file)))
+
+(defun quick/org-publish (project &optional force async)
+ "Publish PROJECT.
+
+PROJECT is either a project name, as a string, or a project
+alist (see `org-publish-project-alist' variable).
+
+When optional argument FORCE is non-nil, force publishing all
+files in PROJECT. With a non-nil optional argument ASYNC,
+publishing will be done asynchronously, in another process."
+ (interactive
+ (list (assoc (completing-read "Publish project: "
+ org-publish-project-alist nil t)
+ org-publish-project-alist)
+ current-prefix-arg))
+ (let ((project (if (not (stringp project)) project
+ ;; If this function is called in batch mode,
+ ;; PROJECT is still a string here.
+ (assoc project org-publish-project-alist))))
+ (cond
+ ((not project))
+ (async
+ (org-export-async-start (lambda (_) nil)
+ `(let ((org-publish-use-timestamps-flag
+ ,(and (not force) org-publish-use-timestamps-flag)))
+ ;; Expand components right now as external process may not
+ ;; be aware of complete `org-publish-project-alist'.
+ (org-publish-projects
+ ',(org-publish-expand-projects (list project))))))
+ (t (save-window-excursion
+ (let ((org-publish-use-timestamps-flag
+ (and (not force) org-publish-use-timestamps-flag)))
+ (org-publish-projects (list project))))))))
+
(chris/org-publish-site)