How to add a calendar to Hugo website
Today I added a calendar to my website, and I was inspired by these two blog posts: Activity Calendar Partial and Generate Yearly and Monthly Archive Pages with Hugo Sections.
Table of Contents
Partials file structure
Here are the partial files I created in the layouts/partials/ folder and they were organized in the following structure.
|-- layouts
| |-- partials
| | |-- archy.html
| | |-- archm.html
| | |-- archd.html
| | |-- calendar.html
| | |-- calendar
| | | |-- year.html
| | | |-- month.html
| | | |-- day.html
| | |-- post
| | | |-- archive.html
calendar.html, year.html, month.html, day.html files were downloaded from the Activity Calendar blog post. However, I edited the calendar.html and day.html files to allow users to click on a date in the calendar and go to the article directly (if there was only one article posted on that day).
In calendar.html under {{ range ($pages.GroupByPublishDate "2006-01-02") }}
, add:
{{ range ($pages.GroupByPublishDate "2006-01-02") }}
{{ $context.Scratch.SetInMap "ArticlesPerDay" .Key (len .Pages) }}
{{ range .Pages }}
{{ $context.Scratch.Set (.PublishDate.Format "2006-01-02") .Permalink }}
{{ end }}
{{ end }}
Then edit day.html, add these lines:
{{ $link := $context.Scratch.Get $dateString }}
<li class="calendar-day {{ if $isFuture }}calendar-day-future{{ end }} {{ if gt $articlesFound 0 }}calendar-day-has-articles{{ end }} {{ if eq (now.Format "2006-01-02") $dateString }}calendar-day-is-today{{ end }}">
{{- if eq $articlesFound 1 -}} <!-- exactly one article that day -->
<a href="{{ $link }}" title="{{ index (last 1 (split (delimit (split $link "/") "," "") ",")) 0 }}">
<time datetime="{{ $dateString }}">{{ $day }}<em>{{ $articlesFound }}</em></time></a>
{{- else if gt $articlesFound 1 -}} <!-- multiple articles on one day -->
<a href="/archive/{{ delimit (slice $year $monthTwoLetters $dayTwoLetters) "-" }}/" title="{{ $articlesFound }} article{{ if gt $articlesFound 1 }}s{{ end }}">
<time datetime="{{ $dateString }}">{{ $day }}<em>{{ $articlesFound }}</em></time></a>
{{- else -}} <!-- no articles that day -->
<time datetime="{{ $dateString }}">{{ $day }}<em>{{ $articlesFound }}</em></time>
{{- end -}}
</li>
The code for three types of listing (by year, month or day) were partly adapted from templates provided in Generate Yearly and Monthly Archive Pages with Hugo Sections.
1
2
3
4
5
6
7
{{ $year := .Date.Format "2006" }}
<h2> Archive for {{ $year }}</h2>
{{ range where .Site.Pages "Type" "post" }}
{{ if eq (.Date.Format "2006") $year }}
{{ partial "post/archive" . }}
{{ end }}
{{ end }}
1
2
3
4
5
6
7
8
{{ $year := .Date.Format "2006" }}
{{ $month := .Date.Format "January" }}
<h2> Archive for {{ $month }} {{ $year }}</h2>
{{ range where .Site.Pages "Type" "post" }}
{{ if and (eq (.Date.Format "2006") $year) (eq (.Date.Format "January") $month) }}
{{ partial "post/archive" . }}
{{ end }}
{{ end }}
1
2
3
4
5
6
7
8
9
{{ $year := .Date.Format "2006" }}
{{ $month := .Date.Format "January" }}
{{ $day := .Date.Format "02" }}
<h2> Archive for {{ $month }} {{ $day }} {{ $year }}</h2>
{{ range where .Site.Pages "Type" "post" }}
{{ if and (eq (.Date.Format "2006") $year) (eq (.Date.Format "January") $month) (eq (.Date.Format "02") $day)}}
{{ partial "post/archive" . }}
{{ end }}
{{ end }}
1
2
3
4
5
6
7
8
9
10
11
12
{{ $year := .Date.Format "2006" }}
{{ $month := .Date.Format "January" }}
<section class="boxes">
<div class="archive archive-year box" data-date="{{ $year }}">
<ul class="archive-posts archive-month" data-date="{{ $year }}{{ $month }}">
<li class="archive-post archive-day">
<a href="{{ .Permalink }}">{{ .Title }}</a>
<span class="post-date">{{ .Date.Format "02 Jan 2006" }}</span>
</li>
</ul>
</div>
</section>
Taxonomy structure
The idea is to archive blog posts by date and users can click on the date on the calendar to go to a specific post. In order for this to work, I added a new way of grouping the posts for this website (aka “Taxonomy”).
In the configuration file config.toml, add:
# adding taxonomy term 'archive'
[taxonomies]
archive = "archive"
Then I created a layout file archive.html to layouts/taxonomy/ folder.
Here I used a Hugo function findRE, which returns a list of strings that match the given regular expression.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{{ partial "head.html" . }}
<body>
<div id="blog">
{{ partial "header.html" . }}
{{ partial "sidebar.html" . }}
<div id="main" data-behavior="{{ .Scratch.Get "sidebarBehavior" }}"
class="{{ with .Params.coverImage }}hasCover{{ end }}
{{ if eq .Params.coverMeta "out" }}hasCoverMetaOut{{ else }}hasCoverMetaIn{{ end }}
{{ with .Params.coverCaption }}hasCoverCaption{{ end }}">
{{ $year := .Date.Format "2006" }}
{{ $currentTaxonomy := index (last 1 (split (delimit (split .URL "/") "," "") ",")) 0 }}
{{ $regex := index (findRE "-" $currentTaxonomy 2) 1 }}
{{ if eq $currentTaxonomy $year }} <!-- archive by year -->
{{ partial "archy.html" . }}
{{ else if eq $regex "-" }} <!-- archive by day -->
{{ partial "archd.html" . }}
{{ else }} <!-- archive by month -->
{{ partial "archm.html" . }}
{{ end }}
</div>
</div>
</body>
{{ partial "foot.html" . }}
Specific date format and the archive variable is required in the front matter of markdown files:
# examplepost.md
---
date: 2020-05-07T17:15:22.000Z
archive: ["2020","2020-05","2020-05-07"]
---
Render calendar style
I compiled the styling.scss file to css format at sassmeister.com, then added the css file to the statics/css folder. The calendar style (font size, color, etc.) can be altered by editing the css file /static/css/style.css.
For hugo to reconize customized css files, toggle the customCSS option in config.toml:
# Custom CSS. Put here your custom CSS files. They are loaded after the theme CSS;
# they have to be referred from static root. Example
[[params.customCSS]]
href = "css/style.css"
If your website is already using a custom css, simply copy and paste the code for calendar styling into the custom css file.
Add the calendar to the frontpage
Call the calendar partial in the layouts/index.html file, and specify start month and end month:
{{ partial "calendar" (dict "context" . "from" 2020 "fromMonth" 1 "to" (now.Format "2006") "toMonth" (now.Format "1") "pages" .Site.Pages) }}
Now the calendar should be visible on the website! Pretty awesome. Check out a live demo.
Issues and solution
Issue 1: The background circles for ‘calendar days with articles’ and ‘today’ are not showing.
Solution:
opacity: 0.9
under .calendar-day.calendar-day-has-articles
and .calendar-day.calendar-day-is-today
.
.calendar-day.calendar-day-has-articles {
color: #ffffff;
position: relative;
opacity: 0.9;
}
.calendar-day.calendar-day-is-today {
position: relative;
font-weight: 800;
color: #ff6600;
opacity: 0.9;
}
Also move .calendar-day.calendar-day-future { opacity: 0.4; }
to the bottom of the file so that the opacity for future dates renders the last.
Issue 2: Links to categories and tags are not working after adding the calendar to the website.
Solution:
[taxonomies]
archive = "archive"
tag = "tags"
category = "categories"
Issue 3: Days with articles are not correctly displayed in the calendar.
Solution:
.GroupByPublishDate
to .GroupByDate
in the layouts/partials/calendar.html file.
{{ range ($pages.GroupByPublishDate "2006") }}
{{ range ($pages.GroupByPublishDate "2006-01") }}
{{ range ($pages.GroupByPublishDate "2006-01-02") }}
# Change to .GroupByDate