Patrick's Blog

How this website works

Last Edited: Tue Dec 24 03:30:30 UTC 2024


For T.H.

Stack

Hosting: A $5/month nanode on linode running debian.

Very simple and nice to use. Plus cheap :)

Language: Clojure

duh

Server: http-kit

A clojure server.

Database: datalevin

This is a cool database that lets you use a subset of logical programming called "datalog." It's where I store my blog pages and my users.

Ex:

(def schema {:name {:db/unique :db.unique/identity
                    :db/valueType :db.type/string}
             :dateofbirth  {:db/valueType :db.type/instant}})

;data/users is a directory and file kinda like sqlite
(def users (datalevin/get-conn "data/users" schema))

;To add data
(datalevin/transact! users [:name "patrick" :dateofbirth (new java.util.Date)])

;To query it
(datalevin/q '[:find ?dob
               :in $ ?name
               :where [?e :name ?name] [?e :dateofbirth ?dob]
              (datalevin/db users) "patrick")
;^ the query language is hard to understand but it's sooooo good once you get it
;This one would return a vector something like [:name "patrick" :dateofbirth [WHENEVER THE JAVA THING MAKES]

Authentication/Authorization: buddy

I use buddy which is a popular clojure library for doing steps in the authentication/authorization steps. I'm using session authorization and I just hash my passwords and store that hash with a uname in a "table."

Routing: reitit

An excellent library that lets you define your routes as data

        ["/:slug" {:get {:parameters {:path {:slug string?}}
                         :handler (fn [{{slug :slug} :path-params}] 
                                    {:status 200 
                                     :content-type "text/html" 
                                     :body (blogp/blogpost slug)})}}]

This block, which would be nested in a list with something like "/blog" ahead of it says:

With the path parameter :slug, define a :get request where the slug has to be a string. When I get this request, call a function that gets the relevant data from the request and returns a response with status 200, content-type "text/html", and a body with the blog page (blogp/blogpost) which that slug represents (which in turn calls the database).

Templating: hiccup

(defn blogpage 
  [{:keys [title date content]}]
  (h/html5 
    [:head
     [:title title]
     [:link {:rel "stylesheet" :href "/css/base.css"}]
     [:link {:rel "stylesheet" :href "/css/blogpost.css"}]
     [:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
     [:meta {:charset "utf-8"}]
     ;Code support
     [:link {:rel "stylesheet" :href "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/default.min.css"}]
     [:script {:src "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"}]
     [:script {:src "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/clojure.min.js"}]
     [:script "hljs.highlightAll();"]]
    [:body
     [:header "Patrick's " [:span.gradient "Blog"]]
     [:main
      [:article
       [:h1.title title]
       [:p.date (str "Last Edited: " date)]
       [:hr]
       (md/md-to-html-string content)]]
     [:footer "© " (currentyear) " Patrick Kingston"]
     [:script {:src "/js/home.js"}]]))

This is the function that returns a blog page. It lets you define html tags as vectors where the first element is a keyword of the type of tag (p, a, h1, etc.).

Blogposts are stored as markdown strings in the database and then rendered to html as part of this template.

Interactivity: HTMX

The main place where I have interactivity is in filtering blog posts by tag. It's just an HTMX post request which swaps the whole list, filtered by the tags selected.

Styles: Plain, CSS, handmade with love

I just like it.

Animation: Javascript

I instantiate a bunch of chess pieces depending on how big the screen is and then they dance around on a set interval.

Site layout

The homepage is basically static (not programmatically generated). The blog pages are generated on demand because markdown rendering isn't that expensive (although I suppose I could cache them).

There's an admin panel which i'm writing this on. There's also the momblog which uses HTMX to give infinite scrolling.

Q&A

Text me questions and I'll answer them here or delete this section if you don't have any.