Emacs configuration and packages
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

11 KiB

Org static blog

Vars and setup

  (jao-load-path "org-static-blog")
  (when (> emacs-major-version 26) (use-package htmlize :ensure t))
  (defvar jao-blog-base-dir "~/doc/jao.io")
  (defun jao-blog-dir (p) (expand-file-name p jao-blog-base-dir))

  (setq jao-org-blog-tag-files
        (seq-difference (directory-files (jao-blog-dir "blog") nil "tag-.*")
                        "tag-norss.html")

        jao-org-blog-tags
        (mapcar (lambda (f)
                  (string-match "tag-\\(.+\\)\\.html" f)
                  (format "<a href=\"/blog/%s\">%s</a>"
                          f (match-string 1 f)))
                jao-org-blog-tag-files)

        jao-org-blog-tag-rss
        (mapcar (lambda (f)
                  (string-match "\\(.+\\)-rss\\.xml" f)
                  (format "<a href=\"/blog/%s\">%s</a>"
                          f (match-string 1 f)))
                (directory-files (jao-blog-dir "blog") nil ".*-rss.xml"))

        jao-org-blog-tag-names
        (mapcar (lambda (f)
                  (string-match "tag-\\(.+\\)\\.html" f)
                  (match-string 1 f))
                jao-org-blog-tag-files))

HTML headers and footers

Header

  (setq org-static-blog-page-header
        (concat
         "<meta name=\"author\" content=\"jao\">\n"
         "<meta name=\"referrer\" content=\"no-referrer\">\n"
         "<link rel=\"stylesheet\" href=\"/static/style.css\""
         "  type=\"text/css\">\n"
         "<link rel=\"apple-touch-icon\" sizes=\"180x180\""
         "  href=\"/static/apple-touch-icon.png\" >\n"
         "<link rel=\"icon\" type=\"image/png\""
         "  sizes=\"32x32\" href=\"/static/favicon-32x32.png\">\n"
         "<link rel=\"icon\" type=\"image/png\""
         "  sizes=\"16x16\" href=\"/static/favicon-16x16.png\">\n"
         "<link rel=\"icon\" href=\"/static/favicon.ico\">\n"
         "<link rel=\"manifest\" href=\"/static/site.webmanifest\">\n")

        org-static-blog-page-preamble
        (concat
         "<div class=\"header\">"
         "  <a href=\"https://jao.io\">programming (and other) musings</a>"
         "  <div class=\"sitelinks\">"
         "    <a href=\"/blog/about.html\">about</a>"
         "    | <a href=\"/blog/hacking.html\">hacking</a>"
         "    | <a href=\"/blog/archive.html\">archive</a>"
         "    | <div class=\"dropdown\">"
         "       <a href=\"/blog/tags.html\" class=\"dropbtn\">tags</a>"
         "       <div class=\"dropdown-content\">"
         (mapconcat #'identity jao-org-blog-tags "")
         "       </div>"
         "      </div>"
         "    | <div class=\"dropdown\">"
         "       <a href=\"/blog/rss.xml\" class=\"dropbtn\">rss</a>"
         "       <div class=\"dropdown-content\">"
         (mapconcat #'identity jao-org-blog-tag-rss "")
         "       </div>"
         "      </div>"
         "  </div>"
         "</div>"))

Footer

<center>
  <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">
  <img alt="Creative Commons License" style="border-width:0"
       src="https://i.creativecommons.org/l/by-sa/3.0/88x31.png" />
  </a>
  <br />
  <span xmlns:dct="https://purl.org/dc/terms/"
        href="https://purl.org/dc/dcmitype/Text" property="dct:title"
        rel="dct:type">jao.io</span> by
  <a xmlns:cc="https://creativecommons.org/ns#" href="https://jao.io"
     property="cc:attributionName" rel="cc:attributionURL">jao</a>
  is licensed under a
  <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">
    Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.
</center>
  (setq org-static-blog-page-postamble
        (with-temp-buffer
          (insert-file-contents "~/.emacs.d/commons.html")
          (buffer-string)))

Package

  (use-package org-static-blog
    :ensure t
    :init
    (setq org-static-blog-use-preview t
          org-static-blog-preview-link-p t
          org-static-blog-preview-start "<!-- preview-start -->"
          org-static-blog-preview-end "<!-- preview-end -->"
          org-static-blog-preview-date-first-p t
          org-static-blog-index-length 30
          org-static-blog-preview-convert-titles t
          org-static-blog-preview-ellipsis "more ..."
          org-static-blog-enable-tags t
          org-static-blog-tags-file "tags.html"
          org-static-blog-rss-file "rss.xml"
          org-static-blog-publish-url "https://jao.io/blog/"
          org-static-blog-publish-title "programming (and other) musings"
          org-static-blog-posts-directory (jao-blog-dir "posts/")
          org-static-blog-drafts-directory (jao-blog-dir "pages/")
          org-static-blog-publish-directory (jao-blog-dir "blog/")
          org-static-blog-rss-extra "" ; "<author>mail@jao.io</author>\n"
          org-static-blog-rss-max-entries 30
          org-static-blog-rss-excluded-tag "norss"
          org-static-blog-enable-tag-rss t
          org-export-with-toc nil
          org-export-with-section-numbers nil)

    :config
    (defun jao-org-static-post-path (pf dt)
      (cond ((string-match-p "pages/.*\\|in-no-particular-order" pf)
             (file-name-nondirectory pf))
            ((string-match-p "drafts/.*" pf) pf)
            ((string-match-p "^[[:digit:]]+-.*" pf) pf)
            (t (concat (format-time-string "%Y-%m-%d-" dt)
                       (file-name-nondirectory pf)))))
    (advice-add 'org-static-blog-generate-post-path :override
                #'jao-org-static-post-path)

    :bind (:map org-mode-map (("C-c B" . jao-transient-org-blog))))

Commands

New entries

  (defun jao-org-blog-publish-file (fname)
    (interactive (list (read-file-name "Publish: "
                                       nil
                                       (buffer-file-name)
                                       t
                                       (buffer-file-name))))
    (let ((geiser-active-implementations '(guile))
          (geiser-default-implementation 'guile))
      (org-static-blog-publish-file fname)))

  (defconst jao-org-static-blog--prev-beg
    "#+begin_export html\n    <!-- preview-start -->\n#+end_export ")

  (defconst jao-org-static-blog--prev-end
    "#+begin_export html\n    <!-- preview-end -->\n#+end_export ")

  (defun jao-org-static-blog-create-new-post (&optional draft)
    (interactive)
    (let* ((title (read-string "Title: "))
           (file (replace-regexp-in-string "\s" "-" (downcase title)))
           (tags (completing-read-multiple "Tags: " jao-org-blog-tag-names)))
      (find-file (expand-file-name (concat file ".org")
                                   (if draft
                                       org-static-blog-drafts-directory
                                     org-static-blog-posts-directory)))
      (insert "#+title: " title "\n"
              "#+date: " (format-time-string "<%Y-%m-%d %H:%M>") "\n"
              "#+filetags: "
              (mapconcat #'identity tags " ")
              "\n\n")
      (when (member "books" tags)
        (insert jao-org-static-blog--prev-beg
                "\n\n[[https://jao.io/img/" file ".jpg]]\n\n"))
      (save-excursion (insert jao-org-static-blog--prev-end "\n"))))

Drafts

  (defun jao-org-static-blog-update-date ()
    (interactive)
    (when (y-or-n-p "Update date? ")
      (goto-char (point-min))
      (when (re-search-forward "^#\\+date: " nil t)
        (let ((kill-whole-line nil)) (kill-line))
        (insert (format-time-string "<%Y-%m-%d %H:%M>"))
        (save-buffer))))

  (defun jao-org-static-blog-create-new-draft ()
    (interactive)
    (jao-org-static-blog-create-new-post t))

  (defun jao-org-static-blog-publish-draft ()
    (interactive)
    (let* ((from (read-file-name "Post: "
                                 org-static-blog-drafts-directory
                                 nil t))
           (to (expand-file-name (file-name-nondirectory from)
                                 org-static-blog-posts-directory)))
      (rename-file from to)
      (when-let ((b (get-buffer from)))
        (kill-buffer b))
      (find-file to)
      (jao-org-static-blog-update-date)
      (when (y-or-n-p "Generate HTML? ")
        (jao-org-blog-publish))))

  (defun jao-org-static-blog-edit-draft ()
    (interactive)
    (find-file (read-file-name "Edit: "
                               org-static-blog-drafts-directory
                               nil
                               t)))

Publish

  (defun jao-org-blog-publish (&optional force)
      (interactive "P")
      (let ((geiser-active-implementations '(guile))
            (geiser-default-implementation 'guile))
        (org-static-blog-publish force)))

  (defun jao-org-blog-republish ()
    (interactive)
    (jao-org-blog-publish t))

Transient

  (defun jao-org-static-prev-begin ()
    (interactive)
    (insert jao-org-static-blog--prev-beg))

  (defun jao-org-static-prev-end ()
    (interactive)
    (insert jao-org-static-blog--prev-end))

  (jao-transient-major-mode+ org
    ["Insert blog snippet"
     ("s" "preview begin" jao-org-static-prev-begin)
     ("S" "preview end" jao-org-static-prev-end)
     ("T" "update date" jao-org-static-blog-update-date)]
    ["Edit blog"
     ("n" "create post" jao-org-static-blog-create-new-post)
     ("d" "create draft" jao-org-static-blog-create-new-draft)
     ("e" "edit draft" jao-org-static-blog-edit-draft)]
    ["Publish blog"
     ("D" "publish draft" jao-org-static-blog-publish-draft)
     ("f" "publish single file" jao-org-blog-publish-file)
     ("p" "publish all" jao-org-blog-publish)
     ("r" "republish" jao-org-blog-republish)])