Skip to content
sun2otPublic

About

一个本地优先的简历编辑器

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Folio · 纯前端简历工作室

一个本地优先的简历编辑器。React + TypeScript + Vite,不需要服务器、账户、API Key 或数据库服务。全部数据留在浏览器 IndexedDB,部署产物为纯静态文件。

启动

需要 Node.js 22.13+ 与 pnpm 12.6.0(项目 packageManager 固定版本)。

pnpm install
pnpm dev
# http://127.0.0.1:5173
pnpm test                 # 协议、安全 Markdown、字体分片、GitHub 卡片、分页与布局测试
pnpm format:check         # 检查统一代码格式
pnpm check:tests          # 独立检查浏览器测试与 Playwright 配置的类型
pnpm check:release        # 校验应用版本与倒序更新日志一致
pnpm snapshot:github      # 预取 github-repos.json 中的公开仓库(可选,需要外网)
pnpm build                # 严格 TypeScript 检查 + 生产打包
pnpm exec playwright install chromium
pnpm test:e2e             # 对已构建的 dist 运行 Chromium 集成与导出测试
pnpm preview              # 本地检查 dist 部署产物

若测试浏览器下载不可用,可使用本机 Chrome:PowerShell 执行 $env:PLAYWRIGHT_CHANNEL='chrome'; pnpm test:e2e;POSIX Shell 使用 PLAYWRIGHT_CHANNEL=chrome pnpm test:e2e。该方式启动独立无头实例。仓库固定间接依赖 browserslist 4.28.0,避免最初安装时刚发布版本触发 pnpm 发布时间保护;升级时保留正常发布时间策略并重新验证。

功能

  • 工作台品牌与浏览器标签使用 public/folio.svg。新建简历默认显示 public/avatar.webp;「基本信息 → 使用默认头像」可恢复,替换或移除后刷新会保留选择。默认头像首次使用时转为本地 PNG data URL,导出文件无需访问图片路径。
  • 基本信息支持电话、邮箱、性别、GitHub、网站、民族、出生日期、政治面貌、籍贯、户籍、城市和工作年限等预设字段;字段可改名(例如把「出生日期」改成「生日」)、换图标、上下移动、删除,也可插入预设或空白字段。非空字段带图标,可选 1–3 列及信息区域宽度。列宽随内容分配,缩窄信息区域优先收紧列间距,较长字段保留所需宽度;超过纸张可用空间的内容完整换行。
  • 基本信息可设置姓名字号(9–60px)、求职意向字号(9–30px)、信息字段默认字号(9–30px),每条字段还可单独覆盖字号或恢复「跟随默认」;字段图标同步缩放。省略设置时沿用原来的 34 / 13 / 12px,测量、预览、PDF、HTML 与打印共用实际字号。
  • 模块标题和个人信息共用完整的 Lucide 本地图标选择器,当前锁定版本提供 1,564 个选项(含别名与原有短键)。原先 17 个图标同样来自 lucide-react,并非手绘;现在可以选择完整目录,包含 pencil、trend、gear 快捷键及 lucide:Microscope 等库名称。小窗支持 SVG 预览、英文 key / 名称搜索和常用中文词(如铅笔、趋势、齿轮、科研),每页 60 个选项,支持方向键、Home / End、Enter、Escape 与翻页。图标随应用本地打包,不调用 Iconify 或其他远程图标服务,导出为内联 SVG,不依赖图标字体。
  • 头像与二维码独立于章节:在「头像与二维码」设置页码、尺寸和坐标,或直接在预览中自由拖动(支持跨已有页面)、用方向键微调。Shift + 拖动锁定水平或垂直方向(轴向由起始移动量决定),Shift + 方向键移动 10 px。头像保留圆形/方形裁切与取景缩放;二维码完整显示白边。
  • 文本、工作经历、精选项目、教育背景四类模块。经历以独立条目填写单位/学校/项目、角色/学历、专业、时间、地点与 Markdown 详情;分别使用「添加工作经历」「添加项目」「添加教育背景」,标题布局按工作 / 项目 / 教育区分名称。可增删、上下移动条目,选择左右或左中右紧凑布局,日期与地点同行呈现,空间不足自然换行。
  • 项目条目可附加 GitHub 仓库卡片(作者头像、名称、作者、简介、语言、Star / Fork)。默认离线:可用构建时预取的公开仓库快照,或手动填写;需要关键词搜索或刷新 Star 时打开联网开关(GitHub API 需要外网),并可填写自建 HTTPS 代理加速。作者头像在查询时抓取一次并转成本地图片存档,之后卡片、备份与导出都不再联网;简历上不显示快照日期。
  • 「精选项目 → 科研卡片」支持英文论文、中文论文、基金和专利:填写中英文成果名称、期刊 / 会议(基金与专利可填资助 / 授予机构)、作者排序、自定义级别或类型标签。提供 SCI 分区、CCF-A/B/C、EI、核心、基金级别和三种专利类型建议;可明确填写分区口径,例如 SCI Q1(JCR)。状态支持出版、校稿、反修、外审、投稿及立项 / 结项 / 授权;开源信息、状态、链接均可隐藏。DOI 或完整 HTTP / HTTPS 地址只通过图标链接呈现,不显示原始地址,也不联网读取元数据。科研卡片与仓库卡片可共存,随保存、模板、备份、HTML、PDF 与打印保留;文字继承模块颜色,级别与状态使用克制的标签样式。
  • 新建简历默认开启虚构的 folio-demo/atlas-workspace GitHub 卡片,以及论文 Diffusion-based contrastive learning for multimodal recommendation 的科研卡片(Knowledge and Information Systems、第二作者兼通讯作者、SCI 二区、出版、已开源、DOI 10.1007/s10115-026-02735-z),便于预览组件样式。示例仅用于演示,两种卡片都不自动联网;用户修改或隐藏后刷新会保留选择,已有文档不会自动补卡片。
  • Markdown 支持加粗、斜体、高亮 ==内容==、行内代码及格式嵌套。工具栏、Ctrl/Cmd+B / I、Tab 列表缩进。为简历安全和可移植性,禁用任意 HTML 样式、脚本、外部图片和嵌入内容。
  • 拖动模块排序;上移/下移按钮支持键盘操作。整行/半行布局、显示隐藏、模块前换页。相邻半行模块组成一行。浮动图片不占正文空间,请主动留白;指向尚不存在的页会新增空白页。
  • 默认智能分页:工作 / 项目 / 教育在完整条目之间换页,文本在完整段落或顶层列表项之间换页,尽量使用上一页余量。模块标题只显示一次,跨页直接衔接正文;有序列表接续编号,嵌套列表随父项保留,双栏分别续排并保持原列位置。模块的「保持整个模块在同一页」可恢复整体换页,「在此模块前换页」仍控制模块开始位置。
  • 「样式 → 页眉与页脚」可编辑或独立关闭页眉、页脚标识 / ID、页码,分别设置颜色、字体和 9–30px 字号。默认跟随全局正文色、全局字体,默认字号 9px;重置恢复默认样式。页码格式支持 {page}、{pages},过大的页脚会提示缩小字号或缩短内容后导出。工作台主要控件字号提升至 14px,辅助文字至少 12px;预览缩放独立于简历纸张排版。
  • 同时关闭「显示页脚标识」和「显示页码」时,原先的 54px 页脚预留会释放给正文,下边距从 74px 降为 20px,正文可用高度从 994px 增至 1048px,能放下的后续模块会自动上浮。只关闭其中一项时仍保留显示区域;重新开启会重新分页。预览、隐藏测量、HTML、PDF 和打印共用动态尺寸。
  • 颜色分层设置:「样式」分别设置全局标题颜色和全局正文颜色,两者各提供七种中国传统预设色与自定义取色,悬停显示传统色名称。姓名与模块标题(含标题图标)跟随标题颜色;求职意向、每条基本信息(含图标)、模块正文、仓库名称与默认 GitHub 图标跟随正文颜色,各项均可单独取色。模块的字体、字号和颜色在同一行设置,圆形取色按钮显示当前生效颜色,旁边的重置图标恢复「跟随全局」,已继承时置灰。
  • 「样式 → 分割线」分别设置基本信息、模块标题、正文 Markdown 分割线和页脚的颜色与粗细(0–12 px,0 表示隐藏);构筑模板另支持顶部色带。重置使用当前模板默认值,切换模板保留单独设置,测量、预览与所有导出共用这些样式。
  • 三套模板:青序、书简、构筑。模板切换不修改正文、图片、标题及字体;会重设模块初始栏宽。
  • 侧栏底部显示 GitHub、博客与「更新日志」图标,以及当前应用版本号,并保留「备份我的数据」按钮。更新日志弹窗按版本倒序展示新增、优化与修复,支持滚轮、键盘和 Escape 关闭,内容随应用打包,离线也能查看。GitHub 与博客分别指向 sun2ot/folio 与 abdc.net.cn,悬停提示和可访问名称保留作者信息。JSON 备份也可从顶栏「导出简历」进入。
  • 220ms 防抖实时预览,也可手动更新;500ms 防抖自动保存;40 步会话内撤销重做(连续输入合并)。
  • PDF、可离线查看的独立 HTML、完整 JSON 数据导出及校验导入。

导出与兼容性

预览、分页、HTML、PDF 和打印共用 src/resume.css 与 ResumeView。纸张为 A4,内部画布固定 794 × 1122 CSS px,不随编辑器缩放改变排版。

保真 PDF:html2canvas 以 2 倍分辨率逐页绘制,jsPDF 写入 A4。复用预览 DOM,在无缩放、无滚动裁切的临时容器中生成,避免后续页坐标偏移。逐页释放画布避免超长 canvas 的浏览器尺寸限制。等待字体与图片解码,导出时冻结编辑器。输出为图片型 PDF,文字不可选择、不能保证 ATS 自动解析。高级 CSS 渲染受 html2canvas 支持范围限制;新增样式需做视觉回归。推荐招聘系统使用下述文字版。

保真 PDF 在相同 DOM 的链接位置写入可点击注释,保留科研图标、仓库卡片和 Markdown 的网页 / 邮件 / 电话链接,不需要在纸面显示 URL。

打印 / 文字 PDF:浏览器原生打印保留可选择文字与链接。选择「另存为 PDF」、A4、缩放 100%、无边距、开启背景图形、关闭页眉页脚。不同浏览器和打印驱动可能产生细微差异,不声称所有平台像素一致。

HTML:只内嵌正文实际用到的字体分片和上传图片,不含应用 JavaScript、编辑器或网络依赖;保留多页布局、Markdown 链接和打印样式。文件约数百 KB 至数 MB,取决于字符数与图片。

分页:以完整条目、段落或顶层列表项为单位,避免把能部分放下的长模块整体推到下一页。小标题与随后的一段内容保持同页;一条经历连同 GitHub / 科研卡片不会分开。单个不可分内容块高于一页,或开启「保持整个模块在同一页」后模块仍过高时,会明确警告并阻止排版导出,请拆分该内容或减小字号。JSON 备份仍可导出。测量使用同宽的实际片段并保留亚像素高度,不自动压缩字体,也不越过正文顺序回填后续模块。浮动图片仍不自动绕排。

目标浏览器为现代 Chromium、Firefox、Safari,使用 IndexedDB、HTML dialog、CSS zoom、Font Loading API。自动化默认覆盖 Chromium;Firefox/Safari 需在发布前按 docs/TESTING.md 手动验证。手机可编辑与预览;大屏更适合完整排版。

数据与隐私

  • 当前协议为 v4,IndexedDB 键 folio.resume.v4。开发阶段不兼容或迁移旧数据;旧 JSON 会拒绝导入,旧存储键不读取或覆盖。相同站点、相同浏览器保留数据;更换域名/浏览器、清理站点数据或隐私模式退出会影响保存。
  • 等待顶栏显示「已保存在此浏览器」再关闭页面。保存失败时会明确显示错误,建议立即导出 JSON。
  • 无统计追踪、上传 API、外部字体 CDN。上传图片转换为本地 PNG;只允许 PNG/JPEG/WebP,单文件最大 5 MB,解码后最大 4000 万像素。
  • 唯一的外网请求是用户显式开启的 GitHub 仓库查询与作者头像抓取,只发送仓库标识或搜索关键词;头像一次抓取后存为本地图片。离线快照、手动卡片与所有导出都不联网。代理地址仅保存在当前会话内存中,不写入文档或备份。
  • JSON 文件最大 30 MB,协议校验版本、类型、唯一 ID、唯一字段键、颜色、字号、图片 data URL 及图片坐标边界。最大 80 个模块,每个经历模块最多 30 个条目,每段 Markdown 最多 30,000 字符。导入失败不替换当前文档。
  • 导入会替换当前文档,可立即撤销;跨设备迁移请导出后导入 JSON。备份含个人信息与图片,请自行妥善保管。暂不提供多文档库、多人协作、云同步和跨标签页冲突合并。

字体

中文:Noto Sans SC(思源黑体)、Noto Serif SC(思源宋体);英文:Inter、Source Serif 4。通过 Fontsource 依赖本地打包,中文使用简体字集。罕见字和其他语言会回退到系统字体,需检查最终效果。为控制体积只装载 400 常规字重,粗体及斜体由浏览器合成。

字体按 unicode-range 拆分为 300 多个分片。预览时浏览器只下载命中的分片;构建产物仍包含全部资源文件,但不会一次加载。HTML 导出不嵌入整套字体:build/fonts.ts 把 @font-face 规则编译成 virtual:folio-fonts 模块,导出时按文档实际字符筛选分片再内嵌,文件大小与正文字符数相关。切换字体后请重新导出以刷新嵌入内容。

字体许可均随上游包提供。pnpm build 自动保留 public/licenses/ 的字体许可,并将项目许可证、源码获取说明与运行时依赖的许可文本写入 dist;参考 docs/THIRD_PARTY.md。

静态部署

pnpm install --frozen-lockfile
pnpm test
pnpm build

上传 dist 目录内容 到任何静态 Web 服务。Vite base: './' 支持域名根目录和子路径。无客户端路由,无需 SPA rewrite;不要直接双击 dist/index.html(开发产物的模块与字体需 HTTP 服务)。

  • Nginx:将 dist 复制到站点 root,index index.html;。/assets/ 可设置长期 immutable 缓存,index.html 设为 no-cache;启用 HTTPS 与 gzip/Brotli。
  • Cloudflare Pages / Netlify / Vercel:安装命令 pnpm install --frozen-lockfile,构建命令 pnpm build,输出目录 dist。选择 Node 22,不配置 API 或环境变量。
  • GitHub Pages:Actions 执行构建后通过 actions/upload-pages-artifact 上传 dist,再用 actions/deploy-pages 发布。当前仓库的 .github/workflows/ci.yml 只测试并发布 Release 压缩包,不部署 Pages。
  • 内网环境可完全离线部署 dist,应用无运行时外部依赖。首次获取应用资源仍需访问静态服务器;未实现 Service Worker 离线启动缓存。

持续集成与发布

.github/workflows/ci.yml:推送 main、提交 PR 或手动触发。check 任务安装依赖后执行单元测试、格式检查、pnpm check:tests、仓库快照更新(非 PR;失败保留内置快照)、生产构建与 Playwright Chromium 测试。浏览器测试访问本次 dist 的根路径与 /folio/ 子路径,不复用开发服务;PDF 自动检查 A4、页数、正文非空和第二页图片位置。失败时上传 test-results/,其中包含 trace 和 PDF 页面渲染图。

主分支构建成功后,release 任务下载构建产物与对应源码,发布 folio-dist.zip、folio-dist.tar.gz、folio-source.tar.gz 和三者的 SHA256SUMS。源码归档包含该提交的构建文件、lockfile 和构建时更新的离线快照,以便重建发布产物。标签读取 package.json 的应用版本,格式为 v<version>(当前 v1.1.0),指向 $GITHUB_SHA;发布说明与页面弹窗共用 src/changelog.ts 的当前版本内容。已存在的 Release 会跳过,不覆盖原发布包或移动标签。PR 不发布 Release;静态站点包解压后按上述方式部署。

发布新版本时,同时递增 package.json.version 并在 src/changelog.ts 顶部加入对应版本、日期和面向用户的说明,重点写新增功能、体验优化与问题修复。pnpm check:release(也在构建前自动执行)会检查版本匹配、唯一性和倒序,防止页面与 Release 脱节。当前历史记录根据 6 次提交补记:0.1.0 → 6b32425、0.2.0 → a0815f5、0.3.0 → 0afd731、0.3.1 → 07560a7、0.3.2 → 08faa73、1.0.0 → 42556e6;这些是回顾里程碑,不代表当时发布过同名标签,也不补建历史标签。应用版本与简历数据协议 v4 独立。

如配置 CSP,至少允许同源脚本与字体、img-src 'self' data: blob:、font-src 'self' data:,以及动态内联样式(本应用使用 React style 与字体注入)。不要盲目启用阻断内联样式的策略。

开发入口

源码按职责组织,基本信息、模块内容、浮动图片编辑及字体颜色控件位于 src/editor/;共享头像与图标位于 src/ResumePrimitives.tsx。简历 DOM 的全部视觉规则仍在 src/resume.css。单元测试与对应逻辑相邻,浏览器测试按交互、排版、导出、仓库和部署分组。

官方参考:Vite 静态部署、html2canvas 配置。

许可证

Copyright (C) 2026 sun2ot。Folio 项目代码采用 GNU GPL v3,仅此版本(SPDX:GPL-3.0-only)。允许使用、修改和商业分发;分发修改版时须依照许可证提供对应源码、构建文件及修改说明,并保留版权与许可声明。第三方依赖与字体保留各自许可。

官方 Release 同时提供静态站点包与 folio-source.tar.gz;重新分发时应保留对应源码的获取途径。仅部署到服务器供浏览器访问也会向访问者分发前端 JavaScript,需按许可证提供对应源码。简历正文属于用户,不因使用 Folio 而自动变成 GPL 授权内容。

已知权衡

PDF 默认是 2× PNG 页面以换取视觉稳定,不适合依赖文字提取的 ATS;原生打印用于文字版。单个过高的段落或经历仍需用户拆分,整模块不拆分选项可能留下较大空白。浮动图片允许自由叠放,由用户留白,不自动绕排。中文简体字体不覆盖所有语言。仅承诺已运行环境的验证结果,Safari/Firefox 按发布清单检查。

GitHub 仓库查询需要能访问 api.github.com;无外网时请使用离线快照或手动填写,Star 会停留在快照时间。快照只在构建期刷新(CI 主分支构建或本地 pnpm snapshot:github),发布包内的快照可能落后于仓库现状。代理需使用者自行提供,本项目不内置也不推荐任何第三方镜像。

About

一个本地优先的简历编辑器

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages