diff --git a/assets/css/main.css b/assets/css/main.css
index 5ac7bb23..bad8cbbc 100644
--- a/assets/css/main.css
+++ b/assets/css/main.css
@@ -624,4 +624,41 @@ body:has(#menu-controller:checked) {
.2xl\:ratio-16-9 { padding-top: 56.25%; } /* 16:9 Aspect Ratio */
.2xl\:ratio-21-9 { padding-top: 42.85%; } /* 21:9 Aspect Ratio */
.2xl\:ratio-32-9 { padding-top: 28.125%; } /* 32:9 Aspect Ratio */
+}
+
+@screen .mastodon-container {
+ margin-left: 1rem;
+}
+
+@screen .mastodon-comment {
+ border: 1px solid #999;
+ border-radius: 6px;
+ margin: 0.5rem 0;
+ display: flex;
+ padding: 0.5rem 1rem;
+}
+
+@screen .mastodon-comment .avatar img {
+ margin-right: 1rem;
+ min-width: e0px;
+}
+
+@screen .mastodon-comment .content {
+ width: 100%;
+}
+
+@screen .mastodon-comment .date {
+ float: right;
+}
+
+@screen .mastodon-comment .ellipsis::after {
+ content: "\2026";
+}
+
+@screen .mastodon-comment .invisible {
+ font-size: 0;
+ line-height: 0;
+ display: inline-block;
+ width: 0;
+ height: 0;
}
\ No newline at end of file
diff --git a/i18n/en.toml b/i18n/en.toml
new file mode 100644
index 00000000..bef562b8
--- /dev/null
+++ b/i18n/en.toml
@@ -0,0 +1,8 @@
+[Comments]
+ other = "Comments"
+[Use_fediverse_account]
+ other = 'You can use your Mastodon or Fediverse account to reply to this toot to write a comment on this article!'
+[Load_comments]
+ other = "Load comments"
+[No_comment]
+ other = "No comment, yet, be the first to react!"
\ No newline at end of file
diff --git a/layouts/_default/single.html b/layouts/_default/single.html
index 5811dcaa..04e34735 100644
--- a/layouts/_default/single.html
+++ b/layouts/_default/single.html
@@ -47,6 +47,9 @@
{{ $jsPage = $jsPage | resources.Minify | resources.Fingerprint "sha512" }}
+
+{{ partial "comments.html" . }}
+
-{{ end }}
\ No newline at end of file
+
+
+{{ end }}
diff --git a/layouts/partials/comments.html b/layouts/partials/comments.html
new file mode 100644
index 00000000..183abb4f
--- /dev/null
+++ b/layouts/partials/comments.html
@@ -0,0 +1,81 @@
+{{ with .Params.comments }}
+
+ {{ $icon := index $.Site.Data.fontawesome.icons "comments" }}
+ {{ $svg := $icon.svg.solid | default $icon.svg.regular | default $icon.svg.brands }}
+
{{ safeHTML $svg.raw }} {{ i18n "Comments" . }}
+
+ {{ i18n "Use_fediverse_account" . | safeHTML }}
+
+
+
+
+
+
+{{ end }}
diff --git a/static/js/purify.min.js b/static/js/purify.min.js
new file mode 100644
index 00000000..91bd986a
--- /dev/null
+++ b/static/js/purify.min.js
@@ -0,0 +1,3 @@
+/*! @license DOMPurify 3.0.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.0.1/LICENSE */
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(t)}function t(e,n){return t=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},t(e,n)}function n(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}function r(e,o,a){return r=n()?Reflect.construct:function(e,n,r){var o=[null];o.push.apply(o,n);var a=new(Function.bind.apply(e,o));return r&&t(a,r.prototype),a},r.apply(null,arguments)}function o(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,o,a=[],i=!0,l=!1;try{for(n=n.call(e);!(i=(r=n.next()).done)&&(a.push(r.value),!t||a.length!==t);i=!0);}catch(e){l=!0,o=e}finally{try{i||null==n.return||n.return()}finally{if(l)throw o}}return a}(e,t)||i(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function a(e){return function(e){if(Array.isArray(e))return l(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||i(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function i(e,t){if(e){if("string"==typeof e)return l(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?l(e,t):void 0}}function l(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n