summaryrefslogtreecommitdiff
path: root/org-conf.el
diff options
context:
space:
mode:
authorJSDurand <mmemmew@gmail.com>2021-08-28 19:22:12 +0800
committerJSDurand <mmemmew@gmail.com>2021-08-28 19:22:12 +0800
commit3cb027c93ac91b24d6f5c819950d069ad6b4affc (patch)
tree0500feb08ea60067153bd41db2ec05ec3d97487a /org-conf.el
parent3ec6e167fb302aac3b61529be49aaf479b41dd3f (diff)
Refinements to publish the blog
* org-conf.el (durand-org-publish-sidebar) (durand-org-publish-insert-sidebar): Use a sidebar for the navigation: Instead of the built-in UP/HOME buttons, I want to go to sitemap files for different types of blog posts quickly. This is more convenient for the readers I think. This is inspired by the design of Protesilaos' website. (durand-org-publish-css-file): Add my own CSS file in the header. (durand-org-publish-favicon): Add the favicon I produced by a simple C program. (org-publish-project-alist): Add a Math type of blog posts. (durand-sitemap-custom-string-alist): Add a custom string to each type's sitemap file. (durand-org-publish-sitemap, durand-org-publish-sitemap-format): Use a table instead of a list in the sitemap. This is also inspired by the design of Protesilaos' website. (durand-org-publish-plist-get): The built-in `plist-get' mal-functions, and this is a replacement. After I update my Emacs, this problem might be fixed, and this replcement might not be needed anymore. (durand-org-publish-convert-time): Convert the result of `parse-time-string' to a time value. The result may lack some information, as the parsed string does not provide them. So this function supplies 0 for the missing values. Note that it assumes the year, month, and day cannot be missing, though. (durand-org-index-entries-max-num): Show at most a fixed number of entries on the index page. This maximum is set to 10 now. (durand-org-post-process): Shorten the date strings in the sitemap files: I need the exact date for sorting, but I don't want to show those information in the sitemap files. So I convert the long form of dates to comments, and use the shortened form for display. Also this generates a proper index page from the various sitemap files. Right now it will insert the entries to the index file each time this is called, which is kind of inefficient. I might adapt a more efficient method later on. I also want to generate Atom feeds in this function, but right now I don't have such a need, and this is not fulfilled yet. This kind of imitates the behaviour of Protesilaos' website.
Diffstat (limited to 'org-conf.el')
-rw-r--r--org-conf.el349
1 files changed, 322 insertions, 27 deletions
diff --git a/org-conf.el b/org-conf.el
index 019c033..68d4de7 100644
--- a/org-conf.el
+++ b/org-conf.el
@@ -546,13 +546,46 @@ If DESC is non-`nil', then it is the description of the new link."
;;; publishing settings
+;;;;; Custom preamble for the sidebar
+
+(defvar durand-org-publish-sidebar nil
+ "The sidebar that provides the navigation of the website.")
+
+(setq durand-org-publish-sidebar
+ "<div class=\"sidebar\">\n\
+<a href=\"math-sitemap.html\"> Math </a>\n\
+<a href=\"code-sitemap.html\"> Code </a>\n\
+<a href=\"life-sitemap.html\"> Life </a>\n\
+<a href=\"index.html\"> Home </a></div>")
+
+;; REVIEW: This might be unnecessary.
+(defun durand-org-publish-insert-sidebar (_arg)
+ "Return the sidebar."
+ durand-org-publish-sidebar)
+
+;;;;;; Add a custom head
+
+(defvar durand-org-publish-css-file nil
+ "A custom css-file for publishing.")
+
+(setq durand-org-publish-css-file
+ "<link rel=\"stylesheet\" type=\"text/css\" \
+href=\"website.css\"/>")
+
+(defvar durand-org-publish-favicon nil
+ "A custom favicon for publishing.")
+
+(setq durand-org-publish-favicon
+ "<link rel='shortcut icon' \
+href='https://jsdurand.xyz/favicon.ico'/>")
+
;;;;; Projects settings
(setq org-publish-project-alist
(list
(list
"website"
- :components (list "code" "life" "main"))
+ :components (list "math" "code" "life" "main"))
(list
"code"
:base-directory (directory-file-name
@@ -575,11 +608,44 @@ If DESC is non-`nil', then it is the description of the new link."
:sitemap-date-format "Published: %F %a %R"
:sitemap-filename "code-sitemap.org"
:sitemap-title "About coding"
- :html-link-home "index.html"
:sitemap-sort-files 'anti-chronologically
- :html-head "<link rel=\"stylesheet\" type=\"text/css\"
- href=\"website.css\"/>"
- :html-preamble t)
+ :html-head (concat durand-org-publish-css-file
+ "\n"
+ durand-org-publish-favicon)
+ :html-link-home ""
+ :html-link-up ""
+ :html-home/up-format ""
+ :html-preamble #'durand-org-publish-insert-sidebar)
+ (list
+ "math"
+ :base-directory (directory-file-name
+ (expand-file-name
+ "math" (expand-file-name
+ "blog" org-directory)))
+ :base-extension "org"
+ :publishing-directory (directory-file-name
+ (expand-file-name
+ "public" org-directory))
+ :publishing-function #'org-html-publish-to-html
+ :section-numbers nil
+ :with-toc nil
+ :with-email t
+ :with-creator t
+ :auto-sitemap t
+ :recursive t
+ :sitemap-function #'durand-org-publish-sitemap
+ :sitemap-format-entry #'durand-org-publish-sitemap-format
+ :sitemap-date-format "Published: %F %a %R"
+ :sitemap-filename "math-sitemap.org"
+ :sitemap-title "Mathematics"
+ :sitemap-sort-files 'anti-chronologically
+ :html-head (concat durand-org-publish-css-file
+ "\n"
+ durand-org-publish-favicon)
+ :html-link-home ""
+ :html-link-up ""
+ :html-home/up-format ""
+ :html-preamble #'durand-org-publish-insert-sidebar)
(list
"life"
:base-directory (directory-file-name
@@ -602,11 +668,14 @@ If DESC is non-`nil', then it is the description of the new link."
:sitemap-date-format "Published: %F %a %R"
:sitemap-filename "life-sitemap.org"
:sitemap-title "My life"
- :html-link-home "index.html"
:sitemap-sort-files 'anti-chronologically
- :html-head "<link rel=\"stylesheet\" type=\"text/css\"
- href=\"website.css\"/>"
- :html-preamble t)
+ :html-head (concat durand-org-publish-css-file
+ "\n"
+ durand-org-publish-favicon)
+ :html-link-home ""
+ :html-link-up ""
+ :html-home/up-format ""
+ :html-preamble #'durand-org-publish-insert-sidebar)
(list
"main"
:base-directory (directory-file-name
@@ -623,24 +692,32 @@ If DESC is non-`nil', then it is the description of the new link."
:with-creator t
:auto-sitemap nil
:recursive nil
- :html-head "<link rel=\"stylesheet\" type=\"text/css\"
- href=\"website.css\"/>"
- :html-preamble t)))
+ :html-head (concat durand-org-publish-css-file
+ "\n"
+ durand-org-publish-favicon)
+ :html-link-home ""
+ :html-link-up ""
+ :html-home/up-format ""
+ :html-preamble #'durand-org-publish-insert-sidebar)))
;;;;; Sitemap function
;;;;;; A hack to insert some string in the sitemap file.
-(defvar durand-sitemap-custom-string-alist
- (list
- (cons "About coding"
- "This is the coding blog. It contains my coding experiments, or \
-one might think of them as development diaries.")
- (cons "My life"
- "This is my casual blog. It contains articles about my plain \
-life."))
+(defvar durand-sitemap-custom-string-alist nil
"An association list that relates the title of the sitemap and the string to insert.")
+(setq durand-sitemap-custom-string-alist
+ (list
+ (cons "About coding"
+ "This is my coding blog. It contains my coding experiments, or \
+one might think of them as development diaries.")
+ (cons "My life"
+ "This is my casual blog. It contains articles about my plain \
+life.")
+ (cons "Mathematics"
+ "My Mathematics-related articles are put here.")))
+
;;;;;; Custom sitemap function
(defun durand-org-publish-sitemap (title rep)
@@ -650,19 +727,237 @@ TITLE is the title of the sitemap.
REP is a representation of the files and directories in the
project. Use such functions as `org-list-to-org' or
`org-list-to-subtree' to transform it."
- (format "#+TITLE: %s\n#+AUTHOR: JSDurand\n%s#+DATE: <%s>\n\n%s\n\n%s"
+ (format "#+TITLE: %s\n#+AUTHOR: JSDurand\n%s#+DATE: <%s>\n\n%s\n\n\
+#+ATTR_HTML: :border nil :rules nil :frame nil\n\
+%s"
title
"#+HTML_LINK_UP: index.html"
(format-time-string "%F %a %R")
(cdr (assoc title durand-sitemap-custom-string-alist #'string=))
- (org-list-to-org rep)))
+ ;; generate a table
+ (org-list-to-generic
+ rep
+ '(:ustart "|---|"
+ :uend "|---|"
+ :isep "|---|"))))
;;;;;; Custom sitemap format
+;; NOTE: I use a table to style the entries.
+
+;; NOTE: This stores the date in an ugly long format. But worry not:
+;; it will be replaced by a clean form in the post-processing phase.
+;; The long form is inserted here so that we can sort the entries
+;; precisely.
+
(defun durand-org-publish-sitemap-format (entry _style project)
- "Format the entry for the sitemap.
-A date is added."
- (format "[[file:%s][(%s) %s]]"
- entry (format-time-string
- "%F %R" (org-publish-find-date entry project))
+ "Format the entry for the sitemap as a table with a date.
+ENTRY is the entry file name to format.
+
+STYLE is either 'list or 'tree, which is ignored by us.
+
+PROJECT is the current project."
+ (format "| %s | [[file:%s][%s]] |"
+ (format-time-string
+ "%FT%T%z"
+ (org-publish-find-date entry project)
+ (current-time-zone))
+ entry
(org-publish-find-title entry project)))
+
+;;;;; Post-processing
+
+;; I post-process the sitemaps in order to generate a section
+;; of "latest updates" on the index page.
+
+;;;;;; fix: plist-get not working
+
+;; For some reason the built-in `plist-get' does not work...
+(defun durand-org-publish-plist-get (prop plist)
+ (let (res)
+ (while (consp plist)
+ (cond
+ ((eq (car plist) prop)
+ (setq res (cadr plist))
+ (setq plist nil))
+ ((setq plist (cddr plist)))))
+ res))
+
+;;;;;; Helper for converting the format from `parse-time-string'
+
+(defun durand-org-publish-convert-time (spec)
+ "Convert SPEC to a valid time value.
+SPEC should be the result of `parse-time-string'.
+
+It is assumed that the year, the month, and the day components
+are present."
+ (let ((sec (car spec))
+ (minute (cadr spec))
+ (hour (caddr spec)))
+ (encode-time
+ (append
+ (list
+ (or sec 0)
+ (or minute 0)
+ (or hour 0))
+ (cdddr spec)))))
+
+;;;;;; Post process to generate the index page
+
+(defvar durand-org-index-entries-max-num 10
+ "The maximal number of entries to show on the index page.")
+
+(autoload #'durand-take (locate-user-emacs-file "common.el"))
+
+(defun durand-org-post-process (project)
+ "Generate a proper index page and Atom feeds.
+Also shorten the date strings in the sitemap files, and store the
+completion information in an attribute."
+ (let* ((project-plist (cdr (assoc project org-publish-project-alist #'string=)))
+ (components (durand-org-publish-plist-get
+ :components project-plist))
+ (sitemap-file (durand-org-publish-plist-get
+ :sitemap-filename project-plist))
+ ;; I cheat here
+ (publishing-dir (expand-file-name "~/org/public/"))
+ (publish-sitemap-file (cond
+ (sitemap-file
+ (replace-regexp-in-string
+ "org$" "html"
+ (expand-file-name sitemap-file publishing-dir)))))
+ (index-file (expand-file-name "index.html" publishing-dir))
+ contents)
+ (cond
+ ;; depth-first recursion
+ (components
+ (setq contents (apply #'append
+ (delete nil (mapcar #'durand-org-post-process components))))
+ ;; We only want some items
+ (setq contents
+ (durand-take
+ durand-org-index-entries-max-num
+ (sort contents
+ (lambda (x y)
+ (time-less-p
+ (car y) (car x))))))
+ ;; If contents is non-nil, we need to process the info in the
+ ;; index page.
+ (cond
+ (contents
+ (with-temp-buffer
+ (insert-file-contents index-file)
+ (goto-char (point-min))
+ (search-forward "Latest updates")
+ (goto-char (line-end-position))
+ (while (search-forward "<table" nil t)
+ ;; delete existing tables
+ (delete-region
+ (match-beginning 0)
+ (progn (search-forward "</table>")
+ (match-end 0))))
+ (insert "\n")
+ (insert "<table cellspacing=\"0\" cellpadding=\"6\">
+
+
+<colgroup>
+<col class=\"org-right\" />
+
+<col class=\"org-left\" />
+</colgroup>\n\n<tbody>\n")
+ (mapc
+ (lambda (entry)
+ (insert "<tr>")
+ (insert "<td class=\"org-right\">")
+ (insert (format-time-string "%F" (car entry)))
+ (insert "</td>\n")
+ (insert "<td class=\"org-left\">")
+ (insert (cdr entry))
+ (insert "</td>\n</tr>\n"))
+ contents)
+ (insert "</tbody>\n</table>")
+ (setq contents (buffer-substring-no-properties
+ (point-min) (point-max))))
+ (write-region contents nil index-file))))
+ ((and publish-sitemap-file
+ (stringp publish-sitemap-file)
+ (file-exists-p publish-sitemap-file))
+ (with-temp-buffer
+ (insert-file-contents publish-sitemap-file)
+ (goto-char (point-min))
+ (search-forward "</colgroup>" nil t)
+ (let ((regexp (rx-to-string
+ '(seq
+ "<t" (any "hd")
+ " "
+ (one-or-more (not (or ">")))
+ ">")
+ t))
+ pos pos-2 temp temp-time)
+ (while (re-search-forward regexp nil t)
+ (setq pos (point))
+ ;; replace the first org-left by org-right
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (setq pos-2 (match-end 0))
+ (save-match-data
+ (cond
+ ((re-search-forward "left" pos-2 t)
+ (replace-match "right")
+ ;; fix pos
+ (setq pos (1+ pos))))))
+ (search-forward "</t")
+ (setq pos-2 (match-beginning 0))
+ (forward-line 1)
+ (cond
+ ((re-search-forward
+ (rx-to-string
+ '(seq
+ (= 4 (any digit)) "-"
+ (= 2 (any digit)) "-"
+ (= 2 (any digit)) "T")
+ t)
+ (line-end-position) t)
+ (setq temp-time
+ (durand-org-publish-convert-time
+ (parse-time-string
+ (buffer-substring-no-properties
+ (match-beginning 0)
+ (line-end-position))))))
+ (t
+ (setq
+ temp-time
+ (durand-org-publish-convert-time
+ (parse-time-string
+ (buffer-substring-no-properties
+ pos pos-2))))
+ (save-excursion
+ (goto-char pos)
+ (delete-region pos pos-2)
+ (insert (format-time-string "%F" temp-time)))
+ (insert
+ "<!--"
+ (format-time-string
+ "%FT%T%z\n" temp-time (current-time-zone))
+ "-->\n")
+ (write-region nil nil publish-sitemap-file)))
+ (setq
+ temp
+ (cons
+ (cons temp-time
+ (progn
+ (re-search-forward regexp)
+ (setq pos (point))
+ (search-forward "</t")
+ (buffer-substring-no-properties
+ pos (match-beginning 0))))
+ temp)))
+ (reverse temp)))))))
+
+;;;;; Atom feed
+
+;; The Atom feeds are generated in this function.
+
+(defun durand-org-generate-atom-feed (project)
+ "Generate an Atom feed for PROJECT."
+ ;; TODO
+ )