13g10n
Напишите мне
На главную

Расширение возможностей блоков кода в Nuxt Content

Nuxt2 минуты
Also available in English

Несмотря на то что дефолтный парсер маркдаун файлов Nuxt Content достаточно хорошо работает с блоками кода из коробки, мне всё равно относительно много времени пришлось потратить на улучшения их внешнего вида и функциональности.

Про стили хайлайтера говорить не буду, т.к. огромнейшее количество тем (в том числе в стиле популярных IDE) достаточно просто гуглятся.

Что же касается функциональной части, то в дефолте мы не имеем указания файла и языка, хотя эта информация может быть указана и даже передаётся в конечный компонент.

К примеру, для файла main.py на языке python, где мы хотим подсветить первую строку, блок будет выглядеть так:

example.md
```python [main.py] {1}
def sum(a: int, b: int) -> int:
    """Sum two numbers."""
    ...

Модуль Nuxt Content использует папку components/content, чтобы определять глобальные пользовательские компоненты, доступные в маркдаун файлах. Чтобы расширить стандартный компонент, мы должны в папке components/content, создать файл с именем ProseCode.vue.

Будьте осторожны с именованием ваших компонентов, т.к. эта же папка позволяет переопределять встроенные компоненты, используемые при рендеринге.

В новом компоненте мы получаем code, language, filename и highlights как пропсы и имеем дефолтный слот для вставки отрендеренного блока HTML.

components/content/ProseCode.vue
<script setup>
const props = defineProps({
  code: {
    type: String,
    default: ''
  },
  language: {
    type: String,
    default: null
  },
  filename: {
    type: String,
    default: null
  },
  highlights: {
    type: Array,
    default: []
  }
})
</script>

Далее всё сводится только к вашим фантазиям и умениям. Например, выводим язык и имя файла, добавляем кнопку копирования кода:

components/content/ProseCode.vue
<template>
  <div>
    <section>
        <span>{{ props.language }}</span>
        <span>{{ props.filename }}</span>
        <button @click="navigator.clipboard.writeText(props.code)")>Copy</button>
    </section>
    <slot/>
  </div>
</template>

Собственно примерно такую схему использую и я в этом блоге. Результат для изначального блока кода:

main.py
def sum(a: int, b: int) -> int:
    """Sum two numbers."""
    ...

Nuxt
SSG
Nuxt Content