[🛠] 给 GitHub Pages 博客 sidebar 接上日历和活动统计
✨ GPT-5.5 的摘要
博客重启后,我在 sidebar 加上文章日历和分类活动统计,并做出以当前文章为基准的月份显示和月度归档探索。
整理完 /devlog/github-pages-blog/github-pages-blog-restart-system/ 之后,马上看到了下一个问题。
文章又开始写了。可是博客重新活过来的感觉还不够。只靠分类列表,很难看出这个博客什么时候动过、哪一天留下了记录、最近有什么流向。
要重新写 Daily Review,日期感很重要。
这个博客的中心,终究是“哪一天留下了什么”。可是 GitHub Pages 博客不像 Naver Blog 那样,自然就有可见的日期探索。因为是静态博客,更需要自己做出来。
所以今天晚上接上的功能,不只是简单装饰。
这是把 sidebar 从文章列表的辅助装饰,改造成展示日期和活动流向的探索工具。
最先接上的是小而直接的日历
第一个提交是 f6971fc。
f6971fc feat: add sidebar activity widgets
那时新建的文件有两个。
_includes/sidebar-calendar.html
_includes/sidebar-nav-stats.html
我在 sidebar.html 里接上了日历 include。
<section class="sidebar-calendar"
data-sidebar-calendar
data-calendar-lang="zh-Hans"
data-calendar-posts-src="/assets/data/calendar-posts-zh-Hans.json"
data-calendar-weekdays="["日","一","二","三","四","五","六"]"
data-calendar-label-suffix="文章日历"
data-calendar-post-count-label="篇"
data-calendar-post-list-label="文章"
data-initial-month="2026-05"
data-focus-date="2026-05-26"
data-current-path="/zh-Hans/devlog/github-pages-blog/github-pages-blog-sidebar-calendar/"
data-min-month="2024-12"
data-max-month="2026-06"
aria-label="2026.05 文章日历">
<div class="sidebar-calendar__archive" data-calendar-archive aria-label="按年和月份统计文章数">
<div class="sidebar-calendar__years" data-calendar-years></div>
<div class="sidebar-calendar__months" data-calendar-months></div>
</div>
<div class="sidebar-calendar__grid" data-calendar-grid>
<span class="sidebar-calendar__weekday">日</span>
<span class="sidebar-calendar__weekday">一</span>
<span class="sidebar-calendar__weekday">二</span>
<span class="sidebar-calendar__weekday">三</span>
<span class="sidebar-calendar__weekday">四</span>
<span class="sidebar-calendar__weekday">五</span>
<span class="sidebar-calendar__weekday">六</span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">1</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">2</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">3</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">4</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">5</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">6</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">7</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">8</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">9</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">10</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">11</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">12</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">13</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">14</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">15</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">16</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">17</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">18</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">19</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">20</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">21</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">22</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">23</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">24</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">25</span></span>
<span class="sidebar-calendar__day sidebar-calendar__day--focus"><span class="sidebar-calendar__day-number">26</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">27</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">28</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">29</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">30</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">31</span></span>
</div>
<section class="sidebar-calendar__post-list sidebar-calendar__post-list--dynamic" data-calendar-post-list aria-live="polite" hidden></section>
</section>
最初的日历没有 JavaScript,只用 Liquid 做出来。
从 site.posts 里排除隐藏文章,然后计算当前月份的第一天星期几和最后一天日期。连 2 月闰年计算也在 Liquid 里处理。
月份里有文章的日期会变成链接,没有文章的日期只保留数字。最初的基准是 site.time。也就是说,这个阶段的日历,是展示“当前月份文章状况”的 sidebar widget。
即使只做到这个程度,效果也马上出现了。
博客重新开始活动的感觉出来了。和只看文章标题列表不同,日历会显示记录的密度。哪几天文章集中,哪一天空着,今天在哪里,一眼就能看到。
也给分类接上活动信息
只接日历可以看到日期流向,但各分类的流向仍然很迟钝。
所以我也一起做了 sidebar-nav-stats.html。
这个 include 把 sidebar 项目的 URL 看作分类路径,再重新筛选属于该分类的文章。
比如 /daily-review 会显示 daily-review 分类的文章数,/diary/ai 则只留下同时包含 diary 和 ai 的文章。
输出很简单。
文章数 · 最近文章日期
我喜欢这一点,是因为 sidebar 从单纯目录里脱出来了。
可以看到 今天这一天 有几篇,人工智能 文章最近什么时候更新,GitHub Pages Blog 是否真的还在运营。一个博客是死着还是活着,比起文章数量,最近日期更能说明问题。
立刻先调整移动端密度
日历一接上,移动端密度马上成了问题。
sidebar 在桌面端还有余裕,但在移动端会下沉到正文下面,或者和菜单混在一起。如果日历格子太大,文章数标签又太长,一个 widget 就会吃掉太多屏幕。
所以我在 17d074d、b401d8b 里马上缩紧了 sidebar 活动标签和日历密度。
17d074d fix: tighten sidebar activity labels
b401d8b [Fix] | Sidebar calendar: Improve mobile density
SCSS 里把日期格子固定为 aspect-ratio: 1,并用了小字号和 4px radius。分类活动信息也做成在一行里小小显示。
这里重要的是不要让日历变成“主角”。
日历是帮助博客探索的装置。它不能比正文还大。尤其是记录型博客里,sidebar 要提供信息,但不能妨碍阅读文章。
改成以当前文章为基准的月份
很快,更重要的问题出现了。
如果日历以 site.time 为基准,那么读 2025 年的文章时,也会出现 2026 年 5 月的日历。这样日历就无法说明当前文章的语境。
所以我在 ccb58d5 里改了基准日期。
ccb58d5 [Fix] | Sidebar: Refine calendar behavior
核心是这一段。
如果页面有 date,就显示那一天所属的月份。没有日期的页面则照旧使用 site.time。
这个修改改变了日历的性质。
最初的日历是“这个月的博客状况”。现在它变成了“当前正在阅读的文章所在的时间”。读过去的 Daily Review 时,可以看到那个月的记录流向,也能继续找到同一个月里还有哪些文章。
这对以日期为中心的记录博客更合适。
同一天多篇文章时展开成列表
同一个提交里,我也接上了按日期分组的文章列表。
如果一天只有一篇文章,日期直接链接到那篇文章就可以。但如果一天有多篇文章,就会出现问题。只看重启第一天,也有 Daily Review 和 AI 对话归档在同一天。
所以文章数量超过一篇的日期,不再直接跳到某篇文章,而是移动到那一天的文章列表。
<section id="sidebar-calendar-2026-05-25-posts" class="sidebar-calendar__post-list">
<h4 class="sidebar-calendar__post-list-title">5月25日文章</h4>
<ul>
...
</ul>
</section>
这个阶段的规则很简单。
1 篇文章:跳到该文章
2 篇以上:跳到那一天的文章列表
这并不是完美规则,而是先解决当前同一天多篇文章问题的方法。但重要的是没有把问题藏起来。
一个日期上可能有多篇文章,系统必须承认这一点。如果 Daily Review、AI 对话、开发记录会在同一天出现,这个处理就是必要的。
也接上了 JavaScript enhancement
只靠 Liquid 日历,可以做到以当前月份为中心的探索,但跨月份探索不方便。
所以我在 b06b6d6 里接上了 JavaScript。
b06b6d6 [Feat] | Sidebar calendar: Add archive navigation
新文件是这个。
assets/js/custom/sidebar-calendar.js
并且注册到 _config.yml 的 after_footer_scripts。
after_footer_scripts:
- /assets/js/custom/dark-theme.js
- /assets/js/custom/sidebar-calendar.js
Liquid 侧把文章数据作为 JSON 传给页面。
<script type="application/json" data-calendar-posts>
[
{
"title": "...",
"url": "...",
"date": "2026-05-25"
}
]
</script>
JavaScript 读取这份数据,生成 postsByDate、postCountByMonth、postCountByYear、latestPostMonthByYear。然后渲染上一个月/下一个月按钮、month input、按年/月显示文章数的按钮,以及按日期动态出现的文章列表。
这个结构不错,是因为没有丢掉 fallback。
有 JavaScript 时,月份移动和归档探索会变方便。没有 JavaScript 时,Liquid 也已经渲染了当前文章基准月份和同一天多篇文章的 fallback 列表。
在静态博客里,这个平衡很重要。
今天改变了什么
今天夜里到凌晨的流程是这样的。
f6971fc 添加 sidebar 日历和分类活动统计
17d074d 调整 sidebar 活动标签密度
b401d8b 调整移动端日历密度
ccb58d5 处理当前文章基准月份和同一天多篇文章列表
b06b6d6 添加用于月度归档探索的 JavaScript enhancement
核心文件是这些。
_includes/sidebar.html
_includes/sidebar-calendar.html
_includes/sidebar-nav-stats.html
assets/js/custom/sidebar-calendar.js
_sass/custom/customOverride.scss
_config.yml
一句话概括就是这样。
给博客的 sidebar 接上展示日期和分类活动流向的探索层。
结果
现在博客 sidebar 不再只是简单的分类列表。
它会显示当前文章所在的月份,标出有文章的日期,同一天有多篇文章时展开成列表。分类项目也带着文章数和最近文章日期。JavaScript 开启时,还可以在年份和月份之间来回查看博客归档。
从作品集角度看,这次工作的重点在于不用服务器也提高了可探索性。
没有单独 DB,也没有 API。只用 Jekyll 的 site.posts、Liquid、SCSS 和一小段 JavaScript,就补上了静态博客的弱点。记录拥有日期。把日期显示在 UI 上之后,博客就不再只是文章堆,而像一个按时间移动的系统。
今天接上的日历,就是这个开始。
留下评论