commit 526738425362549946bb74ae80d4b45785c0a336 Author: MORRO <3506897731@qq.com> Date: Mon Jun 22 17:15:27 2026 +0800 init: GreLin typst templates diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5a2840d --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# Typst 编译产物 +*.pdf + +# 本地照片(可选提交) +# resume/assets/profile.jpeg + +# 系统文件 +.DS_Store +Thumbs.db diff --git a/README.md b/README.md new file mode 100644 index 0000000..8be95d7 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# GreLin · Typst 文档模板 + +西安高岭绿能团队内部 Typst 模板库,按文档类型分目录维护,用于融资 BP、data room 等场景。 + +## 目录 + +| 文件夹 | 说明 | 入口文件 | +|--------|------|----------| +| [`resume/`](resume/) | 团队简历(双栏中文版) | `cv.typ` | +| [`feasibility-report/`](feasibility-report/) | 可行性研究报告 | `report.typ` | + +## 环境要求 + +- [Typst](https://typst.app/) CLI(`typst compile` / `typst watch`) + +## 快速开始 + +```bash +# 简历 +cd resume +typst compile cv.typ + +# 可行性报告 +cd feasibility-report +typst compile report.typ +``` + +## 推送到 Gitea + +```bash +cd GreLin +git init +git add . +git commit -m "init: GreLin typst templates" +git remote add origin +git push -u origin main +``` + +## 约定 + +- 每个文档类型独立文件夹,互不混用 +- 品牌色与 HyperLabel `foundationPalette` 保持一致 +- 个人/公司数据写在各模板的 `data/config.typ` 中 diff --git a/feasibility-report/README.md b/feasibility-report/README.md new file mode 100644 index 0000000..7e5208f --- /dev/null +++ b/feasibility-report/README.md @@ -0,0 +1,32 @@ +# Feasibility Report · 可行性研究报告模板 + +GreLin 可行性报告 Typst 模板,适用于项目论证、内部评审或 BP 附件。 + +## 快速开始 + +```bash +cd feasibility-report +typst compile report.typ +typst watch report.typ +``` + +## 定制 + +| 文件 | 说明 | +|------|------| +| [`data/config.typ`](data/config.typ) | 公司名、项目名、版本、日期、各章节正文 | +| [`data/theme.typ`](data/theme.typ) | 配色与字号 | +| [`data/layout.typ`](data/layout.typ) | 封面、摘要、章节组件 | + +## 章节结构 + +1. 项目概述 +2. 建设必要性与市场分析 +3. 技术方案 +4. 实施计划 +5. 投资估算与资金用途 +6. 效益分析 +7. 风险分析与对策 +8. 结论 + +在 `data/config.typ` 的 `sections` 数组中逐章填写内容即可。 diff --git a/feasibility-report/data/config.typ b/feasibility-report/data/config.typ new file mode 100644 index 0000000..10aa142 --- /dev/null +++ b/feasibility-report/data/config.typ @@ -0,0 +1,64 @@ +// ============================================================================= +// 可行性报告 — 修改此处定制内容 +// ============================================================================= + +#let company-name = "西安高岭绿能科技有限公司" +#let project-name = "智能矿石分选系统建设项目" +#let report-version = "v0.1" +#let report-date = "2026 年 6 月" + +#let report-summary = [ + 本项目旨在建设面向铝土矿等矿石场景的智能分选软硬件一体化系统,将分选算法工程化为可部署、可运维的产线产品,形成从算法接入、设备控制、运营后台到监控运维的完整闭环,支撑绿色高效矿物加工。 +] + +#let sections = ( + ( + title: "一、项目概述", + body: [ + 说明项目背景、建设目标、建设内容与预期成果。可引用 BP 中的产品定位与目标客户。 + ], + ), + ( + title: "二、建设必要性与市场分析", + body: [ + 行业痛点、政策与环保驱动、目标市场规模与竞争格局。建议配合 BP 市场章节数据。 + ], + ), + ( + title: "三、技术方案", + body: [ + 系统架构(感知、推理、控制、后台、运维)、核心技术路线、与现有产线对接方式。 + 可补充已验证指标:精矿 A/S、尾矿 A/S、回收率、处理量等。 + ], + ), + ( + title: "四、实施计划", + body: [ + 阶段划分(研发验证 → 试点部署 → 规模化推广)、里程碑、团队分工与关键依赖。 + ], + ), + ( + title: "五、投资估算与资金用途", + body: [ + 硬件、软件、人员、市场等费用结构。与 BP 财务预测保持一致。 + ], + ), + ( + title: "六、效益分析", + body: [ + 经济效益(降本增效、回收率提升)、社会效益与环保效益。尽量量化。 + ], + ), + ( + title: "七、风险分析与对策", + body: [ + 技术、市场、交付、政策等风险及应对措施。 + ], + ), + ( + title: "八、结论", + body: [ + 综合可行性判断与建议。 + ], + ), +) diff --git a/feasibility-report/data/layout.typ b/feasibility-report/data/layout.typ new file mode 100644 index 0000000..ca2cf7c --- /dev/null +++ b/feasibility-report/data/layout.typ @@ -0,0 +1,43 @@ +#import "theme.typ": * +#import "config.typ": * + +#let report-title-block() = block(width: 100%, below: space-section)[ + #align(center)[ + #text(font: heading-font, size: size-title, weight: "bold", fill: color-ink)[ + #project-name + ] + #v(6pt) + #text(font: heading-font, size: size-h2, fill: color-muted)[可行性研究报告] + #v(10pt) + #text(size: size-meta, fill: color-muted)[ + #company-name #sym.bar #report-version #sym.bar #report-date + ] + ] + #v(space-section) + #line(length: 100%, stroke: color-divider + 0.6pt) +] + +#let section-block(section) = block(width: 100%, above: space-section, below: space-block)[ + #text(font: heading-font, size: size-h1, weight: "bold", fill: color-ink)[#section.title] + #v(6pt) + #box(width: 18pt, height: 3pt, fill: color-accent) + #v(8pt) + #set par(leading: leading-body, spacing: 6pt, justify: true) + #set text(size: size-body, fill: color-body) + #section.body +] + +#let summary-block() = block(width: 100%, above: space-block, below: space-section)[ + #text(font: heading-font, size: size-h2, weight: "bold", fill: color-ink)[摘要] + #v(6pt) + #box( + width: 100%, + fill: color-bar-bg, + inset: 10pt, + radius: 4pt, + )[ + #set par(leading: leading-body, justify: true) + #set text(size: size-body, fill: color-body) + #report-summary + ] +] diff --git a/feasibility-report/data/theme.typ b/feasibility-report/data/theme.typ new file mode 100644 index 0000000..7c00643 --- /dev/null +++ b/feasibility-report/data/theme.typ @@ -0,0 +1,29 @@ +// HyperLabel 基础色板 + +#let color-ink = rgb("#08090B") +#let color-body = rgb("#2D3135") +#let color-muted = rgb("#434950") +#let color-accent = rgb("#D7F754") +#let color-bar-bg = rgb("#EFF0F2") +#let color-page = rgb("#FDFDFD") +#let color-divider = color-muted.lighten(68%) + +#let heading-font = ("Microsoft YaHei", "Segoe UI") +#let body-font = ("Microsoft YaHei UI", "Microsoft YaHei", "Segoe UI") + +#let size-title = 22pt +#let size-h1 = 14pt +#let size-h2 = 12pt +#let size-body = 10.5pt +#let size-meta = 9pt + +#let leading-body = 12.5pt +#let space-section = 14pt +#let space-block = 10pt + +#let page-margin = ( + top: 2.2cm, + bottom: 2cm, + left: 2.2cm, + right: 2.2cm, +) diff --git a/feasibility-report/report.typ b/feasibility-report/report.typ new file mode 100644 index 0000000..01b758a --- /dev/null +++ b/feasibility-report/report.typ @@ -0,0 +1,36 @@ +#import "data/config.typ": * +#import "data/theme.typ": * +#import "data/layout.typ": * + +#set page( + paper: "a4", + margin: page-margin, + fill: color-page, + header: context { + if counter(page).get().first() > 1 [ + #set text(size: size-meta, fill: color-muted) + #grid( + columns: (1fr, 1fr), + [#company-name], + align(right)[#project-name · 可行性报告], + ) + #v(4pt) + #line(length: 100%, stroke: color-divider + 0.5pt) + ] + }, + footer: context { + set text(size: size-meta, fill: color-muted) + align(center)[#counter(page).display("1")] + }, +) + +#set text(font: body-font, lang: "zh", size: size-body, fill: color-body) +#set par(leading: leading-body, justify: true) +#set heading(numbering: none) + +#report-title-block() +#summary-block() + +#for section in sections { + section-block(section) +} diff --git a/resume/README.md b/resume/README.md new file mode 100644 index 0000000..9bf8b37 --- /dev/null +++ b/resume/README.md @@ -0,0 +1,37 @@ +# Resume · 团队简历模板 + +GreLin 双栏中文简历 Typst 模板(HyperLabel 配色),用于融资 BP data room 附录。 + +## 快速开始 + +```bash +cd resume +typst compile cv.typ +typst watch cv.typ +``` + +## 定制 + +| 文件 | 说明 | +|------|------| +| [`data/config.typ`](data/config.typ) | 个人信息、教育、能力、技术栈、经历、项目 | +| [`data/theme.typ`](data/theme.typ) | 配色、字号、间距 | +| [`data/layout.typ`](data/layout.typ) | 版式组件(一般无需改动) | + +## 照片 + +将证件照放入 `assets/profile.jpeg`,或在 `data/config.typ` 中设置 `author-photo` 路径。 + +## 结构 + +``` +resume/ +├── cv.typ +├── data/ +│ ├── config.typ +│ ├── layout.typ +│ └── theme.typ +└── assets/ + ├── profile.jpeg + └── icons/ +``` diff --git a/resume/assets/icons/bike.svg b/resume/assets/icons/bike.svg new file mode 100644 index 0000000..a064ab8 --- /dev/null +++ b/resume/assets/icons/bike.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/camera.svg b/resume/assets/icons/camera.svg new file mode 100644 index 0000000..0fda3ea --- /dev/null +++ b/resume/assets/icons/camera.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/gamepad.svg b/resume/assets/icons/gamepad.svg new file mode 100644 index 0000000..ecf1ae8 --- /dev/null +++ b/resume/assets/icons/gamepad.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/globe.svg b/resume/assets/icons/globe.svg new file mode 100644 index 0000000..43c5d9a --- /dev/null +++ b/resume/assets/icons/globe.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/mail.svg b/resume/assets/icons/mail.svg new file mode 100644 index 0000000..d182c64 --- /dev/null +++ b/resume/assets/icons/mail.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/map-pin.svg b/resume/assets/icons/map-pin.svg new file mode 100644 index 0000000..4f11805 --- /dev/null +++ b/resume/assets/icons/map-pin.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/phone.svg b/resume/assets/icons/phone.svg new file mode 100644 index 0000000..887660a --- /dev/null +++ b/resume/assets/icons/phone.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/plane.svg b/resume/assets/icons/plane.svg new file mode 100644 index 0000000..ed4210b --- /dev/null +++ b/resume/assets/icons/plane.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/tech-ai.svg b/resume/assets/icons/tech-ai.svg new file mode 100644 index 0000000..202e58f --- /dev/null +++ b/resume/assets/icons/tech-ai.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/tech-backend.svg b/resume/assets/icons/tech-backend.svg new file mode 100644 index 0000000..508876b --- /dev/null +++ b/resume/assets/icons/tech-backend.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/tech-database.svg b/resume/assets/icons/tech-database.svg new file mode 100644 index 0000000..de082bf --- /dev/null +++ b/resume/assets/icons/tech-database.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/tech-devops.svg b/resume/assets/icons/tech-devops.svg new file mode 100644 index 0000000..5af1b59 --- /dev/null +++ b/resume/assets/icons/tech-devops.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/icons/tech-frontend.svg b/resume/assets/icons/tech-frontend.svg new file mode 100644 index 0000000..6db37cb --- /dev/null +++ b/resume/assets/icons/tech-frontend.svg @@ -0,0 +1 @@ + diff --git a/resume/assets/profile.jpeg b/resume/assets/profile.jpeg new file mode 100644 index 0000000..019bc2e Binary files /dev/null and b/resume/assets/profile.jpeg differ diff --git a/resume/cv.typ b/resume/cv.typ new file mode 100644 index 0000000..abde7a2 --- /dev/null +++ b/resume/cv.typ @@ -0,0 +1,49 @@ +#import "data/config.typ": * +#import "data/theme.typ": * +#import "data/layout.typ": * + +#set page( + paper: "a4", + margin: page-margin, + fill: color-page, +) + +#set text( + font: body-font, + size: size-base, + weight: "regular", + fill: color-body, + lang: "zh", +) + +#set par(leading: leading-body, spacing: par-spacing-tight, justify: true) + +#page-corners() +#hero-section() +#header-divider() + +#grid( + columns: (sidebar-column, 0.55pt, main-column), + column-gutter: (space-lg, space-xl), + align: (top, top, top), + [ + #section-title("联系", sidebar: true) + #contact-block() + #sidebar-section-divider() + + #section-title("教育", sidebar: true) + #education-block() + #sidebar-section-divider() + + #section-title("技能", sidebar: true) + #skills-section-block() + ], + line(length: 100%, stroke: color-divider + 0.85pt), + [ + #section-title("工作经历") + #experiences-block() + + #section-title("项目经历") + #projects-block() + ], +) diff --git a/resume/data/config.typ b/resume/data/config.typ new file mode 100644 index 0000000..17a216d --- /dev/null +++ b/resume/data/config.typ @@ -0,0 +1,130 @@ +// ============================================================================= +// 个人信息 — 修改此处即可定制简历 +// ============================================================================= + +#let company-name = "西安高岭绿能科技有限公司" +#let meituan-company-name = "北京三快在线科技有限公司" +#let company-city = "陕西西安" + +#let author-name = "齐梦璠" +#let author-title = "软件研发" + +#let author-summary = [ + 西北大学软件工程本硕。具备从 0 到 1 构建业务系统的能力:在美团 AI 应用组参与大模型 Agent 类应用的工程落地;现于高岭绿能负责矿石智能分选系统的软件全链路交付,将算法能力转化为可部署、可运维的工业产品。 +] + +#let author-address = "陕西西安" +#let author-phone = "19829062833" +#let author-email = "qmf19829062833@gmail.com" +#let author-website = "https://3506897731.github.io/" +#let author-website-label = "3506897731.github.io" + +// 证件照(2 寸)— 源文件:C:/Users/35068/PKB/GoodPhoto/证件照/证件照-ABC.jpeg +#let author-photo = image( + "../assets/profile.jpeg", + width: 100%, + height: 100%, + fit: "cover", +) + +#let education = ( + ( + degree: "软件工程 · 硕士", + school: "西北大学", + period: "2022 – 2025", + location: "西安", + note: none, + ), + ( + degree: "软件工程 · 学士", + school: "西北大学", + period: "2018 – 2022", + location: "西安", + note: none, + ), +) + +#let abilities = ( + (name: "全栈开发", level: 0.9), + (name: "AI Agent 工程化", level: 0.85), + (name: "后端 / API", level: 0.82), + (name: "工业系统对接", level: 0.78), +) + +// 技术栈分类(侧栏 pill 标签) +#let tech-categories = ( + ( + title: "全栈", + icon: "frontend", + tags: ("Vue", "React", "Python", "Java", "REST API"), + ), + ( + title: "AI 工程", + icon: "ai", + tags: ("LLM Agent", "RAG"), + ), + ( + title: "数据库", + icon: "database", + tags: ("MySQL", "Redis"), + ), + ( + title: "DevOps", + icon: "devops", + tags: ("Docker", "Linux"), + ), +) + +#let experiences = ( + ( + company: company-name, + role: "研发工程师", + location: "西安", + start: "2025.06", + end: "至今", + description: [ + - 主导分选系统软件全链路建设:控制端、算法推理服务接入、运营管理后台、产线部署与运维监控。 + - 与算法负责人协作完成模型服务化对接,设计推理回调、异常降级与日志追踪,保障产线连续稳定运行。 + - 搭建运行数据采集与可视化看板,支撑分选效率、设备状态与告警的实时监测与快速定位。 + - 产线落地:1 条产线、1 个客户现场已上线稳定运行(2026.06.22 起),单线处理能力 25 t/h,连续稳定运行 20 小时、月均运行 24 天。 + ], + ), + ( + company: meituan-company-name, + role: "全栈工程师", + location: "北京", + start: "2024.07", + end: "2025.06", + description: [ + - 参与大模型 Agent 应用工程落地,负责对话编排、工具调用(Function Calling)与业务工作流的系统集成。 + - 完成 Agent 应用前后端开发及 LLM 服务对接,支撑智能助手、自动化任务等多场景功能快速迭代上线。 + - 基于 RAG、Multi-Agent 等架构模式,将 AI 能力嵌入现有业务系统,独立承担模块从设计到上线的完整交付。 + ], + ), +) + +#let projects = ( + ( + name: "智能矿石分选软件平台", + org: company-name, + location: "西安", + start: "2025.06", + end: "至今", + description: [ + - 能力体现:将铝土矿分选算法从实验环境工程化为产线可运行系统,覆盖「算法接入 → 设备控制 → 运营后台 → 监控运维」完整闭环。 + - 交付模块:设备控制软件、算法推理服务网关、运营管理后台、产线监控与数据采集。 + - 业务指标(铝土矿,我方 / 第三方 / 客户测试):精矿 A/S 4.0+、尾矿 A/S 1.7-、回收率 30%+;单线处理量 25 t/h;1 条产线、1 个客户现场,2026.06.22 起稳定运行。 + ], + ), + ( + name: "大模型 Agent 业务应用", + org: meituan-company-name, + location: "北京", + start: "2024", + end: "2025", + description: [ + - 能力体现:具备将前沿 AI 能力(Agent、RAG、工具调用)快速产品化并集成进业务系统的工程经验。 + - 交付内容:Agent 对话引擎接入、业务 API 工具链、运营管理后台及上线运维支持。 + ], + ), +) diff --git a/resume/data/layout.typ b/resume/data/layout.typ new file mode 100644 index 0000000..c8910ec --- /dev/null +++ b/resume/data/layout.typ @@ -0,0 +1,276 @@ +#import "theme.typ": * +#import "config.typ": * + +#let icon-map-pin = image("../assets/icons/map-pin.svg") +#let icon-phone = image("../assets/icons/phone.svg") +#let icon-mail = image("../assets/icons/mail.svg") +#let icon-globe = image("../assets/icons/globe.svg") + +#let icon-tech-frontend = image("../assets/icons/tech-frontend.svg") +#let icon-tech-backend = image("../assets/icons/tech-backend.svg") +#let icon-tech-ai = image("../assets/icons/tech-ai.svg") +#let icon-tech-database = image("../assets/icons/tech-database.svg") +#let icon-tech-devops = image("../assets/icons/tech-devops.svg") + +#let tech-category-icon(name) = { + if name == "frontend" { icon-tech-frontend } + else if name == "backend" { icon-tech-backend } + else if name == "ai" { icon-tech-ai } + else if name == "database" { icon-tech-database } + else { icon-tech-devops } +} + +#let profile-photo = if author-photo != none { + box(width: 100%, height: 100%, clip: true, author-photo) +} else { + rect( + width: 100%, + height: 100%, + fill: color-bar-bg, + stroke: color-divider + 0.5pt, + )[ + #align(center + horizon)[ + #text(fill: color-muted, size: size-caption)[照片] + ] + ] +} + +/// 左上 / 右下装饰条 +#let page-corners() = context { + place( + top + left, + dx: -page.margin.left, + dy: -page.margin.top + corner-bar-inset, + block(width: corner-bar-width, height: corner-bar-height, fill: color-accent-bright), + ) + place( + bottom + right, + dx: page.margin.right, + dy: page.margin.bottom - corner-bar-inset, + block(width: corner-bar-width, height: corner-bar-height, fill: color-accent-bright), + ) +} + +/// 页眉:姓名 + 职位 + 简介 + 2 寸照片 +#let hero-section() = block(width: 100%, below: space-md)[ + #grid( + columns: (1fr, photo-width), + column-gutter: space-hero-gutter, + align: (top, top), + [ + #text( + font: heading-font, + size: size-name, + weight: "bold", + fill: color-ink, + )[#author-name] + #v(space-xs) + #text( + font: heading-font, + size: size-subtitle, + weight: "bold", + fill: color-accent-bright, + )[#author-title] + #v(space-md) + #set text(weight: "regular") + #set par(leading: leading-summary, spacing: par-spacing-tight, justify: true) + #text(fill: color-text-light, size: size-body)[#author-summary] + ], + [ + #align(right)[ + #box( + width: photo-width, + height: photo-height, + clip: true, + stroke: color-divider + 0.6pt, + profile-photo, + ) + ] + ], + ) +] + +/// 页眉与正文之间的横线 +#let header-divider() = block(width: 100%, above: space-xs, below: space-section)[ + #line(length: 100%, stroke: color-divider + 0.55pt) +] + +/// 分栏标题 +#let section-title(title, sidebar: false, divider: false) = { + let above = if sidebar { space-section } else { space-between-sections } + let below = if sidebar { space-sidebar-title-gap } else { space-sm } + block(width: 100%, above: above, below: below)[ + #text( + font: heading-font, + size: size-section, + weight: "bold", + fill: color-ink, + )[#title] + #if divider [ + #v(space-sm) + #line(length: 100%, stroke: color-divider + 0.55pt) + ] + ] +} + +/// 侧栏区块分隔线 +#let sidebar-section-divider() = block( + width: 100%, + above: space-sidebar-divider, + below: space-xs, +)[ + #line(length: 100%, stroke: color-divider + 0.55pt) +] + +#let accent-icon(icon) = box( + width: 1em, + height: 1em, + baseline: 0.08em, + icon, +) + +#let contact-line(icon, body) = block(below: space-xs)[ + #grid( + columns: (1em, 1fr), + column-gutter: space-xs, + align: (center + horizon, left), + box(width: 0.95em, height: 0.95em, baseline: 0.08em, icon), + text(fill: color-text-light, size: size-contact)[#body], + ) +] + +#let contact-block() = block(above: 0pt)[ + #contact-line(icon-map-pin, author-address) + #contact-line(icon-phone, link("tel:" + author-phone, author-phone)) + #contact-line(icon-mail, link("mailto:" + author-email, author-email)) + #if author-website != "" { + contact-line(icon-globe, link(author-website, author-website-label)) + } +] + +/// 教育背景条目 +#let edu-entry(degree, school, period, location, note: none) = block(above: space-sm, below: space-xs)[ + #text(fill: color-body, size: size-body)[#degree] + #v(space-xxs) + #text(fill: color-muted, size: size-meta)[ + #school#if period != "" [ · #period]#if location != "" [ · #location] + ] + #if note != none [ + #v(space-xxs) + #text(fill: color-muted, size: size-small)[#note] + ] +] + +#let education-block() = { + for item in education { + edu-entry(item.degree, item.school, item.period, item.location, note: item.note) + } +} + +/// 侧栏技能子标题 +#let sidebar-subtitle(title) = block(above: space-md, below: space-xs)[ + #text( + font: heading-font, + size: size-small, + fill: color-body, + )[#title] +] + +/// 技能进度条(level: 0–1) +#let skill-bar(name, level, subtitle: none) = block(above: space-sm, below: space-xs)[ + #if subtitle != none [ + #grid( + columns: (1fr, auto), + align: horizon, + text(fill: color-body, size: size-body)[#name], + text(fill: color-muted, size: size-meta)[#subtitle], + ) + ] else [ + #text(fill: color-body, size: size-body)[#name] + ] + #v(space-xs) + #box(width: 100%, height: 4pt, radius: 1pt, clip: true)[ + #place(left + top, block(width: 100%, height: 4pt, fill: color-bar-bg)) + #place(left + top, block(width: level * 100%, height: 4pt, fill: color-skill-bar)) + ] +] + +#let tech-pill(label) = box( + fill: color-page, + stroke: color-divider + 0.65pt, + radius: 3pt, + inset: (x: 5pt, y: 2pt), + baseline: 0.15em, + text(fill: color-body, size: size-tech-pill)[#label], +) + +#let tech-category-block(category) = block(above: space-sm, below: space-xxs)[ + #grid( + columns: (0.8em, 1fr), + column-gutter: space-xs, + align: horizon, + box(width: 0.8em, height: 0.8em, baseline: 0.1em, tech-category-icon(category.icon)), + text(font: heading-font, weight: "bold", size: size-tech-category, fill: color-ink)[#category.title] + ) + #v(space-xs) + #box(width: 100%)[ + #for (i, tag) in category.tags.enumerate() [ + #if i > 0 [#h(3pt)] + #tech-pill(tag) + ] + ] +] + +#let tech-stack-block() = block(width: 100%, above: space-xxs)[ + #for category in tech-categories { + tech-category-block(category) + } +] + +#let skills-section-block() = { + sidebar-subtitle("能力") + for item in abilities { + skill-bar(item.name, item.level) + } + sidebar-subtitle("技术栈") + tech-stack-block() +} + +/// 主栏经历 / 项目条目 +#let timeline-entry(entry, title-key: "company", subtitle-key: "role") = block[ + #text(fill: color-accent, size: size-subtitle, weight: "bold")[ + #if subtitle-key != none [ + #entry.at(title-key) / #entry.at(subtitle-key) + ] else [ + #entry.at(title-key) + ] + ] + #v(space-xs) + #text(fill: color-muted, size: size-meta)[ + #entry.location#if entry.location != "" [,]#entry.start - #entry.end + ] + #v(space-sm) + #set text(weight: "regular", fill: color-text-light, size: size-body) + #set par(leading: leading-entry, spacing: par-spacing-tight, justify: true) + #set list(spacing: par-spacing-tight, indent: 0.8em, body-indent: 0.4em) + #entry.description +] + +#let project-entry(entry) = timeline-entry(entry, title-key: "name", subtitle-key: "org") + +/// 工作经历条目 +#let experience-entry(entry) = timeline-entry(entry, title-key: "company", subtitle-key: "role") + +#let experiences-block() = { + for (i, entry) in experiences.enumerate() { + if i > 0 { v(space-between-entries) } + experience-entry(entry) + } +} + +#let projects-block() = { + for (i, entry) in projects.enumerate() { + if i > 0 { v(space-between-entries) } + project-entry(entry) + } +} diff --git a/resume/data/theme.typ b/resume/data/theme.typ new file mode 100644 index 0000000..a6673bf --- /dev/null +++ b/resume/data/theme.typ @@ -0,0 +1,79 @@ +// HyperLabel 基础色板 — 来源:HyperLabel/ComponentsTestPage.tsx foundationPalette + +#let color-ink = rgb("#08090B") // 墨黑:主标题 +#let color-body = rgb("#2D3135") // 石墨:正文 +#let color-muted = rgb("#434950") // 石板灰:次要信息 +#let color-accent-bright = rgb("#D7F754") // 强调绿:点缀、技能条、装饰条 +#let color-bar-bg = rgb("#EFF0F2") // 银灰:进度条底、标签背景 +#let color-page = rgb("#FDFDFD") // 纸灰:页面背景 + +// 语义映射 +#let color-accent = color-muted +#let color-skill-bar = color-accent-bright +#let color-divider = color-muted.lighten(68%) + +#let color-text-light = color-muted.lighten(32%) // 简介、经历描述等长正文 + +#let heading-font = ("Microsoft YaHei", "Segoe UI") +#let body-font = ("Microsoft YaHei UI", "Microsoft YaHei", "Segoe UI") + +// 页眉证件照(略短于标准 2 寸,与简介区高度更协调) +#let photo-width = 33mm +#let photo-height = 40mm + +// --------------------------------------------------------------------------- +// 排版规范(A4 中文简历 · 10.5pt 基准 · 4pt 间距网格) +// --------------------------------------------------------------------------- + +#let size-base = 10.5pt +#let size-name = 20pt +#let size-subtitle = 11pt +#let size-section = 11pt +#let size-body = 10.5pt +#let size-meta = 9pt +#let size-small = 9pt +#let size-caption = 8.5pt +#let size-contact = 8pt +#let size-tech-pill = 7pt +#let size-tech-category = 8pt + +// 行距:10.5pt 正文约 1.2 倍(中文简历常用) +#let leading-normal = 12.5pt +#let leading-body = leading-normal +#let leading-summary = leading-normal +#let leading-entry = leading-normal +#let par-spacing-tight = 3pt + +#let space-xxs = 2pt +#let space-xs = 4pt +#let space-sm = 6pt +#let space-md = 8pt +#let space-lg = 12pt +#let space-xl = 16pt +#let space-section = 14pt +#let space-entry = 10pt +#let space-sidebar-divider = 10pt +#let space-hero-gutter = 24pt + +// 主栏:条目之间 = 一行正文;区块之间 = 小标题级间距 +#let space-between-entries = leading-body +#let space-between-sections = space-xl + +// 双栏比例(左栏约 28%) +#let sidebar-column = 0.85fr +#let main-column = 2.15fr + +// 侧栏标题与内容间距(为常规段落的 2 倍) +#let space-sidebar-title-gap = space-md * 2 + +// 页边装饰条:高度 +20%,向内偏移 +#let corner-bar-width = 5mm +#let corner-bar-height = 21.6mm +#let corner-bar-inset = 11mm + +#let page-margin = ( + top: 2cm, + bottom: 2cm, + left: 1.8cm, + right: 1.8cm, +)