This allows me to have the local-leader be programming-specific, which means that I can standardize on the hierarchy there.
		
			
				
	
	
		
			202 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Org Mode
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Org Mode
		
	
	
	
	
	
| #+TITLE:  Publishing my Website with Org
 | |
| #+AUTHOR: Howard X. Abrams
 | |
| #+DATE:   2020-12-22
 | |
| 
 | |
| A literate programming file for publishing my website using org.
 | |
| 
 | |
| #+begin_src emacs-lisp :exports none
 | |
|   ;;; org-publishing --- Publishing my website using org. -*- lexical-binding: t; -*-
 | |
|   ;;
 | |
|   ;; © 2020-2023 Howard X. Abrams
 | |
|   ;;   Licensed under a Creative Commons Attribution 4.0 International License.
 | |
|   ;;   See http://creativecommons.org/licenses/by/4.0/
 | |
|   ;;
 | |
|   ;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
 | |
|   ;; Maintainer: Howard X. Abrams
 | |
|   ;; Created: December 22, 2020
 | |
|   ;;
 | |
|   ;; This file is not part of GNU Emacs.
 | |
|   ;;
 | |
|   ;; *NB:* Do not edit this file. Instead, edit the original literate file at:
 | |
|   ;;            ~/other/hamacs/org-publishing.org
 | |
|   ;;       And tangle the file to recreate this one.
 | |
|   ;;
 | |
|   ;;; Code:
 | |
| #+end_src
 | |
| * Introduction
 | |
| While the Emacs community have a plethora of options for generating a static website from org-formatted files, I keep my pretty simple, and use the standard =org-publish= feature.
 | |
| 
 | |
| While the following packages come with Emacs, they aren't necessarily loaded:
 | |
| 
 | |
| #+begin_src emacs-lisp :results silent
 | |
|   (require 'ox-rss)
 | |
|   (require 'ox-publish)
 | |
| #+end_src
 | |
| 
 | |
| Variable settings:
 | |
| 
 | |
| #+begin_src emacs-lisp
 | |
|   (setq org-export-with-broken-links t
 | |
|         org-mode-websrc-directory "~/website"
 | |
|         org-mode-publishing-directory (concat (getenv "HOME") "/website-pub/"))
 | |
| #+end_src
 | |
| * The Projects
 | |
| I separate my /website/ into distinct projects separately built:
 | |
| 
 | |
|   - =blog-content= :: The bulk of rendering my =website= org files into HTML
 | |
|   - =blog-static= :: All of the assets, like images are easily copied in place
 | |
|   - =blog-rss= :: Regenerate the feeder files
 | |
|   - =org-notes= :: Optionally render a non-web site collection of notes.
 | |
| 
 | |
| #+begin_src emacs-lisp
 | |
|   (setq org-publish-project-alist
 | |
|         `(("all"
 | |
|            :components ("blog-content" "blog-static" "org-notes" "blog-rss"))
 | |
| 
 | |
|           ("blog-content"
 | |
|            :base-directory       ,org-mode-websrc-directory
 | |
|            :base-extension       "org"
 | |
|            :publishing-directory ,org-mode-publishing-directory
 | |
|            :recursive            t
 | |
|            :publishing-function  org-html-publish-to-html
 | |
|            :preparation-function org-mode-blog-prepare
 | |
|            :export-with-tags     nil
 | |
|            :headline-levels      4
 | |
|            :auto-preamble        t
 | |
|            :auto-postamble       nil
 | |
|            :auto-sitemap         t
 | |
|            :sitemap-title        "Howardisms"
 | |
|            :section-numbers      nil
 | |
|            :table-of-contents    nil
 | |
|            :with-toc             nil
 | |
|            :with-author          nil
 | |
|            :with-creator         nil
 | |
|            :with-tags            nil
 | |
|            :with-smart-quotes    t
 | |
| 
 | |
|            :html-doctype         "html5"
 | |
|            :html-html5-fancy     t
 | |
|            ;; :html-preamble  org-mode-blog-preamble
 | |
|            ;; :html-postamble org-mode-blog-postamble
 | |
|            ;; :html-postamble "<hr><div id='comments'></div>"
 | |
|            :html-head  "<meta http-equiv=\"X-Clacks-Overhead\" content=\"GNU Terry Pratchett\" />
 | |
|                 <link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
 | |
|                 <link href='http://fonts.googleapis.com/css?family=Source+Serif+Pro:400,700&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
 | |
|                 <link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:400,700' rel='stylesheet' type='text/css'>
 | |
|                 <link rel=\"stylesheet\" href=\"/css/styles.css\" type=\"text/css\"/>\n"
 | |
|            :html-head-extra "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js\"></script>
 | |
|                 <script src=\"/js/magic.js\"></script>
 | |
|                 <link rel=\"icon\" href=\"/img/dragon.svg\">
 | |
|                 <link rel=\"shortcut icon\" href=\"/img/dragon-head.png\">
 | |
|                 <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />"
 | |
|            :html-head-include-default-style nil)
 | |
| 
 | |
|           ("blog-static"
 | |
|            :base-directory       ,org-mode-websrc-directory
 | |
|            :base-extension       "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|svg"
 | |
|            :publishing-directory ,org-mode-publishing-directory
 | |
|            :recursive            t
 | |
|            :publishing-function  org-publish-attachment)
 | |
| 
 | |
|           ("blog-rss"
 | |
|            :base-directory        ,org-mode-websrc-directory
 | |
|            :base-extension        "org"
 | |
|            :rss-image-url         "https://howardism.org/img/dragon-head.png"
 | |
|            :publishing-directory  ,org-mode-publishing-directory
 | |
|            :publishing-function   (org-rss-publish-to-rss)
 | |
|            :html-link-home        "https://www.howardism.org/"
 | |
|            :html-link-use-abs-url t
 | |
|            :with-toc              nil
 | |
|            :exclude               ".*"
 | |
|            :include               ("index.org"))
 | |
| 
 | |
|           ("org-notes"
 | |
|            :base-directory        "~/technical/"
 | |
|            :base-extension       "org"
 | |
|            :publishing-directory ,(concat org-mode-publishing-directory "/notes/")
 | |
|            :recursive            t
 | |
|            :publishing-function  org-html-publish-to-html
 | |
|            :headline-levels      4  ; Just the default for this project.
 | |
|            :auto-preamble        t
 | |
|            :auto-sitemap         t  ; Generate sitemap.org automagically...
 | |
|            :makeindex            t
 | |
|            :section-numbers      nil
 | |
|            :style                "<link rel=\"stylesheet\" href=\"../css/styles.css\" type=\"text/css\"/> <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js\" type=\"text/javascript\"></script> <link href=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/smoothness/jquery-ui.css\" type=\"text/css\" rel=\"stylesheet\" />    <script src=\"https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js\" type=\"text/javascript\"></script> <script =\"text/javascript\" src=\"js/magic.js\"></script>"
 | |
|            :table-of-contents    nil
 | |
|            :with-author          nil
 | |
|            :with-creator         nil
 | |
|            :with-tags            nil)
 | |
| 
 | |
|           ("org-notes-static"
 | |
|            :base-directory       "~/technical/"
 | |
|            :base-extension       "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf"
 | |
|            :publishing-directory ,(concat org-mode-publishing-directory "/other/")
 | |
|            :recursive            t
 | |
|            :publishing-function  org-publish-attachment)))
 | |
| #+end_src
 | |
| * Including Sections
 | |
| In the project definitions, I reference a =pre-= and =postamble= that allow me to inject some standard HTML file headers and footers:
 | |
| 
 | |
| #+begin_src emacs-lisp
 | |
| (defun org-mode-blog-preamble (options)
 | |
|   "The function that creates the preamble top section for the blog.
 | |
|     OPTIONS contains the property list from the org-mode export."
 | |
|   (message "Preamble options: %s" (princ options))
 | |
|   (let ((base-directory (plist-get options :base-directory)))
 | |
|     (org-babel-with-temp-filebuffer (expand-file-name "top-bar.html" base-directory) (buffer-string))))
 | |
| 
 | |
| (defun org-mode-blog-postamble (options)
 | |
|   "The function that creates the postamble, or bottom section for the blog.
 | |
|   OPTIONS contains the property list from the org-mode export."
 | |
|   (let ((base-directory (plist-get options :base-directory)))
 | |
|     (org-babel-with-temp-filebuffer (expand-file-name "bottom.html" base-directory) (buffer-string))))
 | |
| #+end_src
 | |
| 
 | |
| Another helper function for the content of website is to make sure to update =index.org=, so that the RSS gets generated.
 | |
| #+begin_src emacs-lisp
 | |
| (defun org-mode-blog-prepare (&optional options)
 | |
|   "`index.org' should always be exported so touch the file before publishing."
 | |
|   (let* ((base-directory (plist-get options :base-directory))
 | |
|          (buffer (find-file-noselect (expand-file-name "index.org" base-directory) t)))
 | |
|     (with-current-buffer buffer
 | |
|       (set-buffer-modified-p t)
 | |
|       (save-buffer 0))
 | |
|     (kill-buffer buffer)))
 | |
| #+end_src
 | |
| * Keybindings
 | |
| Make it easy to publish all or just some of my website:
 | |
| #+begin_src emacs-lisp
 | |
|   (with-eval-after-load 'ha-org
 | |
|     (ha-leader :keymaps 'org-mode-map
 | |
|       ;; "p"  '(:ignore t :which-key "publishing")
 | |
|       "o p a" '("all" . org-publish-all)
 | |
|       "o p p" '("project" . org-publish-project)))
 | |
| #+end_src
 | |
| 
 | |
| And let's put a /leader key/ sequence for my favorite file on my website:
 | |
| #+begin_src emacs-lisp
 | |
|   (ha-leader
 | |
|     "f h"  '(:ignore t :which-key "howards")
 | |
|     "f h i" '("website index" . (lambda ()
 | |
|                                   (find-file (expand-file-name "index.org" "~/website")))))
 | |
| #+end_src
 | |
| * Technical Artifacts :noexport:
 | |
| Let's =provide= a name so we can =require= it:
 | |
| 
 | |
| #+begin_src emacs-lisp :exports none
 | |
| (provide 'ha-org-publishing)
 | |
| ;;; ha-org-publishing.el ends here
 | |
| #+end_src
 | |
| 
 | |
| Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
 | |
| 
 | |
| #+DESCRIPTION: A literate programming version for publishing my website using org.
 | |
| 
 | |
| #+PROPERTY:    header-args:sh :tangle no
 | |
| #+PROPERTY:    header-args:emacs-lisp :tangle yes
 | |
| #+PROPERTY:    header-args    :results none :eval no-export :comments no mkdirp yes
 | |
| 
 | |
| #+OPTIONS:     num:nil toc:nil todo:nil tasks:nil tags:nil date:nil
 | |
| #+OPTIONS:     skip:nil author:nil email:nil creator:nil timestamp:nil
 | |
| #+INFOJS_OPT:  view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
 |