diff options
author | JSDurand <mmemmew@gmail.com> | 2021-08-28 19:22:12 +0800 |
---|---|---|
committer | JSDurand <mmemmew@gmail.com> | 2021-08-28 19:22:12 +0800 |
commit | 3cb027c93ac91b24d6f5c819950d069ad6b4affc (patch) | |
tree | 0500feb08ea60067153bd41db2ec05ec3d97487a /org-conf.el | |
parent | 3ec6e167fb302aac3b61529be49aaf479b41dd3f (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.el | 349 |
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 + ) |