Add sidebar affix (data-affix) to ranking, user/author cards, main/hot/ paid/forum lists, comments, tag cloud, categories and text title with shared sticky CSS.
213 lines
10 KiB
PHP
213 lines
10 KiB
PHP
<?php
|
|
/**
|
|
* Text title / section heading (zibll zib_widget_ui_text_title).
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
namespace AKSRT\Widgets;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
class WidgetTextTitle extends \WP_Widget {
|
|
|
|
public function __construct() {
|
|
parent::__construct(
|
|
'aksrt_text_title',
|
|
esc_html__('AKSRT 文字标题', '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'] ?? ''));
|
|
if ($title === '' && $desc === '') {
|
|
if (current_user_can('manage_options')) {
|
|
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
echo function_exists('aksrt_get_widget_null')
|
|
? aksrt_get_widget_null(__('请填写标题或描述', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
: '<p class="widget-empty">' . esc_html__('请填写标题或描述', 'aksrt') . '</p>';
|
|
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
}
|
|
return;
|
|
}
|
|
|
|
$align = sanitize_key((string) ($instance['align'] ?? 'center'));
|
|
if (!in_array($align, ['left', 'center', 'right'], true)) {
|
|
$align = 'center';
|
|
}
|
|
$icon_left = sanitize_text_field((string) ($instance['title_icon_left'] ?? ''));
|
|
$icon_right = sanitize_text_field((string) ($instance['title_icon_right'] ?? ''));
|
|
$title_size = max(12, min(48, (int) ($instance['title_size'] ?? 22)));
|
|
$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
|
|
|
|
$style = sprintf(
|
|
'--aksrt-tt-title-size:%dpx;--aksrt-tt-desc-size:%dpx;%s%s',
|
|
$title_size,
|
|
$desc_size,
|
|
$title_color !== '' ? '--aksrt-tt-title-color:' . $title_color . ';' : '',
|
|
$desc_color !== '' ? '--aksrt-tt-desc-color:' . $desc_color . ';' : ''
|
|
);
|
|
|
|
$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;
|
|
}
|
|
foreach ($chars as $ch) {
|
|
$pieces[] = $ch;
|
|
}
|
|
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 !== '') {
|
|
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>';
|
|
}
|
|
}
|
|
|
|
$in_affix = !empty($instance['in_affix']);
|
|
$box = 'aksrt-text-title text-title align-' . esc_attr($align) . ($in_affix ? ' is-affix' : '');
|
|
echo '<div class="' . esc_attr($box) . '" style="' . esc_attr($style) . '"' . ($in_affix ? ' data-affix="true"' : '') . '>';
|
|
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>
|
|
<label><?php esc_html_e('标题', 'aksrt'); ?>
|
|
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
|
</label>
|
|
</p>
|
|
<p>
|
|
<label><?php esc_html_e('副标题 / 描述', 'aksrt'); ?>
|
|
<textarea class="widefat" rows="2" name="<?php echo esc_attr($this->get_field_name('desc')); ?>"><?php echo esc_textarea((string) ($instance['desc'] ?? '')); ?></textarea>
|
|
</label>
|
|
</p>
|
|
<p>
|
|
<label><?php esc_html_e('对齐', 'aksrt'); ?>
|
|
<select name="<?php echo esc_attr($this->get_field_name('align')); ?>">
|
|
<option value="center" <?php selected(($instance['align'] ?? 'center'), 'center'); ?>><?php esc_html_e('居中', 'aksrt'); ?></option>
|
|
<option value="left" <?php selected(($instance['align'] ?? ''), 'left'); ?>><?php esc_html_e('左', 'aksrt'); ?></option>
|
|
<option value="right" <?php selected(($instance['align'] ?? ''), 'right'); ?>><?php esc_html_e('右', 'aksrt'); ?></option>
|
|
</select>
|
|
</label>
|
|
</p>
|
|
<p>
|
|
<label><?php esc_html_e('左图标 class', 'aksrt'); ?>
|
|
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title_icon_left')); ?>" value="<?php echo esc_attr((string) ($instance['title_icon_left'] ?? '')); ?>" placeholder="fas fa-star">
|
|
</label>
|
|
</p>
|
|
<p>
|
|
<label><?php esc_html_e('右图标 class', 'aksrt'); ?>
|
|
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title_icon_right')); ?>" value="<?php echo esc_attr((string) ($instance['title_icon_right'] ?? '')); ?>">
|
|
</label>
|
|
</p>
|
|
<p>
|
|
<label><?php esc_html_e('标题字号', 'aksrt'); ?>
|
|
<input class="tiny-text" type="number" min="12" max="48" name="<?php echo esc_attr($this->get_field_name('title_size')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['title_size'] ?? 22))); ?>">
|
|
</label>
|
|
<label><?php esc_html_e('描述字号', 'aksrt'); ?>
|
|
<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'] ?? '')); ?>">
|
|
</label>
|
|
</p>
|
|
<p>
|
|
<label><?php esc_html_e('描述色 #hex', 'aksrt'); ?>
|
|
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('desc_color')); ?>" value="<?php echo esc_attr((string) ($instance['desc_color'] ?? '')); ?>">
|
|
</label>
|
|
</p>
|
|
<p>
|
|
<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
|
|
}
|
|
|
|
/**
|
|
* @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'] ?? '')) ?: '',
|
|
'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))),
|
|
];
|
|
}
|
|
}
|