Recently was reminded by how crazy powerful and easy to use mermaid is. This article is a test for “wow mermaid can do that” type thing.

Given the following code snippet, this is coming directly from a “mermaid " block in Notion. When it gets rendered, the markdown is processed with a pre.language-mermaid > code.language-mermaid html block and code highlighted. Using the mermaid package, it enables us to pass in an html NodeList to find what to render, and if everything is working as expected the mermaid chart should be visible below.

Example language-txt of what the sequenceDiagram is:

sequenceDiagram
  autonumber
  participant Tony
  participant MyDog

  Tony->>MyDog: pet my dog
  MyDog->>Tony: wags tail (is happy)

Below is the “mermaid " version of the above script:

sequenceDiagram
  autonumber
  participant Tony
  participant MyDog

  Tony->>MyDog: pet my dog
  MyDog->>Tony: wags tail (is happy)

Nuxt Snippet:

<template>
    <section class="blog p-2 max-w-2xl m-y-auto">
        <NuxtLink class="text-sm py-4" to="/bits"><i class="fa-solid fa-arrow-left"></i> back</NuxtLink>
        <div v-if="page">
            <h2>{{ page.title }}</h2>
            <ClientOnly>
              <code class="text-sm block mb-8">{{ useLongDate(page.created) }}</code>
            </ClientOnly>
            <div class="post-content" v-html="useMd(page?.page?.parent)"></div>
        </div>
        <div v-else>~ no content ~</div>
        <NuxtLink class="text-center py-4" @click="scrollTop"><i class="fa-solid fa-arrow-up"></i> back to top</NuxtLink>
    </section>
</template>
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { useAppStore } from '~/store/index';
const { scrollTop } = useUtils;
const { $renderMarkdown } = useNuxtApp();
const store = useAppStore();
const route = useRoute();
await store.fetchPage(route.params.slug as any);
const page = await store.getPage(route.params.slug)
useHead({
  title: page.title,
  meta: [
    { name: 'description', content: page.description },
    { property: 'og:title', content: page.title },
    { property: 'og:description', content: page.description },
    { name: 'twitter:title', content: page.title },
    { name: 'twitter:description', content: page.description },
  ]
})

useSeoMeta({
  // will be inferred as the lastmod value in the sitemap
  articleModifiedTime: page.last_edited_time
})

onMounted(() => {
    const { $Prism } = useNuxtApp();
    $Prism.highlightAll();
    $renderMarkdown()
})

</script>


<style>
pre.language-mermaid {
    background-color: var(--background, white)!important;
    color: var(--text, black)!important;
}
</style>

plugins/mermaid.client.ts

a simple plugin to expose mermaid to the application via Nuxt conventions, and a helper script for automatically rendering common code snippets for my posts, instead of copying and pasting that snippet everywhere.

import mermaid from 'mermaid';

export default defineNuxtPlugin(() => {
    return {
        provide: {
            mermaid: mermaid,
            // renderMarkdown automatically renders prisma code snippets for the mermaid type
            renderMarkdown: async function () {
                await mermaid.run({
                    nodes: document.querySelectorAll('code.language-mermaid'),
                });
            }
        },
    };
});

components/Mermaid.vue

This component wraps and renders provided slot text. Allows bespoke usage outside of just tagging class="mermaid" , useful in certain circumstances

<template>
    <div
        v-if="show"
        class="mermaid"
    >
        <slot />
    </div>
</template>

<script setup lang="ts">
const show = ref(false);

const { $mermaid } = useNuxtApp();

onMounted(async () => {
    show.value = true;
    $mermaid.initialize({ startOnLoad: true });
    await nextTick();
    $mermaid.init();
});
</script>

Usage for standalone component

A couple examples on how to use the component

<template>
    ...
    <Mermaid>{{ rawMermaidScript }}</Mermaid>
    or inline:
    <Mermaid>
sequenceDiagram
  autonumber
  participant Tony
  participant MyDog

  Tony->>MyDog: pet my dog
  MyDog->>Tony: wags tail ferociously (is happy)
    </Mermaid>
</template>