VuePress カテゴリーページを追加

vuePress 公開日: 2022-04-21 更新: 2022-04-26
サムネ画像

記事データObjの path からカテゴリーを判別し tampファイルに書き出す処理を追加

別ファイル func/methods.ts に 記事カテゴリー名のユニークな配列を生成してリターンする関数を追加

// docs/.vuepress/func/methods.ts
// ...
// 記事カテゴリー名のユニークな配列を生成してリターン
export const createUniqueCategoryNames = (articles: ArticleData[]) :string[] => {
  // null を含む 記事カテゴリー名のユニークな配列
  let uniqueCategoryNames: string[] = [...new Set(articles.map(obj => obj.category))] // exp.. [ 'vuePress', 'typeScript', null ]
  // null を除外した記事カテゴリー名のユニークな配列をリターン
  return uniqueCategoryNames.filter(category => category); //  [ 'vuePress', 'typeScript' ]
};

onInitialized フックに関数 "createUniqueCategoryNames" を使って、記事カテゴリー名のユニークな配列を生成し、ループ処理で各カテゴリーごとの記事データ 配列Objを一時的ファイルとして書き出す処理を追加

// docs/.vuepress/config.ts
// ...
// 別ファイル 関数インポート
import { createPageObj, createFixedExtractArticles, createUniqueCategoryNames } from './func/methods'

export default defineUserConfig({
  // ...

  // onInitialized フック VuePressアプリが初期化された時点で呼び出される https://vuepress.github.io/reference/plugin-api.html#lifecycle-hooks
  onInitialized: (app) => {
    // ....
    // 各記事データObjの frontmatter.lastUpdatedAt を 文字列(exp '2022-01-01') に変更した配列を生成
    const extractArticlesData: ArticleData[] = createFixedExtractArticles(extractArticles);

    // 👉 カテゴリーページ用に 各カテゴリ別 記事Objの配列を .vuepress/.cache/.temp フォルダに 一時的ファイル "category-{カテゴリー名}.js" として書き出し
    // 記事カテゴリー名のユニークな配列
    const uniqueCategoryNames = createUniqueCategoryNames(extractArticlesData);
    // 各カテゴリー ごとにループ
    uniqueCategoryNames.forEach(categoryName => {
      // カテゴリーが一致する記事データの配列
      const filteredCategoryPost = extractArticlesData.filter(obj => obj.category === categoryName);
      // app.writeTemp() で 一時的ファイル "category-{カテゴリー名}.js" を書き出し
      app.writeTemp(`category-${categoryName}.js`, `export const categoryPosts = ${JSON.stringify(filteredCategoryPost)}`)
    });
  },

})



























書き出された 一時的ファイル "category-{カテゴリー名}.js" の中身 サンプル

export const categoryPosts = [
 {
    key: "v-xxkm06b0",
    path: "/articles/vuePress/setting-up.html",
    category: "vuePress",
    frontmatter: {
      title: "VuePress セットアップ ~ テーマ & マークダウン 設定",
      description: "VuePress の基本設定(カスタマイズ)",
      lastUpdatedAt: "2022-02-10T00:00:00.000Z",
      image: "abc.svg",
    },
    links: [],
    slug: "setting-up",
  },
  // {...}
  // ...
];

カテゴリーページ docs/articles/{カテゴリー}/README.md を追加

カテゴリーページ docs/articles/{カテゴリー}/README.md ファイルを作成し、.mdファイル内の script で、一時的ファイルから該当カテゴリーの記事データObjの配列をインポート

<!-- docs/articles/vuePress/README.md -->
## カテゴリー "vuePress" の記事一覧

<ul>
  <li v-for="pageData in categoryPosts">
    <RouterLink :to="pageData.path">{{ pageData.frontmatter.title }}</RouterLink>
    更新: {{ pageData.frontmatter.lastUpdatedAt.split('T')[0] }}
  </li>
</ul>


<script setup lang="ts">
// 一時的ファイル docs/.vuepress/.temp/category-vuePress.js から記事データObjの配列をインポート
import { categoryPosts } from '@temp/category-vuePress'
</script>
表示例

カードコンポーネントを作成し、カテゴリー記事一覧をカードで表示

リスト形式のテキストリンクでも特に問題ないが、せっかくなので Windi CSS (Tailwind)を利用したカードコンポーネント "CategoryPostsCard.vue" を作成し、カテゴリーページ '/articles/{カテゴリー名}/README.md' で記事一覧リンクをカードで表示するように設定してみる

Windi CSS (Tailwind)を利用したカードコンポーネント "CategoryPostsCard.vue" を作成

props として受け取ったカテゴリー記事データの配列Obj "categoryPosts" から記事の数だけループ処理でカードテキストリンクを表示するコンポーネント

<script setup> 構文のpropsをTypeScriptで定義open in new window

// docs/.vuepress/components/CategoryPostsCard.vue
// カテゴリーページ '/articles/{カテゴリー名}/README.md' でカテゴリー記事一覧をカードで表示するコンポーネント
<script setup lang="ts">
import 'virtual:windi.css'
import { ArticleData } from '../type' // 型エイリアス (type alias)

// https://zenn.dev/azukiazusa/articles/676d88675e4e74#props-%E3%81%A8-emit
interface Props {
  categoryPosts: ArticleData[];
}

const props = defineProps<Props>();
// script 内で propsで受け取った値 categoryPosts にアクセスするには props.categoryPosts とする必要あり
// console.log("🚀 ~ file: CategoryPostsCard.vue ~ line 21 ~ props.categoryPosts", props.categoryPosts);
</script>


<template>
  <div v-if="props.categoryPosts" class="py-3">
    <div v-for="(postObj, index) in props.categoryPosts" :key="index"
     class=" bg-gray-50 hover:bg-gray-100 dark:(bg-gray-800 hover:bg-gray-700) py-1 mx-auto my-2 rounded"
    >
      <div class="flex items-center mx-1">
        <!-- 更新日 -->
        <div class=" mx-1 w-1/7 min-w-60px rounded-2xl sm:mx-2">
          <div class="px-2 text-xs font-semibold tracking-wide text-center ">
            <span class=""> {{ postObj.frontmatter.lastUpdatedAt.split('T')[0] }} </span>
          </div>
        </div>
        <!-- 記事タイトル -->
        <div class="my-1 text-base font-extrabold leading-snug sm:(text-lg my-2)">
          <!-- VuePress で Windi CSS (Tailwind) を利用できるように設定 -->
          <RouterLink :to="postObj.path">
            {{ postObj.frontmatter.title }}
          </RouterLink>
        </div>
      </div>
    </div>
  </div>
</template>

props で カテゴリー記事データの配列を渡してカードコンポーネントで表示

  • カテゴリーページ '/articles/{カテゴリー名}/README.md'ファイルの script で、一時的ファイルから該当するカテゴリーの記事データObjの配列をインポート
  • カードコンポーネント "CategoryPostsCard" に props "categoryPosts" で渡す
<!-- docs/articles/vuePress/README.md -->
## カテゴリー "vuePress" の記事一覧

<CategoryPostsCard :categoryPosts="categoryPosts" />


<script setup lang="ts">
// 一時的ファイル docs/.vuepress/.temp/category-vuePress.js から記事データObjの配列をインポート
import { categoryPosts } from '@temp/category-vuePress'
</script>
表示例

My Custom Footer

Join 31,000+ other and never miss out

About

Company

Blog

Tec

Contact

example@email.com

© Brand 2020 - All rights reserved