Thom Bruce

More Syntax Highlighting

More Syntax Highlighting

Never mind this blog post. I just wanted to dump some theme colours somewhere. After featuring some code snippets in a previous blog post, I had to fix up the highlighting a little. For one, those snippets showed off some non-standard CSS, and I had to explicitly include the necessary grammar. And then I decided I could do a little more with how those snippets actually looked.

When I'm in my terminal, in my editor, in my file explorer or... oh, in pretty much any application I use these days actually, I tend to be using a theme called Catppuccin Mocha (the second example below). What's great about Catppuccin is that they have themes written for so many applications. They even have one for Tailwind CSS; I could apply this theme to my blog!

But Catppuccin is far, far from the only option for syntax highlighting and general theming. After I applied Catppuccin Latte as the base theme for light mode and Catppuccin Mocha as the theme for dark, it got me thinking about adding more themes to my website in general. And applying these themes to code blocks seemed like an ideal way to start playing with that concept. And so... here they are!

Catppuccin Latte and Mocha are listed as these were already previously implemented. The rest I've chosen because I've either used them in the past (looking at you Dracula) or I really, really like the look of them. I'm kind of drawn to Kanagawa Wave, which I think has a rich and varied colour palette and just looks stunning. I'm also keen on the muted simplicity of Nord, though I find it too lacking in variety for my own general use.

Adding support for these themes was pretty straightforward. It required adding support for them to the content config in my nuxt.config.ts file. The highlight feature uses Shiki syntax highlighter under the hood:

export default defineNuxtConfig({
  content: {
    build: {
      markdown: {
        highlight: {
          theme: {
            // See list of themes: https://github.com/shikijs/textmate-grammars-themes/tree/main/packages/tm-themes
            // NOTE: The background is configured separately in ./app/assets/css/main.css
            default: 'catppuccin-latte',
            dark: 'catppuccin-mocha',

            'catppuccin-latte-theme': 'catppuccin-latte',
            'catppuccin-mocha-theme': 'catppuccin-mocha',
            'dracula-theme': 'dracula',
            'kanagawa-dragon-theme': 'kanagawa-dragon',
            'kanagawa-lotus-theme': 'kanagawa-lotus',
            'kanagawa-wave-theme': 'kanagawa-wave',
            'nord-theme': 'nord',
          },
        }
      },
    },
  },
})

I then added some custom variants based on those to my Tailwind CSS and used the variants to apply the background colours. Thinking about it now, there is possibly an easier way. 🤔 I could look to see if I can just have Tailwind's typography plugin please NOT apply its own styles to <pre> tags, as it is essentially those that I'm overriding here. But this does the trick.

Edit: Per the above, Nuxt Content highlighting does not appear to provide background colours for code blocks (just the syntax-highlighting powered by Shiki). I do in fact therefore need to apply these theme colours myself separately.

@custom-variant catppuccin-latte (&:where(.catppuccin-latte-theme, .catppuccin-latte-theme *));
@custom-variant catppuccin-mocha (&:where(.catppuccin-mocha-theme, .catppuccin-mocha-theme *));
@custom-variant dracula (&:where(.dracula-theme, .dracula-theme *));
@custom-variant kanagawa-dragon (&:where(.kanagawa-dragon-theme, .kanagawa-dragon-theme *));
@custom-variant kanagawa-lotus (&:where(.kanagawa-lotus-theme, .kanagawa-lotus-theme *));
@custom-variant kanagawa-wave (&:where(.kanagawa-wave-theme, .kanagawa-wave-theme *));
@custom-variant nord (&:where(.nord-theme, .nord-theme *));

@layer utilities {
  .prose {
    :where(pre):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
      /* Catppuccin Latte Base for light mode and Catppuccin Mocha Crust for dark */
      /* NOTE: Syntax highlighting is configured in ../../../nuxt.config.ts */
      @apply
        bg-[#eff1f5]
        dark:bg-[#11111b]

        catppuccin-latte:bg-[#eff1f5]
        catppuccin-mocha:bg-[#11111b]
        dracula:bg-[#282a36]
        kanagawa-dragon:bg-[#181616]
        kanagawa-lotus:bg-[#F2ECBC]
        kanagawa-wave:bg-[#1F1F28]
        nord:bg-[#2e3440];
    }
  }
}

Now when I wrap a <pre> element inside of some other block element with the class appropriate class, say <div class="kanagawa-wave-theme">, both the syntax highlighting and the background colour will be applied.

The results... well, take a look:

Catppuccin Latte

const colorMode = useColorMode()

const isDark = computed({
  get() {
    return colorMode.value === 'dark'
  },
  set() {
    colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
  }
})

Catppuccin Mocha

const colorMode = useColorMode()

const isDark = computed({
  get() {
    return colorMode.value === 'dark'
  },
  set() {
    colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
  }
})

Dracula

const colorMode = useColorMode()

const isDark = computed({
  get() {
    return colorMode.value === 'dark'
  },
  set() {
    colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
  }
})

Kanagawa Dragon

const colorMode = useColorMode()

const isDark = computed({
  get() {
    return colorMode.value === 'dark'
  },
  set() {
    colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
  }
})

Kanagawa Lotus

const colorMode = useColorMode()

const isDark = computed({
  get() {
    return colorMode.value === 'dark'
  },
  set() {
    colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
  }
})

Kanagawa Wave

const colorMode = useColorMode()

const isDark = computed({
  get() {
    return colorMode.value === 'dark'
  },
  set() {
    colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
  }
})

Nord

const colorMode = useColorMode()

const isDark = computed({
  get() {
    return colorMode.value === 'dark'
  },
  set() {
    colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
  }
})