Files
wordpress-theme-aksrt/inc/helpers/aksrt-icon-picker.php
T
kate522 f629a4f373 feat(icons): add the FA5 catalog, REST endpoint and unified icon helpers
Mirror the reference theme's universal picker on FA5: a generated full
catalog of the bundled FA5 Free 5.15.4 fonts (src/Icons/fa5-icons.php,
generated from the shipped CSS + SVG fonts), a zibsvg group parsed from
the runtime sprite so it cannot drift, and GET /aksrt/v1/icons/catalog.

Shared admin pieces: aksrt_icon_markup()/aksrt_sanitize_icon_value()
with an SVG allowlist, the picker field/modal assets, and one canonical
aksrt-font-awesome handle registered through aksrt_enqueue_fontawesome().
2026-09-06 12:59:03 +08:00

136 lines
5.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* AKSRT Theme — Universal icon picker (admin side)
*
* Server-side assets and modal markup for the shared FA5 + built-in SVG +
* custom SVG picker. Field markup itself comes from aksrt_icon_picker_field().
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
if (!function_exists('aksrt_icon_picker_assets')) :
/**
* Enqueue the universal icon picker on any admin screen that needs it.
*
* Safe to call multiple times; assets and the footer modal are wired once.
* FA5 CSS, the frontend SVG sprite (defines window.aksrt_svgs and injects the
* symbol sheet) and the picker script/CSS are all included.
*
* @param array $deps Extra script dependencies for the picker script.
*/
function aksrt_icon_picker_assets(array $deps = []): void {
static $done = false;
if ($done) {
return;
}
$done = true;
$css_mtime = (string) filemtime(AKSRT_DIR . '/assets/css/admin-icon-picker.css');
$js_mtime = (string) filemtime(AKSRT_DIR . '/assets/js/admin-icon-picker.js');
aksrt_enqueue_fontawesome();
wp_enqueue_style('aksrt-icon-picker', AKSRT_URI . '/assets/css/admin-icon-picker.css', ['aksrt-font-awesome'], $css_mtime);
wp_enqueue_script('aksrt-svg-sprite', AKSRT_URI . '/assets/js/runtime/svg-icon.js', ['jquery'], $js_mtime, true);
wp_enqueue_script('aksrt-icon-picker', AKSRT_URI . '/assets/js/admin-icon-picker.js', array_merge(['jquery', 'aksrt-svg-sprite'], $deps), $js_mtime, true);
wp_localize_script('aksrt-icon-picker', 'aksrtIconPicker', [
'restUrl' => esc_url_raw(rest_url('aksrt/v1/icons/catalog')),
'nonce' => wp_create_nonce('wp_rest'),
'i18n' => [
'title' => __('选择图标', 'aksrt'),
'search' => __('搜索图标…', 'aksrt'),
'empty' => __('未找到匹配图标', 'aksrt'),
'customTitle' => __('粘贴 SVG 图标代码', 'aksrt'),
'customDesc' => __('粘贴 <svg viewBox="0 0 1024 1024">…</svg> 格式的代码,确认后以内联方式保存到当前字段。', 'aksrt'),
'customSubmit' => __('确认插入', 'aksrt'),
'customEmpty' => __('未检测到有效的 SVG 代码。', 'aksrt'),
'loadError' => __('图标目录加载失败,请刷新重试。', 'aksrt'),
'clear' => __('清除', 'aksrt'),
],
]);
add_action('admin_footer', 'aksrt_icon_picker_modal', 20);
add_action('customize_controls_print_footer_scripts', 'aksrt_icon_picker_modal', 20);
}
endif;
if (!function_exists('aksrt_icon_picker_modal')) :
/**
* Print the shared picker modal once per admin page.
*/
function aksrt_icon_picker_modal(): void {
static $printed = false;
if ($printed) {
return;
}
$printed = true;
?>
<div id="aksrt-modal-icon" class="aksrt-icon-modal hidden">
<div class="aksrt-icon-modal__overlay" data-aksrt-icon-close></div>
<div class="aksrt-icon-modal__inner" role="dialog" aria-modal="true" aria-label="<?php esc_attr_e('选择图标', 'aksrt'); ?>">
<div class="aksrt-icon-modal__header">
<strong><?php esc_html_e('选择图标', 'aksrt'); ?></strong>
<button type="button" class="button-link aksrt-icon-modal__close" data-aksrt-icon-close aria-label="<?php esc_attr_e('关闭', 'aksrt'); ?>">×</button>
</div>
<div class="aksrt-icon-modal__toolbar">
<input type="search" class="aksrt-icon-modal__search regular-text" placeholder="<?php esc_attr_e('搜索图标…', 'aksrt'); ?>">
<div class="aksrt-icon-modal__tabs" role="tablist"></div>
</div>
<div class="aksrt-icon-modal__body">
<div class="aksrt-icon-modal__loading" hidden><span class="spinner is-active"></span></div>
<div class="aksrt-icon-modal__error" hidden></div>
<div class="aksrt-icon-modal__grids"></div>
<div class="aksrt-icon-modal__custom" hidden>
<p class="description"><?php esc_html_e('粘贴 SVG 图标代码', 'aksrt'); ?></p>
<textarea class="large-text code" rows="5" placeholder='&lt;svg viewBox="0 0 1024 1024"&gt;&lt;path d="…"&gt;&lt;/path&gt;&lt;/svg&gt;'></textarea>
<div class="aksrt-icon-modal__custom-actions">
<span class="aksrt-icon-modal__custom-preview" aria-hidden="true"></span>
<button type="button" class="button button-primary"><?php esc_html_e('确认插入', 'aksrt'); ?></button>
</div>
<div class="aksrt-icon-modal__grid aksrt-icon-modal__grid--session"></div>
</div>
</div>
</div>
</div>
<?php
}
endif;
if (!function_exists('aksrt_icon_picker_field')) :
/**
* Render a universal icon-picker field (preview + choose/clear + text input).
*
* The text input stays visible so raw class strings remain editable and
* dependency evaluation (which reads the first input in the field) keeps
* working; the picker simply fills it.
*
* @param string $name Input name.
* @param string $id Input id.
* @param string $value Current value.
* @param array $args {placeholder?: string, class?: string}
* @return string
*/
function aksrt_icon_picker_field(string $name, string $id, string $value, array $args = []): string {
$value = (string) $value;
$placeholder = (string) ($args['placeholder'] ?? 'fa fas fa-star');
$wrap_class = trim('aksrt-icon-picker ' . (string) ($args['class'] ?? ''));
$has_value = $value !== '';
ob_start();
?>
<div class="<?php echo esc_attr($wrap_class); ?>" data-aksrt-icon-picker>
<span class="aksrt-icon-picker__preview<?php echo $has_value ? '' : ' hidden'; ?>"><?php echo aksrt_icon_markup($value); // pre-escaped ?></span>
<span class="aksrt-icon-picker__actions">
<button type="button" class="button aksrt-icon-picker__choose"><?php esc_html_e('选择图标', 'aksrt'); ?></button>
<button type="button" class="button-link-delete aksrt-icon-picker__remove<?php echo $has_value ? '' : ' hidden'; ?>"><?php esc_html_e('清除', 'aksrt'); ?></button>
</span>
<input type="text" class="widefat aksrt-icon-picker__value" id="<?php echo esc_attr($id); ?>" name="<?php echo esc_attr($name); ?>" value="<?php echo esc_attr($value); ?>" placeholder="<?php echo esc_attr($placeholder); ?>">
</div>
<?php
return (string) ob_get_clean();
}
endif;