_README.md
@@ -34,4 +34,7 @@ Here are some previews
![no comments](https://user-images.githubusercontent.com/11576465/253985700-e14a66f8-714f-4aca-987e-e074f0b0e5a3.png "Message shown when no reply has been made yet")
### Comment
-![comment](https://user-images.githubusercontent.com/11576465/253999048-31f7b5ad-8adf-4866-8ee1-aa85a4757809.png "How the comment would look like")
\ No newline at end of file
+![comment](https://user-images.githubusercontent.com/11576465/253999048-31f7b5ad-8adf-4866-8ee1-aa85a4757809.png "How the comment would look like")
+
+## Credits
+Original concept and code-snippets: <https://danielpecos.com/2022/12/25/mastodon-as-comment-system-for-your-static-blog/>
\ No newline at end of file
comments.html
@@ -2,7 +2,7 @@
<h2 id="__comments">{{ lang.t("meta.comments") }}</h2>
{% if page.meta.comment_id %}
<noscript>
- <div class="admonition warning">
+ <div class="admonition danger">
<p class="admonition-title">
Please enable Javascript to see comments from Mastodon.
</p>
comments.html
@@ -156,7 +156,7 @@
{% else %}
<div class="admonition warning">
<p class="admonition-title">
- No Mastodon post configured for this page. Ask the post author to link a Mastodon post to comment here.
+ No Mastodon post configured for this page. Contact {{ config.site_author | default('the post author', true) }} if you want to comment here.
</p>
</div>
{% endif %}
_README.md
@@ -22,4 +22,16 @@ This paste contains files to implement a comment system using a Mastodon instanc
host: example.com # Replace with your Mastodon instance domain
user: Example # Replace with your username on the instance
```
-5. You're done! All you need to do is now create a Post on Mastodon, copy the ID from it and add it as `comment_id` YAML frontmatter to your page. Also, make sure to add `comments: true` to the front matter so that the comments.html content is used.
\ No newline at end of file
+5. You're done! All you need to do is now create a Post on Mastodon, copy the ID from it and add it as `comment_id` YAML frontmatter to your page. Also, make sure to add `comments: true` to the front matter so that the comments.html content is used.
+
+## Preview
+Here are some previews
+
+### No Post set
+![no post set](https://user-images.githubusercontent.com/11576465/253985888-7521a64f-5899-49e0-8797-6e7ee262e738.png "Message shown when no post has been set")
+
+### Post set, but no comments (Replies)
+![no comments](https://user-images.githubusercontent.com/11576465/253985700-e14a66f8-714f-4aca-987e-e074f0b0e5a3.png "Message shown when no reply has been made yet")
+
+### Comment
+![comment](https://user-images.githubusercontent.com/11576465/253999048-31f7b5ad-8adf-4866-8ee1-aa85a4757809.png "How the comment would look like")
\ No newline at end of file
comments.html
@@ -156,7 +156,7 @@
{% else %}
<div class="admonition warning">
<p class="admonition-title">
- No Mastodon post connected to this blog post. Please try again later.
+ No Mastodon post configured for this page. Ask the post author to link a Mastodon post to comment here.
</p>
</div>
{% endif %}
_README.md
@@ -22,4 +22,4 @@ This paste contains files to implement a comment system using a Mastodon instanc
host: example.com # Replace with your Mastodon instance domain
user: Example # Replace with your username on the instance
```
-5. You're done! All you need to do is now create a Post on Mastodon, copy the ID from it and add it as `comment_id` YAML frontmatter to your page.
\ No newline at end of file
+5. You're done! All you need to do is now create a Post on Mastodon, copy the ID from it and add it as `comment_id` YAML frontmatter to your page. Also, make sure to add `comments: true` to the front matter so that the comments.html content is used.
\ No newline at end of file
comments.html
@@ -1,161 +1,163 @@
-<h2 id="__comments">{{ lang.t("meta.comments") }}</h2>
-{% if page.meta.comment_id %}
- <noscript>
- <div class="admonition warning">
- <p class="admonition-title">
- Please enable Javascript to see comments from Mastodon.
- </p>
- </div>
- </noscript>
- <p>
- <a href="https://{{ config.extra.mastodon.host }}/@{{ config.extra.mastodon.user }}/{{ page.meta.comment_id }}">Comment on this blog post</a> using a Fediverse-compatible Account (Mastodon or alike).
- </p>
-
- <p id="mastodon-comments-list"></p>
-
- <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.4.1/purify.min.js" integrity="sha512-uHOKtSfJWScGmyyFr2O2+efpDx2nhwHU2v7MVeptzZoiC7bdF6Ny/CmZhN2AwIK1oCFiVQQ5DA/L9FSzyPNu6Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
- <script type="text/javascript">
- var host = '{{ config.extra.mastodon.host }}';
- var user = '{{ config.extra.mastodon.user }}';
- var id = '{{ page.meta.comment_id }}'
-
- function escapeHtml(unsafe) {
- return unsafe
- .replace(/&/g, "&")
- .replace(/</g, "<")
- .replace(/>/g, ">")
- .replace(/"/g, """)
- .replace(/'/g, "'");
- }
-
- var commentsLoaded = false;
-
- function toot_active(toot, what) {
- var count = toot[what+'_count'];
- return count > 0 ? 'active' : '';
- }
-
- function toot_count(toot, what) {
- var count = toot[what+'_count'];
- return count > 0 ? count : '';
- }
-
- function user_account(account) {
- var result =`@${account.acct}`;
- if (account.acct.indexOf('@') === -1) {
- var domain = new URL(account.url)
- result += `@${domain.hostname}`
+{% if page.meta.comments %}
+ <h2 id="__comments">{{ lang.t("meta.comments") }}</h2>
+ {% if page.meta.comment_id %}
+ <noscript>
+ <div class="admonition warning">
+ <p class="admonition-title">
+ Please enable Javascript to see comments from Mastodon.
+ </p>
+ </div>
+ </noscript>
+ <p>
+ <a href="https://{{ config.extra.mastodon.host }}/@{{ config.extra.mastodon.user }}/{{ page.meta.comment_id }}">Comment on this blog post</a> using a Fediverse-compatible Account (Mastodon or alike).
+ </p>
+
+ <p id="mastodon-comments-list"></p>
+
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.4.1/purify.min.js" integrity="sha512-uHOKtSfJWScGmyyFr2O2+efpDx2nhwHU2v7MVeptzZoiC7bdF6Ny/CmZhN2AwIK1oCFiVQQ5DA/L9FSzyPNu6Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+ <script type="text/javascript">
+ var host = '{{ config.extra.mastodon.host }}';
+ var user = '{{ config.extra.mastodon.user }}';
+ var id = '{{ page.meta.comment_id }}'
+
+ function escapeHtml(unsafe) {
+ return unsafe
+ .replace(/&/g, "&")
+ .replace(/</g, "<")
+ .replace(/>/g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
}
- return result;
- }
-
- function render_toots(toots, in_reply_to, depth) {
- var tootsToRender = toots
- .filter(toot => toot.in_reply_to_id === in_reply_to)
- .sort((a, b) => a.created_at.localeCompare(b.created_at));
- tootsToRender.forEach(toot => render_toot(toots, toot, depth));
- }
-
- function render_toot(toots, toot, depth) {
- toot.account.display_name = escapeHtml(toot.account.display_name);
- toot.account.emojis.forEach(emoji => {
- toot.account.display_name = toot.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" style="margin-left: calc(var(--mastodon-comment-indent) * ${depth})">
- <div class="author">
- <div class="avatar">
- <img src="${escapeHtml(toot.account.avatar_static)}" height=60 width=60 alt="">
- </div>
- <div class="details">
- <a class="name" href="${toot.account.url}" rel="nofollow">${toot.account.display_name}</a>
- <a class="user" href="${toot.account.url}" rel="nofollow">${user_account(toot.account)}</a>
- </div>
- <a class="date" href="${toot.url}" rel="nofollow">${toot.created_at.substr(0, 10)} ${toot.created_at.substr(11, 8)}</a>
- </div>
- <div class="content">${toot.content}</div>
- <div class="attachments">
- ${toot.media_attachments.map(attachment => {
- if (attachment.type === 'image') {
- return `<a href="${attachment.url}" rel="nofollow"><img src="${attachment.preview_url}" alt="${attachment.description}" /></a>`;
- } else if (attachment.type === 'video') {
- return `<video controls><source src="${attachment.url}" type="${attachment.mime_type}"></video>`;
- } else if (attachment.type === 'gifv') {
- return `<video autoplay loop muted playsinline><source src="${attachment.url}" type="${attachment.mime_type}"></video>`;
- } else if (attachment.type === 'audio') {
- return `<audio controls><source src="${attachment.url}" type="${attachment.mime_type}"></audio>`;
- } else {
- return `<a href="${attachment.url}" rel="nofollow">${attachment.type}</a>`;
- }
- }).join('')}
- </div>
- <div class="status">
- <div class="twemoji replies ${toot_active(toot, 'replies')}">
- <a href="${toot.url}" rel="nofollow">{% include ".icons/fontawesome/solid/reply.svg" %}${toot_count(toot, 'replies')}</a>
- </div>
- <div class="twemoji reblogs ${toot_active(toot, 'reblogs')}">
- <a href="${toot.url}" rel="nofollow">{% include ".icons/fontawesome/solid/retweet.svg" %}${toot_count(toot, 'reblogs')}</a>
+
+ var commentsLoaded = false;
+
+ function toot_active(toot, what) {
+ var count = toot[what+'_count'];
+ return count > 0 ? 'active' : '';
+ }
+
+ function toot_count(toot, what) {
+ var count = toot[what+'_count'];
+ return count > 0 ? count : '';
+ }
+
+ function user_account(account) {
+ var result =`@${account.acct}`;
+ if (account.acct.indexOf('@') === -1) {
+ var domain = new URL(account.url)
+ result += `@${domain.hostname}`
+ }
+ return result;
+ }
+
+ function render_toots(toots, in_reply_to, depth) {
+ var tootsToRender = toots
+ .filter(toot => toot.in_reply_to_id === in_reply_to)
+ .sort((a, b) => a.created_at.localeCompare(b.created_at));
+ tootsToRender.forEach(toot => render_toot(toots, toot, depth));
+ }
+
+ function render_toot(toots, toot, depth) {
+ toot.account.display_name = escapeHtml(toot.account.display_name);
+ toot.account.emojis.forEach(emoji => {
+ toot.account.display_name = toot.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" style="margin-left: calc(var(--mastodon-comment-indent) * ${depth})">
+ <div class="author">
+ <div class="avatar">
+ <img src="${escapeHtml(toot.account.avatar_static)}" height=60 width=60 alt="">
+ </div>
+ <div class="details">
+ <a class="name" href="${toot.account.url}" rel="nofollow">${toot.account.display_name}</a>
+ <a class="user" href="${toot.account.url}" rel="nofollow">${user_account(toot.account)}</a>
+ </div>
+ <a class="date" href="${toot.url}" rel="nofollow">${toot.created_at.substr(0, 10)} ${toot.created_at.substr(11, 8)}</a>
</div>
- <div class="twemoji favourites ${toot_active(toot, 'favourites')}">
- <a href="${toot.url}" rel="nofollow">{% include ".icons/fontawesome/solid/star.svg" %}${toot_count(toot, 'favourites')}</a>
+ <div class="content">${toot.content}</div>
+ <div class="attachments">
+ ${toot.media_attachments.map(attachment => {
+ if (attachment.type === 'image') {
+ return `<a href="${attachment.url}" rel="nofollow"><img src="${attachment.preview_url}" alt="${attachment.description}" /></a>`;
+ } else if (attachment.type === 'video') {
+ return `<video controls><source src="${attachment.url}" type="${attachment.mime_type}"></video>`;
+ } else if (attachment.type === 'gifv') {
+ return `<video autoplay loop muted playsinline><source src="${attachment.url}" type="${attachment.mime_type}"></video>`;
+ } else if (attachment.type === 'audio') {
+ return `<audio controls><source src="${attachment.url}" type="${attachment.mime_type}"></audio>`;
+ } else {
+ return `<a href="${attachment.url}" rel="nofollow">${attachment.type}</a>`;
+ }
+ }).join('')}
</div>
- </div>
- </div>`;
- document.getElementById('mastodon-comments-list').appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
-
- render_toots(toots, toot.id, depth + 1)
- }
-
- function loadComments() {
- if (commentsLoaded) return;
-
- document.getElementById("mastodon-comments-list").innerHTML = "Loading comments from the Fediverse...";
-
- 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 = "";
- render_toots(data['descendants'], id, 0)
- } else {
- document.getElementById('mastodon-comments-list').innerHTML =
- `<div class="admonition info">
- <p class="admonition-title">
- No comments found. <a href="https://{{ config.extra.mastodon.host }}/@{{ config.extra.mastodon.user }}/{{ page.meta.comment_id }}">Be the first!</a>
- </p>
+ <div class="status">
+ <div class="twemoji replies ${toot_active(toot, 'replies')}">
+ <a href="${toot.url}" rel="nofollow">{% include ".icons/fontawesome/solid/reply.svg" %}${toot_count(toot, 'replies')}</a>
+ </div>
+ <div class="twemoji reblogs ${toot_active(toot, 'reblogs')}">
+ <a href="${toot.url}" rel="nofollow">{% include ".icons/fontawesome/solid/retweet.svg" %}${toot_count(toot, 'reblogs')}</a>
+ </div>
+ <div class="twemoji favourites ${toot_active(toot, 'favourites')}">
+ <a href="${toot.url}" rel="nofollow">{% include ".icons/fontawesome/solid/star.svg" %}${toot_count(toot, 'favourites')}</a>
+ </div>
</div>
- `;
- }
-
- commentsLoaded = true;
- });
- }
-
- function respondToVisibility(element, callback) {
- var options = {
- root: null,
- };
-
- var observer = new IntersectionObserver((entries, observer) => {
- entries.forEach(entry => {
- if (entry.intersectionRatio > 0) {
- callback();
- }
- });
- }, options);
-
- observer.observe(element);
- }
-
- var comments = document.getElementById("mastodon-comments-list");
- respondToVisibility(comments, loadComments);
- </script>
-{% else %}
- <div class="admonition warning">
- <p class="admonition-title">
- No Mastodon post connected to this blog post. Please try again later.
- </p>
- </div>
+ </div>`;
+ document.getElementById('mastodon-comments-list').appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
+
+ render_toots(toots, toot.id, depth + 1)
+ }
+
+ function loadComments() {
+ if (commentsLoaded) return;
+
+ document.getElementById("mastodon-comments-list").innerHTML = "Loading comments from the Fediverse...";
+
+ 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 = "";
+ render_toots(data['descendants'], id, 0)
+ } else {
+ document.getElementById('mastodon-comments-list').innerHTML =
+ `<div class="admonition info">
+ <p class="admonition-title">
+ No comments found. <a href="https://{{ config.extra.mastodon.host }}/@{{ config.extra.mastodon.user }}/{{ page.meta.comment_id }}">Be the first!</a>
+ </p>
+ </div>
+ `;
+ }
+
+ commentsLoaded = true;
+ });
+ }
+
+ function respondToVisibility(element, callback) {
+ var options = {
+ root: null,
+ };
+
+ var observer = new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if (entry.intersectionRatio > 0) {
+ callback();
+ }
+ });
+ }, options);
+
+ observer.observe(element);
+ }
+
+ var comments = document.getElementById("mastodon-comments-list");
+ respondToVisibility(comments, loadComments);
+ </script>
+ {% else %}
+ <div class="admonition warning">
+ <p class="admonition-title">
+ No Mastodon post connected to this blog post. Please try again later.
+ </p>
+ </div>
+ {% endif %}
{% endif %}
\ No newline at end of file
_README.md
@@ -0,0 +1,25 @@
+# Mastodon-based Comment system for Material for MkDocs
+This paste contains files to implement a comment system using a Mastodon instance and user.
+
+## Requirements
+
+- Mastodon account
+- Material for MkDocs theme
+- Knowledge in theme extension
+
+## Set up
+> Note: This setup was made using the dark theme of Material for MkDocs. You may need to edit colour values in the `comments.md` file to make it work with your design.
+
+1. Follow the Guide for [extending the theme](https://squidfunk.github.io/mkdocs-material/customization/#extending-the-theme) and create the necessary folders and files for [adding a comment system](https://squidfunk.github.io/mkdocs-material/setup/adding-a-comment-system/)
+ - Do NOT enable and/or create the Giscus `<script>` part. It's not needed.
+2. Copy and paste the content of `comments.html` into the file with the same name (`<your custom_dir folder>/partials/comments.html`)
+3. Create a new CSS file in your assets directory and copy the content of `comments.css` over. Don't forget to also add it as extra CSS in your mkdocs.yml file!
+4. Add a new section called `mastodon` in the `extra` section. If said section doesn't exist, create it. Add `user` and `host` to the `mastodon` section and add necessary values to it.
+ You should have a `extra` configuration that looks similar to this:
+ ```yaml
+ extra:
+ mastodon:
+ host: example.com # Replace with your Mastodon instance domain
+ user: Example # Replace with your username on the instance
+ ```
+5. You're done! All you need to do is now create a Post on Mastodon, copy the ID from it and add it as `comment_id` YAML frontmatter to your page.
\ No newline at end of file
comments.css
@@ -0,0 +1,116 @@
+:root{
+ --mastodon-comment-indent: 40px;
+ --mastodon-comment-border-radius: 3px;
+
+ --mastodon-comment-bg-color: rgba(0, 0, 0, 0.2);
+ --mastodon-comment-border-color: rgba(0, 0, 0, 0.4);
+ --mastodon-comment-user-color: #939393;
+
+ --mastodon-comment-status--inactive: #5d686f;
+ --mastodon-comment-status-replies--active: #448aff;
+ --mastodon-comment-status-favourite--active: #ff9100;
+ --mastodon-comment-status-reblog--active: #00c853;
+}
+
+@media only screen and (max-width: 1024px){
+ :root{
+ --mastodon-comment-indent: 20px;
+ }
+}
+
+@media only screen and (max-width: 640px){
+ :root{
+ --mastodon-comment-indent: 0px;
+ }
+}
+
+.mastodon-comment{
+ background-color: var(--mastodon-comment-bg-color);
+ border-radius: var(--mastodon-comment-border-radius);
+ border: 1px var(--mastodon-comment-border-color) solid;
+ padding: 20px;
+ margin-bottom: 1.5rem;
+ display: flex;
+ flex-direction: column;
+}
+
+.mastodon-comment p{
+ margin-bottom: 0px;
+}
+
+.mastodon-comment .content{
+ margin: 15px 20px;
+}
+
+.mastodon-comment .content p:first-child{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.mastodon-comment .attachments{
+ max-width: 0px 10px;
+}
+
+.mastodon-comment .attachments > *{
+ max-width: 0px 10px;
+}
+
+.mastodon-comment .author{
+ padding-top: 0;
+ display: flex;
+}
+
+.mastodon-comment .author a{
+ text-decoration: none;
+}
+
+.mastodon-comment .author .avatar img{
+ margin-right: 1rem;
+ min-width: 60px;
+ border-radius: 5px;
+}
+
+.mastodon-comment .author .details{
+ display: flex;
+ flex-direction: column;
+}
+
+.mastodon-comment .author .details .name{
+ font-weight: bold;
+}
+
+.mastodon-comment .author .details .user{
+ color: var(--mastodon-comment-user-color);
+}
+
+.mastodon-comment .author .date{
+ margin-left: auto;
+ font-size: small;
+}
+
+.mastodon-comment .status > div{
+ display: inline-block;
+ margin-right: 15px;
+}
+
+.mastodon-comment .status a{
+ color: var(--mastodon-comment-status--inactive);
+ text-decoration: none;
+}
+
+.mastodon-comment .status .twemoji.replies.active a{
+ color: var(--mastodon-comment-status-replies--active);
+}
+
+.mastodon-comment .status .twemoji.reblogs.active a{
+ color: var(--mastodon-comment-status-reblog--active);
+}
+
+.mastodon-comment .status .twemoji.favourites.active a{
+ color: var(--mastodon-comment-status-favourite--active);
+}
+
+.mastodon-comment .status svg{
+ margin-right: 0.2rem;
+ vertical-align: middle;
+}
\ No newline at end of file
comments.html
@@ -0,0 +1,161 @@
+<h2 id="__comments">{{ lang.t("meta.comments") }}</h2>
+{% if page.meta.comment_id %}
+ <noscript>
+ <div class="admonition warning">
+ <p class="admonition-title">
+ Please enable Javascript to see comments from Mastodon.
+ </p>
+ </div>
+ </noscript>
+ <p>
+ <a href="https://{{ config.extra.mastodon.host }}/@{{ config.extra.mastodon.user }}/{{ page.meta.comment_id }}">Comment on this blog post</a> using a Fediverse-compatible Account (Mastodon or alike).
+ </p>
+
+ <p id="mastodon-comments-list"></p>
+
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.4.1/purify.min.js" integrity="sha512-uHOKtSfJWScGmyyFr2O2+efpDx2nhwHU2v7MVeptzZoiC7bdF6Ny/CmZhN2AwIK1oCFiVQQ5DA/L9FSzyPNu6Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+ <script type="text/javascript">
+ var host = '{{ config.extra.mastodon.host }}';
+ var user = '{{ config.extra.mastodon.user }}';
+ var id = '{{ page.meta.comment_id }}'
+
+ function escapeHtml(unsafe) {
+ return unsafe
+ .replace(/&/g, "&")
+ .replace(/</g, "<")
+ .replace(/>/g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+ }
+
+ var commentsLoaded = false;
+
+ function toot_active(toot, what) {
+ var count = toot[what+'_count'];
+ return count > 0 ? 'active' : '';
+ }
+
+ function toot_count(toot, what) {
+ var count = toot[what+'_count'];
+ return count > 0 ? count : '';
+ }
+
+ function user_account(account) {
+ var result =`@${account.acct}`;
+ if (account.acct.indexOf('@') === -1) {
+ var domain = new URL(account.url)
+ result += `@${domain.hostname}`
+ }
+ return result;
+ }
+
+ function render_toots(toots, in_reply_to, depth) {
+ var tootsToRender = toots
+ .filter(toot => toot.in_reply_to_id === in_reply_to)
+ .sort((a, b) => a.created_at.localeCompare(b.created_at));
+ tootsToRender.forEach(toot => render_toot(toots, toot, depth));
+ }
+
+ function render_toot(toots, toot, depth) {
+ toot.account.display_name = escapeHtml(toot.account.display_name);
+ toot.account.emojis.forEach(emoji => {
+ toot.account.display_name = toot.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" style="margin-left: calc(var(--mastodon-comment-indent) * ${depth})">
+ <div class="author">
+ <div class="avatar">
+ <img src="${escapeHtml(toot.account.avatar_static)}" height=60 width=60 alt="">
+ </div>
+ <div class="details">
+ <a class="name" href="${toot.account.url}" rel="nofollow">${toot.account.display_name}</a>
+ <a class="user" href="${toot.account.url}" rel="nofollow">${user_account(toot.account)}</a>
+ </div>
+ <a class="date" href="${toot.url}" rel="nofollow">${toot.created_at.substr(0, 10)} ${toot.created_at.substr(11, 8)}</a>
+ </div>
+ <div class="content">${toot.content}</div>
+ <div class="attachments">
+ ${toot.media_attachments.map(attachment => {
+ if (attachment.type === 'image') {
+ return `<a href="${attachment.url}" rel="nofollow"><img src="${attachment.preview_url}" alt="${attachment.description}" /></a>`;
+ } else if (attachment.type === 'video') {
+ return `<video controls><source src="${attachment.url}" type="${attachment.mime_type}"></video>`;
+ } else if (attachment.type === 'gifv') {
+ return `<video autoplay loop muted playsinline><source src="${attachment.url}" type="${attachment.mime_type}"></video>`;
+ } else if (attachment.type === 'audio') {
+ return `<audio controls><source src="${attachment.url}" type="${attachment.mime_type}"></audio>`;
+ } else {
+ return `<a href="${attachment.url}" rel="nofollow">${attachment.type}</a>`;
+ }
+ }).join('')}
+ </div>
+ <div class="status">
+ <div class="twemoji replies ${toot_active(toot, 'replies')}">
+ <a href="${toot.url}" rel="nofollow">{% include ".icons/fontawesome/solid/reply.svg" %}${toot_count(toot, 'replies')}</a>
+ </div>
+ <div class="twemoji reblogs ${toot_active(toot, 'reblogs')}">
+ <a href="${toot.url}" rel="nofollow">{% include ".icons/fontawesome/solid/retweet.svg" %}${toot_count(toot, 'reblogs')}</a>
+ </div>
+ <div class="twemoji favourites ${toot_active(toot, 'favourites')}">
+ <a href="${toot.url}" rel="nofollow">{% include ".icons/fontawesome/solid/star.svg" %}${toot_count(toot, 'favourites')}</a>
+ </div>
+ </div>
+ </div>`;
+ document.getElementById('mastodon-comments-list').appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
+
+ render_toots(toots, toot.id, depth + 1)
+ }
+
+ function loadComments() {
+ if (commentsLoaded) return;
+
+ document.getElementById("mastodon-comments-list").innerHTML = "Loading comments from the Fediverse...";
+
+ 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 = "";
+ render_toots(data['descendants'], id, 0)
+ } else {
+ document.getElementById('mastodon-comments-list').innerHTML =
+ `<div class="admonition info">
+ <p class="admonition-title">
+ No comments found. <a href="https://{{ config.extra.mastodon.host }}/@{{ config.extra.mastodon.user }}/{{ page.meta.comment_id }}">Be the first!</a>
+ </p>
+ </div>
+ `;
+ }
+
+ commentsLoaded = true;
+ });
+ }
+
+ function respondToVisibility(element, callback) {
+ var options = {
+ root: null,
+ };
+
+ var observer = new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if (entry.intersectionRatio > 0) {
+ callback();
+ }
+ });
+ }, options);
+
+ observer.observe(element);
+ }
+
+ var comments = document.getElementById("mastodon-comments-list");
+ respondToVisibility(comments, loadComments);
+ </script>
+{% else %}
+ <div class="admonition warning">
+ <p class="admonition-title">
+ No Mastodon post connected to this blog post. Please try again later.
+ </p>
+ </div>
+{% endif %}
\ No newline at end of file