Mastodon comment system for your website

Learn how to add a Mastodon comment system to your website

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

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>&nbsp;&nbsp;
    {{ 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, "&amp;")
           .replace(/</g, "&lt;")
           .replace(/>/g, "&gt;")
           .replace(/"/g, "&quot;")
           .replace(/'/g, "&#039;");
   }

    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

End

You’re done 🎉!

(This post is my 8th post at #100DaysToOffload challenge)

You can use your Mastodon account to reply to this post.

You can contact me if you wish to comment or propose a correction.