update at 2026-02-07 13:32:31
This commit is contained in:
56
PLAN.md
56
PLAN.md
@@ -6,6 +6,13 @@
|
||||
|
||||
**设计来源**: [Figma 设计稿](https://www.figma.com/design/S7WVUzg3Z0DMWjYUC6dJzN/font2svg?node-id=3-5&m=dev)
|
||||
|
||||
## 🔄 最新机制更新(2026-02-07)
|
||||
|
||||
- 字体唯一来源目录调整为 `frontend/public/fonts/`
|
||||
- 删除独立 `font/` 源目录流程
|
||||
- `pnpm run prepare-fonts` 仅执行字体扫描并重建 `frontend/public/fonts.json`
|
||||
- 如本文后续历史段落仍出现 `font/` 或复制流程,请以上述机制为准
|
||||
|
||||
## 📋 Figma Annotations 功能需求清单
|
||||
|
||||
以下所有功能需求来自 Figma 设计中各组件的 annotation 标注:
|
||||
@@ -25,7 +32,7 @@
|
||||
- ✅ **批量导出**: 选中多个字体时批量导出
|
||||
|
||||
### 4. 字体选择区 (节点 21:185)
|
||||
- ✅ **数据源**: 从 `font/` 目录读取所有字体
|
||||
- ✅ **数据源**: 从 `frontend/public/fonts/` 目录读取所有字体
|
||||
- ✅ **树状结构**: 字体按**目录树状分组**
|
||||
- ✅ **展开/收拢**: 支持展开和收拢
|
||||
- ✅ **单选**: 字体支持单个选择
|
||||
@@ -95,7 +102,7 @@
|
||||
### 关键约束
|
||||
- ✅ 保持 `font2svg.py` 不变,仅作为参考
|
||||
- ✅ 纯前端实现,无需后端服务器
|
||||
- ✅ 字体文件放在 `font/` 目录
|
||||
- ✅ 字体文件放在 `frontend/public/fonts/` 目录
|
||||
- ✅ SVG 图标放在 `src/assets/icons/`
|
||||
- ✅ 应用图标为 `src/assets/webicon.png`
|
||||
- ✅ 使用 fonttools.subset 预处理字体(构建时)
|
||||
@@ -106,47 +113,26 @@
|
||||
|
||||
```
|
||||
font2svg/
|
||||
├── font/ # 源字体文件(不打包)
|
||||
│ ├── 庞门正道/
|
||||
│ ├── 王漢宗/
|
||||
│ └── 其他字体/
|
||||
├── public/
|
||||
│ └── fonts/ # 构建时生成的字体子集
|
||||
├── scripts/
|
||||
│ └── prepare-fonts.py # 字体预处理脚本(fonttools.subset)
|
||||
├── src/
|
||||
├── frontend/
|
||||
│ ├── public/
|
||||
│ │ ├── fonts/ # 字体唯一来源目录(支持分类子目录)
|
||||
│ │ └── fonts.json # 由脚本重建的字体清单
|
||||
│ └── src/
|
||||
│ ├── assets/
|
||||
│ │ ├── icons/ # SVG UI 图标
|
||||
│ │ └── webicon.png # 应用图标
|
||||
│ ├── components/
|
||||
│ │ ├── FontSelector.vue # 字体选择器(树状结构)
|
||||
│ │ ├── FontTree.vue # 字体树组件(展开/收拢)
|
||||
│ │ ├── FavoritesList.vue # 收藏字体列表
|
||||
│ │ ├── TextInput.vue # 文本输入框
|
||||
│ │ ├── LetterSpacingSlider.vue# 字间距调整滑块
|
||||
│ │ ├── SvgPreview.vue # SVG 预览区
|
||||
│ │ ├── PreviewItem.vue # 单个字体预览项
|
||||
│ │ └── ExportPanel.vue # 导出面板
|
||||
│ ├── composables/
|
||||
│ │ ├── useFont.ts # 字体加载和管理
|
||||
│ │ ├── useSvgGenerate.ts # SVG 生成核心逻辑
|
||||
│ │ ├── useTextShaping.ts # HarfBuzz text shaping
|
||||
│ │ └── useFavorites.ts # 收藏功能
|
||||
│ ├── stores/
|
||||
│ │ ├── fontStore.ts # 字体状态管理
|
||||
│ │ └── uiStore.ts # UI 状态(预览大小等)
|
||||
│ ├── utils/
|
||||
│ │ ├── harfbuzz.ts # HarfBuzz WASM 封装
|
||||
│ │ ├── font-loader.ts # 字体文件加载
|
||||
│ │ ├── svg-builder.ts # SVG 文档构建
|
||||
│ │ └── download.ts # 文件下载工具
|
||||
│ ├── types/
|
||||
│ │ └── font.d.ts # TypeScript 类型定义
|
||||
│ ├── App.vue # 根组件
|
||||
│ └── main.ts # 应用入口
|
||||
├── vite.config.ts
|
||||
├── tsconfig.json
|
||||
├── uno.config.ts # UnoCSS 配置
|
||||
│ ├── App.vue
|
||||
│ └── main.ts
|
||||
├── scripts/
|
||||
│ └── generate-font-list.py # 扫描 frontend/public/fonts 并重建 fonts.json
|
||||
├── frontend/vite.config.ts
|
||||
├── frontend/tsconfig.json
|
||||
├── frontend/uno.config.ts
|
||||
└── package.json
|
||||
```
|
||||
|
||||
|
||||
17
README.md
17
README.md
@@ -44,11 +44,9 @@
|
||||
## 目录说明
|
||||
|
||||
- `frontend/`: 前端应用源码
|
||||
- `frontend/public/fonts/`: 前端静态字体目录(由脚本生成)
|
||||
- `frontend/public/fonts.json`: 字体清单(由脚本生成)
|
||||
- `font/`: 原始字体目录(按分类子目录组织)
|
||||
- `scripts/generate-font-list.py`: 生成 `fonts.json`
|
||||
- `scripts/copy-fonts.py`: 复制字体到 `frontend/public/fonts`
|
||||
- `frontend/public/fonts/`: 字体目录(唯一字体来源,支持分类子目录)
|
||||
- `frontend/public/fonts.json`: 字体清单(由脚本重建)
|
||||
- `scripts/generate-font-list.py`: 扫描 `frontend/public/fonts` 并生成 `fonts.json`
|
||||
|
||||
## 环境要求
|
||||
|
||||
@@ -69,7 +67,7 @@ pnpm -C frontend install
|
||||
将字体放入如下结构:
|
||||
|
||||
```text
|
||||
font/
|
||||
frontend/public/fonts/
|
||||
手写/
|
||||
字体A.ttf
|
||||
黑体/
|
||||
@@ -82,10 +80,7 @@ font/
|
||||
pnpm run prepare-fonts
|
||||
```
|
||||
|
||||
该命令会:
|
||||
|
||||
1. 扫描 `font/` 生成 `frontend/public/fonts.json`
|
||||
2. 复制字体到 `frontend/public/fonts/`
|
||||
该命令会扫描 `frontend/public/fonts/` 并重新生成 `frontend/public/fonts.json`。
|
||||
|
||||
### 3. 启动开发环境
|
||||
|
||||
@@ -107,7 +102,7 @@ pnpm run build
|
||||
# 本地预览构建产物
|
||||
pnpm run preview
|
||||
|
||||
# 重新生成字体清单并复制字体
|
||||
# 重新生成字体清单
|
||||
pnpm run prepare-fonts
|
||||
```
|
||||
|
||||
|
||||
@@ -104,6 +104,13 @@
|
||||
"category": "庞门正道",
|
||||
"path": "/fonts/庞门正道/庞门正道标题体.ttf"
|
||||
},
|
||||
{
|
||||
"id": "庞门正道-测试/庞门正道标题体",
|
||||
"name": "庞门正道标题体",
|
||||
"filename": "庞门正道标题体.ttf",
|
||||
"category": "庞门正道-测试",
|
||||
"path": "/fonts/庞门正道-测试/庞门正道标题体.ttf"
|
||||
},
|
||||
{
|
||||
"id": "王漢宗/王漢宗勘亭流繁",
|
||||
"name": "王漢宗勘亭流繁",
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"dev": "cd frontend && pnpm run dev",
|
||||
"build": "cd frontend && pnpm run build",
|
||||
"preview": "cd frontend && pnpm run preview",
|
||||
"prepare-fonts": "python3 scripts/generate-font-list.py && python3 scripts/copy-fonts.py"
|
||||
"prepare-fonts": "python3 scripts/generate-font-list.py"
|
||||
}
|
||||
}
|
||||
|
||||
4
run.sh
4
run.sh
@@ -4,3 +4,7 @@ source .venv/bin/activate
|
||||
lsof -ti:5173,5174,5175,5176 | xargs kill -9 2>/dev/null;
|
||||
|
||||
python font2svg.py --fontdir font --text "星程紫微" --outdir svg
|
||||
|
||||
|
||||
# 新增字体放在frontend/public/fonts目录下,运行以下命令,fonts.json会被更新
|
||||
npm run prepare-fonts
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
生成字体清单 JSON 文件
|
||||
扫描 font/ 目录下的所有字体文件,生成一个 JSON 文件供前端使用
|
||||
扫描 frontend/public/fonts/ 目录下的所有字体文件,生成 frontend/public/fonts.json
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
def scan_fonts(font_dir='font'):
|
||||
def scan_fonts(font_dir='frontend/public/fonts'):
|
||||
"""扫描字体目录,返回字体信息列表"""
|
||||
fonts = []
|
||||
font_dir_path = Path(font_dir)
|
||||
@@ -17,25 +17,27 @@ def scan_fonts(font_dir='font'):
|
||||
print(f"字体目录不存在: {font_dir}")
|
||||
return fonts
|
||||
|
||||
# 遍历所有子目录
|
||||
for category_dir in sorted(font_dir_path.iterdir()):
|
||||
if not category_dir.is_dir():
|
||||
# 递归遍历 fonts 目录(支持多级分类)
|
||||
for font_file in sorted(font_dir_path.rglob('*')):
|
||||
if not font_file.is_file():
|
||||
continue
|
||||
|
||||
category_name = category_dir.name
|
||||
|
||||
# 遍历类别下的所有字体文件
|
||||
for font_file in sorted(category_dir.iterdir()):
|
||||
if font_file.suffix.lower() not in ['.ttf', '.otf']:
|
||||
continue
|
||||
|
||||
relative_parent = font_file.parent.relative_to(font_dir_path)
|
||||
category_name = str(relative_parent).replace('\\', '/')
|
||||
if category_name == '.':
|
||||
category_name = '未分类'
|
||||
|
||||
relative_path = font_file.relative_to(font_dir_path).as_posix()
|
||||
|
||||
# 生成字体信息
|
||||
font_info = {
|
||||
'id': f"{category_name}/{font_file.stem}",
|
||||
'name': font_file.stem,
|
||||
'filename': font_file.name,
|
||||
'category': category_name,
|
||||
'path': f"/fonts/{category_name}/{font_file.name}",
|
||||
'path': f"/fonts/{relative_path}",
|
||||
}
|
||||
|
||||
fonts.append(font_info)
|
||||
@@ -44,8 +46,8 @@ def scan_fonts(font_dir='font'):
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
# 扫描字体
|
||||
fonts = scan_fonts()
|
||||
# 扫描字体(唯一来源:frontend/public/fonts)
|
||||
fonts = scan_fonts('frontend/public/fonts')
|
||||
|
||||
print(f"找到 {len(fonts)} 个字体文件")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user