ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

为 Resume-Matcher 添加全新简历模板:从组件到 PDF 渲染的完整实战指南

为 Resume-Matcher 添加全新简历模板:从组件到 PDF 渲染的完整实战指南 为 Resume-Matcher 添加全新简历模板从组件到 PDF 渲染的完整实战指南【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters more, locally with 100 LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher本文围绕 Resume-Matcher 前端的简历模板系统完整讲解如何从零新增一套简历排版模板从创建resume-{name}.tsx组件、理解TemplateProps数据契约与必备 CSS 类到注册进模板选择器、生成缩略图并最终打通 Playwright 驱动的 PDF 渲染链路。读完你将掌握一套可复现、可验证的模板接入流程并理解模板设置TemplateSettings如何在实时预览与打印 PDF 之间共享同一套 CSS 变量体系。模板系统全景先理解你要接入的骨架Resume-Matcher 的简历模板系统是一个前端组件 设置类型 CSS 变量 打印路由四位一体的架构。在动手添加新模板之前需要先看清这条链路模板组件每个模板是一个 React 组件位于 components/resume/例如resume-single-column.tsx、resume-two-column.tsx、resume-modern.tsx等统一出口components/resume/index.ts 集中 re-export 所有模板组件是外部引用模板的唯一入口设置类型定义lib/types/template-settings.ts 定义了TemplateSettings结构、默认值、以及从设置到 CSS 变量的映射函数settingsToCssVarsUI 控制面板components/builder/formatting-controls.tsx 提供模板选择与全部排版控件渲染与打印实时预览通过 CSS 变量直接作用PDF 生成则由后端 routers/resumes.py 拼接打印 URL交给 Playwright 打开 print/resumes/[id] 无头渲染。当前仓库已经注册了七套模板见 template-settings.ts 与 template-registration.test.ts 的断言它们是你新增模板时最好的参考实现模板 ID布局特征适用场景swiss-single全宽单栏内容密度最高1–2 页标准简历swiss-two-column65% 主栏 35% 侧栏内容密集的简历modern单栏 彩色强调标题需要主题色的单栏简历modern-two-column65% 35% 双栏 强调色彩色密集内容latex单栏衬线体、Title-Case 下划线标题、公司优先条目LaTeX 风格学术/经典简历clean极简无衬线单栏、大号灰色 UPPERCASE 标题、单行条目低调现代简历vivid63% 37% 彩色双栏Awesome-CV 血统彩色强调色简历其中latex与clean属于单字体族模板选择它们时会通过applyTemplatePreset自动注入签名字体latex 全衬线、clean 全无衬线但两个字体控件仍然可用用户可随后覆盖。快速接入新增模板的四步清单官方指南给出了一条精简路径这也是模板接入的最小操作集创建components/resume/resume-{name}.tsx—— 编写模板组件本体从components/resume/index.ts导出 —— 让模板进入统一出口加入FormattingControls模板选择器 —— 让用户在构建器中可见可选创建缩略图 —— 为选择器提供可视化预览。值得注意的是模板类型TemplateTypeswiss-single、swiss-two-column、modern、modern-two-column、latex、clean、vivid同样定义在 template-settings.ts因此新增模板时还需要在类型定义中追加你的模板 ID并在TEMPLATE_OPTIONS元数据数组template-settings.ts中登记名称与描述——否则选择器拿不到可渲染的选项。仓库的单元测试 template-registration.test.ts 会校验所有模板 ID 唯一且元数据非空这相当于模板注册的质量门禁。模板组件实现TemplateProps契约每个模板组件都遵循同一份数据契约。指南中的TemplateProps是理论接口而当前仓库实际模板的 props 略有演化——以 resume-vivid.tsx 为例真实签名是interface ResumeVividProps { data: ResumeData; // 简历完整数据 showContactIcons?: boolean; // 是否显示联系图标 sectionHeadings?: PartialResumeSectionHeadings; // 章节标题支持 i18n fallbackLabels?: PartialResumeFallbackLabels; // 兜底文案 }而ResumeData的结构见 docs/agent/design/template-system.md包含personalInfo姓名、职位、联系方式、summary、workExperience、education、personalProjects、additional技能/语言/证书/奖项、sectionMeta顺序与可见性以及customSections用户自定义章节。指南给出的骨架可以视为新模板的起点结合真实实现一个最小但完整的模板组件应当具备以下要素import { getSortedSections, getSectionMeta } from /lib/utils/section-helpers; import { SafeHtml } from ./safe-html; import baseStyles from ./styles/_base.module.css; import styles from ./styles/your-template.module.css; export function ResumeNewTemplate({ data, showContactIcons false }: ResumeNewTemplateProps) { const { personalInfo, summary, workExperience } data; const sortedSections getSortedSections(data); // 按用户设定的顺序/可见性排序 const allSections getSectionMeta(data); const isSectionVisible (key: string) allSections.find((s) s.key key)?.isVisible ?? true; return ( div classNameresume-print {/* Header */} header className{baseStyles[resume-header]} h1 className{baseStyles[resume-name]}{personalInfo?.name}/h1 {personalInfo?.title div className{baseStyles[resume-title]}{personalInfo.title}/div} /header {/* Sections */} {sortedSections.map((section) ( section key{section.id} className{baseStyles[resume-section]} h3 className{baseStyles[resume-section-title]}{section.displayName}/h3 div className{baseStyles[resume-items]} {/* 按 section.sectionType 渲染 text / itemList / stringList */} /div /section ))} /div ); }几个关键实现细节值得注意章节顺序与可见性不要硬编码章节顺序应使用getSortedSections/getSectionMeta见 lib/utils/section-helpers.ts这样用户在主简历中调整的顺序与可见性才能在模板中生效富文本安全渲染条目描述等富文本字段应通过SafeHtmlcomponents/resume/safe-html.tsx渲染保证 HTML 被清洗后再输出自定义章节支持用户通过AddSectionDialog添加的自定义章节text/itemList/stringList三种类型应像 resume-vivid.tsx 中的DynamicResumeSectionVivid那样被模板渲染而不是被忽略。必备 CSS 类模板的结构协议指南强调模板必须提供以下 CSS 类这既是样式约定也是 PDF 渲染的依赖.resume-print /* 根容器Playwright 等待此选择器出现 */ .resume-section /* 章节容器 */ .resume-section-title /* 章节标题 */ .resume-items /* 条目容器 */ .resume-item /* 单个条目禁止跨页断行 */在当前实现中这些类由共享样式表 styles/_base.module.css 提供关键行为包括.resume-section通过margin-bottom: var(--section-gap)控制章节间距.resume-items使用display: flex; flex-direction: column; gap: var(--item-gap)布局条目.resume-item设置了break-inside: avoid; page-break-inside: avoid保证单条记录在 PDF 与打印输出中不被拦腰截断.resume-section-title设置了break-after: avoid与orphans/widows: 3防止标题孤立在页尾media print块中进一步强化了这些防断页规则。因此新模板不要重新发明这些类而应直接复用baseStyles即_base.module.css的模块化导入例如baseStyles[resume-section]、baseStyles[resume-item-subtitle]。这样你的模板会自动响应格式化面板中所有间距与排版设置。模板特有的视觉配色、字体变体、特殊组件则放在自己的*.module.css中例如 styles/vivid.module.css 之于vivid。基础样式表还提供了专门的字号语义类用于提升副标题可读性详见 docs/agent/features/resume-templates.md类字号字重用途resume-item-subtitle0.95× 基准600公司名、学位、项目角色resume-item-subtitle-sm0.88× 基准600紧凑双栏布局中的同字段相比通用resume-meta类0.82× 基准、字重 400这两类让副标题大 13–16% 且为半粗体视觉层级更清晰。导出与注册让模板可见第一步统一出口导出。在 components/resume/index.ts 中追加一行// components/resume/index.ts export { ResumeSingleColumn } from ./resume-single-column; export { ResumeTwoColumn } from ./resume-two-column; // ... 既有导出 export { ResumeNewTemplate } from ./resume-new-template; // 新增第二步登记元数据。在 lib/types/template-settings.ts 中把模板 ID 加入TemplateType联合类型并在TEMPLATE_OPTIONS数组中追加条目export type TemplateType | swiss-single | swiss-two-column | modern | modern-two-column | latex | clean | vivid | new-template; // 新增 // TEMPLATE_OPTIONS 中追加 { id: new-template, name: New Template, description: ... },第三步接入选择器。指南中示意在 components/builder/formatting-controls.tsx 维护一个TEMPLATES数组。当前仓库实现已经演化为选择器直接消费TEMPLATE_OPTIONS元数据并在 template-selector.tsx 中用TemplateThumbnail渲染每个模板的迷你缩略图。因此真正需要做的是在TemplateThumbnail中为你的模板 ID 增加一个分支绘制代表该布局的线框缩略图可参考 template-selector.tsx 中七个既有分支的写法为模板名称/描述补充 i18n 文案formatting-controls.tsx 中的templateLabels使用useTranslations读取翻译键。模板设置与 CSS 变量让控件自动生效新增模板最省力的地方在于只要你的组件复用baseStyles并通过settingsToCssVars注入的 CSS 变量取样式格式化面板里几乎所有控件就会免费生效。settingsToCssVarstemplate-settings.ts会把TemplateSettings映射为一组 CSS 自定义属性--section-gap、--item-gap、--line-height—— 间距体系--font-size-base、--header-scale、--section-header-scale—— 字号体系--header-font、--body-font—— 字体族--margin-top/bottom/left/right—— 页面边距--resume-accent-primary、--resume-accent-light—— 强调色modern / modern-two-column / vivid 使用控件取值范围与默认值来自 docs/agent/features/resume-templates.md 及源码映射表控件取值范围默认值效果Margins5–25mm10mm控制面板滑块范围见 formatting-controls.tsx页面边距Section Spacing1–53章节间距映射 0.375–1.5remItem Spacing1–52条目间距映射 0.125–1remLine Height1–53行高映射 1.15–1.55Base Font Size1–53基准字号映射 11–16pxHeader Scale1–53姓名/章节标题缩放倍率映射 1.5–2.5Header Fontserif/sans-serif/monoserif标题字体族Body Fontserif/sans-serif/monosans-serif正文字体族Compact Modebooleanfalse间距乘以 0.6边距不变Contact Iconsbooleanfalse联系方式旁显示图标Accent Colorblue/green/orange/redbluemodern / modern-two-column / vivid 的强调色其中AccentColor的具体色值定义在 ACCENT_COLOR_MAPblue#1D4ED8/#DBEAFE、green#15803D/#DCFCE7、orange#EA580C/#FED7AA、red#DC2626/#FEE2E2。如果你的模板想支持强调色控件直接引用var(--resume-accent-primary)/var(--resume-accent-light)即可。两个细节对新增模板尤其重要Compact Mode 只压缩间距COMPACT_MULTIPLIER 0.6只作用于--section-gap/--item-gap边距保持字面值行高则使用更温和的COMPACT_LINE_HEIGHT_MULTIPLIER 0.92避免文字重叠见 template-settings.tsEffective Output 摘要格式化面板底部会实时显示间距/行高/字号的最终生效值考虑 compact 调整方便用户核对formatting-controls.tsx。PDF 渲染链路新增模板的最后一公里实时预览通过 CSS 变量即时生效而 PDF 生成走的是完全不同的链路——后端 Playwright 无头渲染。理解这条链路才能确保新模板在下载 PDF时表现正常GET /resumes/{id}/pdf ├── 后端拼接打印 URL{FRONTEND_BASE_URL}/print/resumes/{id}?template...pageSize...margins... ├── Playwright 启动 headless Chrome ├── 等待 .resume-print 选择器出现见 apps/backend/app/pdf.py ├── 等待 document.fonts.ready ├── 以零边距 print_backgroundtrue 生成 PDF └── 返回 PDF 字节要点如下根类名是契约pdf.py 中render_resume_pdf默认等待.resume-print选择器pdf.py这就是为什么新模板根容器必须保留classNameresume-print参数经由 Query 传递resumes.py 的 PDF 端点把template、pageSize、marginTop/Bottom/Left/Right5–25、sectionSpacing、itemSpacing、lineHeight、fontSize、headerScale、headerFont、bodyFont、compactMode、showContactIcons、accentColor全部拼进打印 URL。新增模板只要模板 ID 属于TemplateType就能直接通过template参数被选中边距由 Playwright 负责打印页 print/resumes/[id]/page.tsx 会把 CSS 边距清零margins: {top:0, ...}注释明确说明边距由 Playwright 渲染器应用确保每一页都有边距而非仅第一页——前端只用 CSS 变量控制间距与字体打印白名单 CSS在globals.css的media print中.resume-print及其子元素必须处于可见状态否则 PDF 会空白详见 docs/agent/design/pdf-template-guide.md 中的关键 CSS 规则。测试与验收清单指南最后给出了一份手工验收清单结合仓库现状可扩展为如下完整验证步骤模板注册测试运行 template-registration.test.ts确认新模板 ID 已包含在TEMPLATE_OPTIONS中、ID 唯一、名称与描述非空若为单字体族模板还应验证applyTemplatePreset正确注入签名字体构建器加载打开 Builder确认新模板出现在选择器中缩略图正常显示切换后实时预览立即变化全章节渲染用一份包含 Summary、Experience、Projects、Education、Additional技能/语言/证书/奖项及自定义章节的完整数据测试确认所有章节按sectionMeta的顺序与可见性渲染PDF 生成触发GET /resumes/{id}/pdf确认新模板的 PDF 正常产出、字体就绪、分页合理多页内容压测用超过两页的内容验证.resume-item不跨页断裂、.resume-section-title不孤立在页尾设置联动在格式化面板调整边距、间距、字号、字体族、Compact Mode 与强调色如适用确认新模板全部响应。常见坑位速查PDF 空白多半是打印白名单 CSS 缺失或根容器类名不是.resume-print章节顺序错乱忘记使用getSortedSections而是硬编码了章节顺序控件不生效组件内样式没有引用var(--section-gap)等 CSS 变量或没有复用baseStyles自定义章节丢失模板未处理customSections可参考DynamicResumeSectionVivid的实现富文本 XSS 风险条目描述直接用dangerouslySetInnerHTML而未走SafeHtml。按照上述四步流程创建组件 → 统一导出 → 登记元数据 → 注册选择器与缩略图再结合模板设置、CSS 变量与 Playwright 渲染链路的理解你就可以在 Resume-Matcher 中稳定地接入任意风格的全新简历模板并让它同时服务于实时预览、多语言打印页与 PDF 下载三个场景。【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters more, locally with 100 LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表