From 951eda9c58e166d8074939402417b55090acbcc0 Mon Sep 17 00:00:00 2001 From: douboer Date: Sat, 7 Feb 2026 13:32:31 +0800 Subject: [PATCH] update at 2026-02-07 13:32:31 --- PLAN.md | 70 ++++++++++++++--------------------- README.md | 17 +++------ frontend/public/fonts.json | 7 ++++ package.json | 2 +- run.sh | 4 ++ scripts/generate-font-list.py | 52 +++++++++++++------------- 6 files changed, 73 insertions(+), 79 deletions(-) diff --git a/PLAN.md b/PLAN.md index 48f699b..d23ecea 100644 --- a/PLAN.md +++ b/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/ # 构建时生成的字体子集 +├── frontend/ +│ ├── public/ +│ │ ├── fonts/ # 字体唯一来源目录(支持分类子目录) +│ │ └── fonts.json # 由脚本重建的字体清单 +│ └── src/ +│ ├── assets/ +│ │ ├── icons/ # SVG UI 图标 +│ │ └── webicon.png # 应用图标 +│ ├── components/ +│ ├── composables/ +│ ├── stores/ +│ ├── utils/ +│ ├── types/ +│ ├── App.vue +│ └── main.ts ├── scripts/ -│ └── prepare-fonts.py # 字体预处理脚本(fonttools.subset) -├── 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 配置 +│ └── generate-font-list.py # 扫描 frontend/public/fonts 并重建 fonts.json +├── frontend/vite.config.ts +├── frontend/tsconfig.json +├── frontend/uno.config.ts └── package.json ``` diff --git a/README.md b/README.md index 228cfa6..62e448a 100644 --- a/README.md +++ b/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 ``` diff --git a/frontend/public/fonts.json b/frontend/public/fonts.json index dc8670b..141559d 100644 --- a/frontend/public/fonts.json +++ b/frontend/public/fonts.json @@ -104,6 +104,13 @@ "category": "庞门正道", "path": "/fonts/庞门正道/庞门正道标题体.ttf" }, + { + "id": "庞门正道-测试/庞门正道标题体", + "name": "庞门正道标题体", + "filename": "庞门正道标题体.ttf", + "category": "庞门正道-测试", + "path": "/fonts/庞门正道-测试/庞门正道标题体.ttf" + }, { "id": "王漢宗/王漢宗勘亭流繁", "name": "王漢宗勘亭流繁", diff --git a/package.json b/package.json index 8bb9fb4..05ea520 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/run.sh b/run.sh index ab988bb..569a53c 100755 --- a/run.sh +++ b/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 diff --git a/scripts/generate-font-list.py b/scripts/generate-font-list.py index 851941c..20689fd 100644 --- a/scripts/generate-font-list.py +++ b/scripts/generate-font-list.py @@ -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,35 +17,37 @@ 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 - - # 生成字体信息 - 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}", - } - - fonts.append(font_info) + 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/{relative_path}", + } + + fonts.append(font_info) return fonts def main(): """主函数""" - # 扫描字体 - fonts = scan_fonts() + # 扫描字体(唯一来源:frontend/public/fonts) + fonts = scan_fonts('frontend/public/fonts') print(f"找到 {len(fonts)} 个字体文件")