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:
parent
b8b2f5fe14
commit
5c1039c62d
@ -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`。
|
||||||
|
|||||||
@ -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
186
tech-report/data/body.typ
Normal 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
|
||||||
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
|
||||||
}
|
|
||||||
@ -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("/")
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
|
||||||
@ -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),
|
|
||||||
)
|
|
||||||
@ -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
|
||||||
|
|||||||
@ -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) = {
|
||||||
|
|||||||
@ -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
Loading…
Reference in New Issue
Block a user