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().
This commit is contained in:
+11
-5
@@ -111,11 +111,16 @@ class Admin {
|
||||
}
|
||||
|
||||
// Use the same local FA5 pack as the public stack.
|
||||
wp_enqueue_style(
|
||||
'aksrt-font-awesome',
|
||||
get_template_directory_uri() . '/assets/fontawesome5/css/all.min.css',
|
||||
[],
|
||||
'5.15.4'
|
||||
aksrt_enqueue_fontawesome();
|
||||
|
||||
// Frontend SVG sprite (defines window.aksrt_svgs and injects the symbol
|
||||
// sheet) so schema icon fields can preview built-in zibsvg values.
|
||||
wp_enqueue_script(
|
||||
'aksrt-svg-sprite',
|
||||
get_template_directory_uri() . '/assets/js/runtime/svg-icon.js',
|
||||
['jquery'],
|
||||
(string) filemtime(get_template_directory() . '/assets/js/runtime/svg-icon.js'),
|
||||
true
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
@@ -186,6 +191,7 @@ class Admin {
|
||||
CommentController::class,
|
||||
MessageController::class,
|
||||
AIController::class,
|
||||
\AKSRT\Icons\IconController::class,
|
||||
];
|
||||
|
||||
foreach ($controllers as $class_name) {
|
||||
|
||||
@@ -25,17 +25,12 @@ trait ScriptsPart1b {
|
||||
[],
|
||||
'3.4.1'
|
||||
);
|
||||
wp_enqueue_style(
|
||||
'fontawesome5',
|
||||
$base_uri . '/assets/fontawesome5/css/all.min.css',
|
||||
['bootstrap'],
|
||||
'5.15.4'
|
||||
);
|
||||
aksrt_enqueue_fontawesome(['bootstrap']);
|
||||
$main_css_path = get_template_directory() . '/assets/css/main.min.css';
|
||||
wp_enqueue_style(
|
||||
'aksrt-main',
|
||||
$base_uri . '/assets/css/main.min.css',
|
||||
['fontawesome5'],
|
||||
['aksrt-font-awesome'],
|
||||
file_exists($main_css_path) ? (string) filemtime($main_css_path) : $version
|
||||
);
|
||||
wp_enqueue_style(
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Icons;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Icon catalog for the universal icon picker.
|
||||
*
|
||||
* Two families:
|
||||
* - Font Awesome 5 Free (bundled, 5.15.4): static generated data in fa5-icons.php.
|
||||
* - Theme built-in SVG sprite: keys parsed from assets/js/runtime/svg-icon.js
|
||||
* (aksrt_svgs['key'] = '<path ...>') so the picker can never drift from the
|
||||
* frontend sprite. Parsed per file mtime and cached.
|
||||
*/
|
||||
final class IconCatalog {
|
||||
|
||||
/**
|
||||
* @return array<int, array{id:string,title:string,type:string,icons:string[]}>
|
||||
*/
|
||||
public static function groups(): array {
|
||||
$fa = include AKSRT_DIR . '/src/Icons/fa5-icons.php';
|
||||
if (!is_array($fa)) {
|
||||
$fa = ['fas' => [], 'far' => [], 'fab' => []];
|
||||
}
|
||||
|
||||
return [
|
||||
['id' => 'fas', 'title' => __('FA 实色', 'aksrt'), 'type' => 'fa', 'icons' => array_values((array) ($fa['fas'] ?? []))],
|
||||
['id' => 'far', 'title' => __('FA 常规', 'aksrt'), 'type' => 'fa', 'icons' => array_values((array) ($fa['far'] ?? []))],
|
||||
['id' => 'fab', 'title' => __('FA 品牌', 'aksrt'), 'type' => 'fa', 'icons' => array_values((array) ($fa['fab'] ?? []))],
|
||||
['id' => 'zibsvg', 'title' => __('主题内置 SVG', 'aksrt'), 'type' => 'svg', 'icons' => self::sprite_keys()],
|
||||
['id' => 'custom', 'title' => __('自定义 SVG', 'aksrt'), 'type' => 'custom', 'icons' => []],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sprite symbol keys, e.g. ['like', 'view', ...] — derived from the
|
||||
* frontend sprite file, cached until the file changes.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function sprite_keys(): array {
|
||||
$file = AKSRT_DIR . '/assets/js/runtime/svg-icon.js';
|
||||
if (!is_readable($file)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$mtime = (string) filemtime($file);
|
||||
$cache = get_transient('aksrt_sprite_keys_v1');
|
||||
if (is_array($cache) && ($cache['mtime'] ?? '') === $mtime && isset($cache['keys'])) {
|
||||
return array_values((array) $cache['keys']);
|
||||
}
|
||||
|
||||
$src = (string) file_get_contents($file);
|
||||
$keys = [];
|
||||
if (preg_match_all("/aksrt_svgs\\['([A-Za-z0-9_]+)'\\]\\s*=/", $src, $m)) {
|
||||
$keys = array_values(array_unique($m[1]));
|
||||
}
|
||||
|
||||
set_transient('aksrt_sprite_keys_v1', ['mtime' => $mtime, 'keys' => $keys], MONTH_IN_SECONDS);
|
||||
return $keys;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Icons;
|
||||
|
||||
use AKSRT\Admin\ControllerBase;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* REST endpoint serving the icon picker catalog.
|
||||
*/
|
||||
class IconController extends ControllerBase {
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
public static function get_instance(): self {
|
||||
if (null === self::$instance) self::$instance = new self();
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function register_routes(): void {
|
||||
register_rest_route(self::API_NAMESPACE, '/icons/catalog', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_catalog'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function get_catalog(): \WP_REST_Response {
|
||||
return $this->success([
|
||||
'groups' => IconCatalog::groups(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user