You can contact me if you wish to comment or propose a correction.
Posted: 2024-04-19
Stats: 578 words / ~3 minutes
One of the biggest disadvantages of static site generators is that they are static and can’t include comments.
In this short blog entry, I’ll explain how to add a comment system to Hugo’s static blog engine. I’ll expand on Carl Schwan’s and Tony Cheneau’s blog article and attempt to make it more accessible to Hugo’s newcomers.
Foreword
Most the hard work has been pulled of by Carl. I just made some minor changes. I hope it will help others like me, willing to bring some life into their blogs.
Tutorial structure
- modify your existing template to make it possible to add comments
- adding the comment system
- copying some Javascript dependencies
- how to add comments
Getting started
Modify default themes
Creating files
If you have a file at layouts/_default/single.html
, you don’t have to copy something. If you don’t have his file - no worries, it’s easy!
Just copy the file themes/your-theme-name/layouts/_default/single.html
to layouts/_default/single.html
.
Editing files
If you open the file, you’ll see that there is already some content. Just add this line:
{{ partial "comments/comments.html" .}}
If If you want the comments right above your footer, place this above it. Really simple!
My file is the following
{{ define "css" }}
<link rel="stylesheet" type="text/css" href="{{.Site.BaseURL}}css/article.css" />
{{ end }}
{{ define "main" }}
{{ if eq .Type "blog" }}
{{ if not .Params.menu }}
<p>
<i>
<time datetime="{{ .Date.Format "2006-01-02" }}" pubdate>
{{ .Date.Format (default "2006-01-02" .Site.Params.dateFormat) }}
</time>
</i>
</p>
{{ end }}
{{ end }}
{{ if .Params.toc }}
<details>
<summary>Table of Contents</summary>
{{ .TableOfContents }}
</details>
{{ end }}
<content>
{{ .Content }}
</content>
{{ partial "comments/comments.html" .}}
<p>
{{ range (.GetTerms "tags") }}
<a href="{{ .Permalink }}">#{{ .LinkTitle }}</a>
{{ end }}
</p>
{{ end }}
You can find the newest file at my repo.
Adding comment system
Now is the time to add the comment system.
Just create a file layouts/partials/comments/comments.html and paste the following content:
{{ with .Params.comments }}
<div class="article-content">
<article>
<h2>Comments</h2>
<p>You can use your <a class="link" href="https://joinmastodon.org/">Mastodon</a> account to reply to <a class="link" href="https://{{ .host }}/@{{ .username }}/{{ .id }}">this post</a>.</p>
<p id="mastodon-comments-list"><button id="load-comment">Load comments</button></p>
<noscript><p>You need JavaScript to view the comments.</p></noscript>
<script type="text/javascript">
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
document.getElementById("load-comment").addEventListener("click", function() {
document.getElementById("load-comment").innerHTML = "Loading";
fetch('https://{{ .host }}/api/v1/statuses/{{ .id }}/context')
.then(function(response) {
return response.json();
})
.then(function(data) {
if(data['descendants'] &&
Array.isArray(data['descendants']) &&
data['descendants'].length > 0) {
document.getElementById('mastodon-comments-list').innerHTML = "";
data['descendants'].forEach(function(reply) {
reply.account.display_name = escapeHtml(reply.account.display_name);
reply.account.emojis.forEach(emoji => {
reply.account.display_name = reply.account.display_name.replace(`:${emoji.shortcode}:`,
`<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" height="20" width="20" />`);
});
mastodonComment =
`<div class="mastodon-comment">
<div class="avatar">
<img src="${escapeHtml(reply.account.avatar_static)}" height=60 width=60 alt="">
</div>
<div class="content">
<div class="author">
<a href="${reply.account.url}" rel="nofollow">
<span>${reply.account.display_name}</span>
<span class="disabled">${escapeHtml(reply.account.acct)}</span>
</a>
<a class="date" href="${reply.uri}" rel="nofollow">
${reply.created_at.substr(0, 10)}
</a>
</div>
<div class="mastodon-comment-content">${reply.content}</div>
</div>
</div>`;
var DOMPurifyScript = document.createElement('script');
DOMPurifyScript.src = "/js/comments/purify.min.js";
DOMPurifyScript.onload = function() {
document.getElementById('mastodon-comments-list').appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
};
document.body.appendChild(DOMPurifyScript);
});
} else {
document.getElementById('mastodon-comments-list').innerHTML = "<p>Not comments found</p>";
}
});
});
</script>
</article>
</div>
{{ end }}
You can also find the newest comment partial here.
If you’re lazy you can also clone this:
wget https://codeberg.org/Tuxilio/website/raw/branch/main/layouts/partials/comments/comments.html
Copy Javascript dependencies
DOMPurify
is used to sanitize the code. Therefore, clone it to static/js/comments
:
wget https://raw.githubusercontent.com/cure53/DOMPurify/main/dist/purify.min.js
Add comments!
You’re done copying code! Add some comments!
To add comments, add to your file header:
comments:
host: toot.teckids.org
username: tuxilio
id: 112290674602230410
host
: just your hostusername
: your usernameid
: post id
End
You’re done 🎉!
(This post is my 8th post at #100DaysToOffload challenge)