implement tag pages
[~bandali/bndl.org] / haunt.scm
1 (use-modules (haunt asset)
2 (haunt builder blog)
3 (haunt builder atom)
4 (haunt builder assets)
5 (haunt builder rss)
6 (haunt html)
7 (haunt page)
8 (haunt post)
9 (haunt reader commonmark)
10 (haunt site)
11 (haunt utils)
12 (ice-9 match)
13 (srfi srfi-19))
14
15 (define my-scheme 'https)
16 (define my-domain "bandali.eu.org")
17 (define my-url
18 (string-append (symbol->string my-scheme) "://" my-domain))
19 (define my-tag-prefix "tags")
20 (define my-date-format "~B ~e, ~Y")
21
22 (define (stylesheet name)
23 `(link (@ (rel "stylesheet")
24 (href ,(string-append "/" name ".css")))))
25
26 (define* (aa content #:optional (uri content) . title)
27 `(a (@ (href ,uri) (title ,(apply string-append title))) ,content))
28
29 (define* (base-layout site body #:key title copy license-page?)
30 `((doctype "html")
31 (html
32 (head
33 (meta (@ (charset "utf-8")))
34 (title ,(if title (string-append title " — " (site-title site))
35 "Amin Bandali’s Personal Site"))
36 ,(stylesheet "reset")
37 ,(stylesheet "style"))
38 (body
39 (main ,body)
40 (footer
41 (p "Copyright © "
42 ,(if copy copy "2016–2019")
43 " Amin Bandali. See "
44 ,(if license-page? "the above"
45 (aa "license.html" "/license.html"))
46 " for license conditions. Please copy and share."))))))
47
48 (define* (tag-uri prefix tag #:optional (ext ".html"))
49 "Return a URI relative to the site's root for a page listing entries
50 in PREFIX that are tagged with TAG."
51 (string-append "/" my-tag-prefix "/" tag ext))
52
53 (define* (tag-pages #:key
54 (theme bandali-theme)
55 (prefix "")
56 (filter posts/reverse-chronological))
57 "Return a builder procedure that renders a list page for every tag
58 used in a post. All arguments are optional:
59
60 PREFIX: The directory in which to write the posts
61 FILTER: The procedure called to manipulate the posts list before rendering"
62 (lambda (site posts)
63 (define (tag-list tag posts all-posts)
64 (define (render-list title posts prefix)
65 (let ((body ((theme-collection-template theme)
66 site title posts prefix all-posts tag)))
67 ((theme-layout theme) site title body)))
68 (make-page (tag-uri my-tag-prefix tag)
69 (render-list (string-append "Notes tagged ‘" tag "’")
70 (filter posts)
71 prefix)
72 sxml->html))
73 (let ((tag-groups (posts/group-by-tag posts)))
74 (map (match-lambda
75 ((tag . tagged-posts) (tag-list tag tagged-posts posts)))
76 tag-groups))))
77
78 (define (tag-links posts)
79 "Generate an alphabetically sorted list of links to tagged posts.
80 The link text consists of the tag name and the number of tagged posts
81 in parentheses."
82 `(ul (@ (class "tag-list"))
83 ,(map (match-lambda
84 ((tag . posts)
85 `(li
86 ,(aa (string-append tag
87 " ("
88 (number->string (length posts))
89 ")")
90 (tag-uri my-tag-prefix tag)))))
91 ;; sort by tag
92 (sort (posts/group-by-tag posts)
93 (lambda (a b) (string<? (car a) (car b)))))))
94
95 (register-metadata-parser! 'updated string->date*)
96
97 (define (intersperse lst delim)
98 "Return the elements of LST delimited by DELIM, such that the
99 resulting list is of an odd length and every second element is DELIM."
100 (if (<= (length lst) 1)
101 lst
102 (cons* (car lst)
103 delim
104 (intersperse (cdr lst) delim))))
105
106 (define (my-post-template post)
107 `((header
108 (h1 ,(post-ref post 'title))
109 (address "By " ,(aa (post-ref post 'author) "/")
110 " <" ,(post-ref post 'email) ">")
111 (p (@ (class "date"))
112 "Published "
113 ,(date->string (post-date post) my-date-format))
114 ,(if (post-ref post 'updated)
115 `(p (@ (class "updated"))
116 "Updated "
117 ,(date->string (post-ref post 'updated)
118 my-date-format)) '())
119 ,(if (post-ref post 'tags)
120 `(p (@ (class "tags"))
121 "Tagged "
122 ,@(intersperse
123 (map (lambda (tag)
124 (aa tag (tag-uri my-tag-prefix tag)))
125 (post-ref post 'tags))
126 ", "))
127 '()))
128 ,(post-sxml post)
129 (p (@ (class "muted inbox"))
130 "Have a question or comment? Start a discussion in my "
131 ,(aa "public inbox" "https://lists.sr.ht/~bandali/public-inbox")
132 " by sending an email to "
133 ,(aa "~bandali/public-inbox@lists.sr.ht"
134 "mailto:~bandali/public-inbox@lists.sr.ht")
135 (small
136 " [" ,(aa "mailing list etiquette"
137 "https://man.sr.ht/lists.sr.ht/etiquette.md") "]")
138 ".")))
139
140 (define* (my-collection-template site title posts prefix
141 #:optional all-posts tag)
142 (define (post-uri post)
143 (string-append (or prefix "") "/"
144 (site-post-slug site post) ".html"))
145
146 `((h2 ,title
147 ,(if tag
148 (aa `(img (@ (class "feed-icon")
149 (src "/feed.svg")
150 (alt "subscribe to atom feed")))
151 (tag-uri my-tag-prefix tag ".xml"))
152 '()))
153 (table
154 (@ (class "post-list"))
155 (tbody
156 ,@(map (lambda (post)
157 `(tr
158 (td ,(aa (post-ref post 'title) (post-uri post)))
159 (td (@ (style "font-size: 0.875em;"))
160 ,(date->string (post-date post)
161 my-date-format))))
162 posts)))
163 (h2 "Tags")
164 ,(tag-links (or all-posts posts))
165 ,(if tag
166 '(a (@ (href "/notes.html"))
167 "← all posts")
168 '())))
169
170 (define bandali-theme
171 (theme #:name "bandali"
172 #:layout
173 (lambda (site title body)
174 (base-layout site body
175 #:title title))
176 #:post-template my-post-template
177 #:collection-template my-collection-template))
178
179 (define* (static-page title file-name body copy #:key license?)
180 (lambda (site posts)
181 (make-page file-name
182 (base-layout site body #:title title #:copy copy
183 #:license-page? license?)
184 sxml->html)))
185
186 (define (index-material site posts)
187 `((h1 (@ (style "font-size: 0;"))
188 "Amin Bandali")
189 (p (@ (style "margin-top: 0;"))
190 "Hi, I’m "
191 ,(aa "Amin Bandali" "images/bandali-with-rms.jpg"
192 "photo of bandali with rms wearing a "
193 "“pay cash don’t be tracked” pin")
194 ". I’m a graduate student at "
195 ,(aa "WatForm" "https://watform.uwaterloo.ca")
196 " at University of Waterloo, supervised by "
197 ,(aa "Dr. Nancy Day" "https://cs.uwaterloo.ca/~nday/")
198 ". The main goal of my research is improving "
199 (strong "software and systems reliability")
200 " through application of " (em "formal methods") ".")
201 (p "My research at WatForm focuses on formal logic, model "
202 "checking, and verification. I’m also interested in "
203 "programming languages, theorem provers, and their "
204 "type systems. You may wish to view my academic "
205 ,(aa "curriculum vitae" "bandali-cv.html") ".")
206 (p (@ (class "notice"))
207 (strong "SE 212 students: ")
208 "see " ,(aa "here" "se212-f19/") " for slides and other "
209 "material from the tutorials.")
210 (p "On the side, I dabble in "
211 ,(aa "Lean" "https://leanprover.github.io") " and enjoy "
212 ,(aa "hacking" "https://stallman.org/articles/on-hacking.html")
213 " on "
214 ,(aa "Elisp"
215 "https://www.gnu.org/software/emacs/manual/elisp.html")
216 ". I’m a " ,(aa "Free Software"
217 "https://www.gnu.org/philosophy/free-sw.html")
218 " activist, a GNU "
219 ,(aa "maintainer" "https://www.gnu.org/people/#bandali")
220 " and "
221 ,(aa "webmaster"
222 "https://www.gnu.org/people/webmeisters.html#bandali")
223 ", and an " ,(aa "associate member"
224 "https://www.fsf.org/associate/")
225 " of the " ,(aa "FSF" "https:///www.fsf.org"
226 "Free Software Foundation")
227 ". I co-host the " ,(aa "Emacs.el" "https://emacsel.com")
228 " podcast with " ,(aa "Daniel Gopar" "https://www.pygopar.com")
229 ", and organize " ,(aa "EmacsConf" "https://emacsconf.org")
230 " with help from many wonderful people. I am also a member of"
231 " the Systems Committee for the "
232 ,(aa "CSC" "https://csclub.uwaterloo.ca"
233 "Computer Science Club of the University of Waterloo")
234 ".")
235 (p "See my " ,(aa "contact" "contact.html") " page for how to "
236 "best reach me.")
237 (h2 (@ (id "papers")) "Papers")
238 (dl
239 (dt "A Comparison of the Declarative Modelling Languages B, DASH,
240 and TLA" (sup "+")
241 (small
242 " [ " ,(aa "pdf" "papers/modre2018-declarative.pdf") " | "
243 ,(aa "bib" "papers/modre2018-declarative.bib") " ]"))
244 (dd "Ali Abbassi, "
245 ,(aa "Amin Bandali" my-url) ", "
246 ,(aa "Nancy A. Day" "https://cs.uwaterloo.ca/~nday/") ", "
247 "Jose Serna"
248 (br)
249 (em "2018 IEEE 8th International Model-Driven Requirements"
250 " Engineering Workshop (MoDRE)")
251 (br)
252 "Copyright © 2018 IEEE. All Rights Reserved. Sadly."))
253 (h2 (@ (id "talks")) "Talks")
254 (dl
255 (dt
256 "The Magic of Specifications and Type Systems"
257 (small
258 " [ "
259 ,(aa "slides" "talks/cucsc-2017-slides.pdf"
260 "presented at the Canadian Undergraduate Computer Science"
261 " Conference 2017,\n"
262 "University of Toronto, Canada, June 15–17, 2017")
263 " | "
264 ,(aa "poster" "talks/eecs4080-poster.pdf"
265 "presented at the Lassonde Undergraduate Summer Student"
266 " Research Conference,\n"
267 "York University, Toronto, Canada, August 15, 2017")
268 " ]"))
269 (dd ,(aa "Amin Bandali" my-url) ", "
270 ,(aa "Simon Hudon" "https://github.com/cipher1024") ", "
271 ,(aa "Jonathan S. Ostroff"
272 "http://www.cse.yorku.ca/~jonathan/")))
273 (h2 (@ (id "projects")) "Projects")
274 (p "Below are a number of free software projects I have worked "
275 "on:")
276 (dl
277 (dt ,(aa "george-mode" "https://git.sr.ht/~bandali/george-mode"))
278 (dd "Emacs major mode for editing George files")
279 (dt ,(aa "alloy-catalyst"
280 "https://git.uwaterloo.ca/bandali/alloy-catalyst"))
281 (dd "Framework for performance analysis of Alloy models")
282 (dt ,(aa "unitb-web" "https://github.com/unitb/unitb-web"))
283 (dd "Web interface for Unit-B")
284 (dt ,(aa "tex2png-hs" "https://github.com/unitb/tex2png-hs"))
285 (dd "Library and CLI for converting TeX and LaTeX to PNG "
286 "images"))
287 (h2 (@ (id "notes")) "Notes")
288 (p "Here are notes about a variety of topics and issues I care "
289 "about. They’re also available via " ,(aa "Atom" "notes.atom")
290 " and " ,(aa "RSS" "notes.rss") " feeds.")
291 (table
292 (@ (class "post-list"))
293 (tbody
294 ,@(map
295 (lambda (post)
296 (define (post-uri post)
297 (string-append "/"
298 (site-post-slug site post) ".html"))
299 `(tr
300 (td ,(aa (post-ref post 'title) (post-uri post)))
301 (td (small
302 ,(date->string (post-date post) my-date-format)))))
303 (take-up-to 10 (posts/reverse-chronological posts)))))))
304
305 (define (index-page site posts)
306 (make-page
307 "index.html"
308 (base-layout site (index-material site posts))
309 sxml->html))
310
311 (define license-page
312 (static-page
313 "Licensing Information"
314 "license.html"
315 `((h1 "License information for "
316 ,(aa my-domain my-url))
317 (p "I strongly believe in "
318 ,(aa "free culture"
319 "https://questioncopyright.org/what_is_free_culture")
320 " and that all creative works everywhere should be "
321 ,(aa "free" "https://freedomdefined.org/Definition") ".")
322 (p "Unless otherwise noted material on this site is licensed "
323 "under the GNU General Public License as published by the "
324 "Free Software Foundation, either version 3 of the License, "
325 "or (at your option) any later version. A copy of the "
326 "license is included at " ,(aa "gpl-3.0.html") ".")
327 (p "Some resources on free software and licenses:")
328 (ul
329 (li ,(aa "What is free software?"
330 "https://www.gnu.org/philosophy/free-sw.html"))
331 (li ,(aa "Various Licenses and Comments about Them"
332 "https://www.gnu.org/licenses/license-list.html"))
333 (li ,(aa "Proprietary Software Is Often Malware"
334 "https://www.gnu.org/proprietary/proprietary.html"))))
335 "2019"
336 #:license? #t))
337
338 (define contact-page
339 (static-page
340 "Contact Information"
341 "contact.html"
342 `((h1 "Contact information")
343 (p "Email is by far my preferred method of communication. I may"
344 " be contacted at any of the following addresses (choose the"
345 " most closely related):")
346 (ul
347 (li "bandali@gnu.org")
348 (li "bandali@uwaterloo.ca")
349 (li "bandali@csclub.uwaterloo.ca"))
350 (p "If you want to send me GPG-encrypted mail, you can use my "
351 ,(aa "public key" "bandali-pubkey.txt") " with the"
352 " fingerprint "
353 (code "BE62 7373 8E61 6D6D 1B3A 08E8 A21A 0202 4881 6103")
354 ".")
355 (table
356 (tbody
357 (tr
358 (td "IRC")
359 (td "bandali on " ,(aa "freenode" "https://freenode.net") ", "
360 ,(aa "moznet" "https://wiki.mozilla.org/IRC") ", and "
361 ,(aa "oftc" "https://www.oftc.net")))
362 (tr
363 (td "XMPP")
364 (td ,(aa "bandali@member.fsf.org"
365 "xmpp:bandali@member.fsf.org")))
366 (tr
367 (td "Matrix")
368 (td ,(aa "@bandali:matrix.org"
369 "https://matrix.to/#/@bandali:matrix.org")))
370 (tr
371 (td "Fediverse")
372 (td ,(aa "@bandali@pleroma.site"
373 "https://pleroma.site/bandali")))))
374 (h2 "Elsewhere")
375 (p "You may also find me at a few other places online. Stricken"
376 " through accounts are those I don’t use anymore, unless"
377 " absolutely necessary.")
378 (ul
379 (li ,(aa "bandali" "https://libreplanet.org/wiki/User:Bandali")
380 " on LibrePlanet")
381 (li ,(aa "bandali" "https://emacsconf.org/bandali")
382 " on EmacsConf")
383 (li ,(aa "bandali" "https://savannah.gnu.org/users/bandali")
384 " on Savannah")
385 (li ,(aa "bandali" "https://git.sr.ht/~bandali")
386 " on Sourcehut")
387 (li ,(aa "bandali" "https://lobste.rs/u/bandali")
388 " on Lobsters")
389 (li ,(aa "bandali" "https://hackage.haskell.org/user/bandali")
390 " on Hackage")
391 (li ,(aa "bandali" "https://gitlab.com/bandali")
392 " on GitLab")
393 (li ,(aa "bandali"
394 "https://news.ycombinator.com/user?id=bandali")
395 " on HN")
396 (li ,(aa "bandali" "https://www.reddit.com/u/bandali")
397 " on reddit")
398 (li (del ,(aa "bandali0" "https://github.com/bandali0")
399 " on GitHub"))
400 (li (del ,(aa "bandali0" "https://twitter.com/bandali0")
401 " on Twitter"))))
402 "2019"))
403
404 (define cv-page
405 (static-page
406 "Curriculum vitae"
407 "bandali-cv.html"
408 `((h1 "Curriculum vitae (" ,(aa "PDF" "bandali-cv.pdf") ")")
409 (table
410 (tbody
411 (tr
412 (td "Site")
413 (td ,(aa my-domain my-url)))
414 (tr
415 (td "Email")
416 (td "bandali@uwaterloo.ca"))
417 (tr
418 (td "Phone")
419 (td "available upon request via email"))))
420 (h2 "Education")
421 (h3 "Master of Mathematics (Computer Science) | 2018–present")
422 (p "University of Waterloo, Canada")
423 (p "Supervised by Dr. Nancy Day | GPA: 3.7/4.0 | "
424 "Expected completion: April 2020")
425 (p "Research focusing on formal logic, model checking, and "
426 "verification.")
427 (h3 "B.Sc. Honours Computer Science | 2013–2017")
428 (p "York University, Toronto, Canada")
429 (p "GPA: 7.84/9.0")
430 (p "Relevant courses: System Specification & Refinement, "
431 "Software Requirements Eng., Software Design, "
432 "Operating Systems, Computational Complexity, "
433 "Design & Analysis of Algorithms.")
434 (p "Finished first year (2013-14) at " (em "Carleton University")
435 " with a GPA of 11.0/12.0, then transferred to "
436 (em "York University") " in Fall 2014.")
437 (h2 "Publications")
438 (p "Listed on my " ,(aa "homepage" "/#papers"))
439 (h2 "Work & Research Experience")
440 (h3 "Cheriton School of Computer Science, University of Waterloo"
441 " | 2018–present")
442 (p "Instructional Apprentice, Teaching Assistant, "
443 "Research Assistant")
444 (ul
445 (li (abbr (@ (title "Logic and Computation")) "SE 212") ": "
446 (abbr (@ (title "Instructional Apprentice")) "IA") " in "
447 "Fall 2019, "
448 (abbr (@ (title "Teaching Assistant")) "TA") " in "
449 "Fall 2018")
450 (li (abbr (@ (title ,(string-append
451 "Software Requirements Specification and "
452 "Analysis"))) "SE 463")
453 ": TA in Summer 2019 and 2018")
454 (li (abbr (@ (title ,(string-append
455 "Elementary Algorithm Design and "
456 "Data Abstraction"))) "CS 136")
457 ": TA in Winter 2018"))
458 (h3 (abbr (@ (title
459 ,(string-append
460 "Electrical Engineering & Computer Science")))
461 "EECS")
462 " Department, York University | Fall 2017")
463 (p "Teaching Assistant")
464 (p (abbr (@ (title "Net-Centric Introduction to Computing"))
465 "EECS 1012")
466 ": TA in Fall 2017"))
467 "2019"))
468
469 (define se212-f19-page
470 (static-page
471 "SE 212 Material"
472 "se212-f19/index.html"
473 `((h1 "Material from SE 212 tutorials")
474 (p "This page contains slides and other material from "
475 ,(aa "SE 212 tutorials"
476 "https://www.student.cs.uwaterloo.ca/~se212/times.html")
477 " held by me in Fall 2019. "
478 (del "If you have any questions, concerns, or suggestions "
479 "about the presented material, please email me at "
480 "bandali@uwaterloo.ca or come see me during my "
481 ,(aa "Friday office hours"
482 "https://www.student.cs.uwaterloo.ca/~se212/personnel.html")
483 "."))
484 (ul
485 (li "Tutorial 1:"
486 (ul
487 (li ,(aa "TUT 101 slides" "se212-t01-101.pdf"))
488 (li ,(aa "TUT 102 slides" "se212-t01-102.pdf"))
489 (li ,(aa "Org beamer sources" "se212-t01.org"))))
490 (li "Tutorial 2:"
491 (ul
492 (li ,(aa "Homework 2 q04d solution"
493 "se212-h02q04d-soln.grg"))))
494 (li "Tutorial 3: —")
495 (li "Tutorial 4: —")
496 (li "Tutorial 5:"
497 (ul
498 (li ,(aa "Slides" "se212-t05.pdf"))
499 (li ,(aa "Org beamer sources" "se212-t05.org"))))
500 (li "Tutorial 6: —")
501 (li "Tutorial 7: worked through questions 1–5 of Homework 7")
502 (li "Tutorial 8: —")
503 (li "Tutorial 9: —")
504 (li "Tutorial 10: worked through questions 1–10 of "
505 "Homework 10")))
506 "2019"))
507
508 (module-define!
509 (resolve-module '(haunt builder blog))
510 'render-post
511 (lambda (theme site post)
512 (let ((title (post-ref post 'title))
513 (body ((theme-post-template theme) post))
514 (copy (post-ref post 'copyright)))
515 (base-layout site body #:title title #:copy copy))))
516
517 (site #:title "Amin Bandali"
518 ;; TODO: uncomment after new haunt release
519 ;; #:scheme my-scheme
520 #:domain my-domain
521 #:default-metadata
522 '((author . "Amin Bandali")
523 (email . "bandali@gnu.org")
524 (domain . my-domain))
525 #:readers (list commonmark-reader)
526 #:builders (list (blog #:theme bandali-theme
527 #:collections
528 `(("Notes" "notes.html"
529 ,posts/reverse-chronological)))
530 (tag-pages)
531 index-page
532 (atom-feed
533 #:file-name "notes.atom")
534 (atom-feeds-by-tag
535 #:prefix my-tag-prefix)
536 (rss-feed
537 #:file-name "notes.rss")
538 contact-page
539 cv-page
540 license-page
541 se212-f19-page
542 (static-directory "static" "")))