Blob


1 (ns blog.templates
2 (:require [blog.time :as time]
3 [hiccup.page :refer [html5 include-css]]
4 [commonmark-hiccup.core :refer [markdown->hiccup default-config]]))
6 (defn link-item [{:keys [url text]}]
7 [:li [:a {:href url} text]])
9 (defn header [{:keys [tags]}]
10 (list
11 [:header
12 [:nav
13 [:ul
14 (link-item {:url "/", :text "Home"})
15 (link-item {:url "/tags.html", :text "All Tags"})
16 (link-item {:url "https://git.omarpolo.com", :text "Git repos"})]]
17 [:div
18 [:h1 [:a {:href "/"} "yumh"]]
19 [:p "writing about things, sometimes."]]]))
21 (defn with-page
22 [{:keys [title class description], :as d} & body]
23 (html5 {:lang "en"}
24 [:head
25 [:meta {:charset "utf8"}]
26 [:meta {:name "viewport", :content "width=device-width, initial-scale=1"}]
27 [:link {:rel "shortcut icon", :href "/favicon.ico"}]
28 [:link {:rel "alternative" :type "application/rss+xml" :href "https://www.omarpolo.com/rss.xml"}]
29 (when description
30 [:meta {:name "description" :content description}])
31 [:title title]
32 (include-css "/css/style.css")]
33 [:body {:class (or class "")}
34 (header d)
35 [:main body]
36 [:footer
37 [:p "Blog proudly generated with "
38 [:a {:href "https://git.omarpolo.com/blog/"}
39 [:code "(clojure)"]]]]
40 [:noscript
41 [:img {:src "https://goatcounter.omarpolo.com/count?p=/test-img"}]]
42 [:script {:data-goatcounter "https://goatcounter.omarpolo.com/count"
43 :async true
44 :src "//goatcounter.omarpolo.com/count.js"}]]))
46 (defn post-fragment
47 [{:keys [full? title-with-link?]}
48 {:keys [title date slug tags short body toot music], :as post}]
49 [:article
50 [:header
51 [(if full?
52 :h1
53 :h2.fragment)
54 (if title-with-link?
55 [:a {:href (str "/post/" slug ".html")} title]
56 title)]
57 [:p.author "Written by " [:em "Omar Polo"] " on " (time/fmt-loc date)
58 (if music
59 (list " while was listening to " [:a {:href (:url music)
60 :target "_blank"
61 :rel "noopener"}
62 "\"" [:em (:title music)] "\"" " by " [:em (:by music)]] ".")
63 ".")]
64 [:ul.tags (map #(vector :li [:a {:href (str "/tag/" (name %) ".html")}
65 (str "#" (name %))])
66 tags)]
67 (when toot
68 [:p [:a {:href toot,
69 :target "_blank"
70 :rel "noopener"} "Comments over ActivityPub"]])]
71 [:section
72 (if full?
73 (markdown->hiccup default-config body)
74 [:p short])]])
76 (defn home-page
77 [{:keys [posts has-next has-prev nth]}]
78 (with-page {:title "Home"}
79 (map (partial post-fragment {:title-with-link? true})
80 posts)
81 [:nav.post-navigation
82 (if has-prev
83 [:a.prev {:href (str "/" (if (= (dec nth) 1)
84 "index"
85 (dec nth)) ".html")}
86 "« Newer Posts"])
87 (if has-next
88 [:a.next {:href (str "/" (inc nth) ".html")}
89 "Older Posts »"])]))
91 (defn post-page
92 [{:keys [title short], :as post}]
93 (with-page {:title title
94 :class "article"
95 :description short}
96 (post-fragment {:full? true}
97 post)))
99 (defn tags-page
100 [tags]
101 (with-page {:title "All tags"
102 :class "tags"}
103 [:h2 "All tags"]
104 [:nav
105 [:ul
106 (map #(vector :li [:a {:href (str "/tag/" (name %) ".html")} (str "#" (name %))])
107 (sort (fn [a b]
108 (compare (.toLowerCase (name a))
109 (.toLowerCase (name b)))) tags))]]))
111 (defn tag-page
112 [tag posts]
113 (with-page {:title (str "Posts tagged with #" tag)
114 :class "tag"}
115 [:h2 "Posts tagged with " [:code "#" tag]]
116 (map (partial post-fragment {:title-with-link? true})
117 (->> posts
118 (sort-by :date)
119 (reverse)))))