3.2.46: 新增 [Archives] 归档短代码 + 评论关闭时整块零输出 #15

需求一:[Archives] 短代码 —— 归档式全站文章列表
  · 在文章/页面正文写一行 [Archives],该位置渲染全站文章的年月归档
  · 默认显示今年,按月份归类;每篇带浏览/评论/点赞三个数
  · 上下两排各有一组「上一年 / 下一年」按钮(四角),JS 切换不刷新页面
  · 地址栏同步 ?arc_year=,刷新与分享链接都能保持同一年
  · 只在用到短代码的页面才加载 assets/js|css/archives.js|css
  · 参数:year="2025" 指定首年;month="0" 不按月分组

需求二:评论关闭时评论区整块消失
  · comments.php 在**任何输出之前** `if (!comments_open()) return;`
    —— 零字节,不是空容器、不是 display:none、不留提示文字
  · 已有评论的老文章关评论后也不再显示(需求原话:正文之外什么都没有)
  · inc/theme-comments.php 的资源守卫与之同口径:关评论时不加载
    约 10KB 的 comments.css / comments.js
  · 删掉 .comments-closed 样式与两处「评论已关闭」提示分支

开发中实测抓到并修掉的三个真实 bug(都是"测试把期望值写对之后"才显形):
  · 年份标题 / 导航年份过了 number_format_i18n() ⇒ 输出「2,025」,
    而 JS 侧 String(year) 输出「2025」⇒ 首屏与切年后不一致
  · 月份标题同样过 number_format_i18n(),与 JS 侧 String(m) 口径不一致
  · yang_archives_render_nav() 把 ar-nav-top 写死,而下排也调它生成
    ⇒ 下排被叫成 top(视觉上被更高特异性规则压住,看不出问题)

验证:
  归档  _archives_unit.php        94 通过 / 0 失败
        _archives_e2e.js        109 通过 / 0 失败
        _archives_e2e_falsify.js 反证 25 真红 / 0 无效
        _archives_unit_falsify.py 反证 6 真红 / 0 无效
  评论  _comments_closed_test.php 54 通过 / 0 失败
        _comments_closed_falsify.py 反证 13 真红 / 0 无效
  回归  _test_comments.php        64 通过 / 0 失败
        _hl_unit_run.py          24 通过 / 0 失败
  全量  96 个 PHP 文件语法检查通过;包内 lint 通过
  发布  已推 3.2.46 到 /theme-update/,update.json 已落 3.2.46;
        服务器 wp-content/themes/kratos_yang/ 仍为 3.2.45(未覆盖)

另:把 _archives_unit.php 从 `__DIR__` 定位改为接受根目录参数,
    否则它无法登记进 verify_all.sh,只能手动跑(手动跑 = 长期不跑)。
    5 个新套件已登记进 verify_all.sh(2j ~ 2o)。
This commit is contained in:
2026-10-26 13:25:51 +08:00
parent 9da5e9e2df
commit 7047ab3ece
8 changed files with 1700 additions and 17 deletions
+385
View File
@@ -0,0 +1,385 @@
/*!
* 归档式文章列表([Archives])样式
* Yongquan Yang <yangyq.net>
*
* ── 设计原则 ────────────────────────────────────────────────
* 1. **它是导航,不是内容**:所以字号小一点、颜色退后一步,
* 让文章标题成为这一屏唯一的主角。
* 2. **色值一律带兜底**:`var(--ar-primary, #00a2ff)`。
* 主题**没有**定义全站 CSS 变量(主色是各处硬编码的),
* 照抄 var(--kratos-primary) 会静默失效、整块永远是默认灰。
* 所以本文件自己定义一组 `--ar-*` 局部变量,挂在 `.yang-archives`
* 作用域内,不污染全站;同时每个使用点都带兜底值。
* 3. **与评论区的变量命名区分**:评论用 `--yq-*`,这里用 `--ar-*`。
* 两套互不依赖,将来任一方改色都不会波及另一方。
* 4. **不引入图标字体以外的东西**:三项计数用的 `i-hot`/`i-comments`/`i-good`
* 是主题图标集里已有的三个(page-content.php 同款)。
*/
.yang-archives {
/* 主色 / 文字三级 / 线 —— 与 comments.css 同一套取值,视觉统一 */
--ar-primary: #00a2ff;
--ar-primary-soft: #eaf6ff;
--ar-text: #33383f;
--ar-text-2: #5b6470;
--ar-text-3: #6b7280;
--ar-line: #eaedf2;
--ar-line-soft: #f1f4f8;
--ar-radius: 4px;
margin: 24px 0 8px;
font-size: 14px;
line-height: 1.6;
color: var(--ar-text, #33383f);
}
/*--------------------------------------------------------------
1. 头部:年份 + 总数 + 上排导航
--------------------------------------------------------------*/
.yang-archives .ar-head {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px 12px;
padding-bottom: 12px;
border-bottom: 1px solid var(--ar-line, #eaedf2);
}
.yang-archives .ar-year {
margin: 0;
font-size: 22px;
font-weight: 700;
line-height: 1.2;
color: var(--ar-text, #33383f);
/* 等宽数字:切年时 2026 → 2025 两位都变,不等宽会左右跳一下 */
font-variant-numeric: tabular-nums;
}
.yang-archives .ar-total {
font-size: 12.5px;
color: var(--ar-text-3, #6b7280);
}
/*--------------------------------------------------------------
2. 四角导航
--------------------------------------------------------------*/
/* 上排靠右、下排靠右 —— 两侧按钮分居两端 */
.yang-archives .ar-nav {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-left: auto;
min-width: 240px;
}
.yang-archives .ar-nav-top {
/* 头部是 flex,导航自己靠右;窄屏会换行到标题下方 */
margin-left: auto;
}
.yang-archives .ar-foot {
margin-top: 16px;
padding-top: 14px;
border-top: 1px solid var(--ar-line, #eaedf2);
}
.yang-archives .ar-foot .ar-nav {
margin-left: 0;
min-width: 0;
}
.yang-archives .ar-nav-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border: 1px solid var(--ar-line, #eaedf2);
border-radius: var(--ar-radius, 4px);
background-color: #fff;
color: var(--ar-text-2, #5b6470);
font-size: 13px;
line-height: 1.4;
text-decoration: none;
white-space: nowrap;
transition: border-color 0.16s ease, color 0.16s ease, background-color 0.16s ease;
}
.yang-archives a.ar-nav-btn:hover {
border-color: var(--ar-primary, #00a2ff);
background-color: var(--ar-primary-soft, #eaf6ff);
color: var(--ar-primary, #00a2ff);
text-decoration: none;
}
.yang-archives a.ar-nav-btn:focus-visible {
outline: 2px solid var(--ar-primary, #00a2ff);
outline-offset: 2px;
}
.yang-archives .ar-nav-arrow {
font-size: 11px;
line-height: 1;
opacity: 0.8;
}
.yang-archives .ar-nav-year {
font-size: 12px;
color: var(--ar-text-3, #6b7280);
font-variant-numeric: tabular-nums;
}
.yang-archives a.ar-nav-btn:hover .ar-nav-year {
color: inherit;
}
/* 禁用态:到最早/最新一年。用 opacity + 去掉交互,
* 不用 display:none —— 按钮消失会让"上排只剩一个按钮"看着像坏了。 */
.yang-archives .ar-nav-btn.is-disabled {
opacity: 0.42;
cursor: not-allowed;
background-color: transparent;
}
/*--------------------------------------------------------------
3. 月份分组
--------------------------------------------------------------*/
.yang-archives .ar-month + .ar-month {
margin-top: 18px;
}
.yang-archives .ar-month-title {
display: flex;
align-items: center;
gap: 8px;
margin: 14px 0 6px;
font-size: 14px;
font-weight: 600;
color: var(--ar-text-2, #5b6470);
}
/* 月份标题左侧一小段主色竖线,作为分组视觉锚点 */
.yang-archives .ar-month-title::before {
content: "";
flex: 0 0 auto;
width: 3px;
height: 14px;
border-radius: 2px;
background-color: var(--ar-primary, #00a2ff);
}
.yang-archives .ar-month-count {
padding: 0 6px;
border-radius: 999px;
background-color: var(--ar-line-soft, #f1f4f8);
color: var(--ar-text-3, #6b7280);
font-size: 11.5px;
font-weight: 400;
font-variant-numeric: tabular-nums;
}
/*--------------------------------------------------------------
4. 条目
--------------------------------------------------------------*/
.yang-archives .ar-list {
margin: 0;
padding: 0;
list-style: none;
}
.yang-archives .ar-item {
display: flex;
align-items: baseline;
gap: 10px;
padding: 6px 8px;
border-radius: var(--ar-radius, 4px);
/* 分隔用极浅的线,不抢视觉 */
border-bottom: 1px solid var(--ar-line-soft, #f1f4f8);
}
.yang-archives .ar-item:last-child {
border-bottom: 0;
}
.yang-archives .ar-item:hover {
background-color: var(--ar-primary-soft, #eaf6ff);
}
.yang-archives .ar-date {
flex: 0 0 auto;
min-width: 44px;
color: var(--ar-text-3, #6b7280);
font-size: 12.5px;
font-variant-numeric: tabular-nums;
}
.yang-archives .ar-title {
flex: 1 1 auto;
min-width: 0;
color: var(--ar-text, #33383f);
text-decoration: none;
/* 长标题单行截断:归档是"扫一眼找文章",换行会把行距撑乱 */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.yang-archives .ar-title:hover {
color: var(--ar-primary, #00a2ff);
text-decoration: underline;
text-underline-offset: 2px;
}
.yang-archives .ar-item:hover .ar-title {
color: var(--ar-primary, #00a2ff);
}
/*--------------------------------------------------------------
5. 三项计数
--------------------------------------------------------------*/
.yang-archives .ar-stats {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
gap: 10px;
margin-left: auto;
padding-left: 10px;
}
.yang-archives .ar-stat {
display: inline-flex;
align-items: center;
gap: 3px;
color: var(--ar-text-3, #6b7280);
font-size: 12px;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.yang-archives .ar-stat .kicon {
font-size: 12px;
line-height: 1;
}
/* 零值弱化:0 浏览 / 0 评论 / 0 赞占了相当多,一律同等强调会让
* 计数列看起来全是"0 0 0",反而看不出哪篇有热度。
* 属性由 PHP 在渲染时按真实值打(见 yang_archives_render_item())。 */
.yang-archives .ar-stat[data-zero="1"] {
opacity: 0.45;
}
/*--------------------------------------------------------------
6. 空态
--------------------------------------------------------------*/
.yang-archives .ar-empty {
margin: 20px 0 4px;
padding: 18px 16px;
border: 1px dashed #dfe5ec;
border-radius: var(--ar-radius, 4px);
color: var(--ar-text-3, #6b7280);
font-size: 13.5px;
text-align: center;
}
/*--------------------------------------------------------------
7. 切年时的过渡
--------------------------------------------------------------*/
/* 只做淡入,不做高度动画:
* 高度动画需要先量 scrollHeight 再改 height,在长列表(一年 12 个月)
* 上会强制同步布局,切年时有肉眼可见的卡顿。
* 淡入用 CSS animation 而不是 JS 定时器,是为了让它自己结束、
* 不留 pending 的 timeout(否则快速连点切年,几个 timeout 会交错)。 */
.yang-archives .ar-body.is-switching {
animation: ar-fade 0.18s ease;
}
@keyframes ar-fade {
from {
opacity: 0;
transform: translateY(-2px);
}
to {
opacity: 1;
transform: none;
}
}
/* 尊重系统的"减少动效"设置 */
@media (prefers-reduced-motion: reduce) {
.yang-archives .ar-body.is-switching {
animation: none;
}
}
/*--------------------------------------------------------------
8. 窄屏
--------------------------------------------------------------*/
@media (max-width: 767.98px) {
.yang-archives {
font-size: 13.5px;
}
.yang-archives .ar-head {
/* 窄屏下导航换到标题下方并且铺满,两个按钮各占一半 */
align-items: baseline;
}
.yang-archives .ar-nav {
width: 100%;
min-width: 0;
margin-left: 0;
}
.yang-archives .ar-nav-btn {
flex: 1 1 0;
justify-content: center;
padding: 7px 8px;
}
/* 窄屏隐藏计数图标,只留数字 —— 图标加数字在 320px 宽度下
* 会把标题挤到只剩两三个字 */
.yang-archives .ar-stat .kicon {
display: none;
}
.yang-archives .ar-stats {
gap: 8px;
padding-left: 6px;
}
.yang-archives .ar-date {
min-width: 40px;
font-size: 12px;
}
}
@media (max-width: 400px) {
.yang-archives .ar-title {
/* 极窄屏允许两行,否则标题只剩几个字完全看不出是哪篇 */
white-space: normal;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.yang-archives .ar-item {
/* 计数换到标题下一行,避免和标题抢宽度 */
flex-wrap: wrap;
}
.yang-archives .ar-stats {
width: 100%;
margin-left: 0;
padding-left: 50px;
}
}
+3 -1
View File
@@ -180,7 +180,9 @@
outline-offset: 2px;
}
.comments-closed,
/* .comments-closed 的样式已在 3.2.46 删除:评论关闭时整个评论区
* 一个字节都不输出(见 comments.php 开头的 return),这个类名
* 再也不会出现在页面上。留着它会让后来人以为"还有个关闭态要美化"。 */
.comments-empty {
margin: 20px 0 4px;
padding: 18px 16px;