From 4b18f7ef2c12c0038db837a796b531444d91112f Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 18 Oct 2026 12:55:30 +0800 Subject: [PATCH] fix(user-center): replicate reference theme sidebar icons via SVG sprite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user-center sidebar rendered Font Awesome glyphs while the reference theme paints multi-tone inline SVGs, and several glyphs were simply wrong for their slot: fa-chart-line served both 我的等级 and 推广收益, fa-money-bill served both 余额 and 积分, and fa-pen stood in for 创作收益. The theme already ships every sprite key the reference sidebar needs in assets/js/runtime/svg-icon.js, and main.min.js injects the set on every frontend page, so no new icon system was needed. The two grids now use the reference theme's icon-but-box / user-icon-but-box shell (four per row, em16 icon, 12px muted label) in place of AKSRT's tinted 38px pill, and every remaining sidebar glyph and arrow resolves through aksrt_icon_markup(): 我的服务 我的等级 trend-color, 官方认证 user-auth, 我的订单 order-color 功能设置 消息通知 msg-color, 个人资料 user-color, 账户安全 security-color 资产卡 余额 money-color-2, 积分 points-color 中心卡 创作收益 merchant-color, 推广收益 money-color 其它 VIP 入口 vip_1, 抽屉触发器 menu, 箭头统一 right Dead code went with the swap: the whole .uc-service-grid block including the unused --cart and --revenue tones, the count badge (no caller ever set count), and the tone key. The two card selectors that targeted now also cover so the icon sizes survive the element change, and the VIP arrow keeps uc-sidebar-vip__arrow for its hover animation. level/profile/settings gained their missing tab keys, which completes the icon-but-* class names and lets the existing .is-active sync cover all six entries. Verification: node --test across widget-system, navigation, admin, asset-ledger, dev, front-submit and fixtures (620 tests), plus php -l on the five changed PHP files. Contract-locked in tests/widget-system/user-center-sidebar-icons-contract.test.cjs. --- assets/css/routes/user-center/shell.css | 85 +++---------- .../user-center-renderers/profile-sidebar.php | 3 +- .../sidebar-commerce.php | 11 +- .../user-center-renderers/sidebar-creator.php | 11 +- .../user-center-renderers/sidebar-nav.php | 44 ++++--- .../user-center-renderers/sidebar-vip.php | 5 +- ...ser-center-sidebar-icons-contract.test.cjs | 117 ++++++++++++++++++ 7 files changed, 179 insertions(+), 97 deletions(-) create mode 100644 tests/widget-system/user-center-sidebar-icons-contract.test.cjs diff --git a/assets/css/routes/user-center/shell.css b/assets/css/routes/user-center/shell.css index 8ebf5ef4..0a767a0f 100644 --- a/assets/css/routes/user-center/shell.css +++ b/assets/css/routes/user-center/shell.css @@ -622,25 +622,6 @@ body.aksrt-user-center .uc-content, } } -.uc-service-grid__icon small { - position: absolute; - top: -5px; - right: -7px; - display: grid; - place-items: center; - min-width: 17px; - height: 17px; - padding: 0 4px; - border: 2px solid var(--surface-1); - border-radius: 99px; - background: var(--color-error, #ef4444); - color: #fff; - font-size: 9px; - font-style: normal; - font-weight: 700; - line-height: 1; -} - .uc-sidebar__pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); @@ -684,7 +665,8 @@ body.aksrt-user-center .uc-content, text-overflow: ellipsis; } -.uc-summary-card__body > i { +.uc-summary-card__body > i, +.uc-summary-card__body > svg { font-size: 18px; } @@ -716,14 +698,26 @@ body.aksrt-user-center .uc-content, .uc-center-card strong { font-size: 13px; } .uc-center-card small { margin-top: 3px; color: var(--color-ink-4); font-size: 10px; } -.uc-center-card > i { color: var(--color-ink-4); font-size: 11px; } +.uc-center-card > i, +.uc-center-card > svg { color: var(--color-ink-4); font-size: 11px; } .uc-center-card--creation .uc-center-card__icon { color: #6650c7; background: rgba(124, 92, 220, 0.12); } .uc-center-card--revenue .uc-center-card__icon { color: #ce6b35; background: rgba(234, 112, 55, 0.12); } -.uc-service-grid { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 8px; +/* Services / settings grids, ported from the reference theme sidebar: + four per row, no tinted tile behind the icon. */ +.user-icon-but-box > a { + width: calc(25% - 10px); + margin: 5px; + min-width: 50px; + max-width: 100px; + color: var(--color-ink-3); + text-align: center; + text-decoration: none; +} + +.user-icon-but-box > a:hover, +.user-icon-but-box > a.is-active { + color: var(--color-primary); } .uc-follow-management__list { display: grid; gap: 10px; margin-top: 16px; } @@ -735,44 +729,3 @@ body.aksrt-user-center .uc-content, .uc-follow-management__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-left: auto; } @media (max-width: 560px) { .uc-follow-management__item { align-items: flex-start; flex-wrap: wrap; } .uc-follow-management__actions { width: 100%; margin-left: 60px; } } -.uc-service-grid__item { - display: flex; - flex-direction: column; - align-items: center; - gap: 7px; - min-width: 0; - padding: 4px 2px; - color: var(--color-ink-3); - font-size: 11px; - text-align: center; - text-decoration: none; -} - -.uc-service-grid__icon { - position: relative; - display: grid; - place-items: center; - width: 38px; - height: 38px; - border-radius: 14px; - background: var(--surface-2); - font-size: 16px; -} - -.uc-service-grid__item--cart .uc-service-grid__icon { color: #dd6941; background: rgba(238, 109, 61, 0.12); } -.uc-service-grid__item--level .uc-service-grid__icon { color: #9b6b0a; background: rgba(234, 179, 8, 0.13); } -.uc-service-grid__item--revenue .uc-service-grid__icon { color: #b8377d; background: rgba(219, 39, 119, 0.12); } -.uc-service-grid__item--auth .uc-service-grid__icon { color: #287bc4; background: rgba(14, 165, 233, 0.12); } -.uc-service-grid__item--orders .uc-service-grid__icon { color: #c05621; background: rgba(234, 88, 12, 0.12); } -.uc-service-grid__item--notice .uc-service-grid__icon { color: #d04b65; background: rgba(244, 63, 94, 0.11); } -.uc-service-grid__item--profile .uc-service-grid__icon { color: #6550c7; background: rgba(124, 92, 220, 0.12); } -.uc-service-grid__item--security .uc-service-grid__icon { color: #16816c; background: rgba(16, 185, 129, 0.12); } - -.uc-service-grid__item:hover, -.uc-service-grid__item.is-active { - color: var(--color-primary); -} - -.uc-service-grid__item.is-active .uc-service-grid__icon { - box-shadow: 0 0 0 2px var(--color-primary-soft), 0 5px 14px rgba(15, 23, 42, 0.08); -} diff --git a/inc/helpers/user-center-renderers/profile-sidebar.php b/inc/helpers/user-center-renderers/profile-sidebar.php index 1c0d67a6..b81fbcbb 100644 --- a/inc/helpers/user-center-renderers/profile-sidebar.php +++ b/inc/helpers/user-center-renderers/profile-sidebar.php @@ -15,7 +15,8 @@ require __DIR__ . '/sidebar-vip.php'; require __DIR__ . '/sidebar-commerce.php'; require __DIR__ . '/sidebar-creator.php'; require __DIR__ . '/sidebar-nav.php'; +$drawer_trigger_icon = aksrt_icon_markup('zibsvg-menu'); ?> + diff --git a/inc/helpers/user-center-renderers/sidebar-commerce.php b/inc/helpers/user-center-renderers/sidebar-commerce.php index 4b7dc508..8d32fd2d 100644 --- a/inc/helpers/user-center-renderers/sidebar-commerce.php +++ b/inc/helpers/user-center-renderers/sidebar-commerce.php @@ -20,23 +20,26 @@ try { $wallet = '0.00'; } $points = max(0, (int) ($credit_balance ?? 0)); +$wallet_icon = aksrt_icon_markup('zibsvg-money-color-2'); +$points_icon = aksrt_icon_markup('zibsvg-points-color'); +$arrow_icon = aksrt_icon_markup('zibsvg-right'); ?>
- + - + - + - + diff --git a/inc/helpers/user-center-renderers/sidebar-creator.php b/inc/helpers/user-center-renderers/sidebar-creator.php index c3ce50ec..209d9e8c 100644 --- a/inc/helpers/user-center-renderers/sidebar-creator.php +++ b/inc/helpers/user-center-renderers/sidebar-creator.php @@ -13,20 +13,23 @@ $revenue_url = isset($dashboard_tabs['revenue']) ? aksrt_get_user_center_tab_url if ($creation_url === '' && $revenue_url === '') { return; } +$creation_icon = aksrt_icon_markup('zibsvg-merchant-color'); +$revenue_icon = aksrt_icon_markup('zibsvg-money-color'); +$arrow_icon = aksrt_icon_markup('zibsvg-right'); ?> diff --git a/inc/helpers/user-center-renderers/sidebar-nav.php b/inc/helpers/user-center-renderers/sidebar-nav.php index be6f5800..9fdbe7c4 100644 --- a/inc/helpers/user-center-renderers/sidebar-nav.php +++ b/inc/helpers/user-center-renderers/sidebar-nav.php @@ -2,6 +2,9 @@ /** * User center sidebar: services and account settings. * + * Icon set mirrors the reference theme user-center sidebar: every entry renders + * an inline SVG from the theme sprite through aksrt_icon_markup(). + * * @package AKSRT */ @@ -17,22 +20,20 @@ $orders_url = $orders_available ? (string) ($orders_url ?? '') : ''; $services = array_values(array_filter([ [ 'label' => __('我的等级', 'aksrt'), - 'icon' => 'chart-line', - 'tone' => 'level', + 'icon' => 'trend-color', 'url' => $level_url, + 'tab' => 'level', ], [ 'label' => __('官方认证', 'aksrt'), - 'icon' => 'id-badge', - 'tone' => 'auth', + 'icon' => 'user-auth', 'url' => $auth_url, 'tab' => 'auth', ], [ 'label' => __('我的订单', 'aksrt'), - 'icon' => 'receipt', - 'tone' => 'orders', + 'icon' => 'order-color', 'url' => $orders_url, 'tab' => 'orders', ], @@ -41,35 +42,38 @@ $services = array_values(array_filter([ $settings = array_values(array_filter([ [ 'label' => __('消息通知', 'aksrt'), - 'icon' => 'bell', - 'tone' => 'notice', + 'icon' => 'msg-color', 'url' => isset($dashboard_tabs['msg']) ? aksrt_get_user_center_tab_url('msg') : '', 'tab' => 'msg', ], [ 'label' => __('个人资料', 'aksrt'), - 'icon' => 'user-edit', - 'tone' => 'profile', + 'icon' => 'user-color', 'url' => isset($dashboard_tabs['profile']) ? aksrt_get_user_center_tab_url('profile') : '', + 'tab' => 'profile', ], [ 'label' => __('账户安全', 'aksrt'), - 'icon' => 'shield-alt', - 'tone' => 'security', + 'icon' => 'security-color', 'url' => isset($dashboard_tabs['settings']) ? aksrt_get_user_center_tab_url('settings') : '', + 'tab' => 'settings', ], ], static fn(array $item): bool => (string) $item['url'] !== '')); $render_grid = static function (array $items): void { ?> -
- - data-tab=""> - - - - - + diff --git a/inc/helpers/user-center-renderers/sidebar-vip.php b/inc/helpers/user-center-renderers/sidebar-vip.php index f1df9538..43ec5176 100644 --- a/inc/helpers/user-center-renderers/sidebar-vip.php +++ b/inc/helpers/user-center-renderers/sidebar-vip.php @@ -49,7 +49,8 @@ $sidebar_level = $vip_level > 0 ? $vip_level : $expired_level; $sidebar_icon_url = esc_url((string) ($vip_levels[$sidebar_level]['img_icon'] ?? '')); $sidebar_icon = $sidebar_icon_url !== '' ? '' - : ''; + : aksrt_icon_markup('zibsvg-vip_1'); +$sidebar_arrow = aksrt_icon_markup('zibsvg-right', 'uc-sidebar-vip__arrow'); ?> @@ -57,5 +58,5 @@ $sidebar_icon = $sidebar_icon_url !== '' - + diff --git a/tests/widget-system/user-center-sidebar-icons-contract.test.cjs b/tests/widget-system/user-center-sidebar-icons-contract.test.cjs new file mode 100644 index 00000000..a668748f --- /dev/null +++ b/tests/widget-system/user-center-sidebar-icons-contract.test.cjs @@ -0,0 +1,117 @@ +/** + * 用户中心左侧栏图标契约(参考主题 1:1 对齐)。 + * + * 硬约束: + * 1) 「我的服务 / 功能设置」两个网格使用参考主题的 icon-but-box / user-icon-but-box + * 外壳,图标全部来自主题内置 SVG sprite(aksrt_icon_markup('zibsvg-*')), + * 不再出现 Font Awesome 字形。 + * 2) 侧栏其余部件(余额/积分卡、创作/推广卡、VIP 入口、抽屉触发器)同样只使用 + * sprite 图标,箭头统一为 zibsvg-right,保证侧栏只剩一种图标族。 + * 3) 旧的 uc-service-grid 外壳、色调底色与计数角标必须已彻底移除,不得残留。 + */ +'use strict'; + +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const test = require('node:test'); + +const root = path.resolve(__dirname, '..', '..'); +const read = (file) => fs.readFileSync(path.join(root, file), 'utf8'); + +const sidebarDir = 'inc/helpers/user-center-renderers/'; +const sidebarFiles = [ + 'sidebar-nav.php', + 'sidebar-commerce.php', + 'sidebar-creator.php', + 'sidebar-vip.php', + 'profile-sidebar.php', +]; + +test('服务/设置网格使用参考主题 icon-but-box 外壳与 sprite 图标', () => { + const nav = read(sidebarDir + 'sidebar-nav.php'); + + assert.match(nav, /class="flex ac hh text-center icon-but-box user-icon-but-box"/); + assert.match(nav, /
<\?php echo \$icon_html;/); + assert.match(nav, /
/); + assert.match(nav, /aksrt_icon_markup\('zibsvg-' \. \(string\) \$item\['icon'\]\)/); + + // 参考主题选型:我的服务 = trend-color / user-auth / order-color。 + assert.match(nav, /'icon'\s+=>\s+'trend-color'/); + assert.match(nav, /'icon'\s+=>\s+'user-auth'/); + assert.match(nav, /'icon'\s+=>\s+'order-color'/); + // 功能设置 = msg-color / user-color / security-color。 + assert.match(nav, /'icon'\s+=>\s+'msg-color'/); + assert.match(nav, /'icon'\s+=>\s+'user-color'/); + assert.match(nav, /'icon'\s+=>\s+'security-color'/); + + // 每项都带 tab,保证 icon-but-* 类名完整且选中态可同步。 + for (const tab of ['level', 'auth', 'orders', 'msg', 'profile', 'settings']) { + assert.match(nav, new RegExp(`'tab'\\s+=>\\s+'${tab}'`), `missing tab key: ${tab}`); + } + + // AKSRT 的跳转契约保留 + data-tab,不搬参考主题的 。 + assert.match(nav, //); + assert.doesNotMatch(nav, /data-onclick/); +}); + +test('侧栏五个部件均不再出现 Font Awesome 字形', () => { + for (const file of sidebarFiles) { + const source = read(sidebarDir + file); + assert.doesNotMatch(source, /fa\s+fas\s+fa-/, `${file} still renders a Font Awesome glyph`); + assert.doesNotMatch(source, /