Complete GreLin resume template with sample PDF and shared brand colors.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
MORRO 2026-06-23 14:39:21 +08:00
parent 5267384253
commit 226f74c22c
19 changed files with 5216 additions and 308 deletions

7
.gitignore vendored
View File

@ -1,5 +1,10 @@
# Typst 编译产物
# Typst 编译产物(示例 PDF 除外)
*.pdf
!resume/sample.pdf
# IDE / 编辑器本地配置
.cursor/
.vscode/
# 本地照片(可选提交)
# resume/assets/profile.jpeg

View File

@ -1,43 +1,34 @@
# GreLin · Typst 文档模板
西安高岭绿能团队内部 Typst 模板库,按文档类型分目录维护,用于融资 BP、data room 等场景
GreLin 内部 Typst 模板库,按文档类型分目录维护。
## 目录
| 文件夹 | 说明 | 入口文件 |
|--------|------|----------|
| [`resume/`](resume/) | 团队简历(双栏中文版) | `cv.typ` |
| [`feasibility-report/`](feasibility-report/) | 可行性研究报告 | `report.typ` |
| [`resume/`](resume/) | 团队简历 | `cv.typ` |
| [`feasibility/`](feasibility/) | 可行性研究报告 | `report.typ` |
## 环境要求
- [Typst](https://typst.app/) CLI`typst compile` / `typst watch`
- [VS Code](https://code.visualstudio.com/) 或 [Cursor](https://cursor.com/)
- 扩展:[Tinymist](https://marketplace.visualstudio.com/items?itemName=myriad-dreamin.tinymist)(搜索 `Tinymist` 安装即可,已集成预览与导出,无需单独装 Typst CLI
> 勿安装已废弃的 `Typst LSP`、`Typst Preview`,会与 Tinymist 冲突。
## 快速开始
```bash
# 简历
cd resume
typst compile cv.typ
1. 用 VS Code / Cursor 打开本仓库
2. 打开要编辑的入口文件,例如 `resume/cv.typ`
3. **看效果(预览)**`Ctrl+Shift+P` → 输入 `Typst Preview` → 回车;侧边会实时显示排版效果(快捷键 `Ctrl+K` 然后 `V`
4. **导出 PDF**`Ctrl+Shift+P` → 输入 `Typst Export PDF` → 回车PDF 默认生成在同目录(如 `resume/sample.pdf`
# 可行性报告
cd feasibility-report
typst compile report.typ
```
## 推送到 Gitea
仓库根目录的 [`typst.toml`](typst.toml) 将项目根设为 GreLin以便 `resume/``feasibility/` 共享 [`brand/colors.typ`](brand/colors.typ)。命令行编译示例:
```bash
cd GreLin
git init
git add .
git commit -m "init: GreLin typst templates"
git remote add origin <your-gitea-repo-url>
git push -u origin main
typst compile resume/cv.typ resume/sample.pdf --root .
```
## 约定
已填好的示例 PDF 见 [`resume/sample.pdf`](resume/sample.pdf)。
- 每个文档类型独立文件夹,互不混用
- 品牌色与 HyperLabel `foundationPalette` 保持一致
- 个人/公司数据写在各模板的 `data/config.typ`
不熟悉 Typst可参考社区维护的 [小蓝书Typst 中文教程)](https://tutorial.typst.dev/);英文版见 [官方入门教程](https://typst.app/docs/tutorial/)。

13
brand/colors.typ Normal file
View File

@ -0,0 +1,13 @@
// GreLin 品牌色板 — 全文档统一resume / feasibility 等均 import 此文件)
// 来源 HyperLabel foundationPalette + labelPalette
#let color-ink = rgb("#08090B")
#let color-body = rgb("#2D3135")
#let color-muted = rgb("#434950")
#let color-bar-bg = rgb("#EFF0F2")
#let color-page = rgb("#FDFDFD")
// 强调绿同色系lime → mid品牌主色→ olive
#let color-lime = rgb("#D7F754")
#let color-lime-mid = rgb("#C4D94A") // 浅底装饰、技能条、章节强调、图标
#let color-lime-deep = rgb("#A7C957") // 浅底标题文字

View File

@ -1,11 +1,6 @@
// HyperLabel 基础色板
#import "../../brand/colors.typ": *
#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-accent = color-lime-mid
#let color-divider = color-muted.lighten(68%)
#let heading-font = ("Microsoft YaHei", "Segoe UI")

View File

@ -4,12 +4,15 @@ GreLin 双栏中文简历 Typst 模板HyperLabel 配色),用于融资 BP
## 快速开始
在仓库根目录执行(需共享 `brand/colors.typ`
```bash
cd resume
typst compile cv.typ
typst watch cv.typ
typst compile resume/cv.typ resume/sample.pdf --root .
typst watch resume/cv.typ --root .
```
示例输出:[`sample.pdf`](sample.pdf)(已填内容,供版式参考)。
## 定制
| 文件 | 说明 |
@ -27,6 +30,7 @@ typst watch cv.typ
```
resume/
├── cv.typ
├── sample.pdf
├── data/
│ ├── config.typ
│ ├── layout.typ

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#D7F754" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#C4D94A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 294 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#D7F754" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#C4D94A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>

Before

Width:  |  Height:  |  Size: 285 B

After

Width:  |  Height:  |  Size: 285 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#D7F754" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#C4D94A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg>

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 326 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#D7F754" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#C4D94A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>

Before

Width:  |  Height:  |  Size: 480 B

After

Width:  |  Height:  |  Size: 480 B

View File

@ -10,24 +10,24 @@
#set text(
font: body-font,
size: size-base,
size: size-body,
weight: "regular",
fill: color-body,
lang: "zh",
)
#set par(leading: leading-body, spacing: par-spacing-tight, justify: true)
#set par(leading: leading-body, spacing: space-none, justify: true)
#page-corners()
#hero-section()
#header-divider()
#grid(
columns: (sidebar-column, 0.55pt, main-column),
column-gutter: (space-lg, space-xl),
columns: (sidebar-column, stroke-divider-column, main-column),
column-gutter: (space-column-gap, space-column-gap),
align: (top, top, top),
[
#section-title("联系", sidebar: true)
#section-title("联系", sidebar: true, above: space-none)
#contact-block()
#sidebar-section-divider()
@ -38,9 +38,9 @@
#section-title("技能", sidebar: true)
#skills-section-block()
],
line(length: 100%, stroke: color-divider + 0.85pt),
line(length: 100%, stroke: stroke-divider-sidebar),
[
#section-title("工作经历")
#section-title("工作经历", above: space-none)
#experiences-block()
#section-title("项目经历")

View File

@ -7,72 +7,51 @@
#let company-city = "陕西西安"
#let author-name = "齐梦璠"
#let author-title = "软件研发"
#let author-title = "软件研发 | 系统架构"
#let author-summary = [
西北大学软件工程本硕。具备从 0 到 1 构建业务系统的能力:在美团 AI 应用组参与大模型 Agent 类应用的工程落地;现于高岭绿能负责矿石智能分选系统的软件全链路交付,将算法能力转化为可部署、可运维的工业产品。
西北大学软件工程本硕。具备从 0 到 1 构建业务系统的能力:在美团 AI 应用组参与大模型 Agent 类应用的工程落地;现于高岭绿能负责矿石分选系统的软件全链路交付,将算法能力转化为可部署、可运维的工业产品。
]
#let author-address = "陕西西安"
#let author-phone = "19829062833"
#let author-email = "qmf19829062833@gmail.com"
#let author-email = "19829062833@163.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 language_profile = (
name: "英语",
level: 0.75,
label: "读写",
)
// 证件照路径(空字符串表示无照片)
#let author-photo-path = "../assets/profile.jpeg"
#let education = (
(
degree: "软件工程 · 硕士",
degree: "软件工程 / 硕士",
school: "西北大学",
period: "2022 2025",
location: "西安",
note: none,
),
(
degree: "软件工程 · 学士",
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),
(name: "系统架构", level: 0.75),
)
// 技术栈分类(侧栏 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"),
),
// 技术栈 pill 标签
#let tech-tags = (
"Rust", "Python", "Java", "React", "Tauri", "RAG", "Linux", "MySQL", "Redis",
"LLM Agent",
)
#let experiences = (
@ -83,10 +62,9 @@
start: "2025.06",
end: "至今",
description: [
- 主导分选系统软件全链路建设:控制端、算法推理服务接入、运营管理后台、产线部署与运维监控。
- 与算法负责人协作完成模型服务化对接,设计推理回调、异常降级与日志追踪,保障产线连续稳定运行。
- 搭建运行数据采集与可视化看板,支撑分选效率、设备状态与告警的实时监测与快速定位。
- 产线落地1 条产线、1 个客户现场已上线稳定运行2026.06.22 起),单线处理能力 25 t/h连续稳定运行 20 小时、月均运行 24 天。
- 负责矿石分选系统软件研发,覆盖运维工具、运营后台与产线部署联调。
- 与算法团队协作完成模型服务化接入,设计推理回调、异常降级与运行监控体系。
- 产线落地 1 条 / 1 客户现场,单线 25 t/h精矿 A/S 4.0+、尾矿 A/S 1.7-、回收率 30%+。
],
),
(
@ -96,35 +74,34 @@
start: "2024.07",
end: "2025.06",
description: [
- 参与大模型 Agent 应用工程落地负责对话编排、工具调用Function Calling与业务工作流的系统集成
- 完成 Agent 应用前后端开发及 LLM 服务对接,支撑智能助手、自动化任务等多场景功能快速迭代上线
- 基于 RAG、Multi-Agent 等架构模式,将 AI 能力嵌入现有业务系统,独立承担模块从设计到上线的完整交付
- 参与大模型 Agent 应用工程化,负责前后端模块开发与 LLM 服务对接
- 完成对话编排、工具调用与业务系统集成,独立承担功能从设计到上线交付
- 交付 Skill 工具累计覆盖数千名用户、下载量 1 万+;定时任务类能力日均服务约 200 名用户
],
),
)
#let projects = (
(
name: "智能矿石分选软件平台",
name: "HyperOre 矿石分选",
org: company-name,
location: "西安",
start: "2025.06",
end: "至今",
description: [
- 能力体现:将铝土矿分选算法从实验环境工程化为产线可运行系统,覆盖「算法接入 → 设备控制 → 运营后台 → 监控运维」完整闭环。
- 交付模块:设备控制软件、算法推理服务网关、运营管理后台、产线监控与数据采集。
- 业务指标(铝土矿,我方 / 第三方 / 客户测试):精矿 A/S 4.0+、尾矿 A/S 1.7-、回收率 30%+;单线处理量 25 t/h1 条产线、1 个客户现场2026.06.22 起稳定运行。
- 面向铝土矿产线的矿石分选系统,实现高光谱采集、模型推理与喷阀执行的闭环控制。
- 负责产线运维工具与核心软件模块交付;基于 Rust 实现 Ratatui 运维控制台与 ONNX 推理集成,完成「采集 → 推理 → 喷阀」流程联调。
],
),
(
name: "大模型 Agent 业务应用",
org: meituan-company-name,
location: "北京",
start: "2024",
end: "2025",
name: "HyperLabel 高光谱标注工作站",
org: company-name,
location: "西安",
start: "2025.06",
end: "至今",
description: [
- 能力体现:具备将前沿 AI 能力Agent、RAG、工具调用快速产品化并集成进业务系统的工程经验
- 交付内容Agent 对话引擎接入、业务 API 工具链、运营管理后台及上线运维支持
- 高光谱标注桌面工作站,面向矿石分选场景的训练数据生产与样本管理
- 负责 Tauri + React 前端,以及项目、样本、标签等业务的 CRUD 后端接口
],
),
)

View File

@ -6,140 +6,110 @@
#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-path != "" {
image(author-photo-path, width: 100%, height: 100%, fit: "cover")
} else {
none
}
#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 profile-photo-frame(content) = {
if content != none {
box(width: 100%, height: 100%, clip: true, content)
} else {
rect(
width: 100%,
height: 100%,
fill: color-bar-bg,
stroke: stroke-placeholder,
)[
#align(center + horizon)[
#text(fill: color-muted, size: size-body)[照片]
]
]
]
}
}
/// 左上 / 右下装饰条
#let page-corners() = context {
#let page-corners() = {
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),
dx: -page-margin.left,
dy: -page-margin.top + corner-bar-inset,
block(width: corner-bar-width, height: corner-bar-height, fill: color-skill-bar),
)
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),
dx: page-margin.right,
dy: page-margin.bottom - corner-bar-inset,
block(width: corner-bar-width, height: corner-bar-height, fill: color-skill-bar),
)
}
/// 页眉:姓名 + 职位 + 简介 + 2 寸照片
#let hero-section() = block(width: 100%, below: space-md)[
#let hero-section() = block(width: 100%, below: space-none)[
#grid(
columns: (1fr, photo-width),
column-gutter: space-hero-gutter,
column-gutter: space-hero-to-photo,
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)
#text(font: heading-font, size: size-name, weight: "bold", fill: color-ink)[#author-name]
#v(space-hero-name-gap)
#text(font: heading-font, size: size-heading, weight: "bold", fill: color-accent-bright)[#author-title]
#v(space-hero-title-gap)
#set text(weight: "regular")
#set par(leading: leading-summary, spacing: par-spacing-tight, justify: true)
#set par(leading: leading-summary, spacing: space-none, 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,
)
#box(width: photo-width, height: photo-height, clip: true, stroke: stroke-photo)[
#profile-photo-frame(profile-photo)
]
]
],
)
]
/// 页眉与正文之间的横线
#let header-divider() = block(width: 100%, above: space-xs, below: space-section)[
#line(length: 100%, stroke: color-divider + 0.55pt)
#let header-divider() = block(width: 100%, above: space-block, below: space-block)[
#line(length: 100%, stroke: stroke-divider)
]
/// 分栏标题
#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]
#let section-title(title, sidebar: false, divider: false, above: auto, below: auto) = {
let title-above = if above != auto {
above
} else if sidebar {
space-none
} else {
space-block
}
let title-below = if below != auto { below } else { space-title-gap }
block(width: 100%, above: title-above, below: title-below)[
#text(font: heading-font, size: size-heading, weight: "bold", fill: color-ink)[#title]
#if divider [
#v(space-sm)
#line(length: 100%, stroke: color-divider + 0.55pt)
#v(space-inline)
#line(length: 100%, stroke: stroke-divider)
]
]
}
/// 侧栏区块分隔线
#let sidebar-section-divider() = block(
width: 100%,
above: space-sidebar-divider,
below: space-xs,
)[
#line(length: 100%, stroke: color-divider + 0.55pt)
#let sidebar-section-divider() = block(width: 100%, above: space-block, below: space-block)[
#line(length: 100%, stroke: stroke-divider)
]
#let accent-icon(icon) = box(
width: 1em,
height: 1em,
baseline: 0.08em,
icon,
)
#let contact-line(icon, body) = block(below: space-xs)[
#let contact-line(icon, body) = block(below: space-inline)[
#grid(
columns: (1em, 1fr),
column-gutter: space-xs,
columns: (icon-column-width, 1fr),
column-gutter: space-micro,
align: (center + horizon, left),
box(width: 0.95em, height: 0.95em, baseline: 0.08em, icon),
text(fill: color-text-light, size: size-contact)[#body],
box(width: icon-box-size, height: icon-box-size, baseline: 0.08em, icon),
text(fill: color-body, size: size-secondary)[#body],
)
]
#let contact-block() = block(above: 0pt)[
#let contact-block() = block(above: space-none)[
#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))
@ -149,116 +119,116 @@
]
/// 教育背景条目
#let edu-entry(degree, school, period, location, note: none) = block(above: space-sm, below: space-xs)[
#let edu-entry(degree, school, period, location) = block(above: space-none, below: space-none)[
#text(fill: color-body, size: size-body)[#degree]
#v(space-xxs)
#text(fill: color-muted, size: size-meta)[
#v(space-inline)
#text(fill: color-text-light, size: size-secondary)[
#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)
for (i, item) in education.enumerate() {
if i > 0 {
v(space-between-entries)
}
edu-entry(item.degree, item.school, item.period, item.location)
}
}
/// 侧栏技能子标题
#let sidebar-subtitle(title) = block(above: space-md, below: space-xs)[
#text(
font: heading-font,
size: size-small,
fill: color-body,
)[#title]
]
#let sidebar-subtitle(title, above: auto, below: auto) = {
let gap-above = if above != auto { above } else { space-inline }
let gap-below = if below != auto { below } else { space-subtitle-gap }
block(above: gap-above, below: gap-below)[
#text(font: heading-font, size: size-body, fill: color-body)[#title]
]
}
/// 技能进度条level: 01
#let skill-bar(name, level, subtitle: none) = block(above: space-sm, below: space-xs)[
/// 技能进度条level: 01;条与条之间仅用 above 控制间距
#let skill-bar(name, level, subtitle: none, above: space-none) = block(above: above, below: space-none)[
#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],
text(fill: color-text-light, size: size-secondary)[#name],
text(fill: color-text-light, size: size-secondary)[#subtitle],
)
] else [
#text(fill: color-body, size: size-body)[#name]
#text(fill: color-text-light, size: size-secondary)[#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))
#v(space-inline)
#box(width: 100%, height: skill-bar-height, radius: skill-bar-radius, clip: true)[
#place(left + top, block(width: 100%, height: skill-bar-height, fill: color-bar-bg))
#place(left + top, block(width: level * 100%, height: skill-bar-height, fill: color-skill-bar))
]
]
#let tech-pill(label) = box(
fill: color-page,
stroke: color-divider + 0.65pt,
radius: 3pt,
inset: (x: 5pt, y: 2pt),
stroke: stroke-pill,
radius: pill-radius,
inset: (x: pill-inset-x, y: pill-inset-y),
baseline: 0.15em,
text(fill: color-body, size: size-tech-pill)[#label],
text(fill: color-text-light, size: size-secondary)[#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)
#let tech-stack-block() = block(width: 100%, above: space-none, below: space-inline)[
#box(width: 100%)[
#for (i, tag) in category.tags.enumerate() [
#if i > 0 [#h(3pt)]
#set par(spacing: pill-gap, leading: leading-pill-wrap)
#for (i, tag) in tech-tags.enumerate() [
#if i > 0 [#h(pill-gap)]
#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("技术栈")
sidebar-subtitle("能力", above: space-none)
block(below: space-none)[
#for (i, item) in abilities.enumerate() {
skill-bar(
item.name,
item.level,
above: if i == 0 { space-none } else { space-skill-gap },
)
}
#skill-bar(
language_profile.name,
language_profile.level,
subtitle: language_profile.label,
above: space-skill-gap,
)
]
sidebar-subtitle("技术栈", above: space-subsection-gap)
tech-stack-block()
}
/// 主栏经历 / 项目条目
#let timeline-entry(entry, title-key: "company", subtitle-key: "role") = block[
#text(fill: color-accent, size: size-subtitle, weight: "bold")[
#text(fill: color-body, size: size-body, 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)[
#v(space-body)
#text(fill: color-text-light, size: size-body)[
#entry.location#if entry.location != "" []#entry.start - #entry.end
]
#v(space-sm)
#v(space-body)
#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)
#set par(leading: list-item-leading, spacing: space-none, justify: true)
#set list(
tight: true,
indent: list-indent,
body-indent: list-body-indent,
)
#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() = {

View File

@ -1,72 +1,78 @@
// HyperLabel 基础色板 — 来源HyperLabel/ComponentsTestPage.tsx foundationPalette
#import "../../brand/colors.typ": *
#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-bright = color-lime-deep
#let color-accent = color-muted
#let color-skill-bar = color-accent-bright
#let color-skill-bar = color-lime-mid
#let color-divider = color-muted.lighten(68%)
#let color-text-light = color-muted.lighten(32%) // 简介、经历描述等长正文
#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 寸,与简介区高度更协调)
// =============================================================================
// GreLin Resume · Design Tokens唯一规范源
// 字号四档20 · 12 · 10.5 · 9
// 间距三档6 · 12 · 18+ 4 micro · 10.5 body 级)
// =============================================================================
// --- 字号 ---
#let size-name = 20pt
#let size-heading = 12pt
#let size-body = 10.5pt
#let size-secondary = 9pt
// --- 行距 ---
#let leading-body = 13pt
#let leading-summary = leading-body
#let leading-entry = leading-body
#let leading-pill-wrap = 1.35em
// --- 间距 ---
#let space-none = 0pt
#let space-micro = 4pt
#let space-inline = 6pt
#let space-body = size-body // 10.5pt:条目内块间距、列表行距
#let space-title-gap = 12pt
#let space-between-entries = 12pt
#let space-block = 18pt
#let space-hero-to-photo = space-block
#let space-column-gap = space-title-gap
#let space-subtitle-gap = space-body
#let space-subsection-gap = space-body
#let space-skill-gap = space-body // 能力条 / 英语条之间
#let space-hero-name-gap = space-body
#let space-hero-title-gap = space-body
// --- 列表(行内换行与条目间距统一为正文级 10.5pt ---
#let list-item-leading = space-body
// --- 描边 ---
#let stroke-divider = color-divider + 0.55pt
#let stroke-divider-sidebar = color-divider + 0.85pt
#let stroke-divider-column = 0.55pt
#let stroke-photo = color-divider + 0.6pt
#let stroke-pill = color-divider + 0.65pt
#let stroke-placeholder = color-divider + 0.5pt
// --- 组件尺寸 ---
#let photo-width = 33mm
#let photo-height = 40mm
#let skill-bar-height = 4pt
#let skill-bar-radius = 1pt
#let pill-radius = 3pt
#let pill-inset-x = 5pt
#let pill-inset-y = 2pt
#let pill-gap = space-inline
#let icon-size = 11pt
#let icon-column-width = icon-size
#let icon-box-size = icon-size
#let list-indent = 0.8em
#let list-body-indent = 0.4em
// ---------------------------------------------------------------------------
// 排版规范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
@ -74,6 +80,6 @@
#let page-margin = (
top: 2cm,
bottom: 2cm,
left: 1.8cm,
right: 1.8cm,
left: 2cm,
right: 2cm,
)

4944
resume/sample.pdf Normal file

File diff suppressed because it is too large Load Diff

3
typst.toml Normal file
View File

@ -0,0 +1,3 @@
# GreLin Typst monorepo — 项目根目录,供 resume / feasibility 共享 brand/colors.typ
[project]