Commit Graph
1677 Commits
Author SHA1 Message Date
kate522 fe57022550 fix(frontend): remove duplicate select arrow and show the WordPress brand icon 2026-10-06 13:23:05 +08:00
kate522 962ab5c290 fix(frontend): match the reference post format options in the page set modal
参考主题把文章格式固定为标准/图像/画廊/视频四项,动态读取
get_theme_support('post-formats') 会让本站多出 aside/quote/link
等注册格式,选项集偏离参考主题,故改为固定列表。
2026-10-06 12:55:04 +08:00
kate522 6dbe1fe4c6 fix(frontend): align page-set hint bar and FA5 icons with the reference
- 齿轮提示横条改为参考主题的 .abs-right 垂直居中几何(top:50% +
  right:.7em + translateY(-50%)),本站 legacy .abs-right 是 top:0/right:0
  导致横条贴到按钮顶角
- 新增 front-page-admin-set.js:横条 2 秒后淡出 1 秒消失(对齐参考
  主题 js/page-edit.js),开关关闭时不出队脚本
- 齿轮与弹窗内图标统一为 FA5 惯例 fa fas fa-*,并采用 FA5 的 glyph
  重命名(sliders→sliders-h、pie-chart→chart-pie)
2026-10-06 12:50:20 +08:00
kate522 12f60897d9 fix(frontend): 修复前台页面编辑弹窗并 1:1 复刻参考主题
远端加载的弹窗在 admin-ajax 上下文里拿不到查询对象,enabled()
恒为假,直接返回 success:false;而 AksrtRequest.responseError
只读 message/data.message,读不到 msg,遂报「请求失败(HTTP 200)」。
改为参考主题原生架构:wp_footer 直出 #modal_admin_set,提交走
vendored main.js 的 aksrt_ajax 契约,不再有 AJAX 取 HTML。

对齐参考主题 zib-frontend-set.php:
- 弹窗补齐 aria-hidden=false、win-ajax-replace、role=document
- 隐藏字段改用 taxonomy + post_type
- 字段顺序与 is_page 分支(标题样式、widgets_register、容器位置)
- 多选 checkbox 改 name="id[]",描述允许富文本
- 模块布局指向定制器小工具面板
- term 保存使用 POST 的 taxonomy 字段

清理不再使用的 assets/js/page-admin-set.js。
新增 frontend-page-edit-harness.php 覆盖门禁、渲染与各保存分支。
2026-10-06 12:22:43 +08:00
kate522 b75bf197a3 feat(extensions): 新增系统工具页面与前台投稿分片上传 2026-10-06 11:09:05 +08:00
kate522 613b8a57a3 style(user-center): 优化手机号脱敏数字框与前缀后缀一体呈现 2026-10-06 09:41:11 +08:00
kate522 af72364078 feat(security): 新增网站安全扩展模块并支持修改手机脱敏验证 2026-10-06 09:26:55 +08:00
kate522 224f86ec08 fix(profile): mask bound phone display 2026-10-06 02:16:22 +08:00
kate522 fc9bf27560 fix(profile): anchor verification code buttons 2026-10-06 02:07:13 +08:00
kate522 d8d0b5f290 test(profile): cover account modal styling 2026-10-06 01:51:02 +08:00
kate522 ce429e1caf fix(profile): align account modal UI 2026-10-06 01:46:48 +08:00
kate522 248912f610 fix(profile): align account dialogs and contracts 2026-10-06 01:09:04 +08:00
kate522 f646fa8573 fix(user): repair phone binding and profile fields 2026-10-05 20:55:20 +08:00
kate522 0cf4639d95 fix(profile): match account submit buttons 2026-10-05 19:54:00 +08:00
kate522 0a52bf36f9 fix(profile): refine settings modal actions 2026-10-05 19:21:42 +08:00
kate522 346146b4fa feat(profile): rebuild account settings page 2026-10-05 18:58:49 +08:00
kate522 f00c3faeaa fix(sms): accept empty HTTP 200 responses 2026-10-05 17:25:33 +08:00
kate522 59e9bbf8a6 fix(payment): restore order statistics cards 2026-10-05 17:25:33 +08:00
kate522 1af51ab172 fix(sms): handle empty Smsbao responses 2026-10-05 16:54:12 +08:00
kate522 7b55cfb190 feat(payment): rebuild order details and asset records 2026-10-05 16:42:25 +08:00
kate522 476e2f961d fix(rewards): load and strengthen amount styles 2026-10-05 11:36:39 +08:00
kate522 979639342a feat(rewards): add toast and captcha flow 2026-10-05 03:51:18 +08:00
kate522 356f7fe5bd fix(frontend): align reward modal with shared runtime 2026-10-05 03:24:42 +08:00
kate522 6037ca184b fix(sms): collapse provider settings by default 2026-10-05 02:29:42 +08:00
kate522 8ef2f7e49f fix(sms): remove obsolete init call 2026-10-05 02:17:25 +08:00
kate522 5091da6a60 feat(sms): align provider and verification flow 2026-10-05 02:13:52 +08:00
kate522 d0a3972ca7 fix(identity): surface real sideload failure reason 2026-10-04 23:26:52 +08:00
kate522 2ae2b2fd07 fix(identity): validate evidence by file content 2026-10-04 23:13:48 +08:00
kate522 90c1f7a62b fix(identity): normalize bare li markers in apply intro 2026-10-04 22:54:58 +08:00
kate522 8fcb136d55 fix(identity): draw intro list markers inside list items 2026-10-04 22:51:21 +08:00
kate522 d6e3b377b4 fix(identity): apply safe list styles in modal runtime 2026-10-04 22:25:15 +08:00
kate522 2b3e325d63 fix(identity): keep modal list markers inside scroll area 2026-10-04 22:15:42 +08:00
kate522 4caf81c9e2 fix(identity): keep intro list markers visible 2026-10-04 22:10:18 +08:00
kate522 88661e1574 fix(identity): preserve HTML in application intro 2026-10-04 22:02:20 +08:00
kate522 67ec3c8aeb fix(identity): align application modal with reference 2026-10-04 21:49:39 +08:00
kate522 59901b9e10 feat(identity): align auth flow with reference theme 2026-10-04 21:10:12 +08:00
kate522 5a17b399a0 fix(user-home): add reference tab loading skeletons 2026-10-04 19:40:24 +08:00
kate522 4c6b02a6b9 fix(user-home): restore desktop comment columns 2026-10-04 19:19:29 +08:00
kate522 56bbb63afd fix(user-home): align profile comments with reference theme 2026-10-04 19:11:27 +08:00
kate522andClaude Fable 5 00817766a6 fix(author): keep the follow sub-tab state out of the other panels
uhSub(粉丝/关注)只属于粉丝面板,loadPanelBody 却把它写在每一个面板上,
翻页时又从被点面板自身读回,于是分组状态跨面板串味:先点粉丝 tab 切到
「关注」,再点文章 tab 翻页,#panel-posts 会被永久打上 data-uh-sub=
"following",之后粉丝面板的翻页读到的是文章面板残留的分组。

翻页改为只读**当前面板内**的 .is-active 子页签,读不到就回落默认分组;
uhPage / uhSub 也只在粉丝面板写入,文章 / 收藏 / 评论面板一次都不碰。
目标面板本身仍由被点面板的 id 反解,跨面板跳转这条路径不存在,本次不动。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-04 14:28:43 +08:00
kate522andClaude Fable 5 16d67c8a87 fix(user-home): hide the old panel content while the tab skeleton loads
翻页 / 切 tab 是整页替换语义(author.js 最终就是 panel.innerHTML = html),
但加载态只做了骨架的显示,旧卡片与旧页码仍留在屏上,于是先看到
「第 1 页卡片 + 脚下一摞骨架」,等接口返回才换页。

加载期收起 .aksrt-user-home__post-list 的直接子级 .posts-item 与旧翻页控件,
让骨架独占内容区;对齐参考主题 post_ajax() 的 beforeSend(replace 时
$item.remove() + find(pag).remove())。显隐仍走纯类切换,不写 inline display。

两点刻意的收窄:
- 只收直接子级 .posts-item 而非后代:骨架内层同样带 .posts-item,
  后代选择器会把骨架自己也藏掉,占位就永远出不来。
- 旧页码用 :has(.post_ajax_loader) 限定:关注 / 评论面板没有骨架,
  无条件隐藏会让它们加载时只剩一片空白。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-04 13:58:09 +08:00
kate522andClaude Fable 5 45dc909e4c fix(user-home): span the tab pagination skeleton across the post grid
The posts/favorites tabs turn the article list into a 2-column grid at
>=992px. The AJAX pagination skeleton .post_ajax_loader is a direct
child of that grid, so with no grid-column it was laid out as a single
half-width card and the whole placeholder stack collapsed into one
column while paging or switching tabs.

Span the loader across every column and, while loading, give it the
same 2-column template the real cards use so placeholders line up with
them. The skeleton shape now follows the resolved render mode instead
of a hardcoded 'list', so card mode no longer renders list blocks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-04 13:17:02 +08:00
kate522andClaude Fable 5 20fde1d652 fix(skeleton): put the widget gutter relief on the skeleton's inner item
小工具(首页挂载的 / 侧栏的)骨架加载占位比真实卡片窄一截:card 布局下
每侧窄 8px,视觉上就是「骨架小了一些」。

小工具的卡片走 skip_wrapper=true,直接挂在 .widget-ajaxpager 上
(src/WidgetSystem/PostRenderer.php),不经过 .posts-row,因此只受小工具
这条独立的负边距链作用:

  .widget-ajaxpager            margin: -8px
  .posts-item.card(真实卡片)  margin: 8px   ← 卡片自身自带
  .post_ajax_loader(外层)     margin: 8px   ← f61142ee 加的补偿
  .posts-item.card(骨架内层)  margin: 8px   ← 同一条卡片规则

骨架于是拿到 8px(外层 loader)+ 8px(内层卡片)= 16px,而真实卡片只有
8px,内容区每侧少 8px。list 模式没暴露是因为 .posts-item 的 8px 来自
`.widget-main-post.style-list .posts-item`,该规则只覆盖 style-list、
不作用于骨架,外层的 8px 恰好补上 list 卡片应有的一份,刚好对齐。

修法:把水平补偿从外层 .post_ajax_loader 移到骨架内层的 .posts-item /
.posts-mini —— 与真实卡片同一个元素、同一条选择器,于是两者逐像素同宽,
也顺带回答了「补偿链的拥有者是谁」这个一直在打补丁的问题。

- assets/css/main.css、assets/css/frontend/post-card.css:.posts-row 与
  .widget-ajaxpager 两条链、桌面 8px 与移动 5px 两组,共 8 处规则改为
  内层选择器。
- assets/css/routes/user-home.css:面板归零规则同步改到内层,否则它归零
  的是已经失效的外层,旧补偿会重新显形。
- tests/widget-system/asset-ledger-contract.test.cjs:把守卫断言改成内层
  选择器,并修正规则匹配以支持选择器组(.posts-item, .posts-mini)。
  注释说明为何不能补偿外层。

参考主题 zibll 完全没有 .post_ajax_loader 的 margin 规则;AKSRT 需要它,
是因为骨架多包了一层。定位在内层是与参考主题等价的正确解。

Verification:
- node tests/widget-system/asset-ledger-contract.test.cjs  16/16
- node tests/widget-system/post-visual-contract.test.cjs   22/22
- node tests/widget-system/zibll-modern-widgets-contract.test.cjs 10/10
- node tests/widget-system/lazyload-contract.test.cjs      7/7
- node tests/widget-system/frontend-lifecycle-contract.test.cjs 13/13
- node tests/widget-system/page-display-contract.test.cjs  18/18
- node tests/widget-system/message-center-contract.test.cjs 8/8
- php tools/audit-admin-contracts.php  errors=0
- build:public 已重建;旧外层规则在源与产物中均已归零

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-04 04:07:19 +08:00
kate522andClaude Fable 5 38bbd917a9 fix(skeleton): align the homepage tab and sort loaders with the reference 1:1
首页「更多栏目」tab 与「排序方式」切换的骨架占位与参考主题 zibll 有实质差异,
根因不是几何宽度,而是三处结构/契约错位:

1. 骨架块自身结构与参考主题不同。card 分支用了 `<posts>` 元素 + `.post-graphic`
   包裹层(列表变体,带 margin-right:20px),而参考主题 card 骨架是
   `<div class="posts-item card">` 且 `.item-thumbnail` 是直接子元素。
   → card 骨架右侧多出一条真实卡片没有的 20px 沟槽。

2. 骨架块被错误地打上 `ajax-item`。参考主题的占位块没有该类。它会让
   `find('.ajax-item')` / ajax-list 的 `inject()` 把骨架当成真实条目。

3. 排序切换的骨架被预渲染节点顶替。aksrt_render_pagination() 在 .ajax-pag 内
   渲染了一个写死 2 条、写死 list 形状的 .post_ajax_loader;runtime post_ajax()
   会先在容器内 find('.post_ajax_loader'),找到就复用并丢弃调用方按视口动态
   拼出的骨架 → 切排序永远是 2 条 list 骨架,card 布局下也是、与视口宽度无关。
   参考主题 zib_paging() 根本没有 loader 兄弟节点。

改动:
- inc/helpers/posts-renderer/markup.php:aksrt_render_placeholder() 的
  card/list 分支改为与 zib_get_post_placeholder() 逐字等价的结构;去掉
  ajax-item 类、card 分支的 .post-graphic 包裹层,元素改用 <div>。
- inc/helpers/template-tags/pagination-permissions.php:删除预渲染 loader,
  与参考主题 zib_paging() 一致 —— 只渲染翻页控件。
- assets/js/core/pagination.js:找不到骨架节点时构造与 runtime/main.js 同款
  的文章骨架(卡片 8/6/4 条、列表 4/3 条,按视口与参考主题同阈值),
  不再退化为「转圈 + 文案」这个第二套加载语言;仅评论等非文章面保留该兜底。
- assets/js/core/pagination.js:为排序菜单(.ajax-option)与 tab 触发器
  (.post_ajax_trigger)增加避让 —— 它们归 legacy runtime 管线,
  否则一次点击发两个请求(与 ajax-list.js 的既有避让对称)。
- assets/js/runtime/main.js:post_ajax 的显隐由 fadeIn()/hide() 改为
  .is-loading 类切换。前者写 inline display,优先级高于类规则,一旦残留
  骨架永远打不开,正是骨架契约明令禁止的失败模式。

归档/分类筛选面原本另有一套独立加载语言(spinner 遮罩 + opacity 淡出),
本次一并统一到同一条 .post_ajax_loader + .is-loading 契约:
- inc/helpers/aksrt-archive.php:删除 show_loading 标记位与遮罩 DOM,
  改为在分页之后渲染文章骨架。
- assets/js/core/archive.js:showLoading/hideLoading 只切 .is-loading;
  fetchPosts() 清空内容时保留骨架与分页节点(与参考主题 success 只 hide
  不删的生命周期一致),原先会连带删掉骨架。
- assets/css/frontend/layout.css:删除 .archive__ajax-wrap.is-loading
  的 opacity 淡出与 spinner 遮罩规则。
- category.php / tag.php:删除已失效的 show_loading 实参。

验证:php -l 全部通过;php tools/audit-admin-contracts.php errors=0;
契约测试 post-visual(22) / asset-ledger(16) / message-center(8) /
lazyload(7) / frontend-lifecycle(13) / zibll-modern-widgets(10) /
page-display(18) / a11y 全绿;已重跑 build:public 刷新产物。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-04 03:04:02 +08:00
kate522andClaude Fable 5 f61142ee9a fix(pagination): align the load-more skeleton width with the cards
首页「加载更多」的骨架比列表本身宽出一截:.posts-row 用
margin-left/right:-8px 抵消卡片的水平边距,而卡片边距规则是
`.posts-row > *:not(.post_ajax_loader)`,把骨架排除在补偿链之外,
于是骨架左右各宽出 8px(合计 16px)。移动端的 5px 覆盖块同理。

小工具的 .widget-ajaxpager / tab pane 也是一条独立的负边距补偿链
(margin: -8px 抵消 .posts-item 的 8px),骨架同样溢出。

修法是给骨架补上与卡片等同的水平边距,而不是写 inline display
(会盖过 .is-loading 类规则)。改了 main.css、post-card.css 的
8px / 5px 两组规则,用户中心面板另加一条归零规则,因为那里的
容器 margin 与卡片边距都已清零,不能再叠加补偿。

顺带补一条契约测试:删掉任一 gutter 规则即失败,防止回归。

Verification:
- node --test tests/**/*.test.cjs  471 passed / 0 failed
- php tests/widget-system/run.php  136 assertions
- php tools/audit-widget-system.php
- php tools/audit-admin-contracts.php  errors=0 (56 既有 baseline 警告)
- node tools/build-public-assets.mjs  CSS/JS 产物已重建

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-04 00:25:26 +08:00
kate522andClaude Fable 5 cf4554e7c8 fix(ajax): show the reference skeleton on every load-more surface
Clicking 加载更多 in the 多栏目文章 widget showed no skeleton at all — the
list simply stayed still until the response arrived, then the new cards
appeared. The homepage stream, archives and comments already had a working
skeleton; the widget's AJAX load goes through a different client and never
found its loader.

Root cause was DOM placement, not visibility: ContentRenderer emitted
.post_ajax_loader as a *sibling* of .widget-ajaxpager, while the widget REST
client resolves it with container.querySelector('.post_ajax_loader'). The
node existed but could never match, so .is-loading was never added and the
skeleton stayed display:none. Inactive tab panes had the same shape, and the
direct-load branch of ajaxpager() emitted no loader at all.

Changes, all following the reference theme's post_ajax() contract in
zibll/js/main.js (beforeSend anchors the loader to the end of the list;
success only hides it, never removes it):

- ContentRenderer: nest the loader inside .widget-ajaxpager for both the
  direct-load and inactive-tab branches, and drop the sibling append.
- widgets/frontend.js: anchorLoader() moves the loader to the end of the
  list before .ajax-pag on every request; appended cards are inserted before
  it; a replace preserves the node instead of wiping it with innerHTML; a
  fallback loader is created when the DOM has none; loadItems() now returns
  its promise; drop the unreachable is-loading auto-load branch.
- Message centre, user-home panels and the search page switch from spinner /
  opacity feedback to the same .posts-item-shaped skeleton, so all AJAX
  surfaces share one loading contract.
- Remove the second, never-wired skeleton system (.aksrt-skeleton-* in
  core-ui.css) and the dead spinner stylesheets/rules (skeleton.css,
  ajax-spinner.css, .load-more__*, --skeleton-base/--skeleton-shine) plus the
  unregistered assets/js/waterfall.js.
- Extend the widget, message-centre, user-home and asset-ledger contract
  tests to pin the loader inside the container, the class-only visibility
  switch, and the absence of the deleted dead code.

Verified: 470 node tests, 136 PHP widget assertions, admin-contract and
widget-system audits all green; rebuilt public assets after the CSS/JS
removals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-03 22:22:15 +08:00
kate522andClaude Fable 5 271e7f0518 chore(audit): refresh contract report
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-03 17:24:16 +08:00
kate522andClaude Fable 5 b5f37d6d46 fix(pagination): align AJAX load-more loading state with reference
Loading indication now matches the reference theme's post_ajax() contract:

- Stop overwriting the 加载更多 button label with 正在加载...; the button
  keeps its own text and the .post_ajax_loader skeleton carries the busy
  state instead.
- Add the reference fallback loader (.loading ring + 加载中...) when no
  skeleton exists in the DOM, and reinsert the skeleton after the last
  card on every page load like beforeSend does.
- Retext the loader string to 加载中... (zib__('loading')) and make the
  ajax_trigger default a translatable string.
- Route ajax-list.js / comments.js / widgets frontend.js through the
  .is-loading class instead of inline display, which outranked the class
  rule and could freeze the skeleton shut.
- Drop the search.php inline display:none that defeated .is-loading, and
  remove the unproduced .post-ajax-loader / [data-aksrt-ajax-loader] shims.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-03 17:23:44 +08:00
kate522andClaude Fable 5 e506309434 chore(widgets): re-freeze the drifted widget reference baseline
audit-widget-system.php and validate-widget-golden.php both failed on
"Reference drift: inc/functions/functions.php". The reference theme was
updated from V9.1 to V9.2; its update log records only a message-center
pagination fix, so no widget contract changed.

The file is not a widget source — group_sources in the golden-fixture
generator maps only the five widget-*.php files — so it contributes solely
to the aggregate fingerprint, and re-freezing is safe.

Refresh the pinned SHA256 in .specs/baselines/widget-reference.json and
regenerate tests/fixtures/widget-golden-v1.json so the hash and its
derived fingerprint stay consistent. The fixture diff is those two lines.

Both tools pass again: widget audit (37 widgets, 40 areas, 5 templates)
and golden validation (37 components, 222 screenshot targets).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-03 15:44:02 +08:00
kate522andClaude Fable 5 89a9cf24e9 fix(posts): repair the load-more skeleton and align it with the reference
Clicking 加载更多 showed no skeleton at all, and the placeholder shape did
not match the reference theme's post cards.

- Class-name mismatch: pagination.js queried .post-ajax-loader while every
  PHP producer emits .post_ajax_loader, so showSkeleton() never found a
  target and the loader stayed hidden. Accept both spellings.
- Inline display:none on the loader (pagination, comments, widget tab
  panes) outranked .is-loading, so even the correct selector could not
  reveal it. Drop the inline style; the reference uses a bare
  <div class="post_ajax_loader"> and toggles visibility from JS.
- loadNextPage() set indicator.style.display = "flex", which forced the
  .posts-item.card skeleton blocks (inline-block layout) into a single
  row instead of stacking vertically — the visible symptom. Remove those
  inline writes and drive .is-loading from CSS for every surface.
- Scope the hide/show rules on the class itself rather than requiring an
  .ajaxpager ancestor: homepage tab panes, archive streams and comment
  lists sit at three different depths.
- Rebuild aksrt_render_placeholder() on zib_get_post_placeholder's
  structure — list = t1/k1/k2 + two s1, card = t1 item-heading/k2 + two
  s1, thumb wrapped in post-graphic + radius8 item-thumbnail, all carrying
  ajax-item so the loader is not mistaken for a real card.
- Add mini/mini_thumb modes so ContentRenderer::placeholder() stops
  hand-rolling the same markup; normalize its 'lists' arg to 'list'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-03 15:42:18 +08:00