diff --git a/assets/css/frontend/widget-batch3c.css b/assets/css/frontend/widget-batch3c.css new file mode 100644 index 00000000..4614fd89 --- /dev/null +++ b/assets/css/frontend/widget-batch3c.css @@ -0,0 +1,110 @@ +/** + * Batch3c: reviews + highlights. + */ + +.aksrt-reviews { + margin-bottom: 16px; + --aksrt-rev-pc: 3; + --aksrt-rev-m: 1.2; +} +.aksrt-reviews__track { + display: grid; + grid-auto-flow: column; + grid-auto-columns: calc((100% - (var(--aksrt-rev-pc) - 1) * 12px) / var(--aksrt-rev-pc)); + gap: 12px; + overflow-x: auto; + scroll-snap-type: x mandatory; + padding-bottom: 6px; + -webkit-overflow-scrolling: touch; +} +@media (max-width: 767.98px) { + .aksrt-reviews__track { + grid-auto-columns: calc((100% - (var(--aksrt-rev-m) - 1) * 12px) / var(--aksrt-rev-m)); + } +} +.aksrt-reviews__slide { scroll-snap-align: start; min-width: 0; } +.aksrt-reviews__card { + position: relative; + border: 1px solid var(--color-line, #e5e7eb); + border-radius: 12px; + padding: 16px; + background: var(--surface-1, #fff); + min-height: 100%; +} +.aksrt-reviews__head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; } +.aksrt-reviews__avatar { + width: 44px; + height: 44px; + border-radius: 50%; + object-fit: cover; + background: var(--surface-2, #eee); + display: inline-flex; + align-items: center; + justify-content: center; + color: #999; + flex-shrink: 0; +} +.aksrt-reviews__name { font-weight: 700; font-size: 14px; } +.aksrt-reviews__name a { color: inherit; text-decoration: none; } +.aksrt-reviews__role { font-size: 12px; color: var(--muted-2-color, #888); } +.aksrt-reviews__stars { margin-bottom: 8px; font-size: 12px; } +.aksrt-reviews__stars .is-on { color: #f5a623; } +.aksrt-reviews__stars .is-off { color: #ddd; } +.aksrt-reviews__content { + font-size: 13px; + line-height: 1.55; + color: var(--color-ink-2, #444); + margin: 0; +} +.aksrt-reviews__quote { + position: absolute; + right: 14px; + bottom: 10px; + opacity: .12; + font-size: 28px; +} + +.aksrt-highlights { margin-bottom: 16px; display: flex; flex-direction: column; gap: 12px; } +.aksrt-highlights__row { + display: grid; + gap: 12px; +} +.aksrt-highlights__row.is-large { grid-template-columns: 1fr; } +.aksrt-highlights__row.is-medium { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.aksrt-highlights__row.is-small { grid-template-columns: repeat(3, minmax(0, 1fr)); } +@media (max-width: 767.98px) { + .aksrt-highlights__row.is-medium, + .aksrt-highlights__row.is-small { grid-template-columns: 1fr; } +} +.aksrt-hl-card { + display: flex; + gap: 12px; + border-radius: 12px; + border: 1px solid var(--color-line, #e5e7eb); + background: var(--surface-1, #fff); + padding: 14px; + text-decoration: none; + color: inherit; + overflow: hidden; + min-height: 100%; +} +.aksrt-hl-card.color-blue { --hl: #3b82f6; } +.aksrt-hl-card.color-pink { --hl: #ec4899; } +.aksrt-hl-card.color-purple { --hl: #a855f7; } +.aksrt-hl-card.color-green { --hl: #22c55e; } +.aksrt-hl-card.color-orange { --hl: #f97316; } +.aksrt-hl-card.color-cyan { --hl: #06b6d4; } +.aksrt-hl-card.size-large { min-height: 140px; } +.aksrt-hl-card__media { + width: 96px; + flex-shrink: 0; + border-radius: 10px; + overflow: hidden; + background: var(--surface-2, #f3f4f6); +} +.aksrt-hl-card.size-large .aksrt-hl-card__media { width: 160px; } +.aksrt-hl-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; min-height: 80px; } +.aksrt-hl-card__body { min-width: 0; flex: 1; display: flex; flex-direction: column; } +.aksrt-hl-card__icon { color: var(--hl, #3b82f6); font-size: 22px; margin-bottom: 8px; } +.aksrt-hl-card__title { font-weight: 700; font-size: 15px; margin-bottom: 4px; } +.aksrt-hl-card__desc { font-size: 12px; color: var(--muted-2-color, #888); line-height: 1.5; } diff --git a/assets/css/frontend/widgets.css b/assets/css/frontend/widgets.css index 97ccca5b..6661bdc1 100644 --- a/assets/css/frontend/widgets.css +++ b/assets/css/frontend/widgets.css @@ -4,3 +4,4 @@ @import url("widgets/part-4.css"); @import url("widget-slider.css"); @import url("widget-batch3.css"); +@import url("widget-batch3c.css"); diff --git a/inc/modules/widgets-register.php b/inc/modules/widgets-register.php index 885cdc44..2fa14103 100644 --- a/inc/modules/widgets-register.php +++ b/inc/modules/widgets-register.php @@ -66,6 +66,8 @@ function aksrt_register_widgets() { register_widget('\AKSRT\Widgets\WidgetPricingPlans'); register_widget('\AKSRT\Widgets\WidgetFaq'); register_widget('\AKSRT\Widgets\WidgetStats'); + register_widget('\AKSRT\Widgets\WidgetReviews'); + register_widget('\AKSRT\Widgets\WidgetHighlights'); // Forum widgets diff --git a/src/AKSRT/Widgets/WidgetForumBoardList.php b/src/AKSRT/Widgets/WidgetForumBoardList.php index 5ee4dc9d..5cd9d5d0 100644 --- a/src/AKSRT/Widgets/WidgetForumBoardList.php +++ b/src/AKSRT/Widgets/WidgetForumBoardList.php @@ -26,31 +26,60 @@ class WidgetForumBoardList extends \WP_Widget { echo $args['before_widget']; echo $args['before_title'] . esc_html($title) . $args['after_title']; - $boards = get_terms([ - 'taxonomy' => 'aksrt_forum_board', - 'hide_empty' => true, - 'orderby' => 'meta_value_num', - 'meta_key' => '_aksrt_sort_order', - 'order' => 'ASC', - ]); - - if (!is_wp_error($boards) && !empty($boards)) { - echo '
'; + } + } + if (!$rendered) { + $boards = get_terms([ + 'taxonomy' => 'aksrt_forum_board', + 'hide_empty' => true, + 'orderby' => 'meta_value_num', + 'meta_key' => '_aksrt_sort_order', + 'order' => 'ASC', + ]); + if (!is_wp_error($boards) && !empty($boards)) { + echo ''; + } else { + echo ''; } - echo ''; - } else { - echo ''; } echo $args['after_widget']; diff --git a/src/AKSRT/Widgets/WidgetHighlights.php b/src/AKSRT/Widgets/WidgetHighlights.php new file mode 100644 index 00000000..f9f1d12f --- /dev/null +++ b/src/AKSRT/Widgets/WidgetHighlights.php @@ -0,0 +1,177 @@ + esc_html__('大中小尺寸亮点/卖点卡片栅格。', 'aksrt'), + 'classname' => 'widget_aksrt_highlights', + ] + ); + } + + public function widget($args, $instance): void { + $cards = $this->normalize($instance['cards'] ?? []); + if (!$cards) { + return; + } + $go_link = !empty($instance['go_link']); + + echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base); + if ($title !== '') { + echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + + $large = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'large')); + $medium = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'medium')); + $small = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'small')); + // Fallback: if no size tags, treat all as medium. + if (!$large && !$medium && !$small) { + $medium = $cards; + } + + echo '+ +
++ + +
++ +
+ sanitize_text_field((string) ($new_instance['title'] ?? '')), + 'cards' => $this->normalize($new_instance['cards'] ?? []), + 'go_link' => !empty($new_instance['go_link']) ? 1 : 0, + ]; + } +} diff --git a/src/AKSRT/Widgets/WidgetReviews.php b/src/AKSRT/Widgets/WidgetReviews.php new file mode 100644 index 00000000..370babb5 --- /dev/null +++ b/src/AKSRT/Widgets/WidgetReviews.php @@ -0,0 +1,149 @@ + esc_html__('虚拟用户评价卡片横向滚动。', 'aksrt'), + 'classname' => 'widget_aksrt_reviews', + ] + ); + } + + public function widget($args, $instance): void { + $reviews = $this->normalize($instance['reviews'] ?? []); + if (!$reviews) { + return; + } + $pc = max(1, min(6, (float) ($instance['desktop_per_view'] ?? 3))); + $m = max(1, min(3, (float) ($instance['mobile_per_view'] ?? 1.2))); + + echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base); + if ($title !== '') { + echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + + $style = sprintf('--aksrt-rev-pc:%s;--aksrt-rev-m:%s;', rtrim(rtrim(number_format($pc, 2, '.', ''), '0'), '.'), rtrim(rtrim(number_format($m, 2, '.', ''), '0'), '.')); + echo '+ +
++ +
++ + +
+ sanitize_text_field((string) ($new_instance['title'] ?? '')), + 'reviews' => $this->normalize($new_instance['reviews'] ?? []), + 'desktop_per_view' => max(1, min(6, (float) ($new_instance['desktop_per_view'] ?? 3))), + 'mobile_per_view' => max(1, min(3, (float) ($new_instance['mobile_per_view'] ?? 1.2))), + ]; + } +}