diff --git a/assets/css/frontend/footer/zibll-shell.css b/assets/css/frontend/footer/zibll-shell.css index a8449d51..6929a150 100644 --- a/assets/css/frontend/footer/zibll-shell.css +++ b/assets/css/frontend/footer/zibll-shell.css @@ -144,17 +144,10 @@ background: var(--focus-color, var(--color-primary)); } -.footer .footer-contact > a i, -.footer .footer-contact > a svg { +.footer .footer-contact > a i { vertical-align: middle; } -.footer .footer-contact > a svg { - width: 1em; - height: 1em; - fill: currentColor; -} - .footer .footer-wechat-img { display: none; position: absolute; diff --git a/assets/css/frontend/pages/base-1.css b/assets/css/frontend/pages/base-1.css index 9017c280..2cccdec1 100644 --- a/assets/css/frontend/pages/base-1.css +++ b/assets/css/frontend/pages/base-1.css @@ -205,11 +205,10 @@ html.dark .archive-timeline__badge { color: var(--color-ink-3); transition: border-color 0.2s, color 0.2s; } -.oauth-btn svg { - width: 22px; - height: 22px; +.oauth-btn i { + font-size: 22px; + line-height: 1; display: block; - fill: currentColor; } .oauth-btn:hover { diff --git a/assets/css/frontend/widgets/part-1.css b/assets/css/frontend/widgets/part-1.css index 4081510f..c9d68f41 100644 --- a/assets/css/frontend/widgets/part-1.css +++ b/assets/css/frontend/widgets/part-1.css @@ -119,12 +119,11 @@ html.dark .zib-widget { color: #fff; transition: background 0.2s; } -.profile-social-links a svg, -.social-icon-link svg { - width: 18px; - height: 18px; +.profile-social-links a i, +.social-icon-link i { + font-size: 18px; + line-height: 1; display: block; - fill: currentColor; } diff --git a/assets/css/routes/profile/lists.css b/assets/css/routes/profile/lists.css index 4a984035..a8dcd0b1 100644 --- a/assets/css/routes/profile/lists.css +++ b/assets/css/routes/profile/lists.css @@ -537,9 +537,9 @@ color: var(--color-ink); flex-shrink: 0; } -.binding-item__icon svg { - width: 100%; - height: 100%; +.binding-item__icon i { + font-size: 22px; + line-height: 1; } .binding-item__meta { display: flex; diff --git a/assets/img/icons/bilibili.svg b/assets/img/icons/bilibili.svg deleted file mode 100644 index f89a57ad..00000000 --- a/assets/img/icons/bilibili.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/discord.svg b/assets/img/icons/discord.svg deleted file mode 100644 index f01eec82..00000000 --- a/assets/img/icons/discord.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/email.svg b/assets/img/icons/email.svg deleted file mode 100644 index 272d2b2c..00000000 --- a/assets/img/icons/email.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/facebook.svg b/assets/img/icons/facebook.svg deleted file mode 100644 index c00439cc..00000000 --- a/assets/img/icons/facebook.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/gitee.svg b/assets/img/icons/gitee.svg deleted file mode 100644 index 457e4829..00000000 --- a/assets/img/icons/gitee.svg +++ /dev/null @@ -1 +0,0 @@ -Gitee \ No newline at end of file diff --git a/assets/img/icons/github.svg b/assets/img/icons/github.svg deleted file mode 100644 index 7a51b8e0..00000000 --- a/assets/img/icons/github.svg +++ /dev/null @@ -1 +0,0 @@ -Github \ No newline at end of file diff --git a/assets/img/icons/google.svg b/assets/img/icons/google.svg deleted file mode 100644 index 67517a6c..00000000 --- a/assets/img/icons/google.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/instagram.svg b/assets/img/icons/instagram.svg deleted file mode 100644 index 35d83121..00000000 --- a/assets/img/icons/instagram.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/linkedin.svg b/assets/img/icons/linkedin.svg deleted file mode 100644 index dbb4c049..00000000 --- a/assets/img/icons/linkedin.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/qq.svg b/assets/img/icons/qq.svg deleted file mode 100644 index 5eeb9db8..00000000 --- a/assets/img/icons/qq.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/telegram.svg b/assets/img/icons/telegram.svg deleted file mode 100644 index 685ecb30..00000000 --- a/assets/img/icons/telegram.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/web.svg b/assets/img/icons/web.svg deleted file mode 100644 index 7a4ab33e..00000000 --- a/assets/img/icons/web.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/wechat.svg b/assets/img/icons/wechat.svg deleted file mode 100644 index b2635323..00000000 --- a/assets/img/icons/wechat.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/weibo.svg b/assets/img/icons/weibo.svg deleted file mode 100644 index cd789f5a..00000000 --- a/assets/img/icons/weibo.svg +++ /dev/null @@ -1 +0,0 @@ -Sina Weibo \ No newline at end of file diff --git a/assets/img/icons/x.svg b/assets/img/icons/x.svg deleted file mode 100644 index c4081ad6..00000000 --- a/assets/img/icons/x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/img/icons/youtube.svg b/assets/img/icons/youtube.svg deleted file mode 100644 index fe67f942..00000000 --- a/assets/img/icons/youtube.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/footer.php b/footer.php index 0a37041a..4e7d8406 100644 --- a/footer.php +++ b/footer.php @@ -254,8 +254,12 @@ if ($_footer_conter === '') { $m_url = (string) ($more_item['link'] ?? ''); $m_text = (string) ($more_item['desc'] ?? ''); $m_icon = (string) ($more_item['icon'] ?? ''); - $m_svg = ($m_icon !== '' && function_exists('aksrt_inline_svg')) ? aksrt_inline_svg($m_icon) : ''; - $m_icon_html = $m_svg !== '' ? $m_svg : ''; + $m_icon_html = ($m_icon !== '' && function_exists('aksrt_brand_icon')) + ? aksrt_brand_icon($m_icon) + : ''; + if ($m_icon_html === '') { + $m_icon_html = ''; + } if ($m_img !== '') : ?> @@ -274,14 +278,13 @@ if ($_footer_conter === '') { $c_icon = $contact['icon'] ?? ''; $c_url = $contact['url'] ?? '#'; $c_label = $contact['title'] ?? ($contact['label'] ?? (function_exists('aksrt_icon_key_to_name') ? aksrt_icon_key_to_name($c_icon) : '')); - $c_svg = function_exists('aksrt_inline_svg') ? aksrt_inline_svg($c_icon) : ''; + $c_icon_html = function_exists('aksrt_brand_icon') ? aksrt_brand_icon((string) $c_icon) : ''; + if ($c_icon_html === '') { + $c_icon_html = ''; + } ?> - - - - - + diff --git a/inc/classes/class-aksrt-admin.php b/inc/classes/class-aksrt-admin.php index 00511553..4a439af1 100644 --- a/inc/classes/class-aksrt-admin.php +++ b/inc/classes/class-aksrt-admin.php @@ -115,6 +115,14 @@ class AKSRT_Admin { } } + // Match frontend FA5 pack so FaIcon / menu glyphs render in the SPA. + wp_enqueue_style( + 'aksrt-font-awesome-5', + 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css', + [], + '5.15.4' + ); + wp_enqueue_script( 'aksrt-admin-app', $build_uri . 'index.js', diff --git a/inc/classes/oauth-traits/trait-aksrt-oauth-part-1.php b/inc/classes/oauth-traits/trait-aksrt-oauth-part-1.php index 52f4335d..5c298aff 100644 --- a/inc/classes/oauth-traits/trait-aksrt-oauth-part-1.php +++ b/inc/classes/oauth-traits/trait-aksrt-oauth-part-1.php @@ -239,7 +239,7 @@ trait AKSRT_OAuth_Part_1 { $result[] = [ 'name' => $key, 'label' => $platform_names[$key] ?? ucfirst($key), - 'icon' => aksrt_inline_svg($key), + 'icon' => function_exists('aksrt_brand_icon') ? aksrt_brand_icon((string) $key) : '', 'url' => esc_url($url), ]; } @@ -350,14 +350,14 @@ trait AKSRT_OAuth_Part_1 { if (empty($enabled_providers)) return ''; $icons = [ - 'github' => aksrt_inline_svg('github'), - 'gitee' => aksrt_inline_svg('gitee'), - 'qq' => aksrt_inline_svg('qq'), - 'google' => aksrt_inline_svg('google'), - 'weibo' => aksrt_inline_svg('weibo'), - 'weixin' => aksrt_inline_svg('wechat'), - 'baidu' => 'B', - 'alipay' => 'A', + 'github' => aksrt_brand_icon('github'), + 'gitee' => aksrt_brand_icon('gitee'), + 'qq' => aksrt_brand_icon('qq'), + 'google' => aksrt_brand_icon('google'), + 'weibo' => aksrt_brand_icon('weibo'), + 'weixin' => aksrt_brand_icon('weixin'), + 'baidu' => aksrt_brand_icon('baidu'), + 'alipay' => aksrt_brand_icon('alipay'), ]; ob_start(); diff --git a/inc/classes/oauth-traits/trait-aksrt-oauth-part-2.php b/inc/classes/oauth-traits/trait-aksrt-oauth-part-2.php index e09a7e10..71b30bcd 100644 --- a/inc/classes/oauth-traits/trait-aksrt-oauth-part-2.php +++ b/inc/classes/oauth-traits/trait-aksrt-oauth-part-2.php @@ -16,14 +16,14 @@ trait AKSRT_OAuth_Part_2 { 'baidu' => 'Baidu', 'alipay' => 'Alipay', ]; $icons = [ - 'github' => aksrt_inline_svg('github'), - 'gitee' => aksrt_inline_svg('gitee'), - 'qq' => aksrt_inline_svg('qq'), - 'google' => aksrt_inline_svg('google'), - 'weibo' => aksrt_inline_svg('weibo'), - 'weixin' => aksrt_inline_svg('wechat'), - 'baidu' => 'B', - 'alipay' => 'A', + 'github' => aksrt_brand_icon('github'), + 'gitee' => aksrt_brand_icon('gitee'), + 'qq' => aksrt_brand_icon('qq'), + 'google' => aksrt_brand_icon('google'), + 'weibo' => aksrt_brand_icon('weibo'), + 'weixin' => aksrt_brand_icon('weixin'), + 'baidu' => aksrt_brand_icon('baidu'), + 'alipay' => aksrt_brand_icon('alipay'), ]; $bindings = []; diff --git a/inc/helpers/aksrt-icons.php b/inc/helpers/aksrt-icons.php index 4f46e5e1..8d1c5e75 100644 --- a/inc/helpers/aksrt-icons.php +++ b/inc/helpers/aksrt-icons.php @@ -1,12 +1,12 @@ markup, contact option labels, + * and public social-link renderer. Local SVG inventory removed. * * @package AKSRT - * @version 3.1.0 + * @version 3.4.0 */ defined('ABSPATH') || exit; @@ -37,37 +37,150 @@ function aksrt_parse_country_list($raw) { endif; // ============================================================ -// 本地 SVG 图标:读取 SVGs 目录并缓存 +// Brand icon map (FA 5.15.4 free) // ============================================================ -if (!function_exists('aksrt_inline_svg')) : -function aksrt_inline_svg($name) { - // 兼容 FA5 旧数据:fab fa-github / fabfa-github / fa-github → github - $name = preg_replace('/^(fab|fas|far)[\s-]*/', '', $name); - $name = preg_replace('/^fa[\s-]*/', '', $name); - $name = preg_replace('/^[\s-]+/', '', $name); - $name = trim($name, '- '); - static $cache = array(); - if (isset($cache[$name])) return $cache[$name]; - $path = AKSRT_DIR . '/assets/img/icons/' . $name . '.svg'; - if (file_exists($path)) { - $svg = file_get_contents($path); - // 去除 XML 声明和 DOCTYPE - $svg = preg_replace('/^<\?xml.*?\?>\s*/i', '', $svg); - $svg = preg_replace('/^]*>\s*/i', '', $svg); - // 移除 上的固定宽高,让 CSS 控制尺寸 - $svg = preg_replace('/\swidth="[^"]*"/', '', $svg); - $svg = preg_replace('/\sheight="[^"]*"/', '', $svg); - // 移除 iconfont 冗余属性 - $svg = preg_replace('/\sclass="[^"]*"/', '', $svg); - $svg = preg_replace('/\st="[^"]*"/', '', $svg); - $svg = preg_replace('/\sp-id="[^"]*"/', '', $svg); - $svg = preg_replace('/\sxmlns:xlink="[^"]*"/', '', $svg); - // 移除路径上的 opacity 属性 - $svg = preg_replace('/(<(?:path|circle|rect|polygon|line|polyline|ellipse)[^>]*)\sopacity="[^"]*"/', '$1', $svg); - $cache[$name] = $svg; - return $svg; - } - return ''; + +if (!function_exists('aksrt_brand_icon_map')) : +/** + * Short key → FA5 class string (allowlisted). + * + * @return array + */ +function aksrt_brand_icon_map(): array { + static $map = null; + if ($map !== null) { + return $map; + } + + // FA5 free has no bilibili/gitee brands — use solid stand-ins. + $map = [ + 'github' => 'fab fa-github', + 'google' => 'fab fa-google', + 'x' => 'fab fa-twitter', + 'twitter' => 'fab fa-twitter', + 'email' => 'fas fa-envelope', + 'envelope' => 'fas fa-envelope', + 'wechat' => 'fab fa-weixin', + 'weixin' => 'fab fa-weixin', + 'qq' => 'fab fa-qq', + 'weibo' => 'fab fa-weibo', + 'telegram' => 'fab fa-telegram-plane', + 'discord' => 'fab fa-discord', + 'bilibili' => 'fas fa-tv', + 'linkedin' => 'fab fa-linkedin-in', + 'facebook' => 'fab fa-facebook-f', + 'youtube' => 'fab fa-youtube', + 'instagram' => 'fab fa-instagram', + 'web' => 'fas fa-globe', + 'globe' => 'fas fa-globe', + 'gitee' => 'fas fa-code-branch', + 'baidu' => 'fas fa-paw', + 'alipay' => 'fab fa-alipay', + ]; + + return $map; +} +endif; + +if (!function_exists('aksrt_normalize_icon_key')) : +/** + * Normalize short key or full FA class string to a short map key. + * + * Examples: 'fab fa-github' | 'fabfa-github' | 'fa-github' | 'github' | 'weixin' → 'github' | 'wechat' + * + * @param string $name Raw icon key or FA class string. + * @return string Short key (may be empty). + */ +function aksrt_normalize_icon_key(string $name): string { + $name = trim($name); + if ($name === '') { + return ''; + } + + // Strip style prefixes: fab/fas/far + optional space or hyphen. + $name = preg_replace('/^(fab|fas|far)[\s-]*/i', '', $name); + $name = preg_replace('/^fa[\s-]*/i', '', (string) $name); + $name = trim((string) $name, "- \t\n\r\0\x0B"); + $name = strtolower($name); + + // Aliases → canonical keys used by the map / contact options. + $aliases = [ + 'weixin' => 'wechat', + 'weixingzh' => 'wechat', + 'twitter' => 'x', + 'envelope' => 'email', + 'globe' => 'web', + ]; + if (isset($aliases[$name])) { + return $aliases[$name]; + } + + return $name; +} +endif; + +if (!function_exists('aksrt_brand_icon_class')) : +/** + * Resolve a short key or FA class string to an allowlisted FA5 class. + * + * @param string $name Short key or full FA class string. + * @return string e.g. 'fab fa-github', or '' if unknown. + */ +function aksrt_brand_icon_class(string $name): string { + $raw = trim($name); + if ($raw === '') { + return ''; + } + + // Pass through already-valid full FA class strings (footer contact_more). + if (preg_match('/^(fa[sbr]|fa)\s+fa-[\w-]+(?:\s+fa-[\w-]+)*$/i', $raw)) { + // Prefer mapped short key when strip matches our catalog (normalizes weixin etc.). + $key = aksrt_normalize_icon_key($raw); + $map = aksrt_brand_icon_map(); + if ($key !== '' && isset($map[$key])) { + return $map[$key]; + } + // Allowlisted style + glyph only — collapse whitespace, lower style prefix. + $parts = preg_split('/\s+/', strtolower($raw)); + $parts = array_values(array_filter((array) $parts)); + return implode(' ', $parts); + } + + $key = aksrt_normalize_icon_key($raw); + if ($key === '') { + return ''; + } + + $map = aksrt_brand_icon_map(); + return $map[$key] ?? ''; +} +endif; + +if (!function_exists('aksrt_brand_icon')) : +/** + * Escaped FA markup for a brand/contact icon. + * + * @param string $name Short key or FA class string. + * @param array|string $extra_classes Optional extra classes. + * @return string Safe HTML or empty string when unknown. + */ +function aksrt_brand_icon(string $name, $extra_classes = []): string { + $class = aksrt_brand_icon_class($name); + if ($class === '') { + return ''; + } + + if (is_string($extra_classes) && $extra_classes !== '') { + $extra_classes = preg_split('/\s+/', $extra_classes) ?: []; + } + if (is_array($extra_classes) && $extra_classes !== []) { + $extra = array_filter(array_map('sanitize_html_class', $extra_classes)); + if ($extra !== []) { + $class .= ' ' . implode(' ', $extra); + } + } + + return ''; } endif; @@ -76,16 +189,20 @@ endif; // ============================================================ if (!function_exists('aksrt_icon_key_to_name')) : function aksrt_icon_key_to_name($key) { - $map = array( - 'github' => 'GitHub', 'google' => 'Google', 'x' => 'X', - 'email' => '邮箱', 'wechat' => '微信', 'qq' => 'QQ', - 'weibo' => '微博', 'telegram' => 'Telegram', - 'discord' => 'Discord', 'bilibili' => 'Bilibili', - 'linkedin' => 'LinkedIn', 'facebook' => 'Facebook', - 'youtube' => 'YouTube', 'instagram' => 'Instagram', - 'web' => '网站', - ); - return isset($map[$key]) ? $map[$key] : ucwords(str_replace('-', ' ', $key)); + $key = aksrt_normalize_icon_key((string) $key); + $map = array( + 'github' => 'GitHub', 'google' => 'Google', 'x' => 'X', + 'email' => '邮箱', 'wechat' => '微信', 'qq' => 'QQ', + 'weibo' => '微博', 'telegram' => 'Telegram', + 'discord' => 'Discord', 'bilibili' => 'Bilibili', + 'linkedin' => 'LinkedIn', 'facebook' => 'Facebook', + 'youtube' => 'YouTube', 'instagram' => 'Instagram', + 'web' => '网站', + 'gitee' => 'Gitee', + 'baidu' => 'Baidu', + 'alipay' => 'Alipay', + ); + return isset($map[$key]) ? $map[$key] : ucwords(str_replace('-', ' ', $key)); } endif; @@ -94,28 +211,81 @@ endif; // ============================================================ if (!function_exists('aksrt_contact_icon_options')) : function aksrt_contact_icon_options($selected = '') { - $icons = array( - 'github' => 'GitHub', - 'google' => 'Google', - 'x' => 'X', - 'email' => '邮箱', - 'wechat' => '微信', - 'qq' => 'QQ', - 'weibo' => '微博', - 'telegram' => 'Telegram', - 'discord' => 'Discord', - 'bilibili' => 'Bilibili', - 'linkedin' => 'LinkedIn', - 'facebook' => 'Facebook', - 'youtube' => 'YouTube', - 'instagram' => 'Instagram', - 'web' => '网站', - ); - $html = ''; - foreach ($icons as $key => $label) { - $sel = $key === $selected ? ' selected' : ''; - $html .= ''; - } - return $html; + $icons = array( + 'github' => 'GitHub', + 'google' => 'Google', + 'x' => 'X', + 'email' => '邮箱', + 'wechat' => '微信', + 'qq' => 'QQ', + 'weibo' => '微博', + 'telegram' => 'Telegram', + 'discord' => 'Discord', + 'bilibili' => 'Bilibili', + 'linkedin' => 'LinkedIn', + 'facebook' => 'Facebook', + 'youtube' => 'YouTube', + 'instagram' => 'Instagram', + 'web' => '网站', + ); + $selected = aksrt_normalize_icon_key((string) $selected); + $html = ''; + foreach ($icons as $key => $label) { + $sel = $key === $selected ? ' selected' : ''; + $html .= ''; + } + return $html; +} +endif; + +// ============================================================ +// Public social links (author hero / profile) +// ============================================================ +if (!function_exists('aksrt_render_social_links')) : +/** + * Echo a list of public contact links with FA icons. + * + * @param array $contacts + */ +function aksrt_render_social_links(array $contacts): void { + $links = []; + foreach ($contacts as $contact) { + if (!is_array($contact)) { + continue; + } + $url = isset($contact['url']) ? (string) $contact['url'] : ''; + $icon = isset($contact['icon']) ? (string) $contact['icon'] : ''; + if ($url === '' || $icon === '') { + continue; + } + $icon_html = aksrt_brand_icon($icon); + if ($icon_html === '') { + $icon_html = ''; + } + $label = (string) ($contact['name'] ?? $contact['title'] ?? $contact['label'] ?? ''); + if ($label === '') { + $label = aksrt_icon_key_to_name($icon); + } + $links[] = [ + 'url' => $url, + 'label' => $label, + 'icon' => $icon_html, + ]; + } + + if ($links === []) { + return; + } + + echo ''; } endif; diff --git a/inc/helpers/aksrt-single-render.php b/inc/helpers/aksrt-single-render.php index 424e3299..9b677328 100644 --- a/inc/helpers/aksrt-single-render.php +++ b/inc/helpers/aksrt-single-render.php @@ -205,7 +205,7 @@ if (!function_exists('aksrt_render_share_dropdown')) :