I currently use Jekyll to generate my blog posts that you see hosted here. One thing I have wanted was to add a commenting system. Inspired by this recent toot by @joel@fosstodon.org, and as I am a proponent of the Fediverse and a Mastodon user, I took a first stab at setting up comments collected the notes below.

At the moment the comment solution closely based based on primary work by Carl Schwan and others who have built upon it. See the references section below for more information on the sources I drew upon.

Modifications to Jekyll

Two modifications were needed to get this working form my Jekyll blog set up. First I had to create the fediverse_comments.html file and save it in the _includes directory of my project. The contents of the file are currently as follows.

_includes/fediverse_comments.html

<div class="article-content">
  <h2>Comments</h2>
  <p>You can use a Mastodon accounti to comment on this article by replying to the associated Mastodon <a class="link" href="https://{{ page.comments.host }}/@{{ page.comments.username }}/{{ page.comments.id }}">toot</a>.</p>
  <p>
  <a class="button" href="https://{{ page.comments.host }}/interact/{{ page.comments.id }}?type=reply"><button id="reply">Reply</button></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("load-comment").addEventListener("click", function() {
      document.getElementById("load-comment").innerHTML = "Loading";
      fetch('https://{{ page.comments.host }}/api/v1/statuses/{{ page.comments.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>`;
                document.getElementById('mastodon-comments-list').appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
              });
          } else {
            document.getElementById('mastodon-comments-list').innerHTML = "<p>Not comments found</p>";
          }
        });
      });
  </script>
</div>

The second change I made was to modify the existing posts.html file in my project’s _layouts directory to include the fesiverse_comments.html file (above) if the front matter for a post includes a comments section. The entire file is a below, but the lines that matter are:

{%- if page.comments -%}
    {%- include fediverse_comments.html -%}
{%- endif -%}
 

_layouts/post.html

---
layout: default
---
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">

  <header class="post-header">
    <h1 class="post-title p-name" itemprop="name headline">{{ page.title | escape }}</h1>
    <p class="post-meta">
      <time class="dt-published" datetime="{{ page.date | date_to_xmlschema }}" itemprop="datePublished">
        {%- assign date_format = site.minima.date_format | default: "%b %-d, %Y" -%}
        {{ page.date | date: date_format }}
      </time>
  </header>

  <div class="post-content e-content" itemprop="articleBody">
    {{ content }}
  </div>

  {%- if page.author -%}
  {% assign authorData = site.data.authors[page.author] %}
  <div class="author-bio">
		  <img src="/assets/images/authors/{{ authorData.photo }}" alt="{{ authorData.name }}'s profile picture." />
		  <div class="author-name">{{ author.name }}</div>
		  <p class="bio">{{ authorData.bio }}</p>
          {% for social in authorData.socials %}
		  <a href="{{ social.url }}" class="social-link {{ social.type }}-link">{{ social.type }} </a>
		  {% endfor %}
</div>
  {%- endif -%}</p>

{%- if page.comments -%}
    {%- include fediverse_comments.html -%}
{%- endif -%}

  {%- if site.disqus.shortname -%}
    {%- include disqus_comments.html -%}
  {%- endif -%}

  <a class="u-url" href="{{ page.url | relative_url }}" hidden></a>
</article>

Work Flow and Usage

Work Flow Enabling Comments for Article

  • Create an article for publication on my web log in markdown.
  • Create a toot on Mastodon linking to the article.
  • Get the ID # of the toot from URL of expanded toot.
  • Edit the original web log article and include comments section in the headmatter like such, replacing the id: with the value of that associated with the Mastodon toot related to the artcle:
comments:
  host: floss.social
  username: wchgi09 
  id: 107558689546077392 
---
  • Save and republish the article with no other changes.

Replying and Viewing Comments

  • To view comments (if any) in article in website, click Load Comments button at battom of post.
    • Original toot and related comments should appear after a moment.
    • If there is no Load Comments button, then the article does not have comments enabled.
  • To reply or comment on an article:
    • You should have an account on a Mastodon instance. It is possible other Fediverse accounts will work as well, but I have not tested.
    • Click the reply button at the bottom of the article.
    • If there is no Reply button then comments have not been enabled for the post.
    • After clicking on Reply button, enter your account and Mastodon instance name in the format account@instance.name in the field and click on Proceed to Reply and you should be taken to the toot and comments on Mastodon wher you can reply to the original post or one of the comments.

References