Comments with Mastodon

If you aren’t aware, this blog is created using Hugo. This means this blog is essentially just static files being served by a static web engine. It makes it light, and simply to host/deploy. One thing it makes it hard to do, is host comments, because comments are by nature dynamic (not static).

I came across the idea of using Mastodon a platform that is community-owned and ad-free. This allows “dynamic” comments, without me having to add a comment engine to my blog. Yay! Let’s do it!

Using the code from Carl Schwan I hacked together the following code:

{{ with .Params.comments }}
      <div class="article-content">
        <h2>Comments</h2>
        <p>You can use your Mastodon account to reply to this <a class="link" href="https://{{ .host }}/@{{ .username }}/{{ .id }}">post</a>.</p>
        <p><a class="button" href="https://{{ .host }}/interact/{{ .id }}?type=reply">Reply</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 src="/assets/js/purify.min.js"></script>
        <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("mastodon-comments-list").innerHTML = "Loading comments";
            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" />`
                            );
                          });
                          let mastodonComment = document.createElement("div")
                          mastodonComment.classList.add("mastodon-comment")

                          let mastodonAvatar = document.createElement("div")
                          mastodonAvatar.classList.add("avatar")

                          let mastodonAvatarImage = document.createElement("img")
                          mastodonAvatarImage.src = escapeHtml(reply.account.avatar_static)
                          mastodonAvatarImage.height = 60
                          mastodonAvatarImage.width = 60

                          let mastodonContent = document.createElement("div")
                          mastodonContent.classList.add("content")

                          let mastodonAuthor = document.createElement("div")
                          mastodonAuthor.classList.add("author")

                          let mastodonAuthorLink = document.createElement("a")
                          mastodonAuthorLink.href = reply.account.url
                          mastodonAuthorLink.rel = "nofollow"

                          let mastodonAuthorName = document.createElement("span")
                          mastodonAuthorName.innerText = reply.account.display_name + " "

                          let mastodonAuthorAccount = document.createElement("span")
                          mastodonAuthorAccount.classList.add("disabled")
                          mastodonAuthorAccount.innerHTML = escapeHtml(reply.account.acct)

                          let mastodonCommentDate = document.createElement("a")
                          mastodonCommentDate.classList.add("date")
                          mastodonCommentDate.href = reply.uri
                          mastodonCommentDate.rel = "nofollow"
                          mastodonCommentDate.innerText = reply.created_at.substr(0, 10)

                          let mastodonContentComment = document.createElement("div")
                          mastodonContentComment.classList.add("mastodon-comment-content")
                          mastodonContentComment.innerHTML = reply.content

                          mastodonAvatar.appendChild(mastodonAvatarImage)

                          mastodonAuthorLink.appendChild(mastodonAuthorName)
                          mastodonAuthorLink.appendChild(mastodonAuthorAccount)

                          mastodonAuthor.appendChild(mastodonAuthorLink)
                          mastodonAuthor.appendChild(mastodonCommentDate)

                          mastodonContent.appendChild(mastodonAuthor)
                          mastodonContent.appendChild(mastodonContentComment)

                          mastodonComment.appendChild(mastodonAvatar)
                          mastodonComment.appendChild(mastodonContent)

                          document.getElementById("mastodon-comments-list").appendChild(mastodonComment);
                        });
                      } else {
                        document.getElementById("mastodon-comments-list").innerHTML = "<p>Not comments found</p>";
                      }
                    });
        </script>
      </div>
      {{ end }}

By adding the following to my front matter of each post:

comments:
    host: fosstodon.org
    user: utahcon
    id: {{POSTID}}

I get a nice little comments section at the bottom of each of my posts, additionally I can enable and disable the comments PER POST! That means if I don’t want to see what every Tom, Dick, and Harry has to say about a post, I simply don’t include the above snippet in the front matter, and boom, no comments.

The only downside, as of right now, is that I have to manually create the Mastodon post and bring the ID back here to add into the front matter. Ideally I would like my build agent to recognize new posts, create Mastodon posts automatically, and then inject them into the front matter. This might be a stretch today, but it is something to noodle on.

With that said, if you have a solution for the build agent issue, leave a comment!


Comments

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

Reply