This post explains how to create a Sätteri plugin to transform Markdown links that link to GitHub users or organisations into beautiful badges.

If you are looking for the equivalent Rehype plugin, check out this post.

Create the plugin code

This is the entire code for the Sätteri plugin:

import { defineHastPlugin } from "satteri";

export function satteriGitHubBadgeLinks() {
  return defineHastPlugin({
    name: "github-badge-links",
    element: {
      filter: ["a"],
      visit(node, ctx) {
        const href = node.properties.href;
        if (
          typeof href === "string" &&
          href.startsWith("https://github.com/")
        ) {
          const match = href.match(
            /^https:\/\/github\.com\/([\w-]+)\/?$/
          );

          if (match) {
            const username = match[1];
            const currentClassName = Array.isArray(node.properties.className)
              ? node.properties.className
              : [];
            ctx.setProperty(node, "className", currentClassName.concat("gh-badge"));

            const avatarImg = {
              type: "element",
              tagName: "img",
              properties: {
                src: `https://github.com/${username}.png`,
                alt: username,
              },
              children: [],
            };
            ctx.prependChild(node, avatarImg);
          }
        }
      },
    },
  });
}

Basically all this plugin does, is hook into the Sätteri pipeline through its APIs to traverse all link elements. If it finds one that links to GitHub, it adds an <img> tag before the text content with the profile picture of the GitHub user or organisation.

Add some CSS

In order to make the newly added image look beautiful on your website, add this little snippet of CSS. Feel free to adjust it to your needs.

.gh-badge {
  display: inline-flex;
  align-items: center;
  background-color: #21262d;
  border-radius: 9999px;
  padding: 0em 0.5em 0 0.3em;
  font-size: 0.9em;
  text-decoration: none;
  color: #f0f6fc;
  font-weight: 500;
  transition: background-color 0.2s ease, border-color 0.2s ease;
  transform: translateY(0.29rem);
  border: 1px solid #30363d;
}

.gh-badge:hover {
  background-color: #30363d;
  border-color: #8b949e;
}

.gh-badge img {
  border-radius: 9999px;
  width: 1.3em;
  height: 1.3em;
}

Hook into the pipeline

That's it! Now you just need to hook your plugin into Sätteri's MDAST to HAST pipeline by defining it as a hastPlugin:

import { markdownToHtml } from "satteri";
import { satteriGitHubBadgeLinks } from "./src/lib/satteri-github-badge-links.ts";

markdownToHtml(source, {
  hastPlugins: [satteriGitHubBadgeLinks()],
});

Example: Astro

If you are building your website with Astro and want to use this Sätteri plugin, you can hook the plugin to Sätteri's pipeline directly in your astro.config.mjs:

import { defineConfig } from 'astro/config';
import { satteri } from '@astrojs/markdown-satteri';
import { satteriGitHubBadgeLinks } from './src/lib/satteri-github-badge-links.ts';

export default defineConfig({
  markdown: {
    processor: satteri({
      hastPlugins: [satteriGitHubBadgeLinks()],
    }),
  },
});

Just do not forget to install the @astrojs/markdown-satteri package explicitly.

Read more about how to integrate this plugin into Astro in its documentation.