Rendu d'un article dans VitePress avec Tailwind Typography

- Read in english
Ressources: garabit

Aujourd'hui, nous allons développer la page pour lire un article de blog. Cette page affichera le titre et le contenu de l'article, nous permettant d'explorer les capacités de rendu Markdown de VitePress, le plugin Tailwind Typography et la mise en surbrillance de la syntaxe du code.

Configuration de la Route

Note

Assurez-vous qu'il y a des fichiers Markdown dans le répertoire src/blog. Vous pouvez les reproduire depuis le dépôt GitHub.

Tout d'abord, nous devons appliquer la mise en page à chaque article. Dans chaque article du répertoire src/blog, ajoutons ce qui suit dans le frontmatter :

yaml
layout: blog-show

Ensuite, nous devons créer la page pour afficher notre article. Dans le répertoire .vitepress/theme/pages/blog, créons un nouveau fichier nommé BlogShow.vue. Ce fichier se trouve à côté de BlogIndex.vue créé dans l'article précédent.

vue
<template>
  <Content />
</template>

Maintenant, nous devons lier cette page à la clé de mise en page correcte. Dans le fichier Layout.vue, ajoutons un rendu conditionnel basé sur la clé de mise en page dans le frontmatter de la page actuelle comme suit :

vue
<template>
  <div class="min-h-screen bg-[#FC88FF]">
    <main class="mx-auto max-w-screen-md">
      <BlogIndex v-if="frontmatter.layout === 'blog'" />
      <BlogShow v-else-if="frontmatter.layout === 'blog-show'" />
    </main>
  </div>
</template>

Maintenant, en naviguant vers http://localhost:3000/blog/getting-started-with-laravel, nous devrions voir le contenu de l'article. Ce n'est pas très élégant, mais ça fonctionne !

Le contenu de l'article affiché sur la page
Le contenu de l'article affiché sur la page

Une Table des Matières

Pour améliorer la lisibilité de l'article, nous pouvons incorporer une table des matières. Cela permettra aux lecteurs de naviguer rapidement dans l'article. VitePress inclut un plugin MarkdownIt à cet effet, et ajouter une table des matières à un fichier Markdown est aussi simple que [[toc]].

Sous l'avertissement de chaque fichier Markdown, ajoutons ce qui suit :

md
[[toc]]

Après avoir enregistré le fichier, nous devrions voir la table des matières affichée dans l'article.

Typographie

Notre contenu est présent mais semble illisible. Nous pouvons améliorer cela en appliquant des styles au contenu. Cela peut être effectué manuellement, mais c'est assez fastidieux. Il y a de nombreux aspects à considérer : la taille de la police, la hauteur de ligne, les marges, le rembourrage, les couleurs, etc. De plus, nous devons penser à chaque élément HTML : titres, paragraphes, listes, citations, tableaux, blocs de code, etc., et à la façon dont ils sont imbriqués ou positionnés ensemble. Heureusement, Tailwind CSS inclut un plugin appelé Tailwind Typography qui s'en charge pour nous.

Le plugin officiel Tailwind CSS Typography fournit un ensemble de classes de prose que vous pouvez utiliser pour ajouter de belles options typographiques par défaut à tout HTML classique que vous ne contrôlez pas, comme le HTML rendu à partir de Markdown, ou extrait d'un CMS.

En trois étapes, nous pouvons obtenir une typographie magnifique :

  1. Installons le plugin :
bash
pnpm add -D @tailwindcss/typography
  1. Ajoutons le plugin au fichier tailwind.config.js :
js
module.exports = {
  // ...
  plugins: [
    require('@tailwindcss/typography'),
  ],
}
  1. Appliquons les classes au composant Content dans le fichier BlogShow.vue :
vue
<template>
  <Content class="prose" />
</template>

Tip

La classe prose est une utilité de typographie Tailwind qui applique des styles au contenu.

Le contenu de l'article affiché avec le plugin Tailwind Typography
Le contenu de l'article affiché avec le plugin Tailwind Typography

Maintenant, ajoutons le titre et améliorons les styles pour un article beaucoup plus propre.

vue
<script lang="ts" setup>
const { frontmatter } = useData()
</script>

<template>
  <article
    class="mx-4 border-4 border-black bg-white p-8 shadow-[8px_8px_0_black] space-y-16 md:p-12"
  >
    <h1 class="text-6xl font-semibold">
      {{ frontmatter.title }}
    </h1>

    <Content class="text-black prose prose-zinc" />
  </article>
</template>
Le contenu de l'article affiché avec le titre et le plugin Tailwind Typography
Le contenu de l'article affiché avec le titre et le plugin Tailwind Typography

Mise en Évidence de la Syntaxe du Code

En inspectant les blocs de code dans l'article, nous remarquons l'absence de la coloration syntaxique.

Examinons le HTML généré pour comprendre le problème :

html
<div class="language-bash vp-adaptive-theme">
  <button title="Copy Code" class="copy"></button>
  <span class="lang">bash</span>
  <pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0">
    <code>
      <span class="line">
       <span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">composer</span>
        <span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> global</span>
        <span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> require</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> laravel/installer</span>
      </span>
      <span class="line">
        <span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">laravel</span>
        <span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> new</span>
        <span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> my-laravel-app</span>
      </span>
    </code>
  </pre>
</div>

Typiquement, le bloc de code serait rendu sous forme de balise pre avec une balise code à l'intérieur. Cependant, VitePress enveloppe le bloc de code pour incorporer le bouton de copie du code et la langue. Cela est réalisé par un plugin MarkdownIt.

En même temps, nous remarquons que les couleurs sont appliquées à l'aide de variables CSS, avec les variables --shiki-light et --shiki-dark. Pour notre blog, une seule couleur de thème est nécessaire. Changeons le thème en everforest-light dans le fichier de configuration VitePress config.mts :

Tip

Vous pouvez explorer tous les thèmes sur le site Shiki Themes.

ts
import { defineConfig } from 'vitepress'

export default defineConfig({
  markdown: {
    theme: 'everforest-light',
  },
})

Le navigateur se rafraîchira automatiquement, et les blocs de code seront joliment colorés.

Nous n'avons pas encore terminé. En examinant ces blocs de près, il y a une marge autour d'eux, et le langage est mal affichée.

Pour remédier à cela, créons un fichier code.css dans le répertoire .vitepress/theme/styles :

css
div[class*="language-"] {
  position: relative;
  margin: 1.75em 0;
}

div[class*="language-"] > button.copy {
  display: none;
}

div[class*="language-"] > span.lang {
  position: absolute;
  top: -1.25rem;
  right: 0px;
  z-index: 2;
  font-size: 12px;
  font-weight: 500;
}

Pour ce blog, nous avons supprimé le bouton de copie du code et positionné la langue en haut à droite du bloc de code. Nous avons également défini la marge autour de la div, l'élément HTML le plus extérieur, pour chevaucher correctement les marges des autres éléments.

Tip

Si vous avez besoin du bouton de copie de code, vous pouvez reproduire les styles du thème VitePress, les adapter et les incorporer dans le fichier code.css. C'est simple puisque la fonctionnalité existe déjà.

Ensuite, importons ce fichier CSS dans le fichier index.ts :

ts
// ...

import './styles/app.css'
import './styles/code.css'

// ...

Enfin, mettons à jour notre prose pour supprimer une partie de la marge autour de la balise pre et les aligner avec notre thème :

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./src/**/*.md', './.vitepress/theme/**/*.{vue,ts}'],
  theme: {
    extend: {
      typography: {
        DEFAULT: {
          css: {
            code: {
              'backgroundColor': '#fdf6e3',
              'padding': '0 0.25rem',
              'borderRadius': '0',
              '&::before': {
                content: '""!important',
              },
              '&::after': {
                content: '""!important',
              },
            },
            pre: {
              'background-color': '#fdf6e3',
              'border-radius': '0',
              'border': '2px solid black',
              'margin': '0',
            },
          },
        },
      },
    },
  },

  plugins: [require('@tailwindcss/typography')],
}

Maintenant, les blocs de code sont mis en évidence syntaxiquement et stylisés selon notre thème. 🎨

Alertes

Au début de chacun des articles, j'ai ajouté une alerte pour informer le lecteur que le contenu est généré par IA. Ce n'est pas un matériel éducatif, simplement un texte de remplacement plus réaliste que le traditionnel texte "Lorem Ipsum".

Par défaut, VitePress comprend les alertes Markdown Flavored de GitHub. Comme le bouton de copie, nous pouvons copier les styles du thème VitePress et les ajuster à vos préférences. Mais je les trouve insatisfaisants, donc nous allons les désactiver et implémenter un autre plugin.

Tout d'abord, installons le plugin :

bash
pnpm add -D markdown-it-github-alerts

Ensuite, désactivons le plugin par défaut et connectons le nouveau dans le fichier config.mts :

ts
import MarkdownItGitHubAlerts from 'markdown-it-github-alerts'
import { defineConfig } from 'vitepress'

export default defineConfig({
  // ...

  markdown: {
    config(md) {
      md.use(MarkdownItGitHubAlerts)
    },
    gfmAlerts: true,

    theme: 'everforest-light',
  },

  // ...
})

Grâce à la fonction config, nous avons un contrôle total sur l'instance MarkdownIt utilisée par VitePress. Nous pouvons ajouter et configurer n'importe quel plugin que nous voulons. 🤌

Maintenant, ajoutons les styles dans le fichier index.ts, après notre CSS personnalisé :

ts
// ...

import 'markdown-it-github-alerts/styles/github-base.css'

Nos alertes sont maintenant bien formatées mais pas colorées. Nous pourrions inclure un autre fichier CSS pour les couleurs, mais je préfère des couleurs personnalisées pour ce thème.

Créons un autre fichier appelé alerts.css dans le répertoire .vitepress/theme/styles :

css
:root {
  --color-note: #3a85ff;
  --color-tip: #00ddb3;
  --color-warning: #ffbf00;
  --color-severe: #ff7002;
  --color-caution: #f34720;
  --color-important: #8746ff;
}

Ce fichier spécifie quelques variables CSS avec des couleurs pour les alertes. Importons ce fichier dans le fichier index.ts :

ts
// ...

import './styles/app.css'
import './styles/code.css'
import './styles/alerts.css'

// ...

Maintenant, nos alertes sont colorées selon notre thème. 🌈

Retour au Blog

Il serait pratique d'avoir un bouton pour revenir à l'index du blog à la fin de l'article. Nous pouvons facilement ajouter cela en copiant le bouton du fichier BlogIndex.vue et en le collant à la fin du fichier BlogShow.vue :

vue
<script lang="ts" setup>
// ...
</script>

<template>
  <!-- ... -->

  <div class="mt-16 flex justify-center">
    <a
      href="/"
      class="border-4 border-black bg-[#FFEB00] px-8 py-4 shadow-[4px_4px_0_black] transition duration-150 ease-linear hover:bg-[#fff90d] hover:shadow-[6px_6px_0_black] hover:-translate-x-[0.125rem] hover:-translate-y-[0.125rem]"
    >
      Retour au Blog
    </a>
  </div>
</template>

Un Peu de Refactoring

Je n'aime pas copier un bouton d'un fichier à un autre. Si nous voulons changer la couleur du bouton, nous devons le mettre à jour à plusieurs endroits.

Tout d'abord, nous allons centraliser nos couleurs dans le fichier app.css :

css
// ...

:root {
  --color-yellow: #ffbf00;
  --color-sand: #fdf6e3;
}

Ensuite, nous pouvons refactoriser ce bouton dans un composant ButtonPrimary.vue situé dans le répertoire .vitepress/theme/components :

vue
<template>
  <a
    href="/"
    class="border-4 border-black bg-[var(--color-yellow)] px-8 py-4 shadow-[4px_4px_0_black] transition duration-150 ease-linear hover:bg-[#ffdf1b] hover:shadow-[6px_6px_0_black] hover:-translate-x-[0.125rem] hover:-translate-y-[0.125rem]"
  >
    <slot />
  </a>
</template>

Et mettons à jour nos fichiers BlogShow.vue et BlogIndex.vue pour utiliser ce nouveau composant :

vue
<template>
  <!-- ... -->

  <div class="mt-16 flex justify-center">
    <ButtonPrimary href="/blog">
      Retour au Blog
    </ButtonPrimary>
  </div>
</template>
vue
<template>
  <section>
    <!-- ... -->

    <div class="flex justify-center">
      <ButtonPrimary href="/">
        Retour à l'Accueil
      </ButtonPrimary>
    </div>
  </section>
</template>

Mettons à jour notre fichier alerts.css pour utiliser la variable CSS nouvellement créée :

css
:root {
  --color-note: #3a85ff;
  --color-tip: #00ddb3;
  --color-warning: var(--color-yellow); 
  --color-severe: #ff7002;
  --color-caution: #f34720;
  --color-important: #8746ff;
}

Pour améliorer notre contenu, ajoutons quelques couleurs à la prose en personnalisant le fichier tailwind.config.js :

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  // ...
  theme: {
    extend: {
      typography: {
        DEFAULT: {
          css: {
            'ul > li': {
              '--tw-prose-bullets': 'var(--color-yellow)',
            },
            'hr': {
              'border-top': '2px solid var(--color-yellow)',
            },
            // ...
          },
        },
      },
    },
  },

  // ...
}

Grâce à notre variable CSS, la personnalisation est sans effort !

Dans le fichier Layout.vue, transformons pt-16 en py-16 pour ajouter du rembourrage en haut et en bas et empêcher le bouton de toucher le bord inférieur de l'écran :

vue
<template>
  <div class="min-h-screen bg-[#FC88FF] py-16">
    <!-- ... -->
  </div>
</template>
Résultat final de la page de l'article
Résultat final de la page de l'article

Et nous avons terminé ! 🎉

J'espère que cet article a été agréable et a montré à quel point VitePress est ouvert à la personnalisation.