- 移除微信订阅推送功能(云函数/订阅管理页),回归纯客户端零后端架构 - 新增今日黄历默认展示卡片 TodayAlmanacCard(9 语言翻译) - i18n 修复:启用 globalInjection 修复 $t 未注入,插值消息全部改为 Messages Functions 适配小程序端(63 处) - 修复底部导航切换失效与运势页数据不刷新 - 统一设计令牌(深褐主色 + 印红强调色),组件 UI 规范重构 - 图标 iconfont 化(FontAwesome 子集化,修复 Android 豆腐块) - 新增 postcss-px2rpx 机型自适应(仅 mp-weixin 构建生效) - 新增 5 个用户旅程 E2E 测试(31 用例)与验收报告 - 补充微信小程序项目配置(appid)
135 lines
4.1 KiB
Python
135 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
小程序 iconfont 生成工具(FontAwesome 子集化 + base64 输出)
|
||
|
||
用法: python3 scripts/iconfont-build.py <woff2路径> <输出css路径> [--names name1,name2,...]
|
||
示例: python3 scripts/iconfont-build.py node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff2 src/styles/iconfont.css --names calendar,star,heart
|
||
|
||
功能:
|
||
1. 将 woff2 转为 ttf
|
||
2. 按 --names 指定的图标名子集化(保留最小字形,减小包体)
|
||
3. 生成 base64 内联 @font-face CSS(font-family: 'fa-icons')
|
||
4. 输出 unicode 映射 JSON(供 Icon 组件使用)
|
||
|
||
图标名 -> unicode 映射(FontAwesome v6 fa-solid):
|
||
"""
|
||
import sys
|
||
import json
|
||
import base64
|
||
import argparse
|
||
from pathlib import Path
|
||
|
||
from fontTools.ttLib import TTFont
|
||
from fontTools import subset
|
||
|
||
# FontAwesome v6 fa-solid 图标名 -> unicode 码点
|
||
ICON_NAMES = {
|
||
'arrow-up': 0xF062,
|
||
'arrow-down': 0xF063,
|
||
'arrow-left': 0xF060,
|
||
'arrow-right': 0xF061,
|
||
'check': 0xF00C,
|
||
'close': 0xF00D,
|
||
'right': 0xF054,
|
||
'checkbox-checked': 0xF14A,
|
||
'checkbox-unchecked': 0xF0C8,
|
||
'plus': 0xF067,
|
||
'minus': 0xF068,
|
||
'search': 0xF002,
|
||
'calendar': 0xF073,
|
||
'star': 0xF005,
|
||
'heart': 0xF004,
|
||
'settings': 0xF013,
|
||
'home': 0xF015,
|
||
'user': 0xF007,
|
||
'info': 0xF129,
|
||
'warning': 0xF071,
|
||
'refresh': 0xF021,
|
||
'download': 0xF019,
|
||
'upload': 0xF093,
|
||
'share': 0xF064,
|
||
'copy': 0xF0C5,
|
||
'delete': 0xF1F8,
|
||
'edit': 0xF044,
|
||
'filter': 0xF0B0,
|
||
'sort': 0xF0DC,
|
||
'export': 0xF14D,
|
||
'history': 0xF1DA,
|
||
'bookmark': 0xF02E,
|
||
'chevron-up': 0xF077,
|
||
'chevron-down': 0xF078,
|
||
'chevron-left': 0xF053,
|
||
'chevron-right': 0xF054,
|
||
}
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(description='FontAwesome iconfont 子集化构建')
|
||
parser.add_argument('woff2', help='fa-solid woff2 字体路径')
|
||
parser.add_argument('output_css', help='输出 CSS 路径')
|
||
parser.add_argument('--names', help='逗号分隔的图标名(默认全部)')
|
||
parser.add_argument('--font-family', default='fa-icons', help='字体族名')
|
||
args = parser.parse_args()
|
||
|
||
# 解析图标名
|
||
if args.names:
|
||
names = [n.strip() for n in args.names.split(',') if n.strip()]
|
||
else:
|
||
names = list(ICON_NAMES.keys())
|
||
|
||
# 收集 unicode
|
||
unicodes = []
|
||
mapping = {}
|
||
missing = []
|
||
for n in names:
|
||
if n not in ICON_NAMES:
|
||
print(f'⚠️ 未知图标名: {n}'); continue
|
||
unicodes.append(ICON_NAMES[n])
|
||
mapping[n] = ICON_NAMES[n]
|
||
|
||
# 加载并验证 cmap
|
||
tmp_ttf = Path('/tmp/fa-icons-subset.ttf')
|
||
font = TTFont(args.woff2)
|
||
cmap = font.getBestCmap()
|
||
for n, cp in mapping.items():
|
||
if cp not in cmap:
|
||
missing.append(f'{n}(U+{cp:04X})')
|
||
if missing:
|
||
print(f'⚠️ 缺失字形: {", ".join(missing)}')
|
||
print(f'图标数: {len(mapping)}')
|
||
|
||
# 子集化
|
||
options = subset.Options()
|
||
options.desubroutinize = True
|
||
options.ignore_missing_glyphs = True
|
||
options.drop_tables += ['GSUB', 'GPOS', 'GDEF', 'kern', 'cmap'] if False else []
|
||
sub = subset.Subsetter(options=options)
|
||
sub.populate(unicodes=unicodes)
|
||
sub.subset(font)
|
||
font.save(str(tmp_ttf))
|
||
|
||
# base64
|
||
b64 = base64.b64encode(tmp_ttf.read_bytes()).decode()
|
||
print(f'子集 ttf: {(tmp_ttf.stat().st_size/1024):.0f}KB | base64: {(len(b64)/1024):.0f}KB')
|
||
|
||
# 生成 CSS
|
||
css = f"""/* 自动生成: scripts/iconfont-build.py —— FontAwesome 子集化图标字体(仅含所需字形) */
|
||
@font-face {{
|
||
font-family: '{args.font_family}';
|
||
src: url(data:font/ttf;charset=utf-8;base64,{b64}) format('truetype');
|
||
font-weight: normal;
|
||
font-style: normal;
|
||
}}
|
||
"""
|
||
out = Path(args.output_css)
|
||
out.parent.mkdir(parents=True, exist_ok=True)
|
||
out.write_text(css)
|
||
print(f'CSS 已生成: {out} ({len(css)/1024:.0f}KB)')
|
||
|
||
# 输出映射 JSON(供 Icon 组件)
|
||
json_path = Path(args.output_css).with_suffix('.json')
|
||
json_path.write_text(json.dumps(mapping, ensure_ascii=False, indent=2))
|
||
print(f'映射已生成: {json_path}')
|
||
|
||
if __name__ == '__main__':
|
||
main()
|