org-mode website

How I'm managing this website with org mode

Just as a disclaimer, I'm still at the very start on this site project, so this article will probably be somewhat constantly updated while I try things out.

Resources

The most relevant resources I read was the community documentation on using org-mode (org-publish) for websites, and the org-mode manual itself, specifically the org-publish and source code sections.

Directory structure


.
├── aboutme.org          # This is the "about me" section you can click on the index
├── css
│   ├── CozetteVector.ttf # The custom font, my favourite
│   └── stylesheet.css    # The css stylesheet
├── img                   # The images directory
│   ├── irl.jpg
│   ├── keeb2.jpeg
├── index.org            # The website index
└── txt                   # Where I keep the articles
    └── index.org        # The "all articles" page

Once I make some art that I'm actually proud off I'll have a gallery index too.

This site directory is kept separate from the actual site I'm pushing to neocities. The directory with the HTML files gets generated with org-publish-project, which runs a bunch of hooks you will see in the configuration.

Configuration

Keeping the directory structure in mind, there's some configuration on my init.el file that is responsible for generating the directory structure, handling links, themes and even more things that I disable for the sake of keeping my site less cluttered (i.e making sitemaps automatically, or pre/postamble).

(setq   org-publish-project-alist
  '(("org-notes"
     :base-directory "~/dox/notes/projects/site/"
     :base-extension "org"
     :publishing-directory "~/site/"
     :recursive t
     :publishing-function org-html-publish-to-html
     :headline-levels 4             ; Just the default for this project.
     :auto-preamble t
     :section-numbers nil
     :with-toc nil
     :html-head-include-default-style nil
     :html-head "<link rel='stylesheet' type='text/css' href='css/stylesheet.css'>"
     :html-postamble nil
     )
    ("org-static"
     :base-directory "~/dox/notes/projects/site/"
     :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|ttf"
     :publishing-directory "~/site/"
     :recursive t
     :publishing-function org-publish-attachment
     )
    ("org-txt"
     :base-directory "~/dox/notes/projects/site/txt/"
     :base-extension "org"
     :publishing-directory "~/site/txt/"
     :recursive t
     :publishing-function org-html-publish-to-html
     :headline-levels 4             ; Just the default for this project.
     :auto-preamble t
     :section-numbers nil
     :with-toc nil
     :html-head-include-default-style nil
     :html-head "<link rel='stylesheet' type='text/css' href='../css/stylesheet.css'>"
     :html-postamble nil
     )

     ("org" :components ("org-notes" "org-static" "org-txt"))
    )
  )

First, there's "org-notes", where most of the work is done:

  • :base-directory is the address of the separate directory where I keep all the .org files
  • :base-extension only operates with .org files
  • :publishing-directory is where the generated html files go
  • :recursive t makes it works on the directory recursively duh
  • :publishing-function is the internal function that's run for converting the .org files into html
  • :section-numbers nil prevents the headers from having 1. numbers, just a aesthetic thing
  • :with-toc nil disables the automatically generated table of contents, there's only a few situations where I might want it, for that I can overwrite this option in the files themselves with "#+HTML_OPTIONS: toc: t"
  • :html-head-include-default-style nil disables the default style, since I have my own stylesheet
  • :html-head has the tag necessary for referencing the stylesheet
  • :html-postamble nil disables the postamble, I don't have anything significant to put at the bottom of every page.

Then, there's the "org-static" bit where all the non-html stuff get exported and it's links handled.

Also, there's "org-txt", an extra thing I put in for handling linking stuff that is a directory above.

Finally, with the line ("org" :components ("org-notes" "org-static" "org-txt")) all those options run when I do a org-publish-project org

On a side note, for you to be able to change image sizes, you have to put (setq org-image-actual-width nil) somewhere in your configuration. You can change image sizes by putting #+ATTR_HTML: :width 500px one line above the image you want to resize. You can do way more with this technique, reference the documentation for more info.

"Dynamic" stuff

My site has no JS, so there's no real "dynamic" stuff, but there's some stuff that gets generated and written in some web pages automatically.

For now, there's only automation around the "articles". In the index.org and txt/index.org pages I have this code block:


#+begin_src bash :exports results :results output list raw :shebang "#!/bin/bash" :tangle test.sh
readarray -t files < <(ls -t1 txt | head -n 5 | grep -v "index.org")
 for x in "${files[@]}"; do
    title=$(grep -m 1 "#+title:" txt/"$x"| cut -d ':' -f 2-)
    date=$(stat -c "%y" txt/"$x" | cut -d ' ' -f 1)
    echo "$date [[./txt/$x][$title]]"
done
\#+end_src

Inside the block there's a simple bash script that echoes out a list of the 5 most recent articles, the results are written to the page in a #+RESULTS: block right below it, and through the header arguments, the source code itself doesn't show up in the page.

  • #begin_src bash indicates that it's a bash shell script
  • :exports results is the part that makes that the source code block doesn't show up in the final HTML file
  • In the :results argument output makes that results of the script get written out verbatim, list formats the results into a standard org-mode list, and finally raw makes it so that it's just normal text, not inside a source code block like in the default configuration

For extra there's the :shebang arguments which are a bit redundant since I indicated that it was a bash script, and the :tangle option points to a file I was testing and running shellcheck in.

And just for the record, by default if you try to evaluate any source code block that isn't elisp, org babel will fail. To fix this you have to put (org-babel-do-load-languages 'org-babel-load-languages '((shell . t))) somewhere in your configuration. You can also add more languages by customizing the variable (C-h v).

Publishing

Every time I want to reference some file, or write something in a org file, it goes in the "~/dox/notes/projects/site" directory. When I'm done I do a M-x org-publish-project <RET> org <RET> which converts all the files to HTML, handles all the links and runs all the code responsible for parts of the page. Then I open a terminal, navigate to the "~/site/" directory and run neocities push ., which pushes all the new/modified files and skips the unmodified ones (I should probably automate that with a entr daemon).