Skip to main content
Nordlys logo, a drawing of two gray mountains with green northern lights in the background 陈迪の自留地

Back to all posts

博客增码字热力图

Published on by Chen Di · 3 min read

在 components 目录下新增 Heatmap.astro 组件

---
import { format, eachDayOfInterval, startOfYear, endOfYear } from 'date-fns';
import { getColorScale } from '../utils/colorscale';
import wordCountData from '../data/word-counts.json'

// 格式化数据为字典
const wordCountMap = new Map(wordCountData.map(({ date, charCount }) => [date, charCount]));
// 计算所有日期的字数总和
const getTotalWordCount = wordCountData.reduce((total, { charCount }) => {
  return total + charCount; // 累加每个日期的字数
}, 0);

console.log(getTotalWordCount)
const today = new Date();
const startDate = startOfYear(today);
const endDate = endOfYear(today);
const days = eachDayOfInterval({ start: startDate, end: endDate });


---

<div class="bg-white dark:bg-zinc-900 dark:text-zinc-200 p-4 rounded-lg shadow-md">
  <h3 class="text-center mb-2">码字热力图</h3>
  <div class="relative">
    <div class="grid grid-cols-52 gap-[6px] h-[100px]">
      {days.map(day => {
        const date = format(day, 'yyyy-MM-dd');
        const wordCount = wordCountMap.get(date) || 0;
        const bgColor = getColorScale(wordCount);
                      
        return (
          <div
            class="w-[6px] h-[6px] rounded-[1px] tooltip"
            style={`background-color: ${bgColor};`}
            data-tip={`${format(day, 'yyyy-MM-dd')}: ${wordCount} 字符`}
          />
        );
      })}
    </div>
  </div>
  <div class="flex items-center justify-end gap-2 mt-2 text-xs text-gray-600">
    <span>总字符:{getTotalWordCount}</span>
  </div>
</div>



<style>
  .grid-cols-52 {
    grid-template-columns: repeat(52, minmax(0, 1fr));
  }
  
  .tooltip {
    position: relative;
  }
  
  .tooltip:hover::after {
    content: attr(data-tip);
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    padding: 2px 4px;
    background-color: #333;
    color: white;
    border-radius: 2px;
    font-size: 10px;
    white-space: nowrap;
    z-index: 10;
  }
</style>

在 utils 目录下新增 `colorscale.ts

export function getColorScale(count: number): string {
  if (count === 0) return '#ebedf0';
  if (count < 600) return '#A5D6A7';
  if (count < 900) return '#66BB6A';
  if (count < 1200) return '#43A047';
  if (count < 1500) return '#2E7D32';
  return '#1B5E20';
}

在 types 目录下新增 Article.ts

Article.ts

定义类型

export interface Article {
    id: string;
    title: string;
    content: string;
    date: Date;
    wordCount: number;
  }

在 index.astro 文件中引用

---
import { SITE_DESCRIPTION, SITE_TITLE } from "../consts";
import Heatmap from '../components/Heatmap.astro';
import Layout from "../layouts/Layout.astro";
---

<Layout
  title={SITE_TITLE}
  description={SITE_DESCRIPTION}
  className="flex h-svh  flex-col justify-center"
>
  <main class="space-y-4">
    <p>
      偶尔想到的一些内容会做记录,题材不限于技术文章,更多的是一些个人的只言片语。博主平时喜欢运动,以糊代码为乐趣,偶尔也靠读些哲学书籍来打发无聊。
    </p>
    <Heatmap />

  </main>
</Layout>

注意组件之间的相互引用关系