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.
This commit is contained in:
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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 '<div class="swiper-slide ajax-item">';
|
||||
}
|
||||
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 '<div class="aksrt-product-widget__item ajax-item">';
|
||||
if ($image !== '') {
|
||||
echo '<a href="' . esc_url(get_permalink($pid)) . '" class="aksrt-product-widget__thumb">';
|
||||
echo '<img src="' . esc_url($image) . '" alt="' . esc_attr(get_the_title($pid)) . '" loading="lazy">';
|
||||
echo '</a>';
|
||||
}
|
||||
echo '<div class="aksrt-product-widget__info">';
|
||||
echo '<a href="' . esc_url(get_permalink($pid)) . '" class="aksrt-product-widget__title">' . esc_html(get_the_title($pid)) . '</a>';
|
||||
echo '<div class="aksrt-product-widget__meta">';
|
||||
echo '<span class="aksrt-product-widget__price">¥' . esc_html(number_format_i18n($price, 2)) . '</span>';
|
||||
if (!empty($card['sales'])) {
|
||||
echo '<span class="aksrt-product-widget__sales">' . esc_html((string) $card['sales']) . esc_html__(' 已售', 'aksrt') . '</span>';
|
||||
}
|
||||
echo '</div></div></div>';
|
||||
}
|
||||
// Fallback mini card.
|
||||
$price = (float) ($card['price'] ?? 0);
|
||||
$image = (string) ($card['image'] ?? '');
|
||||
echo '<div class="aksrt-product-widget__item ajax-item">';
|
||||
if ($image !== '') {
|
||||
echo '<a href="' . esc_url(get_permalink($pid)) . '" class="aksrt-product-widget__thumb">';
|
||||
echo '<img src="' . esc_url($image) . '" alt="' . esc_attr(get_the_title($pid)) . '" loading="lazy">';
|
||||
echo '</a>';
|
||||
if ($oneline) {
|
||||
echo '</div>';
|
||||
}
|
||||
echo '<div class="aksrt-product-widget__info">';
|
||||
echo '<a href="' . esc_url(get_permalink($pid)) . '" class="aksrt-product-widget__title">' . esc_html(get_the_title($pid)) . '</a>';
|
||||
echo '<div class="aksrt-product-widget__meta">';
|
||||
echo '<span class="aksrt-product-widget__price">¥' . esc_html(number_format_i18n($price, 2)) . '</span>';
|
||||
if (!empty($card['sales'])) {
|
||||
echo '<span class="aksrt-product-widget__sales">' . esc_html((string) $card['sales']) . esc_html__(' 已售', 'aksrt') . '</span>';
|
||||
}
|
||||
echo '</div></div></div>';
|
||||
}
|
||||
wp_reset_postdata();
|
||||
return (string) ob_get_clean();
|
||||
@@ -231,12 +238,25 @@ class WidgetProductList extends \WP_Widget {
|
||||
|
||||
$style_class = 'aksrt-product-widget--' . $style;
|
||||
echo '<div class="aksrt-product-widget ' . esc_attr($style_class) . '" data-aksrt-product-widget data-aksrt-product-config="' . esc_attr(wp_json_encode($cfg)) . '">';
|
||||
// Items sit directly under .ajaxpager so ajax-list inject/append works (zibll product-lists-row).
|
||||
echo '<div class="ajaxpager aksrt-product-widget__grid product-lists-row" data-aksrt-ajaxpager data-aksrt-ajax-url="' . esc_url($ajax_url) . '">';
|
||||
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped — cards escaped upstream
|
||||
echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div class="post_ajax_loader" data-aksrt-ajax-loader data-aksrt-ajax-loader-hide hidden></div>';
|
||||
echo '</div></div>';
|
||||
|
||||
if ($style === 'oneline') {
|
||||
// zibll-style horizontal swiper-scroll (shared slider.js Type A).
|
||||
echo '<div class="swiper-container swiper-scroll aksrt-product-oneline-swiper">';
|
||||
echo '<div class="swiper-wrapper product-lists-row">';
|
||||
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '</div>';
|
||||
echo '<div class="swiper-button-prev" aria-label="' . esc_attr__('上一页', 'aksrt') . '"></div>';
|
||||
echo '<div class="swiper-button-next" aria-label="' . esc_attr__('下一页', 'aksrt') . '"></div>';
|
||||
echo '</div>';
|
||||
} else {
|
||||
// Items sit directly under .ajaxpager so ajax-list inject/append works (zibll product-lists-row).
|
||||
echo '<div class="ajaxpager aksrt-product-widget__grid product-lists-row" data-aksrt-ajaxpager data-aksrt-ajax-url="' . esc_url($ajax_url) . '">';
|
||||
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped — cards escaped upstream
|
||||
echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div class="post_ajax_loader" data-aksrt-ajax-loader data-aksrt-ajax-loader-hide hidden></div>';
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
@@ -67,7 +67,22 @@ class WidgetStats extends \WP_Widget {
|
||||
if ($s['prefix'] !== '') {
|
||||
echo '<span class="aksrt-stats__prefix">' . esc_html($s['prefix']) . '</span>';
|
||||
}
|
||||
echo '<span class="aksrt-stats__number" data-target="' . esc_attr($s['number']) . '">' . esc_html($s['number']) . '</span>';
|
||||
// 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(
|
||||
'<span class="aksrt-stats__number" data-aksrt-countup data-target="%s" data-duration="1600" data-decimals="%d">0</span>',
|
||||
esc_attr((string) $raw_num),
|
||||
(int) $dec
|
||||
);
|
||||
} else {
|
||||
echo '<span class="aksrt-stats__number" data-target="' . esc_attr($s['number']) . '">' . esc_html($s['number']) . '</span>';
|
||||
}
|
||||
if ($s['unit'] !== '') {
|
||||
echo '<span class="aksrt-stats__unit">' . esc_html($s['unit']) . '</span>';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user