Organization
2023-06-21
As I’ve wanted to write about different topics that I would consider “technical” as well as some of my hobbies (which I would categorize as “fun”), splitting the two into visually distinct and separated presentations while keeping them on the same site seemed to be the best course of action. This is my first proper foray into using Hugo, so completing this task required learning a bit about the syntax that it utilizes when generating pages.
Initially, I picked the wonderful Ficurinia theme from the list on the Hugo site at random, but ended up really liking it and set about modifying it to suit my intended output. As it ships, this is how pages are iterated for most of the partials in this theme:
1 {{ $postsDir := .Site.Params.Posts | default (slice "posts" "post") }}
2 {{ $allPosts := where (where site.RegularPages "Section" "in" $postsDir) "Section" "!=" "" }}
Making use of tags, I assign them as necessary when writing the posts - either “#technical” or “#fun” - then filter as follows:
1 {{ $technicalPosts := where $allPosts "Params.tags" "intersect" (slice "technical") }}
2 {{ $funPosts := where $allPosts "Params.tags" "intersect" (slice "fun") }}
Using those newly defined selections, I can then iterate over them and generate the article cards for each:
1 {{ range $funPosts }}
2 {{- partial "article_card.html" . -}}
3 {{ end }}
Dump them into separate <div>
elements with a simple flex display styling to handle the columns:
1 <div class="splitpostlist" id="postlist">
2 <div class="splitpostlistcol splitpostlistcol-technical">
3 <h3 class="splitpostlistcol-header"><a href="/tags/technical">> technical <</a></h3>
4 {{ range $technicalPosts }}
5 {{- partial "article_card.html" . -}}
6 {{ end }}
7 </div>
8 <div class="splitpostlistcol splitpostlistcol-fun">
9 <h3 class="splitpostlistcol-header"><a href="/tags/fun">~ fun ~</a></h3>
10 {{ range $funPosts }}
11 {{- partial "article_card.html" . -}}
12 {{ end }}
13 </div>
14 </div>
This is fine if I only ever have a few posts in total (which depending on my motivation for writing may actually be true), but if I have 30+ posts that page may start to get a bit long. I’d rather solve that problem now rather than when I notice it in the future - using a variable as a counter for posts as they are iterated over I can break out of the loop in a predictable manner, e.g. after 12 posts:
1 {{ $count := 0 }}
2 {{ range $funPosts }}
3 {{- partial "article_card.html" . -}}
4
5 {{ $count = add $count 1 }}
6
7 {{ if eq $count 12 }}
8 {{ break }}
9 {{ end }}
10 {{ end }}
…and insert a simple link at the end to view the rest of the posts that feature the given tag:
1 <a href="/tags/fun">more </a>
Mobile
On mobile devices (or other small screens), having two columns of large titles and descriptions looked far too crowded. Solution: media queries - from basic research, common low resolution breakpoint is 720p. I’m not worried too much about excessively optimization presentation, so I just went with that - max display width of 1000px is what the theme shipped with, minimum 70% of that for two columns of ~350px is what I ended up settling on. Below 700px, revert to a single column with at most 3 articles displayed at once. I went with this restriction since on a smaller screen, in a single column, the other category that would’ve been displayed in a right column would now be pushed at least 12 articles down the page.
Reusing the count
variable:
1 {{ $count := 0 }}
2 {{ range $funPosts }}
3 {{ if lt $count 3 }}
4 <div class="splitpostlistcol-upper">
5 {{- partial "article_card.html" . -}}
6 </div>
7 {{ else }}
8 <div class="splitpostlistcol-lower">
9 {{- partial "article_card.html" . -}}
10 </div>
11 {{ end }}
12 {{ $count = add $count 1 }}
13 {{ if eq $count 12 }}
14 {{ break }}
15 {{ end }}
16 {{ end }}
count
less than 3? Put the article card in a <div>
with a class specifying “upper” or “lower” and hide them as necessary using the aforementioned media query:
1 .splitpostlist {
2 display: flex;
3
4 @media (max-width: 700px) {
5 flex-direction: column;
6 }
7
8 .splitpostlistcol {
9 margin: 0 $margin;
10 flex-basis: 50%;
11
12 @media (max-width: 700px) {
13 flex-basis: 100%;
14 }
15 }
16
17 article {
18 margin: $margin 0;
19 }
20
21 .splitpostlistcol-lower {
22 @media (max-width: 700px) {
23 display: none;
24 }
25 }
26 }
What about posts with both tags?
Logically, you shouldn’t have a post with both tags. However, I started writing the first post that I’d classify as “fun” and ended up going off onto how to manage the project with git - an otherwise fairly “technical” topic. I still wanted to maintain a logical divide here, so I accepted having both tags on that post, with a filter on the display for the home page that does not show any posts with the tag “fun” in the column relegated to “technical” posts. This is handled by a simple check inside the loop:
1 {{ if not (in .Params.tags "fun") }}
2 {{ if lt $count 3 }}
3 <div class="splitpostlistcol-upper">
4 {{- partial "article_card.html" . -}}
5 </div>
6 {{ else }}
7 <div class="splitpostlistcol-lower">
8 {{- partial "article_card.html" . -}}
9 </div>
10 {{ end }}
11 {{ $count = add $count 1 }}
12 {{ end }}