Mastodon-powered comments in Astro
Building on the work of Jan Wildeboer (@jwildeboer) and Daniel Pecos Martínez (@dpecos) (and others before them, I’m sure), I have implemented Mastodon-powered comments for Astro.
How does this work then?
I’ve built it as an Astro
component, which expects to be passed an object called
mastodon
which should look like this:
{
"host": "mastodon.me.uk",
"user": "pikesley",
"toot": "109916350521031860"
}
or in frontmatter
like this:
mastodon:
host: "mastodon.me.uk"
user: "pikesley"
toot: "109916350521031860"
The host
and user
are optional, and default
to mastodon.me.uk
and pikesley
, which you’ll
probably want to sweeten to taste.
It uses these to construct the “These comments are generated from replies to
this Mastodon post” link at the top of the comment thread, then it pulls that
Toot from the Mastodon API and renders
its descendants
as the comment thread.
A brief aside: there’s something weird going on which I don’t quite understand: it only seems to work for a Toot which has no ancestors - a Root Toot, if you will. I tried giving it the ID of a Toot from within a thread, and although its
decendants
list was definitely populated, nothing was rendered. I guess it doesn’t actually matter for our purposes here, though.
How I’m using it
The way this site is structured, a blogpost uses the
BlogPost.astro
layout. Within this layout, if mastodon
exists in the frontmatter
, we include the component, passing it the
data:
{frontmatter.mastodon && <MastodonComments mastodon={frontmatter.mastodon} />}
This site also has project
pages - a
project is basically a blogpost generated from a Github README. These are driven
from some
JSON which feeds a dynamic
Astro page, which is rendered through the ProjectPage
layout and similarly, if there’s a mastodon
object in the enclosing
object, we call the component:
{mastodon && <MastodonComments mastodon={mastodon}>}
There is, as pointed-out in @jwildeboer’s post, a bootstrapping problem, where we have to Toot first to get the Toot ID, then come back and insert it, but this is not really a big deal.
I think this will mostly work as a drop-in component, modulo changing
the default host
and user
values. I might actually
look into packaging it as a proper Astro plugin, if anybody has any
hints on how to do that.
Isolating the CSS
The Astro way to build components is to put the CSS in a
<style>
tag right in the component, and then Astro namespaces
everything at build-time so nothing leaks. That doesn’t really work for us here,
though, because those component styles only apply to the static content, where
Astro is able to apply a class="41fb17f6"
or whatever to keep
everything scoped. There’s no way for it to style client-side dynamic content
using this approach (is there? maybe I’ve missed something), so each Mastodon
comment goes into a <article class="mastodon-comment">
and
then the styles are all like
article.mastodon-comment {
& span.mastodon-metadata {
font-size: 0.9rem;
}
}
inside a <style is:global>
tag, which makes them into
site-wide CSS.
So if you’re using Astro (and you should, it’s really nice once you lean into its way of thinking) and you’re interested in Mastodon-powered comments, please try this out and let me know where it breaks.
These comments are generated from replies to this Mastodon post