Blob


1 (ns blog.gemini
2 (:require
3 [blog.time :as time]
4 [blog.gemtext :as gemtext]))
6 (defn feed-page [posts]
7 (gemtext/unparse
8 (list
9 [:header-1 "yumh"]
10 [:quote "Writing about things, sometimes"]
11 [:text ""]
12 (for [post posts]
13 (let [{:keys [title date slug]} post
14 url (str "gemini://gemini.omarpolo.com/post/" slug ".gmi")]
15 [:link url (str (time/fmt-iso8601 date) " - " title)])))))
17 (defn with-page [_ & body]
18 (gemtext/unparse
19 (list
20 body
21 [:text ""]
22 [:text ""]
23 [:text ""]
24 [:text "-- text: CC-BY-SA-4.0; code: public domain unless specified otherwise"]
25 [:text "For comments, write at < blog at omarpolo dot com > or @op@bsd.network in the fediverse."]
26 [:link "//git.omarpolo.com/blog/" "Capsule proudly assembled with Clojure"])))
28 (defn with-default-template [_ & body]
29 (with-page {}
30 [:header-1 "yumh"]
31 [:quote "Writing about things, sometimes"]
32 [:text ""]
33 [:link "/" "Home"]
34 [:link "/tags.gmi" "All Tags"]
35 [:link "/pages/projects.gmi" "Projects"]
36 [:text ""]
37 body))
39 (defn post-fragment
40 [{:keys [full? title-with-link?]}
41 {:keys [title date slug tags short body toot music xkcd] :as post}]
42 (list
43 (if title-with-link?
44 [:link (str "/post/" slug ".gmi") (str (time/fmt-iso8601 date) " - " title)]
45 [(if full? :header-1 :header-2) title])
46 (if full?
47 [:text ""]
48 [:quote short])
49 (when music
50 [:text (str "Written while listening to “" (:title music) "”"
51 (when-let [by (:by music)]
52 (str " by " by))
53 ".")])
54 (when full?
55 [:text (str "Published: " (time/fmt-iso8601 date))])
56 [:text "Tagged with:"]
57 (map #(vector :link (str "/tag/" (name %) ".gmi") (str "#" (name %)))
58 (sort tags))
59 (when xkcd
60 [:link (str "https://xkcd.com/" xkcd) (format "Relevant XKCD – #%d" xkcd)])
61 (when full?
62 (list [:text ""]
63 (gemtext/parse body)))
64 [:text ""]))
66 (defn home-page [{:keys [posts has-next has-prev nth]}]
67 (with-default-template
68 [:text ""]
69 [:text "Welcome to my gemlog! Sometimes I remember that I have a blog and post something here. My main interests are computer science, operating systems (BSDs in particular), programming languages (especially C, Go, LISP in its various incarnations). I also have an Italian capsule where I write about more casual stuff:"]
70 [:link "gemini://it.omarpolo.com" "l'angolo di yumh"]
71 [:text ""]
72 [:text "Some Gemini services on this capsule:"]
73 [:link "/cgi/man" "Look up a manpage"]
74 [:link "/cgi/gempkg" "Browse the OpenBSD ports tree"]
75 [:text ""]
76 [:header-2 "Recent posts"]
77 [:text ""]
78 (map (partial post-fragment {:title-with-link? true})
79 posts)
80 (when has-prev
81 [:link (str "/"
82 (if (= (dec nth) 1)
83 "index"
84 (dec nth))
85 ".gmi")
86 "Newer Posts"])
87 (when has-next
88 [:link (str "/" (inc nth) ".gmi")
89 "Older Posts"])))
91 (defn custom-page [{:keys [body]}]
92 (apply with-default-template (gemtext/parse body)))
94 (defn post-page [{:keys [title short] :as post}]
95 (with-page {}
96 [:link ".." "↩ back to the index"]
97 [:text ""]
98 (post-fragment {:full? true}
99 post)))
101 (defn tags-page [tags]
102 (with-default-template
103 [:header-2 "All tags"]
104 [:text ""]
105 (map #(vector :link (str "/tag/" (name %) ".gmi") (str "#" (name %)))
106 (sort (fn [a b]
107 (compare (.toLowerCase (name a))
108 (.toLowerCase (name b)))) tags))))
110 (defn tag-page [tag posts]
111 (with-default-template
112 [:header-2 (format "Posts tagged with #%s" tag)]
113 [:text ""]
114 [:text "Note: not every post is currently available over Gemini."]
115 [:text ""]
116 (map (partial post-fragment {:title-with-link? true})
117 (->> posts
118 (sort-by :date)
119 (reverse)))))