Skip to content

归档页贡献图

什么是归档页贡献图?您可以在导航栏 功能页 -> 归档页 点击查看。

安装 Echarts 依赖

首先需要安装 Echarts 依赖,根据您项目的包管理器选择安装方式:

sh
pnpm add -D echarts
sh
yarn add -D echarts
sh
npm add -D echarts

创建贡献图组件

.vitepress/theme/components 目录下创建 ContributeChart.vue 文件,并添加以下代码:

vue
<script setup lang="ts" name="ContributeChart">
import * as echarts from "echarts";
import { ref, watch, nextTick, computed, useTemplateRef } from "vue";
import { useData } from "vitepress";
import { formatDate, usePosts } from "vitepress-theme-teek";

const { isDark } = useData();
const posts = usePosts();

// 今天
const today = formatDate(new Date(), "yyyy-MM-dd");
// 获取前一年的时间
const beforeOnYear = formatDate(new Date(new Date().getTime() - 365 * 24 * 60 * 60 * 1000), "yyyy-MM-dd");

// 贡献图数据
const contributeList = computed(() => {
  const contributeObject = ref({});

  posts.value.sortPostsByDate.forEach(item => {
    if (!item.date) return;

    const date = item.date.substring(0, 10);
    if (contributeObject.value[date]) contributeObject.value[date]++;
    else contributeObject.value[date] = 1;
  });

  const contributeDays = Object.keys(contributeObject.value);

  return contributeDays.map((item: string) => [item, contributeObject.value[item]]).reverse();
});

const chartRef = useTemplateRef("chartRef");
const contributeChart = ref();

// Echarts 配置项
const option = {
  tooltip: {
    formatter: function (params) {
      return `${params.value[0]} <br/> ${params.value[1]} 篇文章`;
    },
  },
  visualMap: {
    show: false,
    min: 0,
    max: 5,
    inRange: {
      color: ["#ebedf0", "#c6e48b", "#7bc96f", "#239a3b", "#196127", "#196127"],
    },
  },
  calendar: {
    left: "center",
    itemStyle: {
      color: "#ebedf0",
      borderWidth: 5,
      borderColor: "#fff",
      shadowBlur: 0,
    },
    cellSize: [20, 20],
    range: [beforeOnYear, today],
    splitLine: true,
    dayLabel: {
      firstDay: 7,
      nameMap: "ZH",
      color: "#3c3c43",
    },
    monthLabel: {
      color: "#3c3c43",
    },
    yearLabel: {
      show: true,
      position: "right",
    },
    silent: {
      show: false,
    },
  },
  series: {
    type: "heatmap",
    coordinateSystem: "calendar",
    data: [],
  },
};

// 渲染贡献图
const renderChart = (data: any) => {
  option.calendar.itemStyle.borderColor = isDark.value ? "#1b1b1f" : "#fff";
  option.calendar.itemStyle.color = isDark.value ? "#787878" : "#ebedf0";

  if (contributeChart.value) echarts.dispose(contributeChart.value);
  if (chartRef.value) contributeChart.value = echarts.init(chartRef.value);

  option.series.data = data;
  contributeChart.value?.setOption(option);
};

watch(
  contributeList,
  async newValue => {
    await nextTick();
    renderChart(newValue);
  },
  { immediate: true }
);

watch(isDark, () => {
  renderChart(contributeList.value);
});
</script>

<template>
  <div class="contribute__chart">
    <div class="chart__box" ref="chartRef"></div>
  </div>
</template>

<style>
.tk-article-page.tk-archives {
  width: 1220px;
}

.tk-archives .contribute__chart {
  width: 100%;
  height: 260px;
}

.tk-archives .contribute__chart .chart__box {
  margin: auto;
  width: 100%;
  height: 100%;
}
</style>

组件默认时间是近两年,且颜色已在代码里体现,您可以自行修改为你喜欢的风格。

使用贡献图组件

.vitepress/theme/index.ts 中通过 Teek 提供的归档页顶部插槽插入贡献图组件。

ts
import Teek from "vitepress-theme-teek";
import ContributeChart from "./components/ContributeChart.vue";
import { h } from "vue";

export default {
  extends: Teek,
  Layout: () =>
    h(Teek.Layout, null, {
      "teek-archives-top-before": () => h(ContributeChart),
    }),
};