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>
The 推广收益 detail card no longer renders the QR code as its own row. The
card becomes a fixed-label info list: 推广链接 [Url][复制链接][推广海报] /
佣金比例 / 累计佣金 / 返佣详解, mirroring the reference theme's 推广中心 card.
- profile-revenue.php: QR row removed; poster button moved into the link row and
gated server-side on the poster switch; copy label now 复制链接; 推广人数 row
dropped; 返佣详解 heading reads the existing pay_rebate_text_details_title;
dead $vip_ratios, aksrt-revenue-page class and data-min-amount removed
- new affiliate-poster-modal.php: poster previews in a modal before download
(reuses .uc-modal + single-render guard), since the QR now only exists inside
the poster
- credits.js: renderAffiliateQr and its call deleted, along with the dead
[data-affiliate-payers] lookup and the inline ch-width hack; initAffiliatePoster
builds the poster into the modal stage and reveals 保存海报
- PaymentRuntime: expose affiliate details_title
- user-center.js: remove never-defined AKSRTRevenueCenterInit guards (2 sites)
- CSS: revenue-earnings.css pruned to live rules plus the new link-row grid and
poster stage styles; routes/user-center/revenue.css pruned to its only
definitions; dead leaves routes/revenue.css and routes/commerce.css deleted and
dequeued from the user-center part list
- tests: referral-qr-contract test 2 rewritten for the QR-free card, link row and
poster modal; post-visual-contract leaf list updated with regression guards
qrcode.min.js stays enqueued — buildPosterCanvas still draws the QR inside the
poster. Net -833 lines.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Rebuild checkin details modal HTML 1:1 with reference theme:
colorful header c-blue, user card (points/level), daily reward
card and 7-day continuous mini cards
- Signed entry buttons (header dropdown, user-card badge, user
center) become clickable checkin-details-link modal triggers
instead of disabled buttons
- Swap data-signin-btn to details link in place after successful
signin (reference .initiate-checkin replacement behavior)
- Add aksrt-checkin-details-modal runtime shell (modal-mini 400px)
- Remove dead code: legacy lite modal, admin-ajax details handler,
/signin/history route, signin calendar; rebuild public bundles
- Update contract tests to the new checkin modal contract
aksrt_get_comment_icon(), aksrt_renderer_svg_icon() and the widget
renderer's private icon_markup() all delegate to the unified helper,
and the duplicated 24px empty-state SVGs in user-center/user-home now
come from one aksrt_empty_state_svgs(). Contract tests follow the
delegation (sprite <use> markup asserted in the helper).
Sidebar visibility had two disconnected decisions: the body site-layout-*
class (via aksrt_is_show_sidebar_filter) only checked widget activity for
singles, while the homepage aside renderer skipped the column and
sidebar.php rendered an empty one. With the toggle on and no widgets, the
homepage kept a reserved gutter and squeezed the main content aside.
- collapse every scene to no-sidebar when the sidebar widget stack is empty
- resolve home_sidebar before the page branch so a static front page is
checked against the zones the homepage renders
- guard the homepage aside with aksrt_is_show_sidebar() alone and drop the
duplicate aksrt_homepage_has_sidebar gate
- early-return sidebar.php instead of rendering an empty column
- drop dead code: archive helper $preferred param, wp_is_mobile fallback,
container--no-sidebar class, unreachable front-page fallback
- update post-visual-contract to pin the single visibility decision
Verification: php -l on all changed files; node --test
tests/widget-system/*.test.cjs 242/243 (the toast-contract failure is
pre-existing and unrelated).