Files
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

173 lines
3.6 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* AKSRT Enhancements — 全局 UI 增强
*
* 包含:悬停动效、暗色过渡、滚动感知
* 所有选择器使用 aksrt- 前缀避免冲突
*
* 骨架屏不在此文件:唯一契约是 .placeholder 块 + .post_ajax_loader 容器
* (inc/helpers/posts-renderer/markup.php 的 aksrt_render_placeholder)。
*/
@keyframes aksrt-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* ============================================================
* 1. 悬停交互动效
* ============================================================ */
/* 卡片放大 */
.aksrt-hover-zoom {
transition: transform 0.3s ease;
}
.aksrt-hover-zoom:hover {
transform: scale(1.02);
}
/* 卡片轻微放大 */
.aksrt-hover-zoom-sm {
transition: transform 0.3s ease;
}
.aksrt-hover-zoom-sm:hover {
transform: scale(1.02);
}
/* 悬停显示内容 */
.aksrt-hover-show {
position: relative;
}
.aksrt-hover-show__content {
position: absolute;
opacity: 0;
visibility: hidden;
transform: translateY(6px);
transition: opacity 0.3s, transform 0.3s, visibility 0.3s;
z-index: 10;
}
.aksrt-hover-show:hover .aksrt-hover-show__content {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
/* 关闭按钮旋转 */
.aksrt-ic-close {
transition: transform 0.3s;
cursor: pointer;
}
.aksrt-ic-close:hover {
transform: rotate(270deg);
}
/* 图片悬停缩放(缩略图容器) */
.aksrt-hover-zoom-img img {
transition: transform 0.3s ease;
}
.aksrt-hover-zoom-img:hover img {
transform: scale(1.02);
}
.aksrt-hover-zoom-img-sm img {
transition: transform 0.3s ease;
}
.aksrt-hover-zoom-img-sm:hover img {
transform: scale(1.02);
}
/* 按钮悬停上浮 */
.aksrt-hover-lift {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.aksrt-hover-lift:hover {
transform: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
/* ============================================================
* 3. 暗色模式过渡 (View Transitions API)
* ============================================================ */
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
.dark::view-transition-old(root),
body.dark-theme::view-transition-old(root) {
z-index: 1;
}
.dark::view-transition-new(root),
body.dark-theme::view-transition-new(root) {
z-index: 2147483646;
}
::view-transition-old(root) {
z-index: 2147483646;
}
::view-transition-new(root) {
z-index: 1;
}
/* backdrop-filter 不支持时的降级 */
@supports not ((-webkit-backdrop-filter: blur(20px)) or (backdrop-filter: blur(20px))) {
:root {
--aksrt-blur-bg: #ffffff;
}
.dark {
--aksrt-blur-bg: var(--surface-1);
}
}
/* ============================================================
* 4. 滚动方向感知
* ============================================================ */
/* 向下滚动时隐藏导航栏 */
body.aksrt-scroll-down .site-nav.nav-scroll-hide {
transform: translateY(-100%);
transition: transform 0.3s ease;
}
body.aksrt-scroll-up .site-nav.nav-scroll-hide {
transform: translateY(0);
transition: transform 0.3s ease;
}
/* 滚动时隐藏浮动按钮 */
body.aksrt-scrolling .aksrt-floating-right.scrolling-hide {
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
}
/* body-scroll 状态类 */
body.aksrt-body-scroll .aksrt-show-on-scroll {
opacity: 1;
visibility: visible;
}
.aksrt-show-on-scroll {
opacity: 0;
visibility: hidden;
transition: opacity 0.3s, visibility 0.3s;
}
/* 可缩放图片的光标 */
.aksrt-cursor-zoom-in {
cursor: zoom-in;
}