Ξ  


AlBasmala Archive Tags RSS About

AlBasmala:
Blogging with Emacs & Org-mode (•̀ᴗ•́)و

Article image
Abstract

How my blog is setup (•̀ᴗ•́)و

Here are some notable features of my blog.

1. Why not use an existing blogging platform?

I dislike coding in any website's primitive textarea, likewise for general writing.

Typical workflow: How do I publish an article?
  1. (org-babel-load-file "~/blog/AlBasmala.org")
  2. Invoke blog/new-article

    This sets up a new article based on existing tags and posts. Moreover it also does:

    1. Do M-x org-preview-html-mode
    2. Now every alteration, followed by a save C-x C-s will result in a live preview of the blog article, nearly instantaneous.
  3. Until content:

    1. Write, write, and write!
    2. C-x C-s
    3. Preview

    Consider using C-x n s, or C-x n n, to focus your attention on a particular section, thereby dramatically increasing the speed at which the preview renders.

  4. Execute blog/publish-current-article when you're done.
    • This gets the new article showing up in index, RSS, archive, and updates the tags.
  5. NOTE: It takes about. 20secs ~ 1min for the changes to be live on github pages.

2. Style! ✨ What do we want to be inserted into the head of every page?

For each article, I'll have a set of styles loaded as well as a set of <script> code fragments. Here is an overview of these fragments, and throughout the rest of this article, I'll tangle code to where appropriate.

2.1. Style Header Elements

Firstly, we want some styling rules to be loaded.

1: (concat
2: "<meta name=\"author\" content=\"Musa Al-hassy\">
3:  <meta name=\"referrer\" content=\"no-referrer\">"
4: "<link href=\"usual-org-front-matter.css\" rel=\"stylesheet\" type=\"text/css\" />"
5: "<link href=\"org-notes-style.css\" rel=\"stylesheet\" type=\"text/css\" />"
6: "<link href=\"floating-toc.css\" rel=\"stylesheet\" type=\"text/css\" />"
7: "<link href=\"blog-banner.css\" rel=\"stylesheet\" type=\"text/css\" />"
8: "<link rel=\"icon\" href=\"images/favicon.png\">")
usual-org-front-matter.css
Org-static-blog ignores any styling exported by Org, so let's bring that back in. I just exported this file with the usual C-c C-e h o, then saved the CSS it produced.
org-notes-style.css
I like the rose-style of this org-notes-style for HTML export. However, it seems loading the CSS directly from its homepage does not work, so I've copied the CSS file for my blog.
floating-toc.css
I want to have an unobtrusive floating table of contents, see §4.
blog-banner.css
Finally, we want a beautiful welcome mat, see §8.

2.2. Script Header Elements

In addition, we have two more pieces we would like to add to the header: Support for dynamic code-line highlighting, §8, and support for using LaTeX-style notation to write mathematics, §10. We will use a noweb-ref named my-html-header to refer to them, which are then catenated below.

Full, tangled, value of org-static-blog-page-header
 (setq org-static-blog-page-header
  (concat
   org-html-head-extra  ;; Altered by ‘org-special-block-extras
   (concat
   "<meta name=\"author\" content=\"Musa Al-hassy\">
    <meta name=\"referrer\" content=\"no-referrer\">"
   "<link href=\"usual-org-front-matter.css\" rel=\"stylesheet\" type=\"text/css\" />"
   "<link href=\"org-notes-style.css\" rel=\"stylesheet\" type=\"text/css\" />"
   "<link href=\"floating-toc.css\" rel=\"stylesheet\" type=\"text/css\" />"
   "<link href=\"blog-banner.css\" rel=\"stylesheet\" type=\"text/css\" />"
   "<link rel=\"icon\" href=\"images/favicon.png\">")
   "<script type=\"text/javascript\">
   /*
   @licstart  The following is the entire license notice for the
   JavaScript code in this tag.
   
   Copyright (C) 2012-2020 Free Software Foundation, Inc.
   
   The JavaScript code in this tag is free software: you can
   redistribute it and/or modify it under the terms of the GNU
   General Public License (GNU GPL) as published by the Free Software
   Foundation, either version 3 of the License, or (at your option)
   any later version.  The code is distributed WITHOUT ANY WARRANTY;
   without even the implied warranty of MERCHANTABILITY or FITNESS
   FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
   
   As additional permission under GNU GPL version 3 section 7, you
   may distribute non-source (e.g., minimized or compacted) forms of
   that code without the copy of the GNU GPL normally required by
   section 4, provided you include this license notice and a URL
   through which recipients can access the Corresponding Source.
   
   
   @licend  The above is the entire license notice
   for the JavaScript code in this tag.
   */
   <!--/*--><![CDATA[/*><!--*/
    function CodeHighlightOn(elem, id)
    {
      var target = document.getElementById(id);
      if(null != target) {
        elem.cacheClassElem = elem.className;
        elem.cacheClassTarget = target.className;
        target.className = \"code-highlighted\";
        elem.className   = \"code-highlighted\";
      }
    }
    function CodeHighlightOff(elem, id)
    {
      var target = document.getElementById(id);
      if(elem.cacheClassElem)
        elem.className = elem.cacheClassElem;
      if(elem.cacheClassTarget)
        target.className = elem.cacheClassTarget;
    }
   /*]]>*///-->
   </script>"
   "<script type=\"text/x-mathjax-config\">
       MathJax.Hub.Config({
           displayAlign: \"center\",
           displayIndent: \"0em\",
   
           \"HTML-CSS\": { scale: 100,
                           linebreaks: { automatic: \"false\" },
                           webFont: \"TeX\"
                          },
           SVG: {scale: 100,
                 linebreaks: { automatic: \"false\" },
                 font: \"TeX\"},
           NativeMML: {scale: 100},
           TeX: { equationNumbers: {autoNumber: \"AMS\"},
                  MultLineWidth: \"85%\",
                  TagSide: \"right\",
                  TagIndent: \".8em\"
                }
   });
   </script>
   <script type=\"text/javascript\"
           src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML\"></script>
   "
   ))

2.3. Lisp Header Elements

Some Lisp code is required to string everything together.

3. Seamlessly Previewing Articles within Emacs 😲

The following makes it so that my blog style is appended to my org files.

As outlined above, I'd like to add styles and things, and so I'd like a nonintrusive way to preview what I write.

  • I'd like to have all of my styles automatically loaded in the right places.
  • Have my article image and abstract rendered.
  • See the resulting webpage in a JavaScript-supported browser within Emacs.
  • All of this is to happen whenever I save, C-x C-s.

We accomplish these goals in stages.

3.1. Using My Blog Styles Anywhere: org-link/blog

In any Org-mode file —including random ones that are not even for my blog— I'll use the Org links blog:header and blog:footer to obtain the nice styling of my blog.

Definition of “blog:𝒳𝒴𝒵” link

This is a minor alteration from the examples within the docstring of org-deflink.

(org-deflink blog
  "Provide the styles for “www.alhassy.com”'s “header” and “footer”.

The use of “blog:footer” aims to provide a clickable list of tags, produce an HTMLized version of the Org source,
and provides a Disqus comments sections. For details, consult the `org-static-blog-post-postamble' function.

Finally, I want to avoid any `@@backend:...@@' from appearing in the browser frame's title.
We accomplish this with the help of some handy-dandy JavaScript: Just use “blog:sanitise-title”.
"
      (pcase o-label
        ("header" (concat
                   org-static-blog-page-preamble
                   org-static-blog-page-header
                   "<link href=\"https://alhassy.github.io/org-notes-style.css\" rel=\"stylesheet\" type=\"text/css\" />"
                   "<link href=\"https://alhassy.github.io/floating-toc.css\" rel=\"stylesheet\" type=\"text/css\" />"
                   "<link href=\"https://alhassy.github.io/blog-banner.css\" rel=\"stylesheet\" type=\"text/css\" />"
                   ;; The use of the “post-title” class is so that the org-static-blog-assemble-rss method can work as intended.
                   (thread-last (org-static-blog-get-title (buffer-file-name))
                                (s-replace-regexp "@@html:" "")
                                (s-replace-regexp "@@" "")
                                (format "<br><center><h1 class=\"post-title\">%s</h1></center>"))))
        ("footer" (org-static-blog-post-postamble (buffer-file-name)))
        ("sanitise-title" "<script> window.parent.document.title =  window.parent.document.title.replace(/@@.*@@/, \"\") </script>")
        (_ "")))

See also: How do I make a new Org link type?

3.3. Inserting org-link/blog seamlessly via the export process; then preview with every save

(cl-defun blog/preview ()
  "Enable preview-on-save, and add blog/style-setup from Org's export hook."
  (interactive)
  ;; Let's ensure we have no xwidget buffer lying around, otherwise Emacs might hang.
  (-let [kill-buffer-query-functions nil]
    (mapcar #'kill-buffer (--filter (equal 'xwidget-webkit-mode (buffer-local-value 'major-mode it)) (buffer-list))))
  ;; Inserting doc:org-link/blog /seamlessly/ via the export process
  (add-hook 'org-export-before-processing-hook  #'blog/style-setup)
  ;; Preview with every save
  (org-preview-html-mode))

(cl-defun blog/preview/disable ()
  "Disable preview-on-save, and remove blog/style-setup from Org's export hook."
  (interactive)
  (remove-hook 'org-export-before-processing-hook #'blog/style-setup)
  (org-preview-html-mode -1))

Upon a save, C-x C-s, a new HTML file is created —bearing the same name as the Org file. It seems an incremental export is performed and so this is rather fast —at least much faster than manually invoking C-c C-e h o.

3.4. Abstract Special Block   Relocate_near_blog_setup

The above “Abstract” is an Org-mode Special Block

Below is an alteration from the examples of the docstring of org-defblock.

(org-defblock abstract (main) nil
  "Render a block in a slightly narrowed blueish box, titled \"Abstract\".

   Supported backends: HTML. "
   (format (concat
            "<div class=\"abstract\" style=\"border: 1px solid black;"
            "padding: 10px; margin-top: 50px; margin-bottom: 50px;"
            "margin-right: 150px; margin-left: 80px; background-color: lightblue;\">"
            "<center> <strong class=\"tooltip\""
            "title=\"What's the goal of this article?\"> Abstract </strong> </center>"
            "%s </div>")
           contents))

4. Ξ: Floating Table of Contents

I would like to have a table of contents that floats so that it is accessible to the reader in case they want to jump elsewhere in the document quickly —possibly going to the top of the document.

When we write #+toc: headlines 2 in our Org, HTML export produces the following.

 1: <div id="table-of-contents">
 2:   <h2>Table of Contents</h2>
 3:   <div id="text-table-of-contents">
 4:     <ul>
 5:       <li> section 1 </li>
 6:  7:       <li> section 𝓃 </li>
 8:     </ul>
 9:   </div>
10: </div>

Hence, we can style the table of contents by writing rules that target those id's. We use the following rules, adapted from the Worg community.

 1: /*TOC inspired by https://orgmode.org/worg/ */
 2: #table-of-contents {
 3:     /* Place the toc in the top right corner */
 4:     position: fixed; right: 0em; top: 0em;
 5:     margin-top: 120px; /* offset from the top of the screen */
 6: 
 7:     /* It shrinks and grows as necessary */
 8:     padding: 0em !important;
 9:     width: auto !important;
10:     min-width: auto !important;
11: 
12:     font-size: 10pt;
13:     background: white;
14:     line-height: 12pt;
15:     text-align: right;
16: 
17:     box-shadow: 0 0 1em #777777;
18:     -webkit-box-shadow: 0 0 1em #777777;
19:     -moz-box-shadow: 0 0 1em #777777;
20:     -webkit-border-bottom-left-radius: 5px;
21:     -moz-border-radius-bottomleft: 5px;
22: 
23:     /* Ensure doesn't flow off the screen when expanded */
24:     max-height: 80%;
25:     overflow: auto;}
26: 
27: /* How big is the text “Table of Contents” and space around it */
28: #table-of-contents h2 {
29:     font-size: 13pt;
30:     max-width: 9em;
31:     border: 0;
32:     font-weight: normal;
33:     padding-left: 0.5em;
34:     padding-right: 0.5em;
35:     padding-top: 0.05em;
36:     padding-bottom: 0.05em; }
37: 
38: /* Intially have the TOC folded up; show it if the mouse hovers it */
39: #table-of-contents #text-table-of-contents {
40:     display: none;
41:     text-align: left; }
42: 
43: #table-of-contents:hover #text-table-of-contents {
44:     display: block;
45:     padding: 0.5em;
46:     margin-top: -1.5em; }

[Strange:

If I zoom in over 100% in my browser, the toc disappears until I zoom out.

]

Since the table of contents floats, the phrase Table of Contents is rather ‘in your face’, so let's use the more subtle Greek letter Ξ.

 1: (advice-add 'org-html--translate :before-until 'display-toc-as-Ξ)
 2: ;; (advice-remove 'org-html--translate 'display-toc-as-Ξ)
 3: 
 4: (defun display-toc-as-Ξ (phrase info)
 5:   (when (equal phrase "Table of Contents")
 6:     (s-collapse-whitespace
 7:     " <a href=\"javascript:window.scrollTo(0,0)\"
 8:         style=\"color: black !important; border-bottom: none !important;\"
 9:         class=\"tooltip\"
10:         title=\"Go to the top of the page\">
11:       Ξ
12:     </a> ")))

How did I get here?

  1. How does Org's HTML export TOCs? ⇒ org-html-toc
  2. Looking at its source, we see org-html--translate being the only place mentioning the string Table of Contents
  3. Let's advise it, with advice-add, to return Ξ only on that particular input string.
  4. Joy ♥‿♥

5. Ensuring Useful HTML Anchors

This section has been #+include'd from my init.org,
Upon HTML export, each tree heading is assigned an ID to be used for hyperlinks. Default IDs are something like org1957a9d, which does not endure the test of time: Re-export will produce a different id. Here's a rough snippet to generate IDs from headings, by replacing spaces with hyphens, for headings without IDs.

(defun my/ensure-headline-ids (&rest _)
  "Org trees without a

All non-alphanumeric characters are cleverly replaced with ‘-’.

If multiple trees end-up with the same id property, issue a
message and undo any property insertion thus far.

E.g., ↯ We'll go on a ∀∃⇅ adventure
   ↦  We'll-go-on-a-adventure
"
  (interactive)
  (let ((ids))
    (org-map-entries
     (lambda ()
       (org-with-point-at (point)
         (let ((id (org-entry-get nil "CUSTOM_ID")))
           (unless id
             (thread-last (nth 4 (org-heading-components))
               (s-replace-regexp "[^[:alnum:]']" "-")
               (s-replace-regexp "-+" "-")
               (s-chop-prefix "-")
               (s-chop-suffix "-")
               (setq id))
             (if (not (member id ids))
                 (push id ids)
               (message-box "Oh no, a repeated id!\n\n\t%s" id)
               (undo)
               (setq quit-flag t))
             (org-entry-put nil "CUSTOM_ID" id))))))))

;; Whenever html & md export happens, ensure we have headline ids.
(advice-add 'org-html-export-to-html   :before 'my/ensure-headline-ids)
(advice-add 'org-md-export-to-markdown :before 'my/ensure-headline-ids)

One may then use [[#my-custom-id]] to link to the entry with CUSTOM_ID property my-custom-id.

Interestingly, org-set-property, C-c C-x p, lets us insert a property from a selection of available ones, then we'll be prompted for a value for it from a list of values you've used elsewhere. This is useful for remaining consistent for when trees share similar properties.

6. Clickable Headlines

This section has been #+include'd from my init.org,
By default, HTML export generates ID's to headlines so they may be referenced to, but there is no convenient way to get at them to refer to a particular heading. The following spell fixes this issue: Headlines are now clickable, resulting in a link to the headline itself.

;; Src: https://writepermission.com/org-blogging-clickable-headlines.html
(setq org-html-format-headline-function
      (lambda (todo todo-type priority text tags info)
        "Format a headline with a link to itself."
        (let* ((headline (get-text-property 0 :parent text))
               (id (or (org-element-property :CUSTOM_ID headline)
                       (ignore-errors (org-export-get-reference headline info))
                       (org-element-property :ID headline)))
               (link (if id
                         (format "<a href=\"#%s\">%s</a>" id text)
                       text)))
          (org-html-format-headline-default-function todo todo-type priority link tags info))))

Warning: The header cannot already be a link! Otherwise you get cyrptic and unhelpful error (wrong-type-argument plistp :section-number); which then pollutes the current Emacs session resulting in stange nil errors after C-x C-s, thereby forcing a full Emacs restart. Instead, you need at least one portion of each heading to be not a link.

  1. Need to have a custom id declared.

      :PROPERTIES:
      :CUSTOM_ID: my-header
      :END:
    
  2. Failing headers: * [[link]] nor * ~code~ nor * $math$.
    • Any non-link text before it will work: ok [[link]].
      • Using Unicode non-breaking space ‘ ’ is ok.
    • Text only after the link is insufficient.

7. Curvy Source Blocks & Pink Inline

The border-radius property defines the radius of an element's corners, we use it to make curvy looking source blocks. Its behaviour changes depending on how many arguments it is given.

  • We also style the code block's label to be curvy.
  • Both .src and pre.src:before are used by Org.
 1: .src {
 2:   border: 0px !important;
 3:   /* 50px for top-left and bottom-right corners;
 4:      20px for top-right and bottom-left cornerns. */
 5:   border-radius: 50px 20px !important;
 6: }
 7: 
 8: pre.src:before {
 9:     /* border: 0px !important; */
10:     /* background-color: inherit !important; */
11:     padding: 3px !important;
12:     border-radius: 20px 50px !important;
13:     font-weight:700
14: }
15: 
16:  /* wrap lengthy lines for code blocks */
17:  pre{white-space:pre-wrap}
18: 
19:  /* Also curvy inline code with ~ ⋯ ~ and = ⋯ = */
20:  code {
21:      /* background: Cyan !important; */
22:      background: pink !important;
23:      border-radius: 7px;
24:      /* border: 1px solid lightgrey; background: #FFFFE9; padding: 2px */
25:  }

Code such as (= 2 (+ 1 1)) now sticks out with a cyan background ♥‿♥

 table {
     background: pink;
     border-radius: 10px;
     /* width:90% */

     border-bottom: hidden;
     border-top: hidden;

     display: table !important;

     /* Put table in the center of the page, horizontally. */
     margin-left:auto !important;margin-right:auto !important;

     font-family:"Courier New";
     font-size:90%;
 }

 /* Styling for ‘t’able ‘d’ata and ‘h’eader elements */
 th, td {
     border: 0px solid red;
 }
Table 1: Example table
Prime 2Prime
1 2
2 4
3 8
5 32
7 128
11 2048
;; Table captions should be below the tables
(setq org-html-table-caption-above nil
      org-export-latex-table-caption-above nil)
Let's show folded, details, regions with a nice greenish colour

This is part of org-special-block-extras, and it's something like this:

details {
  padding: 1em;
  background-color: #e5f5e5;
  /* background-color: pink; */
  border-radius: 15px;
  color: hsl(157 75% 20%);
  font-size: 0.9em;
  box-shadow: 0.05em 0.1em 5px 0.01em  #00000057;
}

8. Blog Banner and Dynamic Code Highlighting

I want to have a nice banner at the top of every page, which should link to useful parts of my blog.

 1: (setq org-static-blog-page-preamble
 2: "<div class=\"header\">
 3:   <a href=\"https://alhassy.github.io/\" class=\"logo\">Life & Computing Science</a>
 4:   <br>
 5:     <a href=\"https://alhassy.github.io/AlBasmala\">AlBasmala</a>
 6:     <a href=\"https://alhassy.github.io/archive\">Archive</a>
 7:     <a href=\"https://alhassy.github.io/tags\">Tags</a>
 8:     <a href=\"https://alhassy.github.io/rss.xml\">RSS</a>
 9:     <a href=\"https://alhassy.github.io/about\">About</a>
10: </div>")

I want to style it as follows:

  • Line 1: The banner is in a box at the top with some shadowing and centerd text using the fantasy font
  • Line 13: The blog's title is large and bold
  • Line 18: All links in the banner are black
  • Line 25: When you hover over a link, it becomes blue
 1: .header {
 2:   /* Try to load ‘fantasy’ if possible, else try to load the others. */
 3:   font-family: fantasy, monospace, Times;
 4:   text-align: center;
 5:   overflow: hidden;
 6:   /* background-color: #f1f1f1 !important; */
 7:   /* background: #4183c4 !important; */
 8:   padding-top: 10px;
 9:   padding-bottom: 10px;
10:   box-shadow: 0 2px 10px 2px rgba(0, 0, 0, 0.2);
11: }
12: 

14:   font-size: 50px;
15:   font-weight: bold;
16: }
17: 
18: .header a {
19:   color: black;
20:   padding: 12px;
21:   text-decoration: none;
22:   font-size: 18px;
23: }
24: 
25: .header a:hover {
26:   background-color: #ddd;
27:   background-color: #fff;
28:   color: #4183c4;
29: }

Notice that as you hover over the references, such as this, the corresponding line of code is highlighted! Within a src block, one uses the switches -n -r to enable references via line numbers, then declares (ref:name) on line and refers to it by [[(name)][description]]. Org-mode by default styles such highlighting.

Dynamic Code Highlighting
 1: "<script type=\"text/javascript\">
 2: /*
 3: @licstart  The following is the entire license notice for the
 4: JavaScript code in this tag.
 5: 
 6: Copyright (C) 2012-2020 Free Software Foundation, Inc.
 7: 
 8: The JavaScript code in this tag is free software: you can
 9: redistribute it and/or modify it under the terms of the GNU
10: General Public License (GNU GPL) as published by the Free Software
11: Foundation, either version 3 of the License, or (at your option)
12: any later version.  The code is distributed WITHOUT ANY WARRANTY;
13: without even the implied warranty of MERCHANTABILITY or FITNESS
14: FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
15: 
16: As additional permission under GNU GPL version 3 section 7, you
17: may distribute non-source (e.g., minimized or compacted) forms of
18: that code without the copy of the GNU GPL normally required by
19: section 4, provided you include this license notice and a URL
20: through which recipients can access the Corresponding Source.
21: 
22: 
23: @licend  The above is the entire license notice
24: for the JavaScript code in this tag.
25: */
26: <!--/*--><![CDATA[/*><!--*/
27:  function CodeHighlightOn(elem, id)
28:  {
29:    var target = document.getElementById(id);
30:    if(null != target) {
31:      elem.cacheClassElem = elem.className;
32:      elem.cacheClassTarget = target.className;
33:      target.className = \"code-highlighted\";
34:      elem.className   = \"code-highlighted\";
35:    }
36:  }
37:  function CodeHighlightOff(elem, id)
38:  {
39:    var target = document.getElementById(id);
40:    if(elem.cacheClassElem)
41:      elem.className = elem.cacheClassElem;
42:    if(elem.cacheClassTarget)
43:      target.className = elem.cacheClassTarget;
44:  }
45: /*]]>*///-->
46: </script>"

[Editor Remark:

Before we move on, I'd like to have heavy red font for links.

HERE PLS

But this causes the table of contents to be red, which I dislike ლ(ಠ益ಠ)ლ

]

9. Article Tile & Image

Every article declaratively has an associated image ^_^

  • Images are loaded from the ~/blog/images/ directory, but may be explicit paths or URLs.
  • If none declared, we use emacs-birthday-present.png :-)

    (cl-defun my/org-static-blog-assemble-image (file &optional explicit-image-path-prefix)
      "Assemble the value of ‘#+fileimage: image width height border?’ as an HTML form.
    
    By default, the image should be located in the top-level `images/' directory.
    If the image is located elsewhere, or is a URL, is dictated by the presence of a `/'
    in the image path.
    
    Here are 4 example uses:
    
    #+fileimage: emacs-birthday-present.png
    #+fileimage: ../images/emacs-birthday-present.png
    #+fileimage: https://upload.wikimedia.org/wikipedia/en/6/64/Dora_and_Boots.jpg 350 300
    #+fileimage: https://unsplash.com/photos/Vc2dD4l57og
    
    + Notice that the second indicates explicit width and height.
    + (To make the first approach work with local previews,
       we need the variable EXPLICIT-IMAGE-PATH-PREFIX which is used for local previews in `my/blog/style-setup'. This requires a slash at the end.)
    + The unsplash approach is specific: It shows the *main* image in the provided URL, and links to the provided URL.
    "
     (with-temp-buffer
       (insert-file-contents file)
       (goto-char 0)
       (search-forward-regexp "^\\#\\+fileimage: \\(.*\\)" nil t)
       (-let [(image width height no-border?)
              (s-split " " (substring-no-properties
                            (or (match-string 1)
                                "emacs-birthday-present.png")))]
         (setq width (or width 350))
         (setq height (or height 350))
         (setq no-border? (if no-border? "" "style=\"border: 2px solid black;\""))
         (cond
          ((s-contains? "/" image) t) ;; It's a URL, or explicit path, do nothing to it.
          (explicit-image-path-prefix (setq image (format "%s%s"  explicit-image-path-prefix image)))
          ((not (s-contains? "/" image)) (setq image (format "images/%s" image)))
           )
    
         (-let [unsplash (cl-second (s-match ".*unsplash.com/photos/\\(.*\\)" image))]
           (setq href (if unsplash (concat "https://unsplash.com/photos/" unsplash) image))
           (setq title (format "Image credit “%s”" (if unsplash (concat "https://unsplash.com/photos/" unsplash) image)))
           (setq src (if unsplash (format "https://source.unsplash.com/%s/%sx%s" unsplash width height) image))
           (format "<center><a href=\"%s\" class=\"tooltip\" title=\"%s\"><img src=\"%s\" alt=\"Article image\"
                 %s width=\"%s\" height=\"%s\" align=\"top\"/></a></center>"
                 href title src no-border? width height)))))
    

9.1. Making this work with org-notes-style and org-static-blog

To make use of org-notes-style, I need the title to use the title class but org-static-blog uses the post-title blog, so I'll override the org-static-blog preamble method to simply use an auxiliary div.

  • Along the way, I'll position the article image under the article's title.
  • Line 9: org-notes-style has too much vertical space after the title, let's reduce it so that the article's data can follow it smoothly.
 1: ;; MA: This can be deleted?? Do a search for post-title in this article to see why?
 2: (defun org-static-blog-post-preamble (post-filename)
 3:   "Returns the formatted date and headline of the post.
 4: This function is called for every post and prepended to the post body.
 5: Modify this function if you want to change a posts headline."
 6:   (concat
 7:    ;; The title
 8:    "<h1 class=\"post-title\">"
 9:    "<div class=\"title\" style=\"margin: 0 0 0 0 !important;\">"
10:    "<a href=\"" (org-static-blog-get-post-url post-filename) "\">"
11:    (org-static-blog-get-title post-filename)
12:    "</a>"
13:    "</h1></div>"
14:    ;; The date
15:    "<div style=\"text-align: center;\">"
16:    (format-time-string (org-static-blog-gettext 'date-format)
17:                        (org-static-blog-get-date post-filename))
18:    "</div>"
19:    ;; The article's image
20:    (my/org-static-blog-assemble-image post-filename)
21:    "<br><center><strong>Abstract</strong></center>"))

10. MathJax Support — \(e^{i \cdot \pi} + 1 = 0\)

Org loads the MathJax display engine for mathematics whenever users write LaTeX-style math delimited by $...$ or by \[...\]. Here is an example.

The CSS that Org loads by default
 1: "<script type=\"text/x-mathjax-config\">
 2:     MathJax.Hub.Config({
 3:         displayAlign: \"center\",
 4:         displayIndent: \"0em\",
 5: 
 6:         \"HTML-CSS\": { scale: 100,
 7:                         linebreaks: { automatic: \"false\" },
 8:                         webFont: \"TeX\"
 9:                        },
10:         SVG: {scale: 100,
11:               linebreaks: { automatic: \"false\" },
12:               font: \"TeX\"},
13:         NativeMML: {scale: 100},
14:         TeX: { equationNumbers: {autoNumber: \"AMS\"},
15:                MultLineWidth: \"85%\",
16:                TagSide: \"right\",
17:                TagIndent: \".8em\"
18:              }
19: });
20: </script>
21: <script type=\"text/javascript\"
22:         src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML\"></script>
23: "

Source

\[ p ⊓ q = p \quad ≡ \quad p ⊔ q = q \label{Golden-Rule}\tag{Golden-Rule}\]

Look at \ref{Golden-Rule}, it says, when specialised to numbers, /the minimum
of two items is the first precisely when the maximum of the two is the second/
---d'uh!

Result

\[ p ⊓ q = p \quad ≡ \quad p ⊔ q = q \label{Golden-Rule}\tag{Golden-Rule}\]

Look at \ref{Golden-Rule}, it says, when specialised to numbers, the minimum of two items is the first precisely when the maximum of the two is the second —d'uh!

10.1. Unicode Warning!

We can make an equation ℰ named 𝒩 and refer to it by ℒ by declaring \[ℰ \tag{𝒩} \label{ℒ} \] then refer to it with \ref{ℒ}. However, if 𝒩 contains Unicode, then the reference will not generally be ‘clickable’ —it wont take you to the equation's declaration site. For example, \ref{⊑-Definition} (⊑-Definition) below has Unicode in both its tag and label, and so clicking that link wont go anywhere, whereas \ref{Order-Definition} has Unicode only in its tag, with the label being \label{Order-Definition}, and clicking it takes you to the formula.

Source

\[ p ⊑ q \quad ≡ \quad p ⊓ q = p \tag{⊑-Definition}\label{⊑-Definition} \]

\[ p ⊑ q \quad ≡ \quad p ⊔ q = q \tag{⊑-Definition}\label{Order-Definition} \]

Result

\[ p ⊑ q \quad ≡ \quad p ⊓ q = p \tag{⊑-Definition}\label{⊑-Definition} \]

\[ p ⊑ q \quad ≡ \quad p ⊔ q = q \tag{⊑-Definition}\label{Order-Definition} \]

10.2. Rule Resurrection

The following rule for anchors a {⋯} resurrects \ref{} calls via MathJax —which org-notes-style kills.

a { white-space: pre !important; }

10.3. Making Math Stick-out with Spacing!   TODO LowPriority

This is low priority, since I'm not writing much math these days.

Notice how the math expressions stick out in these following sentences:

  1. We use \(x\) as the name of the unknown.
  2. The phrase \(∀ x • ∃ y • x 〔R〕 y\) indicates that relation \(R\) is “total”.

Nice, the following adds extra whitespace around MathJax, so that math elements have extra whitespace about them so as to make them stand-out.

TODO: Actually add the required script to the header code section of my org-static-blog configuration. OR add it as CSS as was done for the MathJax styling above. OR add to my MathJax.org file? Something to think about.

11. Using org-static-block

Let's use org-static-block to make our blog. Why?

  • It's a Lisp program smaller than 900 lines, its source is easy to read and understand, and, most importantly, it was super easy to get started using it using the given example.
The necessary basic facts of our blog
 1: (use-package org-static-blog)
 2: (use-package lf) ;; So we can use `lf-string' for multi-line strings supporting interpolation:
 3: ;; (lf-string "100/2 is ${ (/ 100 2) }; neato!") ;; ⇒ "100/2 is 50; neato!"
 4: 
 5: (setq org-static-blog-publish-title "Life & Computing Science")
 6: (setq org-static-blog-publish-url "https://alhassy.github.io/")
 7: (setq org-static-blog-publish-directory "~/blog/")
 8: (setq org-static-blog-posts-directory "~/blog/posts/")
 9: (setq org-static-blog-drafts-directory "~/blog/drafts/")
10: 
11: ;; Use “#+filetags: τ₁ τ₂ … τₙ”
12: (setq org-static-blog-enable-tags t)
13: 
14: ;; I'd like to have tocs and numbered headings
15: (setq org-export-with-toc t)
16: (setq org-export-with-section-numbers t)

11.1. Article Footers: HTMLized Source and Git History

Here is the main function:

 1: (defun org-static-blog-post-postamble (post-file-name)
 2:   "Returns the HTML rendering the htmlised source, version history, and comment box at the end of a post.
 3: 
 4: This function is called for every post and the returned string is appended to the post body."
 5:   (concat
 6:    "<hr>"
 7:    "<center>"
 8:    (blog/htmlize-file post-file-name)
 9:    "&ensp;"
10:    (blog/history-of-file post-file-name)
11:    ;;
12:    (blog/css/arabic-font-setup)
13:    ;;
14:    "<br>"
15:    "<a href=\"https://www.buymeacoffee.com/alhassy\"><img src="
16:    "\"https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee\">"
17:    "</a>"
18:    ;;
19:    "<br><strong> Generated by Emacs and Org-mode (•̀ᴗ•́)و </strong>"
20:    ;; org-static-blog-page-postamble
21:    (blog/license)
22:    ;; (blog/comments) ;; TODO. Not working as intended; low priority.
23:    "</center>"
24:    ;; The next line is required to make the org-static-blog-assemble-rss method work.
25:    "<div hidden> <div id=\"postamble\" class=\"status\"> </div> </div>"
26:    (blog/read-remaining-js)))

Where its helper methods are below: blog/tags-of-file, blog/history-of-file, blog/htmlize-file, blog/read-remaining-js blog/license blog/comments

Details
(defun blog/tags-of-file (file-name)
  "Get an HTML listing of tags, as shields.io bages, associated with the given file."
          (concat
   ;; Straightforward implementation.
   ;; "<div class=\"taglist\">"
   ;; (org-static-blog-post-taglist file-name)
   ;; "</div>"

  ;; Badges implementation
   (if (not file-name)
       ""
     (concat
      (format "<a href=\"https://alhassy.github.io/tags.html\"> %s </a>"
              (org-link/octoicon "tag" nil 'html))
      (s-join " "
              (--map  (org-link/badge
                       (format "|%s|grey|%stag-%s.html"
                               (s-replace "-" "_" it)
                               org-static-blog-publish-url it)
                       nil 'html)
                      (org-static-blog-get-tags file-name)))))))

(defun blog/history-of-file (file-name)
  "Get an HTML badge that points to the Github history of a given file name, in my blog."
  (concat
     "<a class=\"tooltip\" title=\"See the various edits to this article over time\""
     "href=\"https://github.com/alhassy/alhassy.github.io/commits/master/"
   "posts/" (f-base file-name) ".org\"><img
   src=\"https://img.shields.io/badge/-History-informational?logo=github\"></a>"))
(defun blog/htmlize-file (file-name)
  "Generate an htmlized version of a given source file; return an HTML badge linking to the colourised file.

We do not take the extra time to produce a colourised file when we are previewing an article."
  (unless org-preview-html-mode
(let ((org-hide-block-startup nil))
  (with-temp-buffer
    (find-file file-name)
    ;; (insert "\n#+HTML_HEAD: <link href=\"../doom-solarized-light.css\" rel=\"stylesheet\">\n")
    (org-mode)
    (outline-show-all)
    (switch-to-buffer (htmlize-buffer))
    (write-file (concat "~/blog/" (f-base file-name) ".org.html"))
    (kill-buffer))))
(concat
"<a class=\"tooltip\" title=\"See the colourised Org source of this article; i.e., what I typed to get this nice webpage\" href=\""
   (f-base file-name) ".org.html\"><img
   src=\"https://img.shields.io/badge/-Source-informational?logo=read-the-docs\"></a>"))

(defun blog/license ()
  "Get HTML for Creative Commons Attribution-ShareAlike 3.0 Unported License."
(s-collapse-whitespace (s-replace "\n" ""
"
<center style=\"font-size: 12px\">
  <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\">
     <em>Life & Computing Science</em>
  </span>

  by
  <a xmlns:cc=\"https://creativecommons.org/ns#\"
  href=\"https://alhassy.github.io/\"
  property=\"cc:attributionName\" rel=\"cc:attributionURL\">
    Musa Al-hassy
  </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>")))
 1: (defun blog/comments ()
 2:   "Embed Disqus Comments for my blog"
 3: (s-collapse-whitespace (s-replace "\n" ""
 4: "
 5: <div id=\"disqus_thread\"></div>
 6: <script type=\"text/javascript\">
 7: /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
 8: var disqus_shortname = 'life-and-computing-science';
 9: /* * * DON'T EDIT BELOW THIS LINE * * */
10: (function() {
11:   var dsq = document.createElement('script');
12:   dsq.type = 'text/javascript';
13:   dsq.async = true;
14:   dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
15:   (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
16:     })();
17: </script>
18: <noscript>Please enable JavaScript to view the
19:     <a href=\"http://disqus.com/?ref_noscript\">comments powered by Disqus.</a></noscript>
20: <a href=\"http://disqus.com\" class=\"dsq-brlink\">comments powered by <span class=\"logo-disqus\">Disqus</span></a>")))
(defun blog/read-remaining-js ()
  "Get the HTML required to make use of ReadRemaining.js"

  ;; [Maybe Not True] ReadReamining.js does not work well with xWidget browser within Emacs
  (if (equal org-preview-html-viewer 'xwidget)
      ""

   ;; ReadRemaining.js ∷ How much time is left to finish reading this article?
   ;;
  ;; jQuery already loaded by org-special-block-extras.
  ;; "<script
  ;; src=\
  ;; "https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js\"></script>"
 "<link rel=\"stylesheet\" href=\"readremaining.js-readremainingjs/css/rr_light.css\"
     type='text/css'/>
  <script
     src=\"readremaining.js-readremainingjs/src/readremaining.jquery.js\"></script>
  <script src='readremaining.js/src/readremaining.jquery.js'
     type='text/javascript'></script>
  <script type=\"text/javascript\"> $('body').readRemaining({showGaugeDelay : 10,
     showGaugeOnStart : true}); </script>"))

ReadRemaining.js gives us a little floating clock on the bottom left of the screen which says, e.g., 4m 9s left when reading an article.

  • It tells us how much time is left before the article is done.
  • The time adjusts dynamically as the user scrolls down —but not up.
  • Apparently it has to be at the end of the HTML <body>, otherwise it wont work for me.
    • It may be best to avoid loading jQuery multiple times; see here for the necessary conditional.

[ლ(ಠ益ಠ)ლ:

I want to consistently use the same theme to htmlize Org source, rather than the current session's theme.

]

11.2. Arabic Font Setup

I'd like inline Arabic to be displayed using الخط الأمیری since that's how it looks within Emacs for me. But, Arabic within tables should be displayed in a more formal font, Scheherazade, that makes it really clear where letters start and end, and where the vowels above/below letters are positioned.

Details
(defun blog/css/arabic-font-setup ()
  "Setup the CSS/HTML required to make my Arabic writing look nice.

For a one-off use in an article, just place an “#+html:” in front of the result
of this function."

  "
  <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Amiri'>
  <style>
     body {font-family: 'Amiri', sans-serif;}
     table {font-family:  'Scheherazade'; font-size: 105%; }
   </style>")

To understand why these styling rules work, see this website: Right-to-left Styling.


Source

For example,
+ Inline: اهلاً وسهلاً
+ Within a table:
    |  اهلاً وسهلاً |

Result

For example,

  • Inline: اهلاً وسهلاً
  • Within a table:

    اهلاً وسهلاً

As the above left source demonstrates, unless some explicit action is taken, Arabic fonts are by default rendered hideously small.

11.3. The Index Page

I'd like to be able to quickly change the blurb on the index page, so we make a variable for that —consisting of Org-markup.

1: (setq index-content-header
2:   (concat
3:    "Here are some of my latest thoughts..."
4:    " badge:Made_with|Lisp such as doc:thread-first and doc:loop (•̀ᴗ•́)و"
5:    " tweet:https://alhassy.github.io/"))

The actual look and feel of index.html is due to the method org-static-blog-assemble-multipost-page.

Details

The existing org-static-blog-assemble-index is really fast, since it just dumps articles wholesale into the landing page; not ideal. I'd rather have a ‘preview’ of articles.

The index page is a multipost page, so I'll override the org-static-blog-assemble-multipost-page method so that articles are summarised by their title, data & image, ‘abstract’, and a read-more badge.

  • Every article is intended to have a section named Abstract, whose contents are used as the preview of the article. See §13 for a template.
 1: (defun org-static-blog-assemble-multipost-page
 2:     (pub-filename post-filenames &optional front-matter)
 3:   "Assemble a page that contains multiple posts “previews” one after another.
 4: 
 5: - Each “preview” consists of a post's title, tags, image, and abstract.
 6: - Previews are sorted in descending time.
 7: 
 8: You can view the generated ~/blog/index.html by invoking:
 9:    (progn (my/blog/style-setup/disable) (org-static-blog-assemble-index))
10: "
11:   (setq show-reading-time nil) ;; Experimental.
12:   (setq post-filenames
13:         (sort post-filenames (lambda (x y)
14:                                (time-less-p (org-static-blog-get-date y)
15:                                             (org-static-blog-get-date x)))))
16: 
17:   (let ((org-header (concat "#+EXPORT_FILE_NAME: " pub-filename
18:                             "\n#+options: toc:nil title:nil html-postamble:nil"
19:                             "\n#+title: " (if (equal "index" (f-base pub-filename))
20:                                               org-static-blog-publish-title
21:                                             (f-base pub-filename))
22:                             "\n#+begin_export html\n "
23:                             org-static-blog-page-preamble
24:                             org-static-blog-page-header
25:                             (if front-matter front-matter "")
26:                             "\n#+end_export"
27:                             ;; Extra styling of abstracts.
28:                             ;; Works; but not needed.
29:                             ;; "\n#+HTML_HEAD_EXTRA: <style> div.abstract {background-color: pink !important;} </style>"
30:                             ))
31:         (index-header (if (equal "index" (f-base pub-filename))
32:                           (format "#+begin_export html\n%s\n#+end_export\n%s"
33:                                   org-static-blog-page-header index-content-header)
34:                         ""))
35:         (_ (view-echo-area-messages))
36:         (abstracts-of-posts (--map
37:                              (concat
38:                               (progn (message "Processing %s..." it) "") ;; Progress indicator
39: 
40:                               ;; ⟨0⟩ Title and link to article
41:                               (format "#+HTML: <h2 class=\"title\"><a href=\"%s\"> %s</a></h2>"
42:                                       (concat org-static-blog-publish-url (f-base it))
43:                                       (org-static-blog-get-title it))
44: 
45:                               ;; ⟨1⟩ Tags and reading time
46:                               (format "\n#+begin_export html\n<center>%s\n%s</center>\n#+end_export"
47:                                       (blog/tags-of-file it)
48:                                       ;; Experimenting.
49:                                       (if (not show-reading-time)
50:                                           ""
51:                                         (format "\n%s %s mins read"
52:                                                 "octoicon:clock"
53:                                                 (with-temp-buffer (insert-file-contents it)
54:                                                                   (org-ascii-export-as-ascii)
55:                                                                   (setq __x
56:                                                                         (count-words (point-min) (point-max)))
57:                                                                   (kill-buffer "*Org ASCII Export*")
58:                                                                   (delete-other-windows)
59:                                                                   (/ __x 200)))) ;; 200 words per minute reading
60:                                       )
61: 
62:                               ;; ⟨2⟩ Article image
63:                               (format "\n@@html:%s@@\n" (my/org-static-blog-assemble-image it))
64: 
65:                               ;; ⟨3⟩ Preview
66:                               (format "\n#+INCLUDE: \"%s::*Abstract\" :only-contents t" it)
67: 
68:                               ;; ⟨4⟩ “Read more” link
69:                               (format (concat "\n@@html:<p style=\"text-align:right\">@@"
70:                                               " badge:Read|more|green|%s|read-the-docs @@html:</p>@@")
71:                                       (concat org-static-blog-publish-url (f-base it))))
72:                              post-filenames))
73:         ;; This is the bottom-most matter in the index.html page
74:         (show-older-posts (concat  "\n#+begin_export html\n"
75:                                    "<hr> <div id=\"archive\">"
76:                                    "<a href=\""
77:                                    (org-static-blog-get-absolute-url org-static-blog-archive-file)
78:                                    "\">" (org-static-blog-gettext 'other-posts) "</a>"
79:                                    "</div>"
80:                                    "</div>"
81:                                    (blog/license)
82:                                    "\n#+end_export")))
83:     (with-temp-buffer
84:       (insert (s-join "\n\n" (list org-header
85:                                    index-header
86:                                    (s-join "\n\n" abstracts-of-posts)
87:                                    show-older-posts)))
88:       (org-mode)
89:       (org-html-export-to-html))))

12. Actually publishing an article

(cl-defun blog/git (cmd &rest args)
  "Execute git command CMD, which may have %s placeholders whose values are positional in ARGS."
  (shell-command (apply #'format (concat "cd ~/blog; git " cmd) args)))

(cl-defun blog/publish-current-article ()
  "Place HTML files in the right place, update arhives, index, rss, tags; git push!"
  (interactive)
    (blog/git "add %s" (buffer-file-name))
  ;; Placed article html into the published blog directory
  (blog/preview)
  (save-buffer)
  (-let [article (concat (f-base (buffer-file-name)) ".html")]
    (shell-command (concat "mv " article " ~/blog/"))
    (blog/git "add %s %s" (buffer-file-name) article)
    (when (equal (f-base (buffer-file-name)) "AlBasmala")
      (blog/git "add AlBasmala.el")))

  ;; Updated index.html, tags, archive, and rss to now include this new article

  ;; Need to disable my export-preprocessing hooks, when using org-static-blog utils.
  (blog/preview/disable)
  (view-echo-area-messages)

  (message "⇒ HTMLizing article...")
  (blog/htmlize-file (buffer-file-name))
  (blog/git "add %s.org.html" (f-base (buffer-file-name)))

  (message "⇒ Assembling tags...")
  (org-static-blog-assemble-tags)
  (blog/git "add tag*")

  (message "⇒ Assembling archive...")
  (org-static-blog-assemble-archive)
  (blog/git "add archive.html")

  (message "⇒ Assembling RSS feed...")
  (org-static-blog-assemble-rss)
  (blog/git "add rss.xml")

  (message "⇒ Assembling landing page...")
  (org-static-blog-assemble-index)
  (blog/git "add index.html")

  (blog/git "commit -m \"%s\"; git push"
            (if current-prefix-arg
                (read-string "Commit message: ")
              (format "Publish: Article %s.org" (f-base (buffer-file-name)))))

  (message "⇒ It may take up 20secs to 1minute for changes to be live at alhassy.com; congratulations!"))


13. Getting Started: blog/new-article

Helper function to make a new article.

 1: (defvar blog/tags
 2:   '(emacs faith category-theory order-theory
 3:     lisp types packages haskell agda
 4:     c frama-c program-proving)
 5:   "Tags for my blog articles.")
 6: 
 7: (defun blog/new-article ()
 8: "Make a new article for my blog; prompting for the necessary ingredients.
 9: 
10: If the filename entered already exists, we simply write to it.
11: The user notices this and picks a new name.
12: 
13: This sets up a new article based on existing tags and posts.
14: + Use C-SPC to select multiple tag items
15: 
16: Moreover it also enables `org-preview-html-mode' so that on every alteration,
17: followed by a save, C-x C-s, will result in a live preview of the blog article,
18: nearly instantaneously."
19:   (interactive)
20:   (let (file desc)
21: 
22:     (thread-last org-static-blog-posts-directory
23:       f-entries
24:       (mapcar #'f-filename)
25:       (completing-read "Filename (Above are existing): ")
26:       (concat org-static-blog-posts-directory)
27:       (setq file))
28: 
29:     ;; For some reason, ‘find-file’ in the thread above
30:     ;; wont let the completing-read display the possible completions.
31:     (find-file file)
32: 
33:     (insert "#+title: " (read-string "Title: ")
34:             "\n#+author: " user-full-name
35:             "\n#+email: "  user-mail-address
36:             ;; "\n#+date: " (format-time-string "<%Y-%m-%d %H:%M>")
37:             "\n#+filetags: " (s-join " " (helm-comp-read "Tags: "
38:                                                          blog/tags
39:                                                          :marked-candidates t))
40:             "\n#+fileimage: emacs-birthday-present.png"
41:             ;; "\n#+fileimage: " (completing-read
42:             ;;                    "Image: "
43:             ;;                    (mapcar #'f-filename (f-entries "~/blog/images/")))
44:             ;; "\n#+include: ../MathJaxPreamble.org" ;; TODO. Is this someting I actually want here? If so, then consider tangling it from AlBasmala! (and add the whitespace-MathJax setup from above!)
45:             "\n#+description: "
46:                (setq desc (read-string "Article Purpose: "))
47:             "\n\n* Abstract :ignore: \n" desc
48:             "\n\n* ???")
49:     (save-buffer)
50:     (blog/preview)))

The #+description is exported as HTML meta-data which is used to ‘unfurl’ a link to an article: When a link to an article is pasted in a social media website, it unfurls into a little card showing some information about the link, such as its image, description, and author.

  • For long descriptions, one can use multiple #+description lines; I'd like to have a terse one-liner with a longer description in the Abstract heading.

14. The name: al-bas-mala

The prefix al is the Arabic definite particle which may correspond to English's the; whereas basmala refers to a beginning.

That is, this is a variation on the traditional "hello world" ;-)

15. Appendix: Using a Custom Domain: alhassy.com

  1. Go to your repo: https://github.com/alhassy/alhassy.github.io/settings/pages
  2. Add a Custom Domain such as an “apex domain” like alhassy.com (or a www domain like www.alhassy.com)
    • Apex domains require A records to be setup on your DNS provider.
    • www domains require CNAME records.
    • On my DNS provider, I setup both: That way, with or without www., people will arrive at my blog.
  3. Go to your DNS provider, and add two records

    Type Name Priority Content TTL
    CNAME www 0 alhassy.github.io 14400
    CNAME @ 0 alhassy.github.io 14400
  4. In a terminal, run: dig www.alhassy.com +nostats +nocomments +nocmd
    • The www. is intentional.
  5. You should see something like:

        www.alhassy.com.	14400	IN	CNAME	alhassy.github.io.
        alhassy.github.io.	3600	IN	A	185.199.111.153
        alhassy.github.io.	3600	IN	A	185.199.108.153
        alhassy.github.io.	3600	IN	A	185.199.109.153
        alhassy.github.io.	3600	IN	A	185.199.110.153
    

    This says that it may take 3600 seconds, or 1hour, for the redirect of alhassy.com to alhassy.github.io to be completed. It may take longer; keep reading.

  6. In your DNS provider, add 4 records, one for each IP Address you got from the dig command. (These addresses are also on the official Github docs).

    Type Name Priority Content TTL
    A @ 0 185.199.108.153 14400
    A @ 0 185.199.109.153 14400
    A @ 0 185.199.110.153 14400
    A @ 0 185.199.111.153 14400
  7. Run dig alhassy.com +noall +answer -t A and ensure it points to these IP addresses.
    • Notice the lack of a www.
  8. Open an incognito browser, private browsing session, and navigate to alhassy.com.
    1. If this redirects to your alhassy.github.io blog, then joy!
      • If the redirect does not happen in your non-incognito browser, just clear your browsing history and try again.
    2. Otherwise, it may take some time (something like 1/2hour to 3 days) for the DNS propagation to be completed.
      • You can check the progress by using a service like this.
      • It took me about 1/2hour for the URL to redirect to my github.io blog.

Further resources:




Generated by Emacs and Org-mode (•̀ᴗ•́)و
Creative Commons License
Life & Computing Science by Musa Al-hassy is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License