feat(vip): skeleton loading state and faster modal/site startup
The VIP purchase/renew modal opened with a single "loading..." line, which reads as a hang while /pay/vip/modal round-trips. Every frontend pageview also paid an option write inside wp_head, and the header user-card CSS was enqueued even for guests who never see the card. pay-vip.js now builds a full-layout skeleton (user box, level tabs, the two-column package panel) from vipSkeleton(), reusing the global aksrt-modal-runtime__skeleton line/block classes; the VIP-specific shapes live in the conditionally loaded vip-modal.css, and the 640px two-column threshold matches .pay-vip-form-row. The modal cache TTL goes 15s -> 60s (purchase, card-pass redeem and points exchange already invalidate the vip tag), and hover/focus on a .pay-vip trigger now prefetches the payload through the same cacheKey and flight openRemote uses, so a warm click opens instantly. The bottom note and the whole help_text pipeline behind it are removed; the admin-editable pay_user_vip_desc still renders at the top of the modal, and the recharge/gateway help_text keys are untouched. get_catalog() reads points and wallet balance through one new LedgerService::points_and_balance() call. The StatsTracker counter write moves to shutdown so wp_head only does the visitor check and setcookie, and header-userbox.css is enqueued for logged-in users only. Verification: node --test across the suite (628 tests, including the 7 new contract assertions in tests/widget-system/vip-modal-skeleton.test.cjs) and php -l on every changed PHP file. No visual acceptance performed, per request.
This commit is contained in:
1 parent
319ec2f47f
commit
cb76b95b01
9 files changed
+376
-13
No files matched your search
@@ -101,3 +101,86 @@
|
||||
opacity: 0.7;
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
/* 会员弹窗骨架屏(pay-vip.js vipSkeleton()):仿真实弹窗布局——
|
||||
用户框 + 等级卡行 + 双列套餐面板。线条/色块与 shimmer 动画复用全局
|
||||
.aksrt-modal-runtime__skeleton-line/-block 与 @keyframes
|
||||
aksrt-modal-skeleton(build/public.min.css 已全局入队);
|
||||
这里只定义 VIP 专属形状(头像圆、tab 卡、双列 grid、按钮条),
|
||||
与 .pay-vip-form-row 的 640px 双列阈值保持一致。 */
|
||||
.aksrt-vip-modal-skeleton {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.aksrt-vip-modal-skeleton__user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.aksrt-vip-modal-skeleton__avatar {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.aksrt-vip-modal-skeleton__lines {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.aksrt-vip-modal-skeleton__tabs {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.aksrt-vip-modal-skeleton__tab {
|
||||
flex: 1;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.aksrt-vip-modal-skeleton__pane {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.aksrt-vip-modal-skeleton__info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.aksrt-vip-modal-skeleton__products {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.aksrt-vip-modal-skeleton__button {
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
/* 专属形状共用骨架底色与 shimmer(值与 modal-runtime.css 的线条/块一致)。 */
|
||||
.aksrt-vip-modal-skeleton__avatar,
|
||||
.aksrt-vip-modal-skeleton__tab,
|
||||
.aksrt-vip-modal-skeleton__button {
|
||||
display: block;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(90deg, rgba(148, 163, 184, 0.16), rgba(148, 163, 184, 0.3), rgba(148, 163, 184, 0.16));
|
||||
background-size: 200% 100%;
|
||||
animation: aksrt-modal-skeleton 1.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.aksrt-vip-modal-skeleton__pane {
|
||||
grid-template-columns: 1fr 1.2fr;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user