<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>前端 on life's logs</title><link>https://blog.butubb.cn/tags/%E5%89%8D%E7%AB%AF/</link><description>Recent content in 前端 on life's logs</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sat, 28 Mar 2026 16:26:31 +0800</lastBuildDate><atom:link href="https://blog.butubb.cn/tags/%E5%89%8D%E7%AB%AF/index.xml" rel="self" type="application/rss+xml"/><item><title>给 Hugo 博客归档页加上 Github 风格热力图</title><link>https://blog.butubb.cn/posts/%E7%BB%99hugo%E5%8D%9A%E5%AE%A2%E5%8A%A0%E4%B8%8Agithub%E9%A3%8E%E6%A0%BC%E7%83%AD%E5%8A%9B%E5%9B%BE/</link><pubDate>Sat, 28 Mar 2026 16:26:31 +0800</pubDate><guid>https://blog.butubb.cn/posts/%E7%BB%99hugo%E5%8D%9A%E5%AE%A2%E5%8A%A0%E4%B8%8Agithub%E9%A3%8E%E6%A0%BC%E7%83%AD%E5%8A%9B%E5%9B%BE/</guid><description>&lt;p&gt;最近看着博客的归档页面，总觉得光秃秃的列表差点意思。平时经常看 Github 主页那块绿色的代码提交热力图（Heatmap），看着自己的“绿格子”一天天变多，那种正反馈确实挺让人上瘾的。&lt;/p&gt;
&lt;p&gt;于是就萌生了一个想法：&lt;strong&gt;能不能在我的博客归档页也加一个类似 Github 风格的文章更新热力图？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;折腾了一番后，完美搞定。这篇文章记录一下具体的实现过程。&lt;/p&gt;
&lt;h2 id="需求分析"&gt;需求分析&lt;/h2&gt;
&lt;p&gt;在动手之前，我给自己定了几个硬性要求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;零依赖，不拖慢速度&lt;/strong&gt;：网上很多教程教的是用 ECharts 之类的图表库。虽然效果好，但为了一个小图引入这么大的库，对静态博客的加载速度很不友好。我要用纯原生 JS 和 CSS 来画。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主题适配&lt;/strong&gt;：我的博客用的是 PaperMod 主题，支持暗黑模式切换。这个热力图必须能无缝跟着主题切换颜色。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;响应式布局，拒绝丑陋的滚动条&lt;/strong&gt;：手机端和电脑端屏幕宽度不一样。我不希望在手机上出现一个很长很长的横向滚动条。它必须能根据当前窗口的宽度，自动计算并显示能够放得下的“周数”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;边缘防遮挡的悬浮提示&lt;/strong&gt;：鼠标放上去要能显示当天的文章信息，而且如果是最右侧（今天）或者最顶部的数据，提示框不能被屏幕边缘截断。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="动手实现"&gt;动手实现&lt;/h2&gt;
&lt;p&gt;Hugo 的修改逻辑很简单，不要去动 &lt;code&gt;themes/&lt;/code&gt; 目录下的源码，而是利用它的覆盖机制。&lt;/p&gt;
&lt;p&gt;把 &lt;code&gt;themes/PaperMod/layouts/_default/archives.html&lt;/code&gt; 复制到项目根目录的 &lt;code&gt;layouts/_default/archives.html&lt;/code&gt;。接下来所有的修改都在这个本地文件里进行。&lt;/p&gt;
&lt;h3 id="1-数据获取"&gt;1. 数据获取&lt;/h3&gt;
&lt;p&gt;第一步是把博客里所有文章的日期拿出来。这一步利用 Hugo 强大的模板语法，在 HTML 里直接把数据渲染成 JS 的数组：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;postsData&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {{&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;range&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;where&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;site&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;RegularPages&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Type&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;in&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;site&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Params&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;mainSections&lt;/span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;{{ .Date.Format &amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2006&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;01&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;02&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; }}&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;{{ .Title | htmlEscape }}&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {{&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;end&lt;/span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 按日期归类统计
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;postMap&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Map&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;postsData&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;forEach&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;postMap&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;has&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;)) &lt;span style="color:#a6e22e"&gt;postMap&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;, []);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;postMap&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这段代码会在编译时把所有文章遍历一遍，最终生成一个干净的 JSON 数据交给浏览器的 JS 处理。&lt;/p&gt;</description></item></channel></rss>