From 0cf3d440e231541ed400fba080f556187e3725eb Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Jul 2026 08:36:00 +0800 Subject: [PATCH] feat(widgets): Stats count-up + product oneline swiper-nav Wire data-aksrt-countup for numeric stats; oneline products use swiper-scroll slides with prev/next; batch12 CSS for video/links/oneline. --- assets/css/frontend/widget-batch5.css | 129 ++++++++++++++++++++++++ src/AKSRT/Widgets/WidgetProductList.php | 66 +++++++----- src/AKSRT/Widgets/WidgetStats.php | 17 +++- 3 files changed, 188 insertions(+), 24 deletions(-) diff --git a/assets/css/frontend/widget-batch5.css b/assets/css/frontend/widget-batch5.css index 6d0a9e8c..a51c6701 100644 --- a/assets/css/frontend/widget-batch5.css +++ b/assets/css/frontend/widget-batch5.css @@ -1303,3 +1303,132 @@ .aksrt-faq__main { grid-template-columns: 1fr; } .aksrt-faq__a { padding-left: 14px; } } + +/* ---- batch12: video shell + bookmark links styles + product oneline swiper ---- */ +.aksrt-video-widget { + position: relative; + width: 100%; + overflow: hidden; + border-radius: 10px; + background: #000; +} +.aksrt-video-widget.radius8 { border-radius: 10px; } +.aksrt-video-widget__frame, +.aksrt-video-widget__player, +.aksrt-video-widget .aksrt-video { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} +.aksrt-video-widget__frame { + border: 0; + display: block; +} +.aksrt-video-widget.controller-hide .aksrt-video video::-webkit-media-controls { + opacity: 0; + transition: opacity .2s ease; +} +.aksrt-video-widget.controller-hide:hover .aksrt-video video::-webkit-media-controls { + opacity: 1; +} + +.aksrt-bookmark-links.links-box { + display: flex; + flex-wrap: wrap; + gap: 12px; +} +.aksrt-bookmark-links.style-card .author-minicard, +.aksrt-bookmark-links.style-bigcard .author-minicard { + flex: 1 1 calc(50% - 12px); + min-width: 140px; + background: var(--surface-2, #f8fafc); + border: 1px solid var(--color-line, #e5e7eb); + padding: 12px; + box-sizing: border-box; +} +.aksrt-bookmark-links.style-bigcard .author-minicard { + flex: 1 1 100%; + text-align: center; +} +.aksrt-bookmark-links .avatar-img img, +.aksrt-bookmark-links .link-img img { + width: 42px; + height: 42px; + border-radius: 50%; + object-fit: cover; +} +.aksrt-bookmark-links.style-bigcard .avatar-img img { + width: 64px; + height: 64px; +} +.aksrt-bookmark-links.style-image { + display: flex; + flex-wrap: wrap; + gap: 10px; +} +.aksrt-bookmark-links.style-image .link-only-img img { + width: 48px; + height: 48px; + border-radius: 10px; + object-fit: cover; +} +.aksrt-bookmark-links.style-simple { + display: block; + line-height: 1.9; + font-size: 13px; +} +.aksrt-bookmark-links.style-simple a { + color: inherit; + text-decoration: none; + margin-right: 8px; +} +.aksrt-bookmark-links.style-simple a:hover { + color: var(--color-primary, #3b82f6); +} +.aksrt-bookmark-links.has-box { + padding: 12px; + border: 1px solid var(--color-line, #e5e7eb); + border-radius: 12px; + background: var(--surface-1, #fff); +} + +.aksrt-product-oneline-swiper { + position: relative; + overflow: hidden; + padding: 0 28px 4px; +} +.aksrt-product-oneline-swiper .swiper-wrapper { + display: flex; +} +.aksrt-product-oneline-swiper .swiper-slide { + width: auto; + max-width: 46%; + min-width: 150px; + height: auto; +} +.aksrt-product-oneline-swiper .aksrt-product-card { + height: 100%; +} +.aksrt-product-oneline-swiper .swiper-button-prev, +.aksrt-product-oneline-swiper .swiper-button-next { + width: 28px; + height: 28px; + margin-top: 0; + top: 42%; + border-radius: 50%; + background: var(--surface-1, #fff); + border: 1px solid var(--color-line, #e5e7eb); + color: var(--color-ink, #111); + box-shadow: 0 2px 8px rgba(0,0,0,.06); +} +.aksrt-product-oneline-swiper .swiper-button-prev:after, +.aksrt-product-oneline-swiper .swiper-button-next:after { + font-size: 12px; + font-weight: 700; +} +.aksrt-product-oneline-swiper .swiper-button-prev { left: 0; } +.aksrt-product-oneline-swiper .swiper-button-next { right: 0; } +.aksrt-product-widget--oneline .aksrt-product-widget__grid { + /* legacy flex fallback if swiper unavailable */ +} diff --git a/src/AKSRT/Widgets/WidgetProductList.php b/src/AKSRT/Widgets/WidgetProductList.php index 8a76c6c3..e6847945 100644 --- a/src/AKSRT/Widgets/WidgetProductList.php +++ b/src/AKSRT/Widgets/WidgetProductList.php @@ -93,6 +93,7 @@ class WidgetProductList extends \WP_Widget { if (!$products->have_posts()) { return ''; } + $oneline = $style === 'oneline'; ob_start(); while ($products->have_posts()) { $products->the_post(); @@ -100,30 +101,36 @@ class WidgetProductList extends \WP_Widget { $card = class_exists('\AKSRT\Shop\Shop') ? \AKSRT\Shop\Shop::get_instance()->build_product_card_view($pid) : []; + if ($oneline) { + echo '
'; + } if (function_exists('get_template_part') && !empty($card['id'])) { get_template_part('templates/parts/shop/product', 'card', [ 'product' => $card, 'show_sales' => true, ]); - continue; + } else { + // Fallback mini card. + $price = (float) ($card['price'] ?? 0); + $image = (string) ($card['image'] ?? ''); + echo '
'; + if ($image !== '') { + echo ''; + echo '' . esc_attr(get_the_title($pid)) . ''; + echo ''; + } + echo '
'; + echo '' . esc_html(get_the_title($pid)) . ''; + echo '
'; + echo '¥' . esc_html(number_format_i18n($price, 2)) . ''; + if (!empty($card['sales'])) { + echo '' . esc_html((string) $card['sales']) . esc_html__(' 已售', 'aksrt') . ''; + } + echo '
'; } - // Fallback mini card. - $price = (float) ($card['price'] ?? 0); - $image = (string) ($card['image'] ?? ''); - echo '
'; - if ($image !== '') { - echo ''; - echo '' . esc_attr(get_the_title($pid)) . ''; - echo ''; + if ($oneline) { + echo '
'; } - echo '
'; - echo '' . esc_html(get_the_title($pid)) . ''; - echo '
'; - echo '¥' . esc_html(number_format_i18n($price, 2)) . ''; - if (!empty($card['sales'])) { - echo '' . esc_html((string) $card['sales']) . esc_html__(' 已售', 'aksrt') . ''; - } - echo '
'; } wp_reset_postdata(); return (string) ob_get_clean(); @@ -231,12 +238,25 @@ class WidgetProductList extends \WP_Widget { $style_class = 'aksrt-product-widget--' . $style; echo '
'; - // Items sit directly under .ajaxpager so ajax-list inject/append works (zibll product-lists-row). - echo '
'; - echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped — cards escaped upstream - echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo ''; - echo '
'; + + if ($style === 'oneline') { + // zibll-style horizontal swiper-scroll (shared slider.js Type A). + echo '
'; + echo '
'; + echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo '
'; + echo '
'; + echo '
'; + echo '
'; + } else { + // Items sit directly under .ajaxpager so ajax-list inject/append works (zibll product-lists-row). + echo '
'; + echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped — cards escaped upstream + echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo ''; + echo '
'; + } + echo ''; echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } diff --git a/src/AKSRT/Widgets/WidgetStats.php b/src/AKSRT/Widgets/WidgetStats.php index 5614ee31..9eded52e 100644 --- a/src/AKSRT/Widgets/WidgetStats.php +++ b/src/AKSRT/Widgets/WidgetStats.php @@ -67,7 +67,22 @@ class WidgetStats extends \WP_Widget { if ($s['prefix'] !== '') { echo '' . esc_html($s['prefix']) . ''; } - echo '' . esc_html($s['number']) . ''; + // Wire effects.js count-up when number is numeric. + $raw_num = preg_replace('/[^\d.]/', '', (string) $s['number']); + $is_numeric = $raw_num !== '' && is_numeric($raw_num); + if ($is_numeric) { + $dec = 0; + if (str_contains((string) $raw_num, '.')) { + $dec = strlen(substr(strrchr((string) $raw_num, '.'), 1)); + } + printf( + '0', + esc_attr((string) $raw_num), + (int) $dec + ); + } else { + echo '' . esc_html($s['number']) . ''; + } if ($s['unit'] !== '') { echo '' . esc_html($s['unit']) . ''; }