feat(widgets): buttons/text-title/yiyan depth + batch15 CSS
Buttons gain zibll but/hollow/color + obs animation; text-title supports per-char entrance; yiyan wraps main-bg shell with affix/animate options.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Text title / section heading (zibll zib_widget_ui_text_title lite).
|
||||
* Text title / section heading (zibll zib_widget_ui_text_title).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
@@ -16,12 +16,16 @@ class WidgetTextTitle extends \WP_Widget {
|
||||
'aksrt_text_title',
|
||||
esc_html__('AKSRT 文字标题', 'aksrt'),
|
||||
[
|
||||
'description' => esc_html__('自定义标题 + 副标题区块,用于模块分隔。', 'aksrt'),
|
||||
'description' => esc_html__('自定义标题 + 副标题区块,支持逐字入场动画。', 'aksrt'),
|
||||
'classname' => 'widget_aksrt_text_title',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $args
|
||||
* @param array<string,mixed> $instance
|
||||
*/
|
||||
public function widget($args, $instance): void {
|
||||
$title = trim((string) ($instance['title'] ?? ''));
|
||||
$desc = trim((string) ($instance['desc'] ?? ''));
|
||||
@@ -39,6 +43,9 @@ class WidgetTextTitle extends \WP_Widget {
|
||||
$desc_size = max(11, min(24, (int) ($instance['desc_size'] ?? 14)));
|
||||
$title_color = sanitize_hex_color((string) ($instance['title_color'] ?? '')) ?: '';
|
||||
$desc_color = sanitize_hex_color((string) ($instance['desc_color'] ?? '')) ?: '';
|
||||
$anim = sanitize_key((string) ($instance['obs_animation'] ?? ''));
|
||||
$anim_repeat = !empty($instance['animation_repeat']);
|
||||
$icon_width = max(0, min(64, (int) ($instance['title_icon_width'] ?? 0)));
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
@@ -50,26 +57,63 @@ class WidgetTextTitle extends \WP_Widget {
|
||||
$desc_color !== '' ? '--aksrt-tt-desc-color:' . $desc_color . ';' : ''
|
||||
);
|
||||
|
||||
echo '<div class="aksrt-text-title align-' . esc_attr($align) . '" style="' . esc_attr($style) . '">';
|
||||
if ($title !== '') {
|
||||
echo '<div class="aksrt-text-title__main">';
|
||||
if ($icon_left !== '') {
|
||||
echo '<span class="aksrt-text-title__icon"><i class="' . esc_attr($icon_left) . '" aria-hidden="true"></i></span>';
|
||||
$icon_w_attr = $icon_width > 0 ? ' style="--icon-width:' . (int) $icon_width . 'px;"' : '';
|
||||
$left_html = $icon_left !== ''
|
||||
? '<span class="text-title-icon aksrt-text-title__icon mr6"' . $icon_w_attr . '><i class="' . esc_attr($icon_left) . '" aria-hidden="true"></i></span>'
|
||||
: '';
|
||||
$right_html = $icon_right !== ''
|
||||
? '<span class="text-title-icon aksrt-text-title__icon ml6"' . $icon_w_attr . '><i class="' . esc_attr($icon_right) . '" aria-hidden="true"></i></span>'
|
||||
: '';
|
||||
|
||||
$title_html = '';
|
||||
if ($title !== '' && $anim !== '' && function_exists('aksrt_obs_animate_attrs')) {
|
||||
// Split title into per-char spans with staggered delay (zibll).
|
||||
$chars = preg_split('//u', $title, -1, PREG_SPLIT_NO_EMPTY) ?: [];
|
||||
$pieces = [];
|
||||
if ($left_html !== '') {
|
||||
$pieces[] = $left_html;
|
||||
}
|
||||
echo '<span class="aksrt-text-title__text">' . esc_html($title) . '</span>';
|
||||
if ($icon_right !== '') {
|
||||
echo '<span class="aksrt-text-title__icon"><i class="' . esc_attr($icon_right) . '" aria-hidden="true"></i></span>';
|
||||
foreach ($chars as $ch) {
|
||||
$pieces[] = $ch;
|
||||
}
|
||||
echo '</div>';
|
||||
if ($right_html !== '') {
|
||||
$pieces[] = $right_html;
|
||||
}
|
||||
foreach ($pieces as $i => $piece) {
|
||||
$pack = aksrt_obs_animate_attrs($anim, $anim_repeat, $i * 0.05);
|
||||
$is_html = str_starts_with((string) $piece, '<');
|
||||
$inner = $is_html ? $piece : esc_html((string) $piece);
|
||||
$title_html .= '<span class="' . esc_attr(trim($pack['class'])) . '"' . $pack['attr']
|
||||
. ' style="--delay:' . esc_attr((string) ($i * 0.05)) . 's;">' . $inner . '</span>';
|
||||
}
|
||||
} elseif ($title !== '') {
|
||||
$title_html = $left_html . esc_html($title) . $right_html;
|
||||
}
|
||||
|
||||
$desc_html = '';
|
||||
if ($desc !== '') {
|
||||
echo '<div class="aksrt-text-title__desc">' . esc_html($desc) . '</div>';
|
||||
if ($anim !== '' && function_exists('aksrt_obs_animate_attrs')) {
|
||||
$pack = aksrt_obs_animate_attrs($anim, $anim_repeat, 0.6);
|
||||
$desc_html = '<div class="aksrt-text-title__desc' . esc_attr($pack['class']) . '"' . $pack['attr']
|
||||
. ' style="--delay:.6s;">' . esc_html($desc) . '</div>';
|
||||
} else {
|
||||
$desc_html = '<div class="aksrt-text-title__desc">' . esc_html($desc) . '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '<div class="aksrt-text-title text-title align-' . esc_attr($align) . '" style="' . esc_attr($style) . '">';
|
||||
if ($title_html !== '') {
|
||||
echo '<div class="aksrt-text-title__main">' . $title_html . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo $desc_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '</div>';
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $instance
|
||||
*/
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
@@ -109,6 +153,16 @@ class WidgetTextTitle extends \WP_Widget {
|
||||
<input class="tiny-text" type="number" min="11" max="24" name="<?php echo esc_attr($this->get_field_name('desc_size')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['desc_size'] ?? 14))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('入场动画', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('obs_animation')); ?>">
|
||||
<option value="" <?php selected(($instance['obs_animation'] ?? ''), ''); ?>><?php esc_html_e('无', 'aksrt'); ?></option>
|
||||
<option value="fade" <?php selected(($instance['obs_animation'] ?? ''), 'fade'); ?>><?php esc_html_e('淡入', 'aksrt'); ?></option>
|
||||
<option value="slideup" <?php selected(($instance['obs_animation'] ?? ''), 'slideup'); ?>><?php esc_html_e('上滑', 'aksrt'); ?></option>
|
||||
<option value="zoomin" <?php selected(($instance['obs_animation'] ?? ''), 'zoomin'); ?>><?php esc_html_e('放大', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题色 #hex', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title_color')); ?>" value="<?php echo esc_attr((string) ($instance['title_color'] ?? '')); ?>">
|
||||
@@ -122,17 +176,25 @@ class WidgetTextTitle extends \WP_Widget {
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $new_instance
|
||||
* @param array<string,mixed> $old_instance
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'desc' => sanitize_text_field((string) ($new_instance['desc'] ?? '')),
|
||||
'align' => in_array(($new_instance['align'] ?? ''), ['left', 'center', 'right'], true) ? $new_instance['align'] : 'center',
|
||||
'title_icon_left' => sanitize_text_field((string) ($new_instance['title_icon_left'] ?? '')),
|
||||
'title_icon_right' => sanitize_text_field((string) ($new_instance['title_icon_right'] ?? '')),
|
||||
'title_size' => max(12, min(48, (int) ($new_instance['title_size'] ?? 22))),
|
||||
'desc_size' => max(11, min(24, (int) ($new_instance['desc_size'] ?? 14))),
|
||||
'title_color' => sanitize_hex_color((string) ($new_instance['title_color'] ?? '')) ?: '',
|
||||
'desc_color' => sanitize_hex_color((string) ($new_instance['desc_color'] ?? '')) ?: '',
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'desc' => sanitize_text_field((string) ($new_instance['desc'] ?? '')),
|
||||
'align' => in_array(($new_instance['align'] ?? ''), ['left', 'center', 'right'], true) ? $new_instance['align'] : 'center',
|
||||
'title_icon_left' => sanitize_text_field((string) ($new_instance['title_icon_left'] ?? '')),
|
||||
'title_icon_right' => sanitize_text_field((string) ($new_instance['title_icon_right'] ?? '')),
|
||||
'title_size' => max(12, min(48, (int) ($new_instance['title_size'] ?? 22))),
|
||||
'desc_size' => max(11, min(24, (int) ($new_instance['desc_size'] ?? 14))),
|
||||
'title_color' => sanitize_hex_color((string) ($new_instance['title_color'] ?? '')) ?: '',
|
||||
'desc_color' => sanitize_hex_color((string) ($new_instance['desc_color'] ?? '')) ?: '',
|
||||
'obs_animation' => sanitize_key((string) ($new_instance['obs_animation'] ?? '')),
|
||||
'animation_repeat' => !empty($new_instance['animation_repeat']) ? 1 : 0,
|
||||
'title_icon_width' => max(0, min(64, (int) ($new_instance['title_icon_width'] ?? 0))),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user