How this site is made

Table of Contents

1 Introduction

I've made this website with org-mode, a bit of elisp, and emacs. The idea is to be able to checkout out the git repository of this site, tangle the Makefile from README.org, and run make publish, and possibly have this run from a post commit hook.

Now that the site can be generated, I need to sort out the content bits and the css bits.

2 Publishing environment

The Makefile tangled from README.org make assumptions about the environment, specifically make will be run from the top level source directory, index.org exists, and site-create.org exists and contains the elisp code that defines the project. That is emacs is invoked as to load this file, visit index.org and execute (org-publish "jamestechnotes").

(setq this-directory (file-name-directory (or load-file-name buffer-file-name)))
(setq pub-directory "~/public_html/jamestechnotes.com")

I also prefer to have css in an external stylesheet.

(setq org-html-htmlize-output-type 'css)

I have (org-publish) use timestamps to keep from publishing the entire site all the time. This does make it a pain to ensure generated blobs are always updated on the site. I don't that turning off timestamps is really a good idea either. I keep them on, for now but move the location to temporary-file-directory if defined, otherwise to /tmp.1

(setq org-publish-timestamp-directory
      (concat (or (when (boundp 'temporary-file-directory) temporary-file-directory)
                  "/tmp/")
              ".org-timestamps/"))

When org-mode exports a file to html, it creates a preamble section right after the =<body> tag. I would like this to be the same for every page on my site, except for pages where I don't it, or want something different. My résumé page, for instance, will have a different preamble. Since preambles in a publishing project can be created by an elisp function, I was able to solve this by writing such a function that looks for magic files. If first looks for a file with the base name of the org file with a banner extension, then looks for a file named banner in the directory of the org file, then looks for a file named banner in the top level directory. I can have a default banner for the site that can be overridden by a default banner for a subdirectory of the site or for a particular page.

(let ((text (or (get-file-contents-if-exists (concat (file-name-sans-extension (plist-get info :input-file))
                                                     ".banner"))
                (get-file-contents-if-exists (concat (file-name-directory (plist-get info :input-file))
                                                     "banner"))
                (get-file-contents-if-exists (concat (plist-get info :base-directory)
                                                     "banner")))))
  (if text (insert text)))

I would like to do the same thing with navigation

(let ((text (or (get-file-contents-if-exists (concat (file-name-sans-extension (plist-get info :input-file))
                                                     ".nav"))
                (get-file-contents-if-exists (concat (file-name-directory (plist-get info :input-file))
                                                     "nav"))
                (get-file-contents-if-exists (concat (plist-get info :base-directory)
                                                     "nav")))))
  (if text (insert text)))

Let's write a helper function to return the file contents as a string surrounded by comments so we know where the file originated for debugging. I had to use cl-flet from CLISP as I couldn't sort out how to this with straight elisp.2

(cl-flet* ((get-file-contents-if-exists (FILENAME)
                                        (if (file-readable-p FILENAME)
                                            (concat "<!-- start of " FILENAME " -->\n"
                                                    (with-temp-buffer (insert-file-contents FILENAME) (buffer-string))
                                                    "<!-- end of " FILENAME " -->\n"))))

Now let's build a function that will generate the preamble. Move <nav> outside of =<header>.

(require 'cl)
(defun preamble-test (info)
  "function to build preamble"
  (cl-flet* ((get-file-contents-if-exists (FILENAME)
                                          (if (file-readable-p FILENAME)
                                              (concat "<!-- start of " FILENAME " -->\n"
                                                      (with-temp-buffer (insert-file-contents FILENAME) (buffer-string))
                                                      "<!-- end of " FILENAME " -->\n"))))
  (with-temp-buffer
    (insert "<!-- beginning of preamble -->\n<div id=\"header\">")
    (let ((text (or (get-file-contents-if-exists (concat (file-name-sans-extension (plist-get info :input-file))
                                                         ".banner"))
                    (get-file-contents-if-exists (concat (file-name-directory (plist-get info :input-file))
                                                         "banner"))
                    (get-file-contents-if-exists (concat (plist-get info :base-directory)
                                                         "banner")))))
      (if text (insert text)))
    (insert "</div> <!-- header -->\n<!-- end of preamble -->\n")
    (let ((text (or (get-file-contents-if-exists (concat (file-name-sans-extension (plist-get info :input-file))
                                                         ".nav"))
                    (get-file-contents-if-exists (concat (file-name-directory (plist-get info :input-file))
                                                         "nav"))
                    (get-file-contents-if-exists (concat (plist-get info :base-directory)
                                                         "nav")))))
      (if text (insert text)))
    (buffer-string))))

Now, define the project. As this is now being run from emacs in batch mode, we first make sure that org-publish-project-alist is defined.

(unless (boundp 'org-publish-project-alist)
  (setq org-publish-project-alist nil))

I define multiple projects, one for the generated bits, one for the static bits, and one to tie everything together. But first, although possibly needlessly, I delete the projects, that way I ensure the proper definition will be found. This also ensures if I load this file into my emacs session, things still work. (If I actually knew lisp, I could use mapcar to loop through the projects,..)

(setq org-publish-project-alist 
      (delete 
       (assoc "jamestechnotes" org-publish-project-alist)
       org-publish-project-alist))

(setq org-publish-project-alist 
      (delete 
       (assoc "jamestechnotes-static" org-publish-project-alist)
       org-publish-project-alist))

(setq org-publish-project-alist 
      (delete 
       (assoc "jamestechnotes-html" org-publish-project-alist)
       org-publish-project-alist))

Now add the bits that will transform the org files into html. The interesting bits here are I turn off the automatic items. I may turn on sitemaps later, if I can sort out actually how to use them. I exlcude .git as I have used git annex to store images and I don't wish to have symlinks leaking into the website.

I use html-head-extra to store things that won't change per page. I put a stylesheet in html-head. This will be over ridden where needed. I am trying to keep the site self contained, so I can publish is locally and rsync it to my web host. #+name jamestechnotes-html

(add-to-list
 'org-publish-project-alist
 `("jamestechnotes-html"
   :base-directory ,this-directory
   :base-extension "org"
   :publishing-directory ,(expand-file-name pub-directory)
   :publishing-function (org-html-publish-to-html)
   :recursive t
   :exclude ".git"
   :headline-levels 6
   :auto-preamble nil
   :html-preamble preamble-test
   :auto-sitemap nil
   :makeindex nil
   :html-doctype "xhtml5"
   :html-head-include-default-style nil
   :html-head-include-scripts nil
   :html-head "<link rel=\"stylesheet\" title=\"Default\" href=\"css/style.css\" type=\"text/css\" />"
   :html-head-extra "<link rel=author href=\"https://plus.google.com/u/0/100087072360376597478?rel=author\" />"
   ))

Now define the static bits.

(add-to-list
 'org-publish-project-alist
 `("jamestechnotes-static"
   :base-directory ,this-directory
   :publishing-directory ,(expand-file-name pub-directory)
   :publishing-function (org-publish-attachment)
   :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|ogg\\|swf\\|txt"
   :recursive t
   :exclude ".git"
   ))

Now define the bit that actually publishes everything.

(add-to-list
 'org-publish-project-alist
 '("jamestechnotes" :components ("jamestechnotes-html" "jamestechnotes-static")))

3 Preamble

The 1 wraps the preamble in a <div id=header>...</div>. It is important for the banner and nav files to not leave any <div> open.

3.1 banner

The first part if the preamble is the banner, which includes my site name and a Duck Duck Go search box. I had to put the search bit first so it could be floated to the right.

3.2 navigation

Do the typical unordered list css menu thing. At some point, this should be process to indicate which tab is actually the current page.

3.2.1 navigation for home

Why can't I have this created automatically?

<div id="nav">
  <ul>
    <li><a href=".." title="Home page">Home</a></li>
    <li><a href="../contact.html" title="Contact">Contact</a></li>
  </ul>
</div>
#+HTML_HEAD: <link rel="stylesheet" title="Default" href="../css/style.css" tpye="text/css" />

3.2.2 navigation for home-etc

Why can't I have this created automatically?

<div id="nav">
  <ul>
    <li><a href=".." title="Home page">Home</a></li>
    <li><a href="../contact.html" title="Contact">Contact</a></li>
  </ul>
</div>
#+HTML_HEAD: <link rel="stylesheet" title="Default" href="../css/style.css" tpye="text/css" />

4 CSS

Fortunately the html files generated by (org-publish PROJECT) have the css mark up already, so controlling the look of the site is achievable.3 I'm starting with the default worg.css changing bits to make things look like I think they should.

4.1 structure

This would be a bit easier, if I actually know css, but I do know more now that I did a while ago. Here I define the overall structure (I think) of the site. I would like to have a blue banner all the way across the top, the main content, and the a footer. I would like the table of content index thing float on the right like the one on the Worg site does.

4.2 basic setup

Let's set the fonts, borders of the html, body, and p elements. I am trying to get the background a pale blue. Set a monospace font for code and pre blocks. and set the border for pre.

html {
    font-family: "Droid Sans", Helvetica, Arial, sans-serif;
}

body {
    margin: 0;
    border: 0;
    background-color: #DFDFFF;
}

#content {
    border: 10px;
    padding: 10px 35px;
}

code, pre {
    font-family: "Droid Sans Mono", monospace, sans-serif;
}

pre {
    margin: 5px 20px;
    border: 2px solid #000000;
    padding: 10px;
}

p {
      font-family: "Droid Serif", Georgia, Times, serif;
}

4.3 Preamble

I set the bits here to make things look right. I set the background on #preabmle to blue, and set the padding to give a border. I increase the font-size in .header-logo, the munge the link to make it look like regular text, but still be a link.

#preamble {
    background-color: #0000FF;
    padding: 50px 25px;
}

.header-logo {
    font-size: 250%;
}

a.logo-container {
    text-decoration: none;
    color: #FFFFFF;
    text-shadow: 2px 2px 2px #000000;
    font-family: "Droid Serif", Geogia, Times, serif;
}

#search {
    float: right;
}

4.3.1 Navigation

#nav ul {
    list-style: none outside none;
    margin: 70px 0 0 0;
}

#nav ul li {
    float: left;
    margin: -4px 1px;
    font-variant: small-caps;
}

#nav ul li a {
    color: white;
    text-decoration: none;
    background-color: #AAAAFF;
}

4.4 Table of Contents

I want the table of contents to float up in the right corner. First we make the table of contents not display.

  #text-table-of-contents {
      display: none;
  }

  #table-of-contents {
      float: right;
      max-height: 80%;
      display: block;
      z-index: 100;
      position: fixed;
      right: 10px;
      top: 10px;
      padding: 0;
      margin: 0;
      border: 1px solid #00FF00;
      overflow: auto;
      background: #CCFFCC;
  }

#table-of-contents h2 {
    border: 0;
    padding: 0em;
    margin: 0em;
}

#table-of-contents:hover #text-table-of-contents {
    display: block;
    padding: 0.5em;
    margin-top: -1.5em;
}

4.5 fonts

Oh, what are good web fonts? I don't know, I also don't know squat about web design. I did how find this site which provides ideas. I've decided to try the Droid Sans and Serif fonts.

@import url(http://fonts.googleapis.com/css?family=Droid+Sans:400,700|Droid+Sans+Mono|Droid+Serif:400,700,400italic,700italic);
@import url(http://fonts.googleapis.com/css?family=Courgette);

Footnotes:

1

I typically don't like to use /tmp for many things due to race conditions. I also define TMP, TEMP, TEMPDIR, and company to point to ~/tmp.

2

Did I mention I had to learn LISP as part of this process?

3

Assuming one knows css, which I do not.

Author: James Richardson

Created: 2013-12-15 Sun 17:12

Emacs 24.3.1 (Org mode 8.2.3c)

Validate