feat(widgets): Notice vertical Swiper + search/FAQ CSS depth

Route notice through .new-swiper vertical autoplay; expand color/align
affix tokens; add batch11 styles for search type/cat and FAQ layout.
This commit is contained in:
2026-07-21 08:19:07 +08:00
parent fb4c047780
commit 08ceac888f
2 changed files with 385 additions and 54 deletions
+78 -47
View File
@@ -1,6 +1,6 @@
<?php
/**
* Scrolling notice bar (zibll widget_ui_notice lite).
* Scrolling notice bar (zibll widget_ui_notice / zib_notice → vertical new-swiper).
*
* @package AKSRT
*/
@@ -13,7 +13,8 @@ class NoticeWidget extends \WP_Widget {
public function __construct() {
parent::__construct('aksrt_notice', esc_html__('AKSRT 滚动公告', 'aksrt'), [
'description' => esc_html__('多条公告滚动显示。', 'aksrt'),
'description' => esc_html__('多条公告垂直滚动(共享 Swiper 栈)。', 'aksrt'),
'classname' => 'widget_aksrt_notice',
]);
}
@@ -23,10 +24,12 @@ class NoticeWidget extends \WP_Widget {
return;
}
$color = sanitize_html_class((string) ($instance['color'] ?? 'c-blue'));
$blank = !empty($instance['blank']);
$radius = !empty($instance['radius']);
$color = sanitize_html_class((string) ($instance['color'] ?? 'c-blue'));
$blank = !empty($instance['blank']);
$radius = !empty($instance['radius']);
$interval = max(2, min(15, (int) ($instance['interval'] ?? 4)));
$align = sanitize_html_class((string) ($instance['alignment'] ?? ''));
$in_affix = !empty($instance['in_affix']);
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
@@ -34,48 +37,47 @@ class NoticeWidget extends \WP_Widget {
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
$uid = 'aksrt-notice-' . esc_attr($this->id);
$class = 'aksrt-scroll-notice color-' . $color . ($radius ? ' is-radius' : '');
echo '<div class="' . esc_attr($class) . '" id="' . $uid . '" data-interval="' . esc_attr((string) ($interval * 1000)) . '">';
echo '<div class="aksrt-scroll-notice__icon"><i class="fas fa-bullhorn" aria-hidden="true"></i></div>';
echo '<div class="aksrt-scroll-notice__viewport">';
foreach ($items as $i => $item) {
$active = $i === 0 ? ' is-active' : '';
$wrap_cls = 'aksrt-scroll-notice swiper-bulletin color-' . $color;
if ($radius) {
$wrap_cls .= ' is-radius radius';
}
if ($align !== '') {
$wrap_cls .= ' ' . $align;
}
if ($in_affix) {
$wrap_cls .= ' is-affix';
}
$attr = $in_affix ? ' data-affix="true"' : '';
echo '<div class="' . esc_attr($wrap_cls) . '"' . $attr . '>';
echo '<div class="aksrt-scroll-notice__icon bulletin-icon"><i class="fas fa-bullhorn" aria-hidden="true"></i></div>';
// Prefer shared vertical new-swiper (zib_notice parity) via slider.js Type C.
echo '<div class="new-swiper aksrt-notice-swiper" data-direction="vertical" data-loop data-autoplay data-interval="' . esc_attr((string) ($interval * 1000)) . '">';
echo '<div class="swiper-wrapper">';
foreach ($items as $item) {
$inner = '';
if ($item['icon'] !== '') {
$inner .= '<i class="' . esc_attr($item['icon']) . '" aria-hidden="true"></i> ';
$icon = $item['icon'];
if (strpos($icon, 'fa-') === 0 && strpos($icon, ' ') === false) {
$icon = 'fa ' . $icon;
}
$inner .= '<div class="relative bulletin-icon mr6"><i class="abs-center ' . esc_attr($icon) . '" aria-hidden="true"></i></div>';
}
$inner .= esc_html($item['title']);
echo '<div class="aksrt-scroll-notice__item' . esc_attr($active) . '">';
echo '<div class="swiper-slide notice-slide">';
if ($item['href'] !== '') {
$tgt = $blank ? ' target="_blank" rel="noopener noreferrer"' : '';
echo '<a href="' . esc_url($item['href']) . '"' . $tgt . '>' . $inner . '</a>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<a class="text-ellipsis"' .
($blank ? ' target="_blank" rel="noopener noreferrer"' : '') .
' href="' . esc_url($item['href']) . '">' . $inner . '</a>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
} else {
echo '<span>' . $inner . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<span class="text-ellipsis">' . $inner . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
echo '</div>';
}
echo '</div></div>';
if (count($items) > 1) {
?>
<script>
(function(){
var root=document.getElementById(<?php echo wp_json_encode($uid); ?>);
if(!root||root._aksrtNotice)return; root._aksrtNotice=1;
var items=[].slice.call(root.querySelectorAll('.aksrt-scroll-notice__item'));
var i=0, ms=parseInt(root.getAttribute('data-interval')||'4000',10)||4000;
setInterval(function(){
if(items.length<2)return;
items[i].classList.remove('is-active');
i=(i+1)%items.length;
items[i].classList.add('is-active');
}, ms);
})();
</script>
<?php
}
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
@@ -86,7 +88,6 @@ class NoticeWidget extends \WP_Widget {
private function normalize_items(array $instance): array {
$raw = $instance['items'] ?? $instance['img_ids'] ?? null;
if ($raw === null && !empty($instance['content'])) {
// Legacy single content.
return [[
'title' => wp_strip_all_tags((string) $instance['content']),
'icon' => sanitize_text_field((string) ($instance['icon'] ?? 'fas fa-bullhorn')),
@@ -130,6 +131,24 @@ class NoticeWidget extends \WP_Widget {
];
}
$json = wp_json_encode($items, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$colors = [
'c-blue' => __('透明蓝', 'aksrt'),
'c-green' => __('透明绿', 'aksrt'),
'c-yellow' => __('透明黄', 'aksrt'),
'c-red' => __('透明粉红', 'aksrt'),
'c-purple' => __('透明紫', 'aksrt'),
'c-blue-2' => __('透明深蓝', 'aksrt'),
'c-green-2' => __('透明墨绿', 'aksrt'),
'c-yellow-2' => __('透明橘黄', 'aksrt'),
'c-red-2' => __('透明红', 'aksrt'),
'c-purple-2' => __('透明深紫', 'aksrt'),
'b-theme' => __('主题色', 'aksrt'),
'b-red' => __('红色', 'aksrt'),
'b-yellow' => __('黄色', 'aksrt'),
'b-blue' => __('蓝色', 'aksrt'),
'b-green' => __('绿色', 'aksrt'),
'b-purple' => __('紫色', 'aksrt'),
];
?>
<p>
<label><?php esc_html_e('标题(可选)', 'aksrt'); ?>
@@ -147,29 +166,41 @@ class NoticeWidget extends \WP_Widget {
</label>
</p>
<p>
<label><?php esc_html_e('主题色 class', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('color')); ?>">
<?php foreach (['c-blue' => '蓝', 'c-green' => '绿', 'c-yellow' => '黄', 'c-red' => '红', 'c-purple' => '紫'] as $k => $label) : ?>
<label><?php esc_html_e('主题色彩', 'aksrt'); ?>
<select class="widefat" name="<?php echo esc_attr($this->get_field_name('color')); ?>">
<?php foreach ($colors as $k => $label) : ?>
<option value="<?php echo esc_attr($k); ?>" <?php selected(($instance['color'] ?? 'c-blue'), $k); ?>><?php echo esc_html($label); ?></option>
<?php endforeach; ?>
</select>
</label>
</p>
<p>
<label><?php esc_html_e('对齐', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('alignment')); ?>">
<option value="" <?php selected(($instance['alignment'] ?? ''), ''); ?>><?php esc_html_e('靠左', 'aksrt'); ?></option>
<option value="text-center" <?php selected(($instance['alignment'] ?? ''), 'text-center'); ?>><?php esc_html_e('居中', 'aksrt'); ?></option>
<option value="text-right" <?php selected(($instance['alignment'] ?? ''), 'text-right'); ?>><?php esc_html_e('靠右', 'aksrt'); ?></option>
</select>
</label>
</p>
<p>
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('blank')); ?>" value="1" <?php checked(!empty($instance['blank'])); ?>> <?php esc_html_e('链接新窗口', 'aksrt'); ?></label><br>
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('radius')); ?>" value="1" <?php checked(!empty($instance['radius'])); ?>> <?php esc_html_e('两端圆形', 'aksrt'); ?></label>
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('radius')); ?>" value="1" <?php checked(!empty($instance['radius'])); ?>> <?php esc_html_e('两端圆形', 'aksrt'); ?></label><br>
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('in_affix')); ?>" value="1" <?php checked(!empty($instance['in_affix'])); ?>> <?php esc_html_e('侧栏随动', 'aksrt'); ?></label>
</p>
<?php
}
public function update($new_instance, $old_instance): array {
return [
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'items' => $this->normalize_items(['items' => $new_instance['items'] ?? []]),
'interval' => max(2, min(15, (int) ($new_instance['interval'] ?? 4))),
'color' => sanitize_html_class((string) ($new_instance['color'] ?? 'c-blue')),
'blank' => !empty($new_instance['blank']) ? 1 : 0,
'radius' => !empty($new_instance['radius']) ? 1 : 0,
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'items' => $this->normalize_items(['items' => $new_instance['items'] ?? []]),
'interval' => max(2, min(15, (int) ($new_instance['interval'] ?? 4))),
'color' => sanitize_html_class((string) ($new_instance['color'] ?? 'c-blue')),
'alignment' => sanitize_html_class((string) ($new_instance['alignment'] ?? '')),
'blank' => !empty($new_instance['blank']) ? 1 : 0,
'radius' => !empty($new_instance['radius']) ? 1 : 0,
'in_affix' => !empty($new_instance['in_affix']) ? 1 : 0,
];
}
}