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>
This commit is contained in:
MORRO 2026-06-25 17:12:20 +08:00
parent ab0f73cbd6
commit ed33425ee9
5 changed files with 77 additions and 9 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

@ -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

@ -99,3 +99,7 @@
) )
#let awards = () #let awards = ()
// 可选:研究经历、代表性成果(留空则不渲染)
#let research = ""
#let publications = ()

View File

@ -234,6 +234,21 @@
} }
} }
#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,
@ -255,11 +270,15 @@
#let skills-section-block() = { #let skills-section-block() = {
abilities-block() abilities-block()
sidebar-subtitle( if has-skill-groups() {
"技术栈", skill-groups-block()
above: if has-abilities-section() { space-subsection-gap } else { space-none }, } else {
) sidebar-subtitle(
tech-stack-block() "技术栈",
above: if has-abilities-section() { space-subsection-gap } else { space-none },
)
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()
@ -280,6 +299,12 @@
#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)
@ -337,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

@ -4733,12 +4733,12 @@ T
endstream endstream
endobj endobj
119 0 obj 119 0 obj
<</Creator(Typst 0.15.0)/ModDate(D:20260625162202+08'00)/CreationDate(D:20260625162202+08'00)>> <</Creator(Typst 0.15.0)/ModDate(D:20260625171058+08'00)/CreationDate(D:20260625171058+08'00)>>
endobj endobj
120 0 obj 120 0 obj
<</Length 996/Type/Metadata/Subtype/XML>> <</Length 996/Type/Metadata/Subtype/XML>>
stream stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?><x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="xmp-writer"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/" xmlns:pdf="http://ns.adobe.com/pdf/1.3/" ><xmp:CreatorTool>Typst 0.15.0</xmp:CreatorTool><dc:language><rdf:Bag><rdf:li>zh</rdf:li></rdf:Bag></dc:language><xmp:ModifyDate>2026-06-25T16:22:02+08:00</xmp:ModifyDate><xmp:CreateDate>2026-06-25T16:22:02+08:00</xmp:CreateDate><xmpTPg:NPages>1</xmpTPg:NPages><dc:format>application/pdf</dc:format><xmpMM:InstanceID>wFnMDS1jMz01jF6pKGYgXA==</xmpMM:InstanceID><xmpMM:DocumentID>wFnMDS1jMz01jF6pKGYgXA==</xmpMM:DocumentID><xmpMM:RenditionClass>proof</xmpMM:RenditionClass><pdf:PDFVersion>1.7</pdf:PDFVersion></rdf:Description></rdf:RDF></x:xmpmeta><?xpacket end="r"?> <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?><x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="xmp-writer"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/" xmlns:pdf="http://ns.adobe.com/pdf/1.3/" ><xmp:CreatorTool>Typst 0.15.0</xmp:CreatorTool><dc:language><rdf:Bag><rdf:li>zh</rdf:li></rdf:Bag></dc:language><xmp:ModifyDate>2026-06-25T17:10:58+08:00</xmp:ModifyDate><xmp:CreateDate>2026-06-25T17:10:58+08:00</xmp:CreateDate><xmpTPg:NPages>1</xmpTPg:NPages><dc:format>application/pdf</dc:format><xmpMM:InstanceID>YG9afPnvozvA+8c8Oh87JQ==</xmpMM:InstanceID><xmpMM:DocumentID>YG9afPnvozvA+8c8Oh87JQ==</xmpMM:DocumentID><xmpMM:RenditionClass>proof</xmpMM:RenditionClass><pdf:PDFVersion>1.7</pdf:PDFVersion></rdf:Description></rdf:RDF></x:xmpmeta><?xpacket end="r"?>
endstream endstream
endobj endobj
121 0 obj 121 0 obj
@ -4869,7 +4869,7 @@ xref
0001005638 00000 n 0001005638 00000 n
0001006711 00000 n 0001006711 00000 n
trailer trailer
<</Size 122/Root 121 0 R/Info 119 0 R/ID[(wFnMDS1jMz01jF6pKGYgXA==)(wFnMDS1jMz01jF6pKGYgXA==)]>> <</Size 122/Root 121 0 R/Info 119 0 R/ID[(YG9afPnvozvA+8c8Oh87JQ==)(YG9afPnvozvA+8c8Oh87JQ==)]>>
startxref startxref
1006881 1006881
%%EOF %%EOF