
HY
折腾进行时
Hello, I'm HY.
这里记录这个博客从上线、写作到页面迭代的每一个重要节点,每一次都按真实改动整理,展开即可查看完整变更说明。
版本规则:Major 代表结构级升级 · Minor 代表新功能 · Patch 代表修复、内容与维护
音乐播放器是自建服务,书签导航里有、顶栏右上角也有个图标按钮,但从「关于」这一排站内服务入口反而点不进去。现在按既有外链项的样子补上,位置跟书签导航里那条对齐(排在「免费图床」前面),外链箭头、新标签页都由 external 标记自动带上。顺手把「本站评论系统」这个啰嗦的名字砍成「本站评论」—— 同一排里就它多带两个字,看着不齐。
「关于」下拉新增「音乐播放器」→ music.9ll.uk 外链(图标沿用书签导航里同款的 material-symbols:music-note-rounded)。位置在「本站评论」之后、「免费图床」之前,与 booknavConfig 里那条的排序一致
「本站评论系统」改名为「本站评论」。改动只有 src/config/navBarConfig.ts 两处,没碰主题文件
V1.36 把开往入口放进顶栏时故意只留文字:那时这一排正好卡在临界点上,多一个图标就可能把标签压成竖排。现在情况变了 —— 拥挤的真正来源是「1280px 起主题恢复导航项图标 + 同一档搜索框展宽」,而 1024–1599px 已经改走紧凑模式、在该区间统一隐藏顶级项图标,加不加图标对这档宽度毫无影响。图标只在 ≥1600px 真的占位,那里余量足够。于是补上:用 material-symbols 的列车造型(train-rounded),呼应页脚开往徽标里的车头,也和其余顶级项同属一个图标集。实测 1024–1599px 余量与加图标前一字不差(1024px +40px、1280px +194px),≥1600px 为 1600px +90px、1760px 以上 +218px,全程无换行、无溢出。
顶栏「开往」补上 material-symbols:train-rounded 图标(列车正面造型,呼应页脚开往徽标的车头造型)。改动只有 src/config/navBarConfig.ts 里的一个 icon 字段,没碰主题文件
测量口径沿用 V1.36:用 Range.getClientRects() 数标签占几行(按钮定高 h-10,量高度看不出换行),余量则先强制 flex:0 0 auto + nowrap 再量内容自然宽度和(.workbuddy/scratch/nav-natural.cjs),且每个宽度都重新加载页面再测
加之前的余量复核:1024–1599px 零影响 —— 页脚注入的紧凑模式那段选择器命中所有 .dropdown-container 直接子项,开往同样被隐藏,实测余量仍是 1024px +40px、1280px +194px,与 V1.36 记录的数字完全一致;只有 ≥1600px 主题原样时才多出这个图标(1600px 余量 +90px,1760px 以上 +218px),全部宽度无换行
V1.37 给全站挂了「最近评论」,本意是把访客互动摆到台面上。跑了两天发现文章页不太合适:右栏本来就要放「文章目录」,再塞一个 8 条的评论列表(实测高约 694px)把整列撑得很长;更麻烦的是目录是吸顶的,两块会抢同一片空间,往下滑时评论会直接压到目录上。中途试过几种排法(把目录夹在动态和评论之间、干脆取消吸顶),结论是右栏那点高度装不下三者,怎么排都得牺牲点什么。最后一刀切:组件只在博客首页显示,文章页彻底不出现。首页没有目录、右栏本来就空,评论列表放进去正好。
「最近评论」只在博客首页显示(/ 与 /2/ /3/ 这类分页),文章页等其余页面保持 hidden、不占布局:recent-comments.js 新增 isHomePage() 门禁,非首页 findMountPoint() 直接返回 null,剩余页面上挂载点保持原来的「右栏「最新动态」之后 / 移动端底部组件栏」。首页判定按 Astro 分页的实际路径 /<页码>/ 写(见 src/pages/[...page].astro 的 paginate),不是 /page/<页码>/,别照惯例猜
本次只动 public/assets/js/recent-comments.js 与 src/config/FooterConfig.html(脚本引用 ?v=2 升到 ?v=5)。改那个 js 必须加 ?v= —— /assets/* 有 30 天强缓存,不加版本号老访客拿到的还是旧脚本。中途试过的「调整右栏顺序 / 取消吸顶」已全部回退,sidebarConfig.ts 还原为原样、未留下改动
留言板的互动原本全藏在各页面评论区里,有人留了言,除了当场那一下别处再也看不到。参考站在右栏挂了「最近评论」,于是给全站都加了一个:数据就在自己的 Waline 后端里,直接调它的公开最近评论接口(CORS 已放开),头像、昵称、相对时间、「评论于 /路径」、两行摘要一应俱全,底部标注「已展示 N 条公开评论 · 内容来自 Waline」。落法还是页脚注入那一套 —— 页面和侧栏的 SideBar.astro 都是上游文件改不得,所以外壳 DOM 与样式追加在 FooterConfig.html,脚本由页脚的 PAGE_SCRIPTS 全站加载:桌面把组件搬进右栏「最新动态」之后,<768px 搬进移动端底部组件栏(#bottom-sidebar),跨断点自动换挂载点;两类容器都在 swup 替换范围外,搬一次永久有效,切页不丢。样式全部自带(主题 CSS 变量 + card-base,几何复刻 WidgetLayout),不碰 Tailwind 工具类,亮/暗主题与 1280px 窄栏都验过。
全站右栏「最新动态」下方新增「最近评论」(移动端在底部组件栏):拉 Waline 最近 8 条公开评论,每条含头像(接口没给头像时用昵称首字 + 哈希色相的文字头像垫底,图片加载失败自动露出文字)、昵称、相对时间、「评论于 /路径」和两行摘要;标题右侧「去留言板」直达留言板,窄栏放不下时优先截断路径、保昵称完整
三个坑留档:① Waline 的 orig 字段是渲染前的 HTML(含 wl-badge 之类标签),不能直接当摘要文本,要用渲染后的 comment 过 DOM 取 textContent;② 条目文字容器类名和内容外包装撞名(都叫 ff-rc-body),外包装的 padding: 1rem 把每条评论多吃 32px,meta 行被挤到 162px;③ 窄栏 flex 布局里文字容器没有 flex-grow 时宽度按 max-content 算(长 URL 把行撑爆),补 flex: 1 1 auto + min-width: 0 后才稳定。另:改完 FooterConfig.html 先用 new Function 校验全部内联脚本 —— 一次编辑把缩排弄坏,整个 PAGE_SCRIPTS IIFE 语法错误静默失效,脚本压根没加载
注入方式:组件外壳与全部样式追加在 src/config/FooterConfig.html,recent-comments.js 由页脚 PAGE_SCRIPTS 全站加载(path: /.*/ ),桌面挂 #right-sidebar 的 top 容器「最新动态」之后、移动端挂 #bottom-sidebar,两类容器都在 swup 替换范围外,搬一次永久有效。以后改那个 js 记得把 ?v= 往上加(/assets/* 有 30 天强缓存)
开往要求把 https://www.travellings.cn/go.html 放在「打开网站就能看到的地方」,于是顶栏加了一个顶级入口、页脚加了一枚徽标。加之前先量了一遍顶栏,发现这一排本来就在临界点上:它是三列网格中间的居中菜单,每项是 px-4 的按钮、里面放图标加名字,而名字是匿名 flex 文本项,只要差 1px 就会逐字各占一行,「主页 / 朋友圈 / 站点统计」全被压成竖排,还因为按钮是固定 h-10 而糊到导航栏外面。真正的压力来自两处正好撞在一起 —— 主题在 1280px 以下隐藏导航图标(navbar.css 里的 .navbar-icon),于是 1280px 起每项突然多出约 30px 需求;而同一档宽度上右侧搜索框还从图标态展宽成输入框,中间那列可用宽度反而从 828px 掉到 758px。实测线上(8 项、主题原样)就已经中招:1024px 差 4px、1280–1366px 差 8–87px;本站导航有 9 项,区间还要再宽一档。所以 1024–1599px 改走紧凑模式:继续隐藏导航项图标(沿用主题小屏的做法)、左右内边距从 16px 收到 8px,1600px 以上保持主题原样。改动全部落在配置与素材上,没有动主题组件。
顶栏新增「开往」顶级入口(外链、新标签打开)。按官方建议本可以配一个地铁图标,但那会让本来就吃紧的顶栏更挤,所以最终只留文字;页脚与移动端抽屉里都还有入口,访客总能点到
修掉顶栏标签在 1024–1599px 被压成竖排的老问题。根因是「1280px 起导航图标出现、同一档搜索框展宽」,两头一挤就溢出;现在该区间隐藏导航项图标(下拉面板里的条目图标保留)并把项目内边距从 16px 收到 8px,实测最小余量 +40px(1024px 处),1600px 以上恢复原样(余量 +119px 起)
页脚在萌 ICP 备案号下方加开往徽标:黑白两版都下到 /assets/images/ 自托管,跟着 html.dark 切换,不依赖对方站点的可用性,也不因图床抽风而空白
核对手法留档:用 Range.getClientRects() 数每个标签占几行(按钮高度固定 h-10,量高度看不出换行);量余量必须「每个宽度重新加载页面」再测 —— 同一页面内改视口会拿到错乱布局,据此得出的结论是反的,这一轮就踩过一次
给站点推了改动,等了十几分钟线上还是旧页面。翻构建日志才发现部署根本没成功:渲染 /dynamic/rss.xml 时报 TypeError: html.replace is not a function,紧接着一条未捕获的 fetch failed 又把 Node 进程带走。链路是这样的 —— Memos 实例(dynamicConfig.memos.apiUrl)解析到的是国内 IP,Vercel 与 Cloudflare 的构建机都在海外,直连必然 ConnectTimeout;接口拿不到数据就落到「回退本地内容集合」那条分支,而那条分支里 createMarkdownProcessor().render() 漏了 await、也没取返回值里的 .code,html 拿到的是个 Promise 对象,再往下当字符串去 replace 就当场抛错。上游 Memos 适配器里还有一句 promise.finally(),它派生出的 promise 没人接管,fetch 一失败就变成未处理的 Promise 拒绝,在 Node 24 下直接把构建进程干掉 —— 这层调用方的 try/catch 是拦不住的。现在改成先花几秒探一次接口可达性,不通就根本不发请求、直接走本地内容;同时对这类网络拒绝挂一层极窄的兜底,只吞超时与连接失败,别的错误照旧抛出。
修掉站长动态 RSS 回退分支里处理器未 await 的问题:processor.render() 是异步的、返回 { code, metadata },之前直接把 Promise 当成 HTML 字符串往下传,走到剥标签那步就 TypeError: html.replace is not a function —— 这次线上构建失败的直接原因
对 Memos 请求失败产生的未处理 Promise 拒绝加了窄范围兜底:只忽略 fetch 超时、连接被重置这一类网络错误并打印告警,其它拒绝照旧抛出,不再让一次接口抖动带走整次构建
构建期先做一次带 4 秒超时的接口可达性探测,连不上就完全不调用 Memos 适配器,直接回退本地内容集合;顺便关掉一整类「接口抽风就炸构建」的可能
顺手清掉该文件里一个未被使用的类型导入;已用真实调用复现原报错(未 await 的 Promise 与 await 后的对象传给剥标签函数,均报 TypeError: html.replace is not a function),确认修复后返回字符串正常
友链页的申请模板本该一条字段一行,实际渲染却挤成一整段、文字还贴着边框。查下来不是 CSS 写错,而是 Tailwind 根本没编译那几个类:内容目录 src/site-content/ 在 .gitignore 里,而 Tailwind v4 的自动内容探测会跳过被 git 忽略的路径 —— 于是「只出现在内容文件、主题源码从没用过」的工具类永远不会生成,类名照旧挂在 HTML 上、规则却不存在。whitespace-pre-wrap、break-words、px-3.5、text-black!、dark:text-white! 五个全中招,邮箱那块 <code> 也因此继承成了主题橙。修法是给 Tailwind 一份扫得到的类名清单:同步脚本把内容里的 class 名汇总到一个没有被忽略的文件里,内容仓那边一个字都没改。
新增 scripts/content-safelist.mjs:扫描内容目录里的 .md / .mdx,抽出 class="…" / className="…" 的类名,去重排序后写进 src/config/content-tailwind-safelist.txt —— 这个文件没被 .gitignore 覆盖,Tailwind 扫得到,等价于给内容里的类名做了一份可扫描的登记表
定位手法:直接调用 @tailwindcss/oxide 的 Scanner 扫项目根目录看候选类,再用 @tailwindcss/node 的 compile() 编译真实 CSS 确认产物里有没有那条规则;修复后 .whitespace-pre-wrap、.break-words、.px-3\.5、.text-black\!、.dark\:text-white\! 五个规则均已在产物中生成
sync-content.mjs 与 watch-content.mjs 在同步完成后自动重写登记表(本地增量监听也覆盖),生成失败只记日志、不中断构建,沿用上一份即可
友链页原来是一个大网格全铺开,友链社区、博客聚合站和个人博客混在一起,看着不像一类东西 —— 博友圈、博客星球、八零圈、BlogsClub、中文独立博客聚合列表、博客故事这六张卡夹在个人博客中间,分类也只在上面的标签筛选里选得出来,视觉上完全没体现。friends.astro 是上游文件不能改,所以走客户端增强:卡片本身带 data-tags 属性,按标签重排成「标题 + 独立网格」的分区区块,结构对齐书签导航页的分组。三个关键点:分区必须留在页面那张 .card-base 内部,因为主题筛选组件是 container.querySelectorAll('.friend-card')、container 取最近的 .card-base,搬出去点标签和搜名字就筛不到了;卡片只改 DOM 位置、不动任何属性,悬停展开、筛选、淡入动画都不受影响;区块显隐跟着筛选结果走,切到「博客社区」时个人博客整块收起,不会留一个只有标题没有卡片的空壳。
新增 public/assets/js/friends-sections.js 与 friends-sections.css:进 /friends/ 时按卡片 data-tags 重排成分区区块,每个区块一个标题(含名称、说明、卡片数)+ 一张独立网格,视觉结构与书签导航页的分组一致
分区仍留在 .card-base 内,主题原有的标签筛选与搜索照常跨区块生效;区块显隐用 MutationObserver 监听 style 变化,只在值变化时写 hidden 以免自触发回环,节流用 setTimeout 而非 rAF(无头环境下 rAF 不一定被调度)
分区配置写在脚本顶部的 GROUPS 数组里(标签、标题、说明),顺序即页面顺序;未归入任何分区的卡片进「其他」兜底区,配置里新加标签也不会丢卡片
日志页的每张卡片原本都会把 description 全量铺开,而这东西普遍四五百字起步,卡片深色描边那条更是 1835 字,整页翻下来就是一堵接一堵的文字墙,扫一眼根本抓不住「这次改了什么」。改法是把背景说明挪进原有的折叠区(默认收起、只有最新一期展开),卡片默认态只剩版本徽章、标题和标签,展开才看全文和变更明细。另外把 V1.29、V1.31 两条明显写飞了的描述压到 250 字左右 —— 细节该写,但不该堆在卡片正文里,变更明细那一栏本来就是干这个的。
ChangelogTimeline.astro:description 从卡片头部挪进 <details>,前面加一个「背景」小标题;折叠按钮文案从「查看当天详细记录」改为「展开这条记录」
V1.29 的描述从 1835 字压到 246 字、V1.31 从 880 字压到 251 字,全 33 条描述的平均长度从 318 字降到 251 字,最长的一条从 1835 字降到 534 字
友链页那个悬停预览做完之后我自己挺喜欢,书签导航页却没有。书签页和友链页结构几乎一样,都是一个链接一张卡片,把那套原样搬过来就行——截图脚本、清单、构建期静态 JSON、前端插封面,四个文件一一对应。搬是搬过来了,坑比预期多:同一个域名挂了好几条书签,只按域名取文件名会互相覆盖;Cloudflare 的 403 页截出来是张白底黑字、看着完全正常的图,不主动筛就会混进线上;headless 的默认 UA 会被直接拒。64 个书签最后 56 个拿到了能看的封面,失败清单脚本会打印出来,可以单独再补。
书签导航 /booknav/ 的卡片支持悬停展开站点首页截图:卡片从 flex 改成 grid,封面独占一整行,高度 0 → 7rem 展开;图片首屏不加载,真悬停/聚焦过才请求
截图加了拦截校验:命令行同时带 --dump-dom 拿渲染后的 HTML,前 4000 字符命中 Cloudflare 403 / 验证页特征就丢弃;再用 sharp 算通道标准差,纯色空白页也丢弃 —— 否则悬停展开会是一张白底黑字的报错页
全程新增独立文件,未改动任何上游文件(booknav.css / booknav.astro 与上游保持零差异),合并上游不受影响
新增 scripts/generate-booknav-covers.ts:从 booknavConfig 取全部书签(用页面同一套 enabled/weight 筛选),chrome-headless-shell 截图 + sharp 转 webp,产物落 public/assets/images/booknav/covers/,清单写 src/data/booknav-covers.json;文件名带路径段的 slug,同域名多条不会互相覆盖;支持增量、--force、--limit=N、--only=关键字
新增 src/pages/api/booknav-covers.json.ts(构建期 prerender 的静态 JSON)与 public/assets/js/booknav-covers.js、public/assets/css/booknav-covers.css;页脚的按需加载器改成数组配置,/friends/ 与 /booknav/ 共用一份逻辑
当前页面没有目录
当前页面没有目录
当前页面没有目录