diff --git a/_config.yml b/_config.yml index b00aafda1139..93dbc64e1466 100644 --- a/_config.yml +++ b/_config.yml @@ -23,7 +23,6 @@ source_dir: source public_dir: public tag_dir: tags archive_dir: articles -category_dir: categories author_dir: authors techcast_dir: techcasts code_dir: downloads/code @@ -35,10 +34,6 @@ author_generator: per_page: 25 url_map: -category_generator: - per_page: 25 - order_by: -date - tag_generator: per_page: 25 order_by: -date diff --git a/scripts/category_chart_helpers.js b/scripts/category_chart_helpers.js new file mode 100644 index 000000000000..e48894a82dd8 --- /dev/null +++ b/scripts/category_chart_helpers.js @@ -0,0 +1,79 @@ +'use strict'; + +/** + * サイトの全投稿を集計し、時間軸ごとのカテゴリ別投稿データを生成する + * - 2018年以前は年ごと、2019年以降は四半期ごと + * @returns {object} { quarters: string[], series: object[], categories: string[] } + */ +function getQuarterlyCategoryData() { + const posts = this.site.posts.sort('date', 1); // 日付順にソート + if (!posts.length) { + return { quarters: [], series: [], categories: [] }; + } + + const dataByTimeBucket = new Map(); + + // 1. 全投稿をループして、時間軸ごとにカテゴリ別投稿数を集計 + posts.forEach(post => { + const year = post.date.year(); + let timeKey; + + if (year >= 2019) { + // 2019年以降は四半期ごと + const quarter = Math.floor(post.date.month() / 3) + 1; + timeKey = `${year}-Q${quarter}`; + } else { + // 2018年以前は年ごと + timeKey = year.toString(); + } + + if (!dataByTimeBucket.has(timeKey)) { + dataByTimeBucket.set(timeKey, new Map()); + } + + const bucketData = dataByTimeBucket.get(timeKey); + const postCategories = post.categories.map(cat => cat.name); + if (!postCategories.length) return; + + postCategories.forEach(catName => { + const currentCount = bucketData.get(catName) || 0; + bucketData.set(catName, currentCount + 1); + }); + }); + + // 2. サイトの全カテゴリを取得し、「合計記事数」で降順にソートする + const sortedCategoryObjects = this.site.categories.toArray().sort((a, b) => b.length - a.length); + const sortedCategoryNames = sortedCategoryObjects.map(cat => cat.name); + + // 3. X軸のラベル(時間軸)を生成し、ソートする + const sortedTimeKeys = Array.from(dataByTimeBucket.keys()).sort(); + + // 4. EChartsのseries形式にデータを整形 + const series = sortedCategoryObjects.map(category => { + const catName = category.name; + const data = sortedTimeKeys.map(timeKey => { + const bucketData = dataByTimeBucket.get(timeKey); + return bucketData.get(catName) || 0; // その期間に投稿がなければ0 + }); + + return { + name: catName, + type: 'line', + stack: 'Total', + areaStyle: {}, + emphasis: { + focus: 'series' + }, + data: data + }; + }); + + return { + quarters: sortedTimeKeys, // キー名はEJS側と合わせるため'quarters'のまま + series: series, + categories: sortedCategoryNames + }; +} + +// ヘルパーとして登録 +hexo.extend.helper.register('get_quarterly_category_data', getQuarterlyCategoryData); diff --git a/source/categories/index.md b/source/categories/index.md new file mode 100644 index 000000000000..ee8639b87892 --- /dev/null +++ b/source/categories/index.md @@ -0,0 +1,4 @@ +--- +title: カテゴリ一覧 +layout: categories +--- diff --git a/themes/future/layout/categories.ejs b/themes/future/layout/categories.ejs index f5dcc9504053..ba04e30bde9b 100644 --- a/themes/future/layout/categories.ejs +++ b/themes/future/layout/categories.ejs @@ -3,12 +3,50 @@
  • Home
  • Categories
  • +
    -

    カテゴリから記事を探す

    - - <%- list_categories() %> + +
    +

    カテゴリ別 投稿数の推移(四半期ごと)

    +
    +
    + + + + + +
    +
    +

    カテゴリから記事を探す

    +
    + +
    - diff --git a/themes/future/layout/category.ejs b/themes/future/layout/category.ejs index ea6e9ea29456..4c0b5a4e8815 100644 --- a/themes/future/layout/category.ejs +++ b/themes/future/layout/category.ejs @@ -2,10 +2,10 @@