Vincent Barrault

Faire des catégories d'articles sur NextJS

Faire des catégories d'articles sur NextJS

Table des matières

Contexte

Si vous avez suivi l'article précedent sur "comment créer un blog avec NextJS", nous sommes en possession d'un blog avec une seule liste d'articles. Pour aller plus loin, nous pouvons créer un système de catégories sur nos articles, pour pouvoir filtrer les articles par thème.

Modification du repository d'articles

Pour commencer, nous allons ajouter la notion de tag dans les articles

./repository/articles.ts
[...]
import slugify from 'slugify'

export interface Article {
    [...]
    tags: string[];
}

export interface ArticleFilters {
    tag?: string;
}

export function getArticleList(filters: ArticleFilters): Article[] {
    return list()
        .map(fileName => ({
            id: fileName.replace(/\.md$/, ''),
            ...read(fileName).data
        } as Article))
        .filter(article => !filters.tag || article.tags.map(tag => slugify(tag, { replacement: '-', lower: true })).findIndex(tag => tag === filters.tag) !== -1);
}
[...]

Maintenant que nous pouvons ajouter des tags dans nos articles, profitons-en pour les modifier

./content/1er-article.md
---
title: 1er article
date: '2020-01-01'
tags: ['Tag 1', 'Tag 2']
---

Ici le contenu de notre premmier article
./content/2eme-article.md
---
title: 2ème article
date: '2020-01-02'
tags: ['Tag 2', 'Tag 3']
---

Ici le contenu de notre deuxième article
./content/3eme-article.md
---
title: 3ème article
date: '2020-01-03'
tags: ['Tag 1', 'Tag 3']
---

Ici le contenu de notre troisième et dernier article

Creation d'un repository de tag

Pour gérer les tags, nous allons avoir besoin de slugifier ces derniers pour qu'ils puissent passer dans l'url.

Pour cela, nous allons installer un paquet dans nos dépendances:

yarn add slugify

Nous pouvons donc créer le repository de tags comme ceci:

./repository/tags.ts
import { list, read } from './articles'
import slugify from 'slugify'

export type Tag = string;

export function getTags(): Tag[] {
    return list()
        .flatMap(fileName => read(fileName).data.tags)
        .filter((tag, index, tags) => tags.findIndex(search => search === tag) === index);
}

export function tagSlug(tag: Tag): string {
    return slugify(tag, {
        replacement: '-',
        lower: true,
    });
}

Creation d'un liste d'article par tag

L'étape suivante est de créer la page qui contiendra la liste d'article, filtrée par un tag. Pour cela, il faut créer une page avec le tag dans l'url.

./pages/tags/[tag].ts
import { GetStaticPaths, GetStaticProps } from 'next'
import Link from 'next/link'
import { getArticleList } from '../../repository/articles'
import { getTags, tagSlug } from '../../repository/tags'

export default function TagArticleList({ tag, articles }) {
    return (
        <div>
            <h2>{tag}</h2>

            {articles.map(({ id, date, title, tags }) => (
                <Link href={`/${id}`} key={id}>
                    <div className="article">
                        <h3>{title}</h3>
                        <div>{date}</div>
                        
                        {tags.map((tag) => (
                            <Link href={`/tags/${tagSlug(tag)}`} key={tag}>
                                {tag}
                            </Link>
                        ))}
                    </div>
                </Link>
            ))}

            <style jsx>{`
                .article {
                    background: #eaeaea;
                    padding: 10px 20px;
                    margin: 20px 0;
                }
            `}</style>
        </div>
    )
}

export const getStaticProps: GetStaticProps = async (context) => {
    const tagId = context.params.tag.toString();
    const tag = getTags().find(tag => tagSlug(tag) === tagId);
    const articles = getArticleList({ tag: tagId })
    return {
        props: {
            tag,
            articles
        }
    }
}

export const getStaticPaths: GetStaticPaths = async () => {
    return {
        paths: getTags().map(tag => ({
            params: { tag: tagSlug(tag) }
        })),
        fallback: false
    }
}

Modification de la liste d'article

Une bonne idée serait de lister de manière unique les tags de tous les articles sur la page principale. Pour cela, modifions le fichier index.tsx

./pages/index.tsx
import { GetStaticProps } from 'next'
import Head from 'next/head'
import Link from 'next/link'
import { getArticleList } from '../repository/articles'
import { getTags, tagSlug } from '../repository/tags'

export default function ArticleList({ articles, tags }) {
    return (
        <div>
            <Head>
                <title>Mon super Blog</title>
                <link rel="icon" href="/favicon.ico" />
            </Head>

            <h1>Articles</h1>
            
            {tags.map((tag) => (
                <Link href={`/tags/${tagSlug(tag)}`} key={tag}>
                    {tag}
                </Link>
            ))}

            {articles.map(({ id, date, title, tags }) => (
                <Link href={`/${id}`} key={id}>
                    <div className="article">
                        <h3>{title}</h3>
                        <div>{date}</div>
                        
                        {tags.map((tag) => (
                            <Link href={`/tags/${tagSlug(tag)}`} key={tag}>
                                {tag}
                            </Link>
                        ))}
                    </div>
                </Link>
            ))}

            <style jsx>{`
                .article {
                    background: #eaeaea;
                    padding: 10px 20px;
                    margin: 20px 0;
                }
            `}</style>
        </div>
    )
}

export const getStaticProps: GetStaticProps = async () => {
    return {
        props: {
            articles: getArticleList({}),
            tags: getTags(),
        }
    }
}

Tester son blog sur son ordinateur

Et voilà, nous avons ajouté un système de tag sur notre blog, vous pouvez lancer la commande suivante pour tester les modifications.

yarn dev

Nous pouvons voir que la liste des tags est générée au-dessus des 3 articles.

Liste de tag

Et que si nous cliquons sur un tag, le site nous emmène bien vers une liste d'articles triés par ce tag.

Liste d'article par tag