Simplify tech-report body layer and remove glossary.

Replace metropole-grelin with body.typ, merge styling into md.typ, drop glossary support, and clean unused theme tokens.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
MORRO 2026-07-08 16:53:50 +08:00
parent b8b2f5fe14
commit 5c1039c62d
12 changed files with 2483 additions and 3185 deletions

View File

@ -1,6 +1,6 @@
# Tech Report · 技术报告模板 # Tech Report · 技术报告模板
GreLin 技术报告 Typst 模板,正文版式参考 [metropole-report](https://typst.app/universe/package/metropole-report)**封面**为自定义深蓝渐变 + 光斑 / 波纹 / 斜向色带(见 `data/cover.typ` GreLin 技术报告 Typst 模板**封面**与**目录**见 `data/cover.typ`、`data/toc.typ`**正文**见 `data/body.typ`
## 快速开始 ## 快速开始
@ -20,7 +20,7 @@ typst compile tech-report/report.typ tech-report/sample.pdf --root .
| [`data/config.typ`](data/config.typ) | 默认公司名、标题等 | | [`data/config.typ`](data/config.typ) | 默认公司名、标题等 |
| [`data/theme.typ`](data/theme.typ) | 字号、行距、GreLin 品牌色 | | [`data/theme.typ`](data/theme.typ) | 字号、行距、GreLin 品牌色 |
| [`data/cover.typ`](data/cover.typ) | 封面装饰与版式 | | [`data/cover.typ`](data/cover.typ) | 封面装饰与版式 |
| [`data/metropole-grelin.typ`](data/metropole-grelin.typ) | 正文 metropole 壳(跳过内联标题 | | [`data/body.typ`](data/body.typ) | 正文版式(标题、表格、代码、页脚 |
| [`report.typ`](report.typ) | 编译入口 | | [`report.typ`](report.typ) | 编译入口 |
## YAML 元数据 ## YAML 元数据
@ -41,11 +41,9 @@ summary: |
| 包 | 用途 | | 包 | 用途 |
|----|------| |----|------|
| [metropole-report](https://typst.app/universe/package/metropole-report) | 报告版式(封面、标题、表格、列表) |
| [cmarker](https://typst.app/universe/package/cmarker) | Markdown → Typst | | [cmarker](https://typst.app/universe/package/cmarker) | Markdown → Typst |
| [codly](https://typst.app/universe/package/codly) | 代码块高亮 | | [codly](https://typst.app/universe/package/codly) | 代码块高亮 |
| [glossarium](https://typst.app/universe/package/glossarium) | 术语表 |
## 样式参考 ## 样式参考
整体风格对齐 `typst init @preview/metropole-report:0.1.0`;后续可引入 [grape-suite](https://typst.app/universe/package/grape-suite) 做更复杂的学术组件 封面与目录样式见 `data/cover.typ`、`data/toc.typ`;正文样式见 `data/body.typ`、`data/theme.typ`

View File

@ -88,8 +88,7 @@ title: "智能矿石分选\n技术报告"
## 摘要与目录 ## 摘要与目录
- **摘要**:写在 YAML 的 `summary` 字段;正文区不再重复「摘要」标题,且与第一章可在同一页连续排版。 - **摘要**:写在 YAML 的 `summary` 字段;正文区不再重复「摘要」标题,且与第一章可在同一页连续排版。
- **目录**:由模板自动生成,仅列出正文章节;摘要与「术语与缩写」不会出现在目录中。 - **目录**:由模板自动生成,仅列出正文章节;摘要不会出现在目录中。
- **术语与缩写**:在 `data/glossary.typ` 维护,报告末尾自动输出,同样不进目录。
# Markdown 语法 # Markdown 语法
@ -156,15 +155,6 @@ for sample in belt_stream:
# 高级功能 # 高级功能
## 术语与缩写
在正文中引用术语表条目,使用 raw-typst 嵌入:
- 首次出现:<!--raw-typst #gls-long("hsi") -->
- 再次出现:<!--raw-typst #gls-short("onnx") -->
术语定义集中在 `data/glossary.typ`,报告末尾会自动生成「术语与缩写」一节。
## 插入 Typst 组件 ## 插入 Typst 组件
复杂图表或自定义组件可在 Markdown 中插入 Typst 代码: 复杂图表或自定义组件可在 Markdown 中插入 Typst 代码:
@ -192,6 +182,6 @@ A保存 `report.md` 后Typst Preview 通常会自动刷新;若无反应
A确认路径相对于 `content/report.md`,且文件位于 `content/assets/` 目录下。 A确认路径相对于 `content/report.md`,且文件位于 `content/assets/` 目录下。
**Q想改主题色或字号** **Q想改主题色或字号**
A编辑 `data/theme.typ`;品牌色也可在仓库根目录 `brand/colors.typ` 统一调整。 A全局 token 在 `data/theme.typ`;正文组件样式在 `data/body.typ`;封面/目录分别在 `data/cover.typ`、`data/toc.typ`。品牌色也可在 `brand/colors.typ` 调整。
完成以上步骤后,你即可基于本模板快速产出 GreLin 风格的技术报告。祝写作顺利。 完成以上步骤后,你即可基于本模板快速产出 GreLin 风格的技术报告。祝写作顺利。

186
tech-report/data/body.typ Normal file
View File

@ -0,0 +1,186 @@
#import "theme.typ": *
#let page-numbering-started = state("page-numbering-started", false)
#let start-body-page-numbering() = {
page-numbering-started.update(true)
counter(page).update(1)
}
#let report-body(
title: none,
author: none,
date: none,
paper-size: "a4",
language: "zh",
font-size: size-body,
leading-ratio: leading-ratio,
body-font: body-font,
heading-font: heading-font,
raw-font: mono-font,
margin-x: body-margin-x,
margin-y: body-margin-y,
accent-color: color-primary,
body-text-color: color-body-text,
body,
) = {
let scale = 1.25
let caption-size = font-size * calc.pow(scale, -1)
let lead-size = font-size * calc.pow(scale, 1)
let heading-size = font-size * calc.pow(scale, 2)
let line-height = font-size * leading-ratio
let muted-color = color.mix(
(rgb("#000000"), 5),
(rgb("#ffffff"), 3),
space: oklab,
)
set document(title: title, date: date)
if author != none {
set document(author: author)
}
set text(
font: body-font,
size: font-size,
fill: body-text-color,
lang: language,
)
show raw: set text(font: raw-font)
set par(
leading: line-height - font-size,
spacing: line-height,
justify: true,
)
set page(
paper: paper-size,
margin: (x: margin-x, top: margin-y, bottom: margin-y),
header: none,
footer: context {
v(line-height / 2)
if page-numbering-started.at(here()) {
align(right, text(
font: heading-font,
size: caption-size,
fill: muted-color,
counter(page).display("1 / 1", both: true),
))
}
},
footer-descent: line-height,
)
let report-heading(it, size, above, below, title-fill: rgb("#000000")) = block(
width: 100%,
breakable: false,
above: above,
below: below,
)[
#context {
if it.numbering != none {
let number = counter(heading).display(it.numbering)
text(font: heading-font, size: size, weight: "bold")[
#text(fill: accent-color)[#number]
#h(0.35em)
#text(fill: title-fill)[#it.body]
]
} else {
text(font: heading-font, size: size, weight: "bold", fill: title-fill, it.body)
}
}
]
show heading.where(level: 1): it => {
report-heading(it, heading-size, line-height * 2, line-height, title-fill: accent-color)
}
show heading.where(level: 2): it => {
report-heading(it, lead-size, line-height * 2, line-height * 0.85)
}
show heading.where(level: 3): it => {
report-heading(it, font-size, line-height, line-height * 0.75)
}
show heading.where(level: 4): it => {
report-heading(it, caption-size, line-height * 0.85, line-height * 0.65)
}
set list(
indent: 0pt,
body-indent: line-height / 2,
marker: text(font: heading-font, fill: accent-color, weight: "bold")[•],
)
set enum(
indent: 0pt,
body-indent: line-height / 2,
numbering: (..nums) => text(
font: heading-font,
fill: accent-color,
weight: "medium",
numbering("1.a.i.", ..nums),
),
)
show quote.where(block: true): it => {
v(line-height * 0.75, weak: true)
block(width: 100%)[
#block(
width: 100%,
inset: (left: tw(3.5)),
stroke: (left: quote-bar-stroke + quote-bar-color),
)[
#text(font: body-font, fill: body-text-color, it.body)
]
]
v(line-height * 0.75, weak: true)
}
show table: it => {
if it.has("label") and it.label == <table-full-width> {
it
} else {
[#table(
columns: (1fr,) * it.columns.len(),
..it.children,
)#label("table-full-width")]
}
}
set table(
stroke: none,
inset: (x: line-height / 2, y: line-height / 2),
fill: (x, y) => if y == 0 {
accent-color
} else if calc.even(y) {
color-block-bg
} else {
none
},
)
show table.cell.where(y: 0): it => {
text(font: heading-font, weight: "bold", size: caption-size, fill: white, it)
}
show raw.where(block: true): block.with(
inset: (x: line-height, y: line-height / 2),
width: 100%,
fill: color-block-bg,
radius: code-block-radius,
)
show raw.where(block: true): set par(justify: false)
show raw.where(block: false): box.with(
inset: (x: 3pt, y: 0pt),
outset: (y: 3pt),
fill: color-block-bg,
radius: code-inline-radius,
)
show link: it => {
if type(it.dest) != str {
it
} else {
text(fill: accent-color, underline(it.body))
}
}
body
}

View File

@ -19,20 +19,7 @@
lang-radius: code-block-radius, lang-radius: code-block-radius,
) )
/// 与 codly 配合的语法高亮色(须在 codly-init 之后注册)
#let code-token-highlight-init(doc) = { #let code-token-highlight-init(doc) = {
show raw.where(block: true): it => { show raw.where(block: true): set text(fill: color-body)
show "keyword": set text(fill: code-token-keyword)
show "comment": set text(fill: code-token-comment)
show "string": set text(fill: code-token-string)
show "number": set text(fill: code-token-number)
show "builtin": set text(fill: code-token-function)
show "function": set text(fill: code-token-function)
show "decor": set text(fill: code-token-function)
show "operator": set text(fill: code-token-operator)
show "punctuation": set text(fill: code-token-operator)
set text(fill: color-body)
it
}
doc doc
} }

View File

@ -1,32 +0,0 @@
#import "@preview/glossarium:0.5.10": make-glossary, register-glossary, print-glossary, gls-long, gls-short
#import "theme.typ": *
#let glossary-entries = (
(
key: "hsi",
short: "HSI",
long: "高光谱成像",
description: "Hyperspectral Imaging获取矿石连续波段光谱信息。",
),
(
key: "onnx",
short: "ONNX",
long: "开放神经网络交换格式",
description: "Open Neural Network Exchange用于跨平台模型推理部署。",
),
(
key: "as-ratio",
short: "A/S",
long: "铝硅比",
description: "精矿品质评价的关键指标之一。",
),
)
#let init-glossary(doc) = {
show: make-glossary
doc
}
#let register-report-glossary() = {
register-glossary(glossary-entries)
}

View File

@ -1,7 +1,40 @@
#import "@preview/cmarker:0.1.8": render-with-metadata #import "@preview/cmarker:0.1.8": render-with-metadata
#import "config.typ": * #import "config.typ": *
#import "theme.typ": * #import "theme.typ": *
#import "styling.typ": underline-accent, text-highlight
#let underline-accent(body) = underline(
body,
stroke: 1.5pt + color-primary,
offset: 4pt,
evade: true,
)
#let text-highlight(body) = highlight(
body,
fill: color-accent-surface,
top-edge: "ascender",
bottom-edge: "descender",
radius: tw(0.5),
)
#let parse-report-date(raw) = {
if type(raw) == datetime {
raw
} else if type(raw) == str {
let parts = raw.split("-")
if parts.len() == 3 {
datetime(
year: int(parts.at(0)),
month: int(parts.at(1)),
day: int(parts.at(2)),
)
} else {
none
}
} else {
none
}
}
#let source-dir(path) = { #let source-dir(path) = {
let parts = path.split("/") let parts = path.split("/")

View File

@ -1,465 +0,0 @@
#let transit-red = rgb("#c53a2f")
#import "theme.typ": color-quote, code-block-radius, code-inline-radius, quote-bar-stroke, quote-bar-color, color-body-text, color-block-bg, tw
#let metro-blue = rgb("#005f9e")
#let deep-teal = rgb("#0f766e")
#let burnt-orange = rgb("#c96b2c")
#let emerald = rgb("#1f7a4f")
#let deep-violet = rgb("#5a4fcf")
#let page-numbering-started = state("page-numbering-started", false)
#let start-body-page-numbering() = {
page-numbering-started.update(true)
counter(page).update(1)
}
#let metropole(
// -- Metadata --
title: none,
subtitle: none,
author: none,
date: none,
// -- Document --
paper-size: "a4",
language: "en",
date-format: "[day] [month repr:long] [year]",
cover-page: false,
inline-title: true,
show-header: false,
// -- Page margins (override metropole defaults) --
margin-x: none,
margin-y: none,
header-skip: none,
// -- Fonts --
font-size: 11pt,
leading-ratio: 1.75,
body-font: "Source Serif 4",
heading-font: "Source Sans 3",
raw-font: "Source Code Pro",
// -- Colors --
background-color: rgb("#ffffff"),
foreground-color: rgb("000000"),
body-text-color: none,
accent-color: transit-red,
// -- Body --
body,
) = {
// ── Type scale (major third × 1.25) --
let scale = 1.25
let fine-size = font-size * calc.pow(scale, -2) // ~7pt
let caption-size = font-size * calc.pow(scale, -1) // ~8.8pt
let lead-size = font-size * calc.pow(scale, 1) // ~13.75pt
let heading-size = font-size * calc.pow(scale, 2) // ~17.2pt
let display-size = font-size * calc.pow(scale, 3) // ~21.5pt
let title-size = font-size * calc.pow(scale, 4) // ~26.8pt
// ── Derived colors --
let secondary-content-color = color.mix(
(foreground-color, 5),
(background-color, 3),
space: oklab,
)
let secondary-accent-color = color.mix(
(accent-color, 2),
(background-color, 1),
space: oklab,
)
let link-color = color.mix(
(accent-color, 3),
(foreground-color, 1),
space: oklab,
)
// ── Baseline grid --
let line-height = font-size * leading-ratio
// ── Spatial system (multiples of line-height) --
let margin-vertical = if margin-y != none { margin-y } else { line-height * 2.2 }
let margin-horizontal = if margin-x != none { margin-x } else { line-height * 2.8 }
let header-gap = if header-skip != none { header-skip } else { line-height * 1.1 }
// ── Configure metadata --
set document(title: title, date: date)
if author != none {
set document(author: author)
}
// ── Configure text --
let body-fill = if body-text-color != none { body-text-color } else { foreground-color }
set text(
font: body-font,
size: font-size,
fill: body-fill,
ligatures: true,
discretionary-ligatures: true,
lang: language,
)
show raw: set text(font: raw-font)
// ── Configure paragraphs --
set par(
leading: line-height - font-size,
spacing: line-height,
justify: true,
justification-limits: (
spacing: (
min: 100% * 2 / 3,
max: 100% * 3 / 2,
),
tracking: (
min: -0.01em,
max: 0.01em,
),
),
)
// ── Configure page --
set page(
paper: paper-size,
fill: background-color,
margin: (
x: margin-horizontal,
top: margin-vertical,
bottom: margin-vertical,
),
header: if show-header {
context {
if counter(page).get().first() > 1 {
v(header-gap)
grid(
columns: (1fr, 1fr),
align(left, text(
font: heading-font,
size: caption-size,
fill: secondary-content-color,
weight: "medium",
if author != none { author } else { "" },
)),
align(right, text(
font: heading-font,
size: caption-size,
fill: secondary-content-color,
weight: "medium",
title,
)),
)
v(line-height / 2)
}
}
} else {
none
},
header-ascent: if show-header { line-height / 2 } else { 0pt },
footer: context {
v(line-height / 2)
if page-numbering-started.at(here()) {
align(right, text(
font: heading-font,
size: caption-size,
fill: secondary-content-color,
counter(page).display("1 / 1", both: true),
))
}
},
footer-descent: line-height,
)
// ── Configure headings --
let report-heading(it, size, above, below, title-fill: foreground-color) = block(
width: 100%,
breakable: false,
above: above,
below: below,
)[
#context {
if it.numbering != none {
let number = counter(heading).display(it.numbering)
text(font: heading-font, size: size, weight: "bold")[
#text(fill: accent-color)[#number]
#h(0.35em)
#text(fill: title-fill)[#it.body]
]
} else {
text(
font: heading-font,
size: size,
weight: "bold",
fill: title-fill,
it.body,
)
}
}
]
show heading.where(level: 1): it => {
report-heading(it, heading-size, line-height * 2, line-height, title-fill: accent-color)
}
show heading.where(level: 2): it => {
report-heading(it, lead-size, line-height * 2, line-height * 0.85)
}
show heading.where(level: 3): it => {
report-heading(it, font-size, line-height, line-height * 0.75)
}
show heading.where(level: 4): it => {
report-heading(it, caption-size, line-height * 0.85, line-height * 0.65)
}
// ── Configure lists --
set list(
indent: 0pt,
body-indent: line-height / 2,
marker: (
text(
font: heading-font,
fill: accent-color,
weight: "bold",
)[•],
text(
font: heading-font,
fill: accent-color,
weight: "bold",
)[‣],
text(
font: heading-font,
fill: accent-color,
weight: "bold",
)[],
),
)
set enum(
indent: 0pt,
body-indent: line-height / 2,
numbering: (..nums) => text(
font: heading-font,
fill: accent-color,
weight: "medium",
numbering("1.a.i.", ..nums),
),
)
set terms(
indent: 0pt,
separator: h(0.5em, weak: true),
)
show terms.item: it => par({
text(
font: heading-font,
weight: "medium",
fill: accent-color,
it.term,
)
h(0.5em)
it.description
})
// -- Configure block quotes --
show quote.where(block: true): it => {
v(line-height * 0.75, weak: true)
block(width: 100%)[
#block(
width: 100%,
inset: (left: tw(3.5)),
stroke: (left: quote-bar-stroke + quote-bar-color),
)[
#text(font: body-font, fill: color-body-text, it.body)
#if it.attribution != none {
v(line-height / 2, weak: true)
align(right, text(
font: heading-font,
size: caption-size,
fill: secondary-content-color,
[— #it.attribution],
))
}
]
]
v(line-height * 0.75, weak: true)
}
// -- Configure tables --
show table: it => {
if it.has("label") and it.label == <table-full-width> {
it
} else {
[#table(
columns: (1fr,) * it.columns.len(),
..it.children,
)#label("table-full-width")]
}
}
set table(
stroke: none,
inset: (x: line-height / 2, y: line-height / 2),
fill: (x, y) => if y == 0 {
accent-color
} else if calc.even(y) {
color-block-bg
} else {
none
},
)
show table.cell.where(y: 0): it => {
text(
font: heading-font,
weight: "bold",
size: caption-size,
fill: background-color,
it,
)
}
// ── Configure code --
show raw.where(block: true): block.with(
inset: (x: line-height, y: line-height / 2),
width: 100%,
fill: color-block-bg,
radius: code-block-radius,
)
show raw.where(block: true): set par(justify: false)
show raw.where(block: false): box.with(
inset: (x: 3pt, y: 0pt),
outset: (y: 3pt),
fill: color-block-bg,
radius: code-inline-radius,
)
show raw.where(block: false): set text(fill: foreground-color)
// ── Configure links --
show link: it => {
if type(it.dest) != str {
it
} else {
text(fill: accent-color, underline(it.body))
}
}
// ── Title --
if cover-page {
// Full cover page
page(
margin: 0pt,
header: none,
footer: none,
)[
#place(left + top, rect(
width: line-height,
height: 100%,
fill: accent-color,
))
#pad(
left: line-height + margin-horizontal,
right: margin-horizontal,
top: margin-vertical * 2,
bottom: margin-vertical,
)[
#v(1fr)
#text(
font: heading-font,
size: title-size,
weight: "bold",
upper(title),
)
#v(line-height)
#if subtitle != none {
text(
font: heading-font,
size: heading-size,
weight: "light",
subtitle,
)
v(line-height)
}
#v(2fr)
#if author != none {
grid(
columns: (1fr, 1fr),
text(
font: heading-font,
size: caption-size,
weight: "medium",
author,
),
align(right, if date != none {
text(
font: heading-font,
size: caption-size,
fill: secondary-content-color,
date.display(date-format),
)
}),
)
} else if date != none {
text(
font: heading-font,
size: caption-size,
fill: secondary-content-color,
date.display(date-format),
)
}
]
]
} else if inline-title {
// Inline title block on first page
// Accent bar bleeding to page edges
place(
left + top,
dx: -margin-horizontal,
dy: -margin-vertical,
rect(
width: line-height,
height: 100% + margin-vertical * 2,
fill: accent-color,
),
)
// Title block
v(line-height)
text(
font: heading-font,
size: display-size,
weight: "bold",
upper(title),
)
v(line-height / 2)
if subtitle != none {
text(
font: heading-font,
size: lead-size,
weight: "light",
subtitle,
)
v(line-height / 2)
}
if author != none {
grid(
columns: (1fr, 1fr),
text(
font: heading-font,
size: caption-size,
weight: "medium",
author,
),
align(right, if date != none {
text(
font: heading-font,
size: caption-size,
fill: secondary-content-color,
date.display("[day] [month repr:long] [year]"),
)
}),
)
} else if date != none {
text(
font: heading-font,
size: caption-size,
fill: secondary-content-color,
date.display("[day] [month repr:long] [year]"),
)
}
v(line-height * 2)
}
// ── Body --
body
}

View File

@ -1,16 +0,0 @@
#import "theme.typ": *
#let underline-accent(body) = underline(
body,
stroke: 1.5pt + color-accent,
offset: 4pt,
evade: true,
)
#let text-highlight(body) = highlight(
body,
fill: color-accent-surface,
top-edge: "ascender",
bottom-edge: "descender",
radius: tw(0.5),
)

View File

@ -3,26 +3,13 @@
// 技术报告 · 主色 #3052c8 // 技术报告 · 主色 #3052c8
#let color-primary = rgb("#3052c8") #let color-primary = rgb("#3052c8")
#let color-accent = color-primary
#let color-accent-surface = color-primary.lighten(88%) #let color-accent-surface = color-primary.lighten(88%)
#let color-heading = color-ink
#let color-body-text = color-body #let color-body-text = color-body
#let color-caption = rgb(110, 110, 110) #let color-caption = rgb(110, 110, 110)
#let color-quote = rgb(90, 90, 90)
#let quote-bar-stroke = 2.5pt #let quote-bar-stroke = 2.5pt
#let quote-bar-color = rgb("#f6f7f8") #let quote-bar-color = rgb("#f6f7f8")
#let table-stroke-color = color-muted.lighten(50%)
#let color-code-inline = color-ink
#let color-page = white
#let color-block-bg = rgb("#f6f7f8") #let color-block-bg = rgb("#f6f7f8")
#let code-token-keyword = color-ink
#let code-token-comment = rgb(130, 130, 130)
#let code-token-string = rgb(40, 40, 40)
#let code-token-number = rgb(70, 70, 70)
#let code-token-function = color-ink
#let code-token-operator = rgb(100, 100, 100)
// 字体:微软雅黑 // 字体:微软雅黑
#let report-font = ("Microsoft YaHei", "Microsoft YaHei UI") #let report-font = ("Microsoft YaHei", "Microsoft YaHei UI")
#let heading-font = report-font #let heading-font = report-font
@ -32,14 +19,9 @@
// 正文text-base · leading-normal // 正文text-base · leading-normal
#let size-body = text-base #let size-body = text-base
#let leading-ratio = leading-normal #let leading-ratio = leading-normal
#let leading-body = size-body * leading-ratio - size-body
#let size-h1 = text-2xl
#let size-caption = text-sm #let size-caption = text-sm
#let space-micro = tw(1) #let space-micro = tw(1)
#let space-block = tw(4)
#let space-section = tw(6)
#let space-chapter = tw(12) #let space-chapter = tw(12)
#let image-max-width = 100% #let image-max-width = 100%
@ -47,7 +29,6 @@
#let code-block-fill = color-block-bg #let code-block-fill = color-block-bg
#let code-block-radius = tw(1.5) #let code-block-radius = tw(1.5)
#let code-inline-radius = tw(0.75) #let code-inline-radius = tw(0.75)
#let code-inline-fill = color-block-bg
// --- 页面边距 --- // --- 页面边距 ---
#let page-margin-a4 = 2.5cm #let page-margin-a4 = 2.5cm

View File

@ -1,16 +1,11 @@
#import "theme.typ": * #import "theme.typ": *
#let toc-unnumbered-bodies = ([摘要], [术语与缩写], [术语与缩略语]) #let toc-unnumbered-bodies = ([摘要],)
#let toc-chapter-counter = counter("toc-chapter")
#let toc-is-unnumbered(body) = {
toc-unnumbered-bodies.contains(body)
}
#let toc-register-chapter-counter() = doc => { #let toc-register-chapter-counter() = doc => {
show heading.where(level: 1): it => { show heading.where(level: 1): it => {
if not toc-is-unnumbered(it.body) { if not toc-unnumbered-bodies.contains(it.body) {
toc-chapter-counter.step() counter("toc-chapter").step()
} }
it it
} }
@ -37,7 +32,7 @@
} }
#let toc-l1-chapter-num(entry) = { #let toc-l1-chapter-num(entry) = {
toc-format-num(toc-chapter-counter.at(entry.element.location()).first()) toc-format-num(counter("toc-chapter").at(entry.element.location()).first())
} }
#let toc-number-cell(skip-number, entry) = { #let toc-number-cell(skip-number, entry) = {

View File

@ -2,64 +2,31 @@
#import "data/theme.typ": * #import "data/theme.typ": *
#import "data/cover.typ": cover-page #import "data/cover.typ": cover-page
#import "data/toc.typ": toc-page, toc-register-chapter-counter #import "data/toc.typ": toc-page, toc-register-chapter-counter
#import "data/metropole-grelin.typ": metropole, start-body-page-numbering #import "data/body.typ": report-body, start-body-page-numbering
#import "data/glossary.typ": init-glossary, register-report-glossary, print-glossary, glossary-entries, gls-long, gls-short
#import "data/diagrams.typ": ore-sorting-flow #import "data/diagrams.typ": ore-sorting-flow
#import "data/code.typ": codly-init-rule, codly-config, code-token-highlight-init #import "data/code.typ": codly-init-rule, codly-config, code-token-highlight-init
#import "data/md.typ": load-report-md #import "data/md.typ": load-report-md, parse-report-date
#show: codly-init-rule #show: codly-init-rule
#show: code-token-highlight-init #show: code-token-highlight-init
#show: init-glossary
#codly-config #codly-config
#register-report-glossary()
#let report = load-report-md( #let report = load-report-md(
read(content-path), read(content-path),
source-path: content-path, source-path: content-path,
extra-scope: ( extra-scope: (
ore-sorting-flow: ore-sorting-flow, ore-sorting-flow: ore-sorting-flow,
gls-long: gls-long,
gls-short: gls-short,
), ),
) )
#let meta = report.metadata #let meta = report.metadata
#let parse-report-date(raw) = {
if type(raw) == datetime {
raw
} else if type(raw) == str {
let parts = raw.split("-")
if parts.len() == 3 {
datetime(
year: int(parts.at(0)),
month: int(parts.at(1)),
day: int(parts.at(2)),
)
} else {
none
}
} else {
none
}
}
#let report-date = parse-report-date(meta.date) #let report-date = parse-report-date(meta.date)
#cover-page(meta, date: report-date) #cover-page(meta, date: report-date)
#show: metropole.with( #show: report-body.with(
title: meta.title, title: meta.title,
subtitle: none,
author: meta.brand, author: meta.brand,
date: report-date, date: report-date,
language: "zh",
paper-size: "a4",
cover-page: false,
inline-title: false,
accent-color: color-primary,
body-text-color: color-body-text,
body-font: body-font, body-font: body-font,
heading-font: heading-font, heading-font: heading-font,
raw-font: mono-font, raw-font: mono-font,
@ -83,7 +50,3 @@
#start-body-page-numbering() #start-body-page-numbering()
#report.body #report.body
#pagebreak(weak: true)
#heading(outlined: false, level: 1)[术语与缩写]
#print-glossary(glossary-entries, show-all: true)

File diff suppressed because it is too large Load Diff