Compare commits

...

2 Commits

Author SHA1 Message Date
ed33425ee9 Extend resume template with optional research, publications, and skill groups.
Ignore resume/local for personal configs and keep sample PDF in sync with template defaults.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 17:12:20 +08:00
ab0f73cbd6 Refine resume template for conservative audiences with grayscale styling.
Remove default ability bars, widen margins and section spacing, fix entry layout, and refresh sample PDF for government-facing delivery.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 16:22:12 +08:00
11 changed files with 764 additions and 747 deletions

3
.gitignore vendored
View File

@ -3,6 +3,9 @@
!resume/sample.pdf !resume/sample.pdf
!feasibility/sample.pdf !feasibility/sample.pdf
# 本地定制简历个人内容、照片、PDF不提交
resume/local/
# IDE / 编辑器本地配置 # IDE / 编辑器本地配置
.cursor/ .cursor/
.vscode/ .vscode/

View File

@ -1,6 +1,6 @@
# Resume · 团队简历模板 # Resume · 团队简历模板
GreLin 双栏中文简历 Typst 模板HyperLabel 配色),用于融资 BP data room 附录。 GreLin 双栏中文简历 Typst 模板,用于融资 BP data room 附录。
## 照片 ## 照片
@ -25,16 +25,17 @@ GreLin 双栏中文简历 Typst 模板HyperLabel 配色),用于融资 BP
) )
#let skills = ( #let skills = (
abilities: (
(name: "全栈开发", level: 0.9),
),
language: (
name: "英语",
level: 0.75,
label: "读写",
),
tags: ("Rust", "Python"), tags: ("Rust", "Python"),
notes: (), // 可选:侧栏技能补充列表 notes: (), // 可选:侧栏技能补充列表
// 可选:能力进度条(有数据时自动显示「能力」子区块)
// abilities: (
// (name: "全栈开发", level: 0.9),
// ),
// language: (
// name: "英语",
// level: 0.75,
// label: "读写",
// ),
) )
#let education = ( #let education = (

View File

@ -1 +1 @@
<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> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#434950" 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="#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> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#434950" 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="#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> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#434950" 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="#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> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#434950" 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

@ -33,12 +33,22 @@
] ]
#let main-content = [ #let main-content = [
#section-title("工作经历", above: space-none) #if research != "" [
#section-title("研究经历", above: space-none)
#research-block()
]
#section-title("工作经历", above: if research != "" { auto } else { space-none })
#experiences-block() #experiences-block()
#section-title("项目经历") #section-title("项目经历")
#projects-block() #projects-block()
#if publications.len() > 0 [
#section-title("代表性成果")
#publications-block()
]
#if awards.len() > 0 [ #if awards.len() > 0 [
#section-title("获奖经历") #section-title("获奖经历")
#awards-block() #awards-block()

View File

@ -22,15 +22,6 @@
) )
#let skills = ( #let skills = (
abilities: (
(name: "全栈开发", level: 0.9),
(name: "系统架构", level: 0.75),
),
language: (
name: "英语",
level: 0.75,
label: "读写",
),
tags: ( tags: (
"Rust", "Python", "Java", "React", "Tauri", "RAG", "Linux", "MySQL", "Redis", "Rust", "Python", "Java", "React", "Tauri", "RAG", "Linux", "MySQL", "Redis",
"LLM Agent", "LLM Agent",
@ -108,3 +99,7 @@
) )
#let awards = () #let awards = ()
// 可选:研究经历、代表性成果(留空则不渲染)
#let research = ""
#let publications = ()

View File

@ -82,9 +82,15 @@
} else if sidebar { } else if sidebar {
space-none space-none
} else { } else {
space-block space-main-section
}
let title-below = if below != auto {
below
} else if sidebar {
space-title-gap
} else {
space-main-title-below
} }
let title-below = if below != auto { below } else { space-title-gap }
block(width: 100%, above: title-above, below: title-below)[ block(width: 100%, above: title-above, below: title-below)[
#text(font: heading-font, size: size-heading, weight: "bold", fill: color-ink)[#title] #text(font: heading-font, size: size-heading, weight: "bold", fill: color-ink)[#title]
#if divider [ #if divider [
@ -121,7 +127,7 @@
/// 教育背景条目notes 可选,一段普通正文) /// 教育背景条目notes 可选,一段普通正文)
#let edu-entry(degree, school, period, location, notes: "") = block(above: space-none, below: space-none)[ #let edu-entry(degree, school, period, location, notes: "") = block(above: space-none, below: space-none)[
#text(fill: color-body, size: size-body)[#degree] #text(fill: color-body, size: size-body)[#degree]
#v(space-inline) #v(space-edu-meta-gap)
#text(fill: color-text-light, size: size-secondary)[ #text(fill: color-text-light, size: size-secondary)[
#school#if period != "" [ · #period]#if location != "" [ · #location] #school#if period != "" [ · #period]#if location != "" [ · #location]
] ]
@ -174,7 +180,7 @@
] ]
} }
/// 技能进度条level: 01条与条之间仅用 above 控制间距 /// 技能进度条level: 01config 提供 abilities / language 时由 abilities-block 渲染
#let skill-bar(name, level, subtitle: none, above: space-none) = block(above: above, below: space-none)[ #let skill-bar(name, level, subtitle: none, above: space-none) = block(above: above, below: space-none)[
#if subtitle != none [ #if subtitle != none [
#grid( #grid(
@ -193,6 +199,56 @@
] ]
] ]
#let has-abilities-section() = {
let ability-list = skills.at("abilities", default: ())
let has-lang = skills.at("language", default: none) != none
ability-list.len() > 0 or has-lang
}
/// 「能力」进度条区块skills.abilities / skills.language 有数据时才显示)
#let abilities-block() = {
if has-abilities-section() {
sidebar-subtitle("能力", above: space-none)
block(below: space-none)[
#for (i, item) in skills.at("abilities", default: ()).enumerate() {
skill-bar(
item.name,
item.level,
above: if i == 0 { space-none } else { space-skill-gap },
)
}
#let lang = skills.at("language", default: none)
#if lang != none {
skill-bar(
lang.name,
lang.level,
subtitle: lang.at("label", default: none),
above: if skills.at("abilities", default: ()).len() == 0 {
space-none
} else {
space-skill-gap
},
)
}
]
}
}
#let has-skill-groups() = skills.at("groups", default: ()).len() > 0
#let skill-groups-block() = {
for (i, group) in skills.at("groups", default: ()).enumerate() {
sidebar-subtitle(
group.title,
above: if i == 0 and not has-abilities-section() { space-none } else { space-subsection-gap },
)
block(below: space-none)[
#set par(leading: list-item-leading, spacing: space-none, justify: true)
#text(fill: color-text-light, size: size-secondary)[#group.items]
]
}
}
#let tech-pill(label) = box( #let tech-pill(label) = box(
fill: color-page, fill: color-page,
stroke: stroke-pill, stroke: stroke-pill,
@ -213,24 +269,16 @@
] ]
#let skills-section-block() = { #let skills-section-block() = {
sidebar-subtitle("能力", above: space-none) abilities-block()
block(below: space-none)[ if has-skill-groups() {
#for (i, item) in skills.abilities.enumerate() { skill-groups-block()
skill-bar( } else {
item.name, sidebar-subtitle(
item.level, "技术栈",
above: if i == 0 { space-none } else { space-skill-gap }, above: if has-abilities-section() { space-subsection-gap } else { space-none },
) )
}
#skill-bar(
skills.language.name,
skills.language.level,
subtitle: skills.language.label,
above: space-skill-gap,
)
]
sidebar-subtitle("技术栈", above: space-subsection-gap)
tech-stack-block() tech-stack-block()
}
if skills.notes.len() > 0 { if skills.notes.len() > 0 {
sidebar-subtitle("补充", above: space-subsection-gap) sidebar-subtitle("补充", above: space-subsection-gap)
skill-notes-block() skill-notes-block()
@ -239,6 +287,7 @@
/// 主栏经历 / 项目条目 /// 主栏经历 / 项目条目
#let timeline-entry(entry, title-key: "company", subtitle-key: "role") = block[ #let timeline-entry(entry, title-key: "company", subtitle-key: "role") = block[
#block(above: space-entry-title-above, below: space-entry-title-below)[
#text(fill: color-body, size: size-body, weight: "bold")[ #text(fill: color-body, size: size-body, weight: "bold")[
#if subtitle-key != none [ #if subtitle-key != none [
#entry.at(title-key) / #entry.at(subtitle-key) #entry.at(title-key) / #entry.at(subtitle-key)
@ -246,10 +295,16 @@
#entry.at(title-key) #entry.at(title-key)
] ]
] ]
#v(space-body) ]
#text(fill: color-text-light, size: size-body)[ #text(fill: color-text-light, size: size-body)[
#entry.location#if entry.location != "" []#entry.start - #entry.end #entry.location#if entry.location != "" []#entry.start - #entry.end
] ]
#let intro = entry.at("intro", default: "")
#if intro != "" [
#v(space-body)
#set par(leading: list-item-leading, spacing: space-none, justify: true)
#text(weight: "regular", fill: color-text-light, size: size-body)[#intro]
]
#v(space-body) #v(space-body)
#set text(weight: "regular", fill: color-text-light, size: size-body) #set text(weight: "regular", fill: color-text-light, size: size-body)
#set par(leading: list-item-leading, spacing: space-none, justify: true) #set par(leading: list-item-leading, spacing: space-none, justify: true)
@ -282,8 +337,9 @@
/// 获奖经历条目bullets 可留空) /// 获奖经历条目bullets 可留空)
#let award-entry(entry) = block[ #let award-entry(entry) = block[
#block(above: space-entry-title-above, below: space-entry-title-below)[
#text(fill: color-body, size: size-body, weight: "bold")[#entry.title] #text(fill: color-body, size: size-body, weight: "bold")[#entry.title]
#v(space-body) ]
#text(fill: color-text-light, size: size-body)[#entry.meta] #text(fill: color-text-light, size: size-body)[#entry.meta]
#if entry.bullets.len() > 0 [ #if entry.bullets.len() > 0 [
#v(space-body) #v(space-body)
@ -306,3 +362,29 @@
award-entry(entry) award-entry(entry)
} }
} }
#let research-block() = {
if research != "" {
block(above: space-none)[
#set par(leading: leading-body, spacing: space-none, justify: true)
#text(fill: color-text-light, size: size-body)[#research]
]
}
}
#let publication-entry(entry, index) = block(above: space-none, below: space-none)[
#if index > 1 { v(space-between-entries) }
#text(fill: color-body, size: size-secondary, weight: "bold")[
\[#index\] #entry.title
]
#v(space-inline)
#text(fill: color-text-light, size: size-secondary)[#entry.authors]
#v(space-micro)
#text(fill: color-text-light, size: size-secondary)[#entry.venue]
]
#let publications-block() = {
for (i, entry) in publications.enumerate() {
publication-entry(entry, i + 1)
}
}

View File

@ -1,8 +1,9 @@
#import "../../brand/colors.typ": * #import "../../brand/colors.typ": *
#let color-accent-bright = color-lime-deep #let color-icon = color-muted
#let color-accent-bright = color-body
#let color-accent = color-muted #let color-accent = color-muted
#let color-skill-bar = color-lime-mid #let color-skill-bar = color-muted
#let color-divider = color-muted.lighten(68%) #let color-divider = color-muted.lighten(68%)
#let color-text-light = color-muted.lighten(32%) #let color-text-light = color-muted.lighten(32%)
@ -35,9 +36,14 @@
#let space-body = size-body #let space-body = size-body
#let space-title-gap = 12pt #let space-title-gap = 12pt
#let space-edu-notes-before = space-title-gap #let space-edu-notes-before = space-title-gap
#let space-edu-meta-gap = 10pt
#let leading-edu-notes = size-secondary #let leading-edu-notes = size-secondary
#let space-between-entries = 12pt #let space-between-entries = 20pt
#let space-entry-title-above = 6pt
#let space-entry-title-below = 14pt
#let space-block = 18pt #let space-block = 18pt
#let space-main-section = 26pt
#let space-main-title-below = 14pt
#let space-hero-to-photo = space-block #let space-hero-to-photo = space-block
#let space-column-gap = space-title-gap #let space-column-gap = space-title-gap
@ -86,6 +92,6 @@
#let page-margin = ( #let page-margin = (
top: 2cm, top: 2cm,
bottom: 2cm, bottom: 2cm,
left: 2cm, left: 1.5cm,
right: 2cm, right: 1.5cm,
) )

File diff suppressed because it is too large Load Diff