Each experience task row closed with a solid `fa-bolt` glyph. The reference marks the same slot with the colour `trend-color` sprite followed by "+ N", and uses that sprite for the 成长体系 heading as well, so the level page also carried a stray `fa-chart-line` there. The sprite already ships in the theme (`jiosvg-trend-color`); its path data is byte-identical to the reference sheet. Both slots now render it, sized to match the reference (`icon mr6 em09` for the rows, `icon mr6 em12` for the heading). The "动态" rows keep their wording without a "+", which is how they read before. The check-in experience badges in src/Credits/Signin.php stay on `fa-line-chart` — the reference uses the same monochrome glyph there. Verification: rendered the real level page through a PHP stub — all ten task rows emit `#icon-trend-color`, the only Font Awesome glyph left is the "每日详情" arrow, matching the reference. Screenshotted against the real stylesheet. A contract test pins both sprite usages and rejects a regression to `fa-bolt` / `fa-chart-line`; 862 widget/navigation tests pass.
205 lines
10 KiB
JavaScript
205 lines
10 KiB
JavaScript
/**
|
||
* 用户中心左侧栏图标契约(参考主题 1:1 对齐)。
|
||
*
|
||
* 硬约束:
|
||
* 1) 「我的服务 / 功能设置」两个网格使用参考主题的 icon-but-box / user-icon-but-box
|
||
* 外壳,图标全部来自主题内置 SVG sprite(jio_icon_markup('jiosvg-*')),
|
||
* 不再出现 Font Awesome 字形。
|
||
* 2) 侧栏其余部件(余额/积分卡、创作/推广卡、VIP 入口、抽屉触发器)同样只使用
|
||
* sprite 图标,箭头统一为 jiosvg-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, /<div class="em16"><\?php echo \$icon_html;/);
|
||
assert.match(nav, /<div class="px12 muted-color mt3">/);
|
||
assert.match(nav, /jio_icon_markup\('jiosvg-' \. \(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}`);
|
||
}
|
||
|
||
// Jio 的跳转契约保留 <a href> + data-tab,不搬参考主题的 <item data-onclick>。
|
||
assert.match(nav, /<a class="<\?php echo esc_attr\(\$item_class\);/);
|
||
assert.match(nav, /data-tab="<\?php echo esc_attr\(\$tab\); \?>/);
|
||
assert.doesNotMatch(nav, /data-onclick/);
|
||
});
|
||
|
||
test('侧栏部件(VIP 与创作/推广卡除外)不再出现 Font Awesome 字形', () => {
|
||
// VIP 入口与创作/推广卡 1:1 参考主题,箭头沿用 fa-chevron-circle-right / fa-angle-right。
|
||
const faAllowed = new Set(['sidebar-vip.php', 'sidebar-creator.php']);
|
||
for (const file of sidebarFiles.filter((f) => !faAllowed.has(f))) {
|
||
const source = read(sidebarDir + file);
|
||
assert.doesNotMatch(source, /fa\s+fas\s+fa-/, `${file} still renders a Font Awesome glyph`);
|
||
assert.doesNotMatch(source, /<i class="fa/, `${file} still renders a Font Awesome <i>`);
|
||
}
|
||
});
|
||
|
||
test('其余侧栏部件按参考主题选型替换为 sprite 图标', () => {
|
||
const commerce = read(sidebarDir + 'sidebar-commerce.php');
|
||
assert.match(commerce, /jio_icon_markup\('jiosvg-money-color-2'\)/);
|
||
assert.match(commerce, /jio_icon_markup\('jiosvg-points-color'\)/);
|
||
assert.match(commerce, /jio_icon_markup\('jiosvg-right'\)/);
|
||
|
||
const creator = read(sidebarDir + 'sidebar-creator.php');
|
||
assert.match(creator, /jio_icon_markup\('jiosvg-merchant-color', 'mr6'\)/);
|
||
assert.match(creator, /jio_icon_markup\('jiosvg-money-color', 'mr6'\)/);
|
||
assert.match(creator, /class="mb10-sm jio-widget-box padding-10 flex1 pointer"/);
|
||
assert.match(creator, /flex ab jsb col-ml6/);
|
||
assert.match(creator, /<i class="ml6 fa fas fa-angle-right em12"/);
|
||
assert.match(creator, /'创作中心'/);
|
||
assert.match(creator, /'推广中心'/);
|
||
assert.match(creator, /'现金收益'/);
|
||
// 收益单位名跟随自定义货币名称,不再硬编码「积分收益」。
|
||
assert.match(creator, /sprintf\(__\('%s收益', 'jio'\), \$currency_name\)/);
|
||
for (const label of ['比例', '待提现', '累计佣金']) {
|
||
assert.ok(creator.includes(`'${label}'`), `creator card missing label: ${label}`);
|
||
}
|
||
// 创作中心不再统计商品数与今日收入。
|
||
for (const label of ['商品', '今日收入', '收入']) {
|
||
assert.ok(!creator.includes(`'${label}'`), `creator card still renders label: ${label}`);
|
||
}
|
||
assert.doesNotMatch(creator, /data-onclick/);
|
||
|
||
const vip = read(sidebarDir + 'sidebar-vip.php');
|
||
assert.match(vip, /jio_icon_markup\('jiosvg-vip_1', 'em12 mr6'\)/);
|
||
assert.match(vip, /jio_icon_markup\('jiosvg-time', 'mr3'\)/);
|
||
assert.match(vip, /mb20 mb10-sm main-radius payvip-icon btn-block badg pointer/);
|
||
assert.match(vip, /style="padding: 14px 10px;"/);
|
||
assert.match(vip, /fa-chevron-circle-right abs-right/);
|
||
assert.match(vip, /开通会员 尊享会员权益/);
|
||
assert.match(vip, /data-tab="vip"/);
|
||
assert.doesNotMatch(vip, /data-onclick/);
|
||
|
||
const profile = read(sidebarDir + 'profile-sidebar.php');
|
||
assert.match(profile, /jio_icon_markup\('jiosvg-menu'\)/);
|
||
});
|
||
|
||
test('旧 uc-service-grid 外壳与色调底色已彻底移除', () => {
|
||
const shell = read('assets/css/routes/user-center/shell.css');
|
||
|
||
assert.doesNotMatch(shell, /uc-service-grid/);
|
||
for (const file of sidebarFiles) {
|
||
assert.doesNotMatch(read(sidebarDir + file), /uc-service-grid/);
|
||
}
|
||
// 计数角标与 tone 键随色调 CSS 一并成为死代码。
|
||
assert.doesNotMatch(shell, /uc-service-grid__icon small/);
|
||
assert.doesNotMatch(read(sidebarDir + 'sidebar-nav.php'), /\$item\['count'\]/);
|
||
assert.doesNotMatch(read(sidebarDir + 'sidebar-nav.php'), /'tone'/);
|
||
|
||
// 参考主题网格尺寸落地。
|
||
assert.match(shell, /\.user-icon-but-box > a \{[^}]*width: calc\(25% - 10px\)/s);
|
||
assert.match(shell, /\.user-icon-but-box > a \{[^}]*min-width: 50px/s);
|
||
// 参考主题网格项没有 hover / 选中变色,只继承正文色。
|
||
assert.doesNotMatch(shell, /\.user-icon-but-box > a\.is-active/);
|
||
assert.match(shell, /\.user-icon-but-box > a \{[^}]*color: inherit/s);
|
||
|
||
// 外壳与标题 1:1 参考主题 jio-widget-box padding-6 / padding-6 ml3。
|
||
const nav = read(sidebarDir + 'sidebar-nav.php');
|
||
assert.match(nav, /class="uc-sidebar-iconbox jio-widget-box padding-6 mb10-sm"/);
|
||
assert.match(nav, /class="uc-sidebar-iconbox jio-widget-box padding-6"/);
|
||
assert.match(nav, /<div class="padding-6 ml3"><\?php esc_html_e\('我的服务'/);
|
||
assert.match(nav, /<div class="padding-6 ml3"><\?php esc_html_e\('功能设置'/);
|
||
assert.doesNotMatch(nav, /uc-sidebar__heading/);
|
||
assert.match(shell, /\.uc-sidebar-iconbox\.jio-widget-box \{/);
|
||
|
||
// 卡片上的 <i> 已换成 <svg>,元素选择器需覆盖两者。
|
||
assert.match(shell, /\.uc-summary-card__body > svg/);
|
||
// 旧的琥珀 VIP 券与 uc-center-card 已被参考主题结构替换。
|
||
assert.doesNotMatch(shell, /uc-center-card/);
|
||
assert.doesNotMatch(shell, /uc-sidebar-vip__/);
|
||
assert.match(shell, /\.uc-sidebar-centers > \.jio-widget-box/);
|
||
|
||
// 文章/评论/收藏/粉丝统计。
|
||
const stats = read(sidebarDir + 'sidebar-stats.php');
|
||
assert.match(stats, /mb10-sm mb20 flex ac jsa jio-widget-box padding-10 text-center/);
|
||
assert.match(stats, /<a class="user-statistics-item"/);
|
||
assert.match(stats, /<div class="em14"><\?php echo esc_html\(jio_cut_count\(/);
|
||
assert.match(stats, /<div class="em09 opacity5 mt6">/);
|
||
assert.doesNotMatch(stats, /uc-stats|uc-sidebar__section/);
|
||
assert.doesNotMatch(shell, /\.uc-stats/);
|
||
assert.doesNotMatch(read('assets/css/routes/user-center/responsive.css'), /\.uc-stats/);
|
||
assert.match(shell, /\.uc-sidebar-statistics\.jio-widget-box \{/);
|
||
});
|
||
|
||
test('所用 sprite key 均在前端 sprite 中定义', () => {
|
||
const sprite = read('assets/js/runtime/svg-icon.js');
|
||
const keys = [
|
||
'trend-color', 'user-auth', 'order-color', 'msg-color', 'user-color', 'security-color',
|
||
'money-color-2', 'points-color', 'merchant-color', 'money-color', 'vip_1', 'time', 'menu', 'right', 'comment-color',
|
||
];
|
||
for (const key of keys) {
|
||
assert.match(sprite, new RegExp(`jio_svgs\\['${key}'\\]\\s*=`), `sprite key missing: ${key}`);
|
||
}
|
||
});
|
||
|
||
test('导航栏用户浮层的余额/积分磁贴与侧栏使用同一组 sprite key', () => {
|
||
const nav = read(sidebarDir + 'sidebar-commerce.php');
|
||
const wallet = read('inc/helpers/jio-header-userbox.php');
|
||
|
||
assert.match(wallet, /jio_icon_markup\('jiosvg-money-color-2', 'em14'\)/);
|
||
assert.match(wallet, /jio_icon_markup\('jiosvg-points-color', 'em14'\)/);
|
||
assert.match(nav, /jio_icon_markup\('jiosvg-money-color-2'\)/);
|
||
assert.match(nav, /jio_icon_markup\('jiosvg-points-color'\)/);
|
||
|
||
// 磁贴箭头沿用参考主题的 fa-angle-right,不做多余替换。
|
||
assert.match(wallet, /fa fas fa-angle-right em12/);
|
||
assert.doesNotMatch(wallet, /fa fas fa-money-bill-wave/);
|
||
assert.doesNotMatch(wallet, /fa fas fa-coins/);
|
||
});
|
||
|
||
test('余额/积分资产卡的标题图标与参考主题一致', () => {
|
||
const wallet = read('inc/helpers/user-center-renderers/credits-wallet.php');
|
||
const balance = read('inc/helpers/user-center-renderers/credits-balance.php');
|
||
|
||
// 参考主题:余额用 money-color-2,积分用 points-color,两者都是彩色 sprite。
|
||
assert.match(wallet, /jio_icon_markup\('jiosvg-money-color-2', 'em12 mr6'\)/);
|
||
assert.match(balance, /jio_icon_markup\('jiosvg-points-color', 'em12 mr6'\)/);
|
||
|
||
// 卡片标题不再退回 Font Awesome 字形。
|
||
for (const [name, source] of [['credits-wallet.php', wallet], ['credits-balance.php', balance]]) {
|
||
const title = source.slice(source.indexOf('uc-asset-card__title'), source.indexOf('uc-asset-card__title') + 400);
|
||
assert.doesNotMatch(title, /fa fas fa-money-bill|fa fas fa-coins/, name);
|
||
}
|
||
});
|
||
|
||
test('等级页经验任务行使用参考主题的 trend-color 图标', () => {
|
||
const level = read('inc/helpers/user-center-renderers/profile-level.php');
|
||
|
||
// 参考主题:每条经验任务 = trend-color + 「+ N」,成长体系标题同图标。
|
||
assert.match(level, /jio_icon_markup\('jiosvg-trend-color', 'icon mr6 em09'\)/);
|
||
assert.match(level, /jio_icon_markup\('jiosvg-trend-color', 'icon mr6 em12'\)/);
|
||
assert.doesNotMatch(level, /fa fas fa-bolt|fa fas fa-chart-line/);
|
||
});
|