diff --git a/packages/preview/modern-sysu-thesis/0.4.1/LICENSE b/packages/preview/modern-sysu-thesis/0.4.1/LICENSE
new file mode 100644
index 0000000000..97048655fb
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 SYSU Typst Thesis Template Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/README.md b/packages/preview/modern-sysu-thesis/0.4.1/README.md
new file mode 100644
index 0000000000..216ba7527a
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/README.md
@@ -0,0 +1,86 @@
+# 基于 Typst 的中山大学学位论文模板
+
+[](https://github.com/sysu/better-thesis)
+
+**[点击此处注册 typst.app 并创建你的论文工程](https://typst.app/app?template=modern-sysu-thesis&version=0.4.0)**
+
+本科生模板已经符合学位论文格式要求(~~[#6](https://gitlab.com/sysu-gitlab/thesis-template/better-thesis/-/issues/6)~~),欢迎同学/校友们[贡献代码](https://github.com/sysu/better-thesis/pulls)/反馈问题([GitHub issue][issues])!
+
+模板交流 QQ 群:[797942860](https://jq.qq.com/?_wv=1027&k=m58va1kd)
+
+
+## 参考规范
+- 本科生论文模板参考 [中山大学本科生毕业论文(设计)写作与印制规范 2020年发](https://spa.sysu.edu.cn/zh-hans/article/1744)
+- 研究生论文模板参考 [中山大学研究生学位论文格式要求](https://graduate.sysu.edu.cn/sites/graduate.prod.dpcms4.sysu.edu.cn/files/2019-04/%E4%B8%AD%E5%B1%B1%E5%A4%A7%E5%AD%A6%E7%A0%94%E7%A9%B6%E7%94%9F%E5%AD%A6%E4%BD%8D%E8%AE%BA%E6%96%87%E6%A0%BC%E5%BC%8F%E8%A6%81%E6%B1%82.pdf)
+
+## 使用方法
+
+### typst.app
+经过近一月紧张的迭代重构,本模板已经[发布在typst-app.universe](https://typst.app/universe/package/modern-sysu-thesis)上,[点击此处直接创建你的论文工程](https://typst.app/app?template=modern-sysu-thesis&version=0.4.0),并直接开始编写你的论文!
+
+
+
+### Windows 用户
+
+1. [下载本仓库][download],或者使用 `git clone https://github.com/sysu/better-thesis` 命令克隆本仓库。
+2. 右键 `install_typst.ps1` 文件,选择“用 Powershell 运行”,等待 Typst 安装完成。
+3. 根据 [Typst 文档](https://typst.app/docs/),参考 [项目结构](#项目结构) 中的说明,按照你的需要修改论文的各个部分。
+4. 双击运行 `compile.bat`,即可生成 `thesis.pdf` 文件。
+
+### Linux/macOS 用户
+
+1. [下载本仓库][download],或者使用 `git clone https://github.com/sysu/better-thesis` 命令克隆本仓库。
+2. 使用命令行安装 Rust 工具链以及 Typst:
+
+```bash
+# 安装 Rust 环境并激活,之前安装过则不需要执行下面这两行
+curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
+source $HOME/.cargo/env
+
+# 安装 Typst CLI
+cargo install typst-cli
+
+# 访问缓慢的话,执行以下命令设置清华镜像源,并从镜像站安装
+cat << EOF > $HOME/.cargo/config
+[source.crates-io]
+replace-with = "tuna"
+
+[source.tuna]
+registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
+EOF
+cargo install typst-cli
+```
+
+3. 根据 [Typst 文档](https://typst.app/docs/),参考 [项目结构](#项目结构) 中的说明,按照你的需要修改论文的各个部分。
+4. 执行 `make` 命令,即可生成 `thesis.pdf` 文件。
+
+## 项目结构
+详见 `template\thesis.typ`
+
+## FAQ
+### 为什么 XXX 的功能不能用/不符合预期?
+1. 先参考 [Typst 中文支持相关问题](https://typst-doc-cn.github.io/docs/chinese/),以及 [Typst 官方文档](https://typst.app/docs/) 与 [tpyst.app/universe 仓库](https://typst.app/universe),了解相关问题进展或解决方案
+2. 如果在以上资料中找不到关联资料,可以参考是否在的 [issue 列表][issues] 中能找到相关问题与进展。
+3. 如果依然没有线索,欢迎反馈问题([GitHub issue][issues])
+
+### 为什么学校学位论文已经有了 [LaTeX 模板](https://github.com/SYSU-SCC/sysu-thesis),还有 Typst 模板?
+- 前述 LaTeX 模板目前仅有计算机学院官方指定使用,其他学院并没有统一指定
+- 考虑到 LaTeX 对于大部分非计算机/理工科的学生入门成本比较高,因此有必要提供一种更加简洁清晰并且方便的论文模板,包括:
+ - 开箱即用:
+ - 如[前文所述](#typstapp),本模板提供了在线直接编辑/保存/备份方案
+ - 本地使用模板时,模板组件可以简单地通过 `typst` 命令自动管理安装
+ - 语法简洁:typst 是与 markdown 类似的标记性语言,可以通过标记的方式来轻松控制语法(如`= 标题`、`*粗体*`、`_斜体_` `@引用`、 数学公式`$E = m c^2$`)
+
+### 为什么有两份 Typst 模板([sysu-thesis-typst] 和 modern-sysu-thesis)?
+后者是在前者的基础上,同时参考 [modern-nju-thesis] ,改造后适配了 [typst.app/universe](https://typst.app/universe)。以及,放到 [@sysu](https://github.com/sysu) 组织下提高了曝光度。
+
+## 致谢
+- 感谢 [sysu-thesis-typst] 提供了中山大学的页面样式与初版源码
+- 感谢 [modern-nju-thesis] 提供了一个更好的代码组织架构
+- 感谢中山大学 Typst 模板交流群([797942860](https://jq.qq.com/?_wv=1027&k=m58va1kd))、Typst 中文交流群(793548390)群友的帮助交流。
+- 感谢 @debeetle 完善了硕博士论文模板([#26](https://github.com/sysu/better-thesis/pull/26))
+
+[issues]: https://github.com/sysu/better-thesis/issues
+[download]: https://github.com/sysu/better-thesis
+[sysu-thesis-typst]: https://github.com/howardlau1999/sysu-thesis-typst
+[modern-nju-thesis]: https://typst.app/universe/package/modern-nju-thesis
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/assets/vi/sysu_logo.svg b/packages/preview/modern-sysu-thesis/0.4.1/assets/vi/sysu_logo.svg
new file mode 100644
index 0000000000..1c14f8ec98
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/assets/vi/sysu_logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/assets/vi/sysu_name.gif b/packages/preview/modern-sysu-thesis/0.4.1/assets/vi/sysu_name.gif
new file mode 100644
index 0000000000..582b100f36
Binary files /dev/null and b/packages/preview/modern-sysu-thesis/0.4.1/assets/vi/sysu_name.gif differ
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/layouts/appendix.typ b/packages/preview/modern-sysu-thesis/0.4.1/layouts/appendix.typ
new file mode 100644
index 0000000000..ee33f6086b
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/layouts/appendix.typ
@@ -0,0 +1,24 @@
+#import "@preview/i-figured:0.2.4"
+#import "../utils/custom-numbering.typ": custom-numbering
+
+// 后记,重置 heading 计数器
+#let appendix(
+ numbering: custom-numbering.with(first-level: "", depth: 4, "1.1 "),
+ // figure 计数
+ show-figure: i-figured.show-figure.with(numbering: "1.1"),
+ // equation 计数
+ show-equation: i-figured.show-equation.with(numbering: "(1.1)"),
+ // 重置计数
+ reset-counter: false,
+ it,
+) = {
+ set heading(numbering: numbering)
+ if reset-counter {
+ counter(heading).update(0)
+ }
+ // 设置 figure 的编号
+ show figure: show-figure
+ // 设置 equation 的编号
+ show math.equation.where(block: true): show-equation
+ it
+}
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/layouts/doc.typ b/packages/preview/modern-sysu-thesis/0.4.1/layouts/doc.typ
new file mode 100644
index 0000000000..011cf8de05
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/layouts/doc.typ
@@ -0,0 +1,34 @@
+// 文稿设置,可以进行一些像页面边距这类的全局设置
+#let doc(
+ // documentclass 传入参数
+ info: (:),
+ // 其他参数
+ fallback: false, // 字体缺失时使用 fallback,不显示豆腐块
+ lang: "zh",
+ margin: (x: 89pt),
+ it,
+) = {
+ // 1. 默认参数
+ info = (
+ title: ("基于 Typst 的", "中山大学学位论文模板"),
+ author: "张三",
+ ) + info
+
+ // 2. 对参数进行处理
+ // 2.1 如果是字符串,则使用换行符将标题分隔为列表
+ if type(info.title) == str {
+ info.title = info.title.split("\n")
+ }
+
+ // 3. 基本的样式设置
+ set text(fallback: fallback, lang: lang)
+ set page(margin: margin)
+
+ // 4. PDF 元信息
+ set document(
+ title: (("",)+ info.title).sum(),
+ author: info.author,
+ )
+
+ it
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/layouts/mainmatter.typ b/packages/preview/modern-sysu-thesis/0.4.1/layouts/mainmatter.typ
new file mode 100644
index 0000000000..b1454bb910
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/layouts/mainmatter.typ
@@ -0,0 +1,173 @@
+#import "@preview/anti-matter:0.0.2": anti-front-end
+#import "@preview/i-figured:0.2.4"
+#import "../utils/style.typ": 字号, 字体
+#import "../utils/custom-numbering.typ": custom-numbering
+#import "../utils/custom-heading.typ": heading-display, active-heading, current-heading
+#import "../utils/unpairs.typ": unpairs
+
+#let mainmatter(
+ // documentclass 传入参数
+ twoside: false,
+ fonts: (:),
+ // 其他参数
+ leading: 1.5 * 15.6pt - 0.7em,
+ spacing: 1.5 * 15.6pt - 0.7em,
+ justify: true,
+ first-line-indent: (amount: 2em, all: true),
+ numbering: custom-numbering.with(first-level: "第一章 ", depth: 4, "1.1 "),
+ // 正文字体与字号参数
+ text-args: auto,
+ // 标题字体与字号
+ heading-font: (字体.黑体, 字体.黑体, 字体.宋体),
+ heading-size: (字号.三号, 字号.四号, 字号.小四),
+ heading-weight: ("regular", "regular", "bold"),
+ heading-above: (2 * 15.6pt - 0.7em, 2 * 15.6pt - 0.7em),
+ heading-below: (2 * 15.6pt - 0.7em, 1.5 * 15.6pt - 0.7em),
+ heading-pagebreak: (true, false),
+ heading-align: (center, left, auto),
+ // 页眉
+ header-render: auto,
+ header-vspace: 0em,
+ display-header: false,
+ skip-on-first-level: true,
+ stroke-width: 0.5pt,
+ reset-footnote: true,
+ // caption 的 separator
+ separator: " ",
+ // caption 样式
+ caption-style: strong,
+ caption-size: 字号.五号,
+ // figure 计数
+ show-figure: i-figured.show-figure,
+ // equation 计数
+ show-equation: i-figured.show-equation,
+ ..args,
+ it,
+) = {
+ // 0. 标志前言结束
+ anti-front-end()
+
+ // 1. 默认参数
+ fonts = 字体 + fonts
+ if (text-args == auto) {
+ text-args = (font: fonts.宋体, size: 字号.小四)
+ }
+ // 1.1 字体与字号
+ if (heading-font == auto) {
+ heading-font = (fonts.黑体,)
+ }
+ // 1.2 处理 heading- 开头的其他参数
+ let heading-text-args-lists = args.named().pairs()
+ .filter((pair) => pair.at(0).starts-with("heading-"))
+ .map((pair) => (pair.at(0).slice("heading-".len()), pair.at(1)))
+
+ // 2. 辅助函数
+ let array-at(arr, pos) = {
+ arr.at(calc.min(pos, arr.len()) - 1)
+ }
+
+ // 3. 设置基本样式
+ // 3.1 文本和段落样式
+ set text(..text-args)
+ set par(
+ leading: leading,
+ justify: justify,
+ first-line-indent: first-line-indent
+ )
+ show par: set block(spacing: spacing)
+ // 3.2 脚注样式
+ show footnote.entry: set text(font: fonts.宋体, size: 字号.五号)
+ // 3.3 设置 figure 的编号
+ show heading: i-figured.reset-counters
+ show figure: show-figure
+ // 3.4 设置 equation 的编号和假段落首行缩进
+ show math.equation.where(block: true): show-equation
+ // 3.5 表格表头置顶 + 不用冒号用空格分割 + 样式
+ show figure.where(
+ kind: table
+ ): set figure.caption(position: top)
+ set figure.caption(separator: separator)
+ show figure.caption: caption-style
+ show figure.caption: set text(font: fonts.宋体, size: 字号.五号)
+ // 3.6 优化列表显示
+ // 术语列表 terms 不应该缩进
+ show terms: set par(first-line-indent: 0pt)
+
+ // 4. 处理标题
+ // 4.1 设置标题的 Numbering
+ set heading(numbering: numbering)
+ // 4.2 设置字体字号并加入假段落模拟首行缩进
+ show heading: it => {
+ set text(
+ font: array-at(heading-font, it.level),
+ size: array-at(heading-size, it.level),
+ weight: array-at(heading-weight, it.level),
+ ..unpairs(heading-text-args-lists
+ .map((pair) => (pair.at(0), array-at(pair.at(1), it.level))))
+ )
+ set block(
+ above: array-at(heading-above, it.level),
+ below: array-at(heading-below, it.level),
+ )
+ it
+ }
+ // 4.3 标题居中与自动换页
+ show heading: it => {
+ if (array-at(heading-pagebreak, it.level)) {
+ // 如果打上了 no-auto-pagebreak 标签,则不自动换页
+ if ("label" not in it.fields() or str(it.label) != "no-auto-pagebreak") {
+ pagebreak(weak: true)
+ }
+ }
+ if (array-at(heading-align, it.level) != auto) {
+ set align(array-at(heading-align, it.level))
+ it
+ } else {
+ pad(left: 2em, it)
+ }
+ }
+
+ // 5. 处理页眉
+ set page(..(if display-header {
+ (
+ header: {
+ // 重置 footnote 计数器
+ if reset-footnote {
+ counter(footnote).update(0)
+ }
+ locate(loc => {
+ // 5.1 获取当前页面的一级标题
+ let cur-heading = current-heading(level: 1, loc)
+ // 5.2 如果当前页面没有一级标题,则渲染页眉
+ if not skip-on-first-level or cur-heading == none {
+ if header-render == auto {
+ // 一级标题和二级标题
+ let first-level-heading = if not twoside or calc.rem(loc.page(), 2) == 0 { heading-display(active-heading(level: 1, loc)) } else { "" }
+ let second-level-heading = if not twoside or calc.rem(loc.page(), 2) == 2 { heading-display(active-heading(level: 2, prev: false, loc)) } else { "" }
+ set text(font: fonts.宋体, size: 字号.五号)
+ stack(
+ first-level-heading + h(1fr) + second-level-heading,
+ v(0.25em),
+ if first-level-heading != "" or second-level-heading != "" { line(length: 100%, stroke: stroke-width + black) },
+ )
+ } else {
+ header-render(loc)
+ }
+ v(header-vspace)
+ }
+ })
+ }
+ )
+ } else {
+ (
+ header: {
+ // 重置 footnote 计数器
+ if reset-footnote {
+ counter(footnote).update(0)
+ }
+ }
+ )
+ }))
+
+ it
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/layouts/preface.typ b/packages/preview/modern-sysu-thesis/0.4.1/layouts/preface.typ
new file mode 100644
index 0000000000..974855e546
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/layouts/preface.typ
@@ -0,0 +1,18 @@
+#import "@preview/anti-matter:0.0.2": anti-matter
+
+// 前言,重置页面计数器
+#let preface(
+ // documentclass 传入的参数
+ twoside: false,
+ // 其他参数
+ spec: (front: "I", inner: "1", back: "I"),
+ ..args,
+ it,
+) = {
+ // 分页
+ if (twoside) {
+ pagebreak() + " "
+ }
+ counter(page).update(0)
+ anti-matter(spec: spec, ..args, it)
+}
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/lib.typ b/packages/preview/modern-sysu-thesis/0.4.1/lib.typ
new file mode 100644
index 0000000000..10f593bc76
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/lib.typ
@@ -0,0 +1,7 @@
+// 中山大学学位论文 Typst 模板 modern-sysu-thesis
+// 基于 [南京大学学位论文模板](https://github.com/nju-lug/modern-nju-thesis) 重构中
+// Repo: https://gitlab.com/sysu-gitlab/thesis-template/better-thesis
+// https://typst.app/universe/package/modern-sysu-thesis
+
+#import "/specifications/bachelor/lib.typ" as bachelor
+#import "/specifications/postgraduate/lib.typ" as postgraduate
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/pages/fonts-display-page.typ b/packages/preview/modern-sysu-thesis/0.4.1/pages/fonts-display-page.typ
new file mode 100644
index 0000000000..5b53249f07
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/pages/fonts-display-page.typ
@@ -0,0 +1,54 @@
+#import "../utils/style.typ": 字号, 字体
+#import "../utils/hline.typ": hline
+
+// 字体显示测试页
+#let fonts-display-page(
+ twoside: false,
+ fonts: (:),
+ size: 字号.小四,
+ lang: "zh",
+) = {
+ // 1. 默认参数
+ fonts = 字体 + fonts
+
+ // 2. 辅助函数
+ let display-font(cjk-name, latin-name) = [
+ #set text(font: fonts.at(cjk-name))
+
+ #cjk-name (#latin-name CJK Regular): 落霞与孤鹜齐飞,秋水共长天一色。
+
+ #cjk-name (#latin-name Latin Regular): The fanfare of birds announces the morning.
+
+ *#cjk-name (#latin-name CJK Bold): 落霞与孤鹜齐飞,秋水共长天一色。*
+
+ *#cjk-name (#latin-name Latin Bold): The fanfare of birds announces the morning.*
+ ]
+
+ // 3. 正式渲染
+ pagebreak(weak: true, to: if twoside { "odd" })
+ set text(size: size, lang: lang)
+
+ [
+ *Fonts Display Page:*
+
+ #hline()
+
+ #display-font("宋体", "SongTi")
+
+ #hline()
+
+ #display-font("黑体", "HeiTi")
+
+ #hline()
+
+ #display-font("楷体", "KaiTi")
+
+ #hline()
+
+ #display-font("仿宋", "FangSong")
+
+ #hline()
+
+ #display-font("等宽", "Mono")
+ ]
+}
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/pages/list-of-figures.typ b/packages/preview/modern-sysu-thesis/0.4.1/pages/list-of-figures.typ
new file mode 100644
index 0000000000..2eb17cc42b
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/pages/list-of-figures.typ
@@ -0,0 +1,74 @@
+#import "@preview/i-figured:0.2.4"
+#import "@preview/outrageous:0.1.0"
+#import "../utils/invisible-heading.typ": invisible-heading
+#import "../utils/style.typ": 字号, 字体
+
+// 表格目录生成
+#let list-of-figures(
+ // documentclass 传入参数
+ twoside: false,
+ fonts: (:),
+ // 其他参数
+ title: "插图目录",
+ outlined: false,
+ title-vspace: 32pt,
+ title-text-args: auto,
+ // caption 的 separator
+ separator: " ",
+ // 字体与字号
+ font: auto,
+ size: 字号.小四,
+ // 垂直间距
+ vspace: 14pt,
+ // 是否显示点号
+ fill: auto,
+ ..args,
+) = {
+ // 1. 默认参数
+ fonts = 字体 + fonts
+ if (title-text-args == auto) {
+ title-text-args = (font: fonts.黑体, size: 字号.三号, weight: "bold")
+ }
+ // 字体与字号
+ if (font == auto) {
+ font = fonts.宋体
+ }
+
+ // 2. 正式渲染
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ // 默认显示的字体
+ set text(font: font, size: size)
+
+ {
+ set align(center)
+ text(..title-text-args, title)
+ // 标记一个不可见的标题用于目录生成
+ invisible-heading(level: 1, outlined: outlined, title)
+ }
+
+ v(title-vspace)
+
+ show outline.entry: outrageous.show-entry.with(
+ // 保留 Typst 基础样式
+ ..outrageous.presets.typst,
+ body-transform: (level, it) => {
+ // 因为好像没找到 separator 的参数,所以这里就手动寻找替换了
+ if (it.has("children") and it.children.at(3, default: none) == [#": "]) {
+ it.children.slice(0, 3).sum() + separator + it.children.slice(4).sum()
+ } else {
+ it
+ }
+ },
+ vspace: (vspace,),
+ fill: (fill,),
+ )
+
+ // 显示目录
+ i-figured.outline(target-kind: image, title: none)
+
+ // 手动分页
+ if (twoside) {
+ pagebreak() + " "
+ }
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/pages/list-of-tables.typ b/packages/preview/modern-sysu-thesis/0.4.1/pages/list-of-tables.typ
new file mode 100644
index 0000000000..949e47f2e9
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/pages/list-of-tables.typ
@@ -0,0 +1,74 @@
+#import "@preview/i-figured:0.1.0"
+#import "@preview/outrageous:0.1.0"
+#import "../utils/invisible-heading.typ": invisible-heading
+#import "../utils/style.typ": 字号, 字体
+
+// 表格目录生成
+#let list-of-tables(
+ // documentclass 传入参数
+ twoside: false,
+ fonts: (:),
+ // 其他参数
+ title: "表格目录",
+ outlined: false,
+ title-vspace: 32pt,
+ title-text-args: auto,
+ // caption 的 separator
+ separator: " ",
+ // 字体与字号
+ font: auto,
+ size: 字号.小四,
+ // 垂直间距
+ vspace: 14pt,
+ // 是否显示点号
+ fill: auto,
+ ..args,
+) = {
+ // 1. 默认参数
+ fonts = 字体 + fonts
+ if (title-text-args == auto) {
+ title-text-args = (font: fonts.黑体, size: 字号.三号, weight: "bold")
+ }
+ // 字体与字号
+ if (font == auto) {
+ font = fonts.宋体
+ }
+
+ // 2. 正式渲染
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ // 默认显示的字体
+ set text(font: font, size: size)
+
+ {
+ set align(center)
+ text(..title-text-args, title)
+ // 标记一个不可见的标题用于目录生成
+ invisible-heading(level: 1, outlined: outlined, title)
+ }
+
+ v(title-vspace)
+
+ show outline.entry: outrageous.show-entry.with(
+ // 保留 Typst 基础样式
+ ..outrageous.presets.typst,
+ body-transform: (level, it) => {
+ // 因为好像没找到 separator 的参数,所以这里就手动寻找替换了
+ if (it.has("children") and it.children.at(3, default: none) == [#": "]) {
+ it.children.slice(0, 3).sum() + separator + it.children.slice(4).sum()
+ } else {
+ it
+ }
+ },
+ vspace: (vspace,),
+ fill: (fill,),
+ )
+
+ // 显示目录
+ i-figured.outline(target-kind: table, title: none)
+
+ // 手动分页
+ if (twoside) {
+ pagebreak() + " "
+ }
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/pages/notation.typ b/packages/preview/modern-sysu-thesis/0.4.1/pages/notation.typ
new file mode 100644
index 0000000000..2b8ac40b28
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/pages/notation.typ
@@ -0,0 +1,35 @@
+#let notation(
+ twoside: false,
+ title: "符号表",
+ outlined: true,
+ width: 350pt,
+ columns: (60pt, 1fr),
+ row-gutter: 16pt,
+ ..args,
+ body,
+) = {
+ heading(
+ level: 1,
+ numbering: none,
+ outlined: outlined,
+ title
+ )
+
+ align(center, block(width: width,
+ align(start, grid(
+ columns: columns,
+ row-gutter: row-gutter,
+ ..args,
+ // 解析 terms 内部结构以渲染到表格里
+ ..body.children
+ .filter(it => it.func() == terms.item)
+ .map(it => (it.term, it.description))
+ .flatten()
+ ))
+ ))
+
+ // 手动分页
+ if (twoside) {
+ pagebreak() + " "
+ }
+}
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/abstract-en.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/abstract-en.typ
new file mode 100644
index 0000000000..93af98cf6c
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/abstract-en.typ
@@ -0,0 +1,44 @@
+// 利用 state 捕获摘要参数,并通过 context 传递给渲染函数
+#import "/utils/style.typ": 字号, 字体
+
+#let abstract-en-keywords = state("keywords-en", (
+ "Sun Yat-sen University",
+ "thesis",
+ "specification",
+))
+#let abstract-en-content = state("abstract-en", [
+英文摘要及关键词内容应与中文摘要及关键词内容相同。中英文摘要及其关键词各置一页内。
+The English abstract and its keywords should be the same as the Chinese one.
+Both Chinese and English should be in seperated pages.
+])
+#let abstract-en(
+ keywords: (),
+ body,
+) = {
+ context abstract-en-keywords.update(keywords)
+ context abstract-en-content.update(body)
+}
+
+// 英文摘要页
+#let abstract-en-page() = {
+ // 英文摘要内容 Times New Roman小四号
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ // 英文摘要标题 Times New Roman加粗三号全部大写
+ show heading.where(level: 1): set text(font: 字体.宋体, size: 字号.三号, weight: "bold")
+
+ // 摘要标题不编号
+ show heading.where(level: 1): set heading(numbering: none)
+
+ [
+ = ABSTRACT
+
+ #context abstract-en-content.final()
+
+ #v(1em)
+
+ // 摘要正文下方另起一行顶格打印“关键词”款项,后加冒号,多个关键词以逗号分隔。
+ // (标题“Keywords”加粗)
+ *Keywords:* #context abstract-en-keywords.final().join(", ")
+ ]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/abstract.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/abstract.typ
new file mode 100644
index 0000000000..c2caaad3a7
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/abstract.typ
@@ -0,0 +1,45 @@
+// 利用 state 捕获摘要参数,并通过 context 传递给渲染函数
+#import "/utils/style.typ": 字号, 字体
+
+#let abstract-keywords = state("keywords", ("中山大学", "论文", "学位论文", "规范"))
+#let abstract-content = state("abstract", [
+摘要应概括论文的主要信息,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。
+摘要内容一般应包括研究目的、内容、方法、成果和结论,要突出论文的创造性成果或新见解,不要
+与绪论相混淆。语言力求精练、准确,以300-500字为宜。关键词是供检索用的主题词条,应体现论
+文特色,具有语义性,在论文中有明确的出处,并应尽量采用《汉语主题词表》或各专业主题词表提
+供的规范词。关键词与摘要应在同一页,在摘要的下方另起一行注明,一般列3-5个,按词条的外延
+层次排列(外延大的排在前面)。
+])
+#let abstract(
+ keywords: (),
+ body,
+) = {
+ context abstract-keywords.update(keywords)
+ context abstract-content.update(body)
+}
+
+// 中文摘要页
+#let abstract-page() = {
+ // 中文摘要内容 宋体小四号
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ // 中文摘要标题 黑体三号居中
+ show heading.where(level: 1): set text(font: 字体.黑体, size: 字号.三号)
+
+ // 摘要标题不编号
+ show heading.where(level: 1): set heading(numbering: none)
+
+ [
+ = 摘要
+
+ #set par(first-line-indent: (amount: 2em, all: true))
+ #context abstract-content.final()
+
+ #v(1em)
+
+ // 摘要正文下方另起一行顶格打印“关键词”款项,后加冒号,多个关键词以逗号分隔。
+ // (标题“关键词”加粗)
+ #set par(first-line-indent: 0em)
+ *关键词:*#context abstract-keywords.final().join(",")
+ ]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/acknowledgement.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/acknowledgement.typ
new file mode 100644
index 0000000000..0c67716d22
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/acknowledgement.typ
@@ -0,0 +1,36 @@
+// 利用 state 捕获摘要参数,并通过 context 传递给渲染函数
+#import "/utils/style.typ": 字号, 字体
+
+// 致谢内容
+#let acknowledgement-content = state("acknowledgement", [
+致谢应以简短的文字对课题研究与论文撰写过程中曾直接给予帮助的人员(例如指导教师、答疑教师
+及其他人员)表达自己的谢意,这不仅是一种礼貌,也是对他人劳动的尊重,是治学者应当遵循的学
+术规范。内容限一页。
+])
+
+#let acknowledgement(
+ body
+) = {
+ context acknowledgement-content.update(body)
+}
+
+#let acknowledgement-page() = {
+ // 致谢、附录内容 宋体小四号
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ // 致谢、附录标题 黑体三号居中
+ show heading.where(level: 1): set text(font: 字体.黑体, size: 字号.三号)
+
+ // 致谢标题不编号
+ show heading.where(level: 1): set heading(numbering: none)
+
+ [
+ = 致谢
+
+ #set par(first-line-indent: (amount: 2em, all: true))
+ #context acknowledgement-content.final()
+
+ #v(1em)
+
+ ]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/appendix.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/appendix.typ
new file mode 100644
index 0000000000..9c0ec0786a
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/appendix.typ
@@ -0,0 +1,42 @@
+// 利用 state 捕获摘要参数,并通过 context 传递给渲染函数
+#import "/utils/style.typ": 字号, 字体
+
+#import "@preview/i-figured:0.2.4"
+
+#let appendix-content = state("appendix", [
+= 附录要求
+对于一些不宜放在正文中的重要支撑材料,可编入毕业论文的附录中,包括某些重要的原始数据、详细数学推导、程序全文及其说明、复杂的图表、设计图纸等一系列需要补充提供的说明材料。如果毕业论文中引用的实例、数据资料,实验结果等符号较多时,为了节约篇幅,便于读者查阅,可以编写一个符号说明,注明符号代表的意义。附录的篇幅不宜太多,一般不超过正文。此项不是必需项,空缺时可以省略。
+])
+
+#let appendix(
+ body
+) = {
+ context appendix-content.update(body)
+}
+
+#let appendix-part() = {
+ // 致谢、附录内容 宋体小四号
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ // 附录标题中不需要分隔中英文
+ show heading: set text(cjk-latin-spacing: none)
+
+ // 致谢、附录标题 黑体三号居中
+ show heading.where(level: 1): set text(font: 字体.黑体, size: 字号.三号)
+
+ // 目录仅展示附录章标题
+ // 论文附录依次用大写字母“附录A、附录B、附录C……”表示,附录内的分级序号可采用“附A1、
+ // 附A1.1、附A1.1.1”等表示,图、表、公式均依此类推为“图A1、表A1、式A1”等。
+ show heading.where(level: 1): set heading(numbering: "附录A", outlined: true)
+ show heading.where(level: 2): set heading(numbering: "附A1", outlined: false)
+ show heading.where(level: 3): set heading(numbering: "附A1.1", outlined: false)
+ show heading.where(level: 4): set heading(numbering: "附A1.1.1", outlined: false)
+
+ show figure: i-figured.show-figure.with(numbering: "A.1")
+ show math.equation: i-figured.show-equation.with(numbering: "(A.1)")
+
+ // 重置 heading 计数
+ counter(heading).update(0)
+
+ context appendix-content.final()
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/cover.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/cover.typ
new file mode 100644
index 0000000000..dea4c9cd5f
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/cover.typ
@@ -0,0 +1,146 @@
+#import "/utils/datetime-display.typ": datetime-display
+#import "/utils/style.typ": 字号, 字体, sysucolor
+
+// 封面
+#let cover(
+ info: (:),
+
+ // 其他参数
+ stoke-width: 0.5pt,
+ min-title-lines: 2,
+ info-inset: (x: 0pt, bottom: 1pt),
+ info-key-width: 72pt,
+ info-key-font: "黑体",
+ info-value-font: "宋体",
+ column-gutter: -3pt,
+ row-gutter: 11.5pt,
+ bold-info-keys: ("title",),
+ bold-level: "bold",
+) = {
+
+ assert(type(info.title) == array)
+ assert(type(info.author) == dictionary)
+
+ info.title = info.title + range(min-title-lines - info.title.len()).map((it) => " ")
+ if type(info.submit-date) == datetime {
+ info.submit-date = datetime-display(info.submit-date)
+ }
+
+ // 内置辅助函数
+ let info-key(
+ font: 字体.at(info-key-font, default: "黑体"),
+ size: 字号.小三,
+ body,
+ ) = {
+ rect(
+ width: 100%,
+ inset: info-inset,
+ stroke: none,
+ text(
+ font: font,
+ size: size,
+ body,
+ ),
+ )
+ }
+
+ let info-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.小三,
+ key,
+ body,
+ ) = {
+ set align(center)
+ rect(
+ width: 100%,
+ inset: info-inset,
+ stroke: (bottom: stoke-width + black),
+ text(
+ font: font,
+ size: size,
+ weight: if (key in bold-info-keys) { bold-level } else { "regular" },
+ bottom-edge: "descender",
+ body,
+ ),
+ )
+ }
+
+ let info-long-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.小三,
+ key,
+ body,
+ ) = {
+ grid.cell(colspan: 3,
+ info-value(
+ font: font,
+ size: size,
+ key,
+ body,
+ )
+ )
+ }
+
+ let info-short-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.小三,
+ key,
+ body
+ ) = {
+ info-value(
+ font: font,
+ size: size,
+ key,
+ body,
+ )
+ }
+
+ // 正式渲染
+ // 居中对齐
+ set align(center)
+
+ // 封面校徽
+ // 使用校方官方 VI 系统的 logo,来源:https://home3.sysu.edu.cn/sysuvi/index.html
+ image("/assets/vi/sysu_logo.svg", width: 3cm)
+
+ text(size: 字号.小初, font: 字体.宋体, weight: "bold", fill: sysucolor.green)[本科生毕业论文(设计)]
+ v(-2em)
+ line(length: 200%, stroke: 0.12cm + sysucolor.green);
+ v(-0.8em)
+ line(length: 200%, stroke: 0.05cm + sysucolor.green);
+ v(1.5cm)
+
+ // 论文题目
+ h(0.7cm)
+ block(width: 100%, grid(
+ columns: (25%, 1fr, 75%, 1fr),
+ column-gutter: column-gutter,
+ row-gutter: row-gutter,
+ info-key(size: 字号.二号, "题目:"),
+ ..info.title.map((s) =>
+ info-long-value(size: 字号.二号, font: 字体.黑体, "title", s)
+ ).intersperse(info-key(size: 字号.二号, " ")),
+ ))
+ v(2.7cm)
+
+ // 学生与指导老师信息
+ set align(center + bottom)
+ block(width: 75%, grid(
+ columns: (info-key-width, 1fr, info-key-width, 1fr),
+ column-gutter: column-gutter,
+ row-gutter: row-gutter,
+ info-key("姓 名"),
+ info-long-value("author", info.author.name),
+ info-key("学 号"),
+ info-long-value("student-id", info.author.sno),
+ info-key("院 系"),
+ info-long-value("department", info.author.department),
+ info-key("专 业"),
+ info-long-value("major", info.author.major),
+ info-key("指导教师"),
+ info-long-value("supervisor", info.supervisor.join(" ")),
+ ))
+ v(2em)
+
+ text(font: 字体.黑体, size: 字号.小四)[#info.submit-date]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/declaration.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/declaration.typ
new file mode 100644
index 0000000000..50b33f5639
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/declaration.typ
@@ -0,0 +1,25 @@
+#import "/utils/style.typ": 字号, 字体
+
+// 学术声明页
+// 参照 [中山大学本科生毕业论文(设计)写作与印制规范 2020年发](https://spa.sysu.edu.cn/zh-hans/article/1744) 电子档的示例设置格式
+#let declaration() = {
+ align(center, text(font: 字体.黑体, size: 字号.三号)[学术诚信声明])
+
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ par(justify: true, first-line-indent: 2em)[
+ 本人郑重声明:所呈交的毕业论文(设计),是本人在导师的指导下,独立进行研究工作所取得的成果。除文中已经注明引用的内容外,本论文(设计)不包含任何其他个人或集体已经发表或撰写过的作品成果。对本论文(设计)的研究做出重要贡献的个人和集体,均已在文中以明确方式标明。本论文(设计)的知识产权归属于培养单位。本人完全意识到本声明的法律结果由本人承担。
+ ]
+ v(2em)
+
+ align(right + top,
+ box(
+ grid(
+ columns: (auto, auto),
+ gutter: 2em,
+ "作者签名:", "",
+ "日" + h(2em) + "期:", h(2.5em) + text("年") + h(2em) + text("月") + h(2em) + text("日")
+ )
+ )
+ )
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/lib.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/lib.typ
new file mode 100644
index 0000000000..15aced60c9
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/lib.typ
@@ -0,0 +1,282 @@
+#import "/specifications/bachelor/cover.typ": cover
+#import "/specifications/bachelor/titlepage.typ": titlepage
+#import "/specifications/bachelor/declaration.typ": declaration
+#import "/specifications/bachelor/abstract.typ": abstract, abstract-page
+#import "/specifications/bachelor/abstract-en.typ": abstract-en, abstract-en-page
+#import "/specifications/bachelor/appendix.typ": appendix, appendix-part
+#import "/specifications/bachelor/acknowledgement.typ": acknowledgement, acknowledgement-page
+
+#import "/utils/bilingual-bibliography.typ": bilingual-bibliography
+#import "/utils/custom-heading.typ": active-heading, heading-display, current-heading
+#import "/utils/style.typ": 字号, 字体, sysucolor
+
+#import "@preview/numbly:0.1.0": numbly
+#import "@preview/numblex:0.1.1": circle_numbers
+#import "@preview/i-figured:0.2.4"
+
+// 中山大学本科生毕业论文(设计)写作与印制规范
+// 参考规范: https://spa.sysu.edu.cn/zh-hans/article/1744
+#let doc(
+ // 毕业论文基本信息
+ thesis-info: (
+ // 论文标题,将展示在封面、扉页与页眉上
+ // 多行标题请使用数组传入 `("thesis title", "with part next line")`,或使用换行符:`"thesis title\nwith part next line"`
+ title: ("中山大学本科生毕业论文(设计)", "写作与印制规范(2020-)"),
+ title-en: ("The Specification of Writting and Printing", "for SYSU thesis"),
+
+ // 论文作者信息:学号、姓名、院系、专业、指导老师
+ author: (
+ sno: "1xxxxxxx",
+ name: "张三",
+ grade: "2024",
+ department: "某学院",
+ major: "某专业",
+ ),
+
+ // 指导老师信息,以`("name", "title")` 数组方式传入
+ supervisor: ("李四", "教授"),
+
+ // 提交日期,默认为论文 PDF 生成日期
+ submit-date: datetime.today(),
+ ),
+
+ // 参考文献来源
+ bibliography: none,
+
+ // 控制页面是否渲染
+ pages: (
+ // 封面可能由学院统一打印提供,因此可以不渲染
+ cover: true,
+
+ // 附录部分为可选。设置为 true 后,会在参考文献部分与致谢部分之间插入附录部分。
+ appendix: false,
+ ),
+
+ // 论文内文各大部分的标题用“一、二…… (或1、2……)”, 次级标题为“(一)、(二)……(或
+ // 1.1、2.1……)”,三级标题用“1、2……(或1.1.1、2.1.1……)”,四级标题用“(1)、(2)……
+ //(或1.1.1.1、2.1.1.1……)”,不再使用五级以下标题。两类标题不要混编。
+ numbering: none,
+
+ // 双面模式,会加入空白页,便于打印
+ twoside: false,
+
+ // 论文正文信息,包括绪论、主体、结论
+ content
+) = {
+ // 论文信息参数处理。要求必须传递,且符合规格的参数
+ assert(type(thesis-info) == dictionary)
+ assert(type(thesis-info.title) == array or type(thesis-info.title) == str)
+ assert(type(thesis-info.title-en) == array
+ or type(thesis-info.title-en) == str
+ )
+ // 论文信息默认参数。函数传入参数会完全覆盖参数值,因此需要提供默认参数补充。
+ // 彩蛋:如果论文参数不传递作者参数,那么论文就会被署名论文模板作者
+ let default-author = (
+ sno: "13xxxx87",
+ name: "Sunny Huang",
+ grade: "2013",
+ department: "数据科学与计算机学院",
+ major: "软件工程",
+ )
+ thesis-info.author = thesis-info.at("author", default: default-author)
+
+ let default-thesis-info = (
+ title: ("中山大学本科生毕业论文(设计)", "写作与印制规范"),
+ title-en: ("The Specification of Writting and Printing", "for SYSU thesis"),
+ supervisor: ("李四", "教授"),
+ submit-date: datetime.today(),
+ )
+ thesis-info = default-thesis-info + thesis-info
+
+ // 论文渲染控制参数处理。设置可选页面的默认设置项
+ let default-pages = (
+ cover: true,
+ appendix: false,
+ )
+ pages = default-pages + pages
+
+ // 文档元数据处理
+ if type(thesis-info.title) == str {
+ thesis-info.title = thesis-info.title.split("\n")
+ }
+ if type(thesis-info.title-en) == str {
+ thesis-info.title-en = thesis-info.title-en.split("\n")
+ }
+
+ set document(
+ title: thesis-info.title.join(""),
+ author: thesis-info.author.name,
+ // keywords: thesis-info.abstract.keywords,
+ )
+
+ // 纸张大小:A4。页边距:上边距25 mm,下边距20 mm,左右边距均为30 mm。
+ set page(paper: "a4", margin: (top: 25mm, bottom: 20mm, x: 30mm))
+
+ // 行距:1.5倍行距
+ // 行距理解为 word 默认行距(1em * 120%)的1.5倍,由于目前尚未实现 [line-height 模
+ // 型],故换算成行间距(leading)
+ //
+ // [line-height 模型]: https://github.com/typst/typst/issues/4224
+ set par(leading: 1em * 120% * 1.5 - 1em)
+
+ // 目录内容 宋体小四号
+ // 正文内容 宋体小四号
+ // 致谢、附录内容 宋体小四号
+ set text(lang: "zh", font: 字体.宋体, size: 字号.小四)
+
+ // 论文内文各大部分的标题用“一、二…… (或1、2……)”, 次级标题为“(一)、(二)……(或
+ // 1.1、2.1……)”,三级标题用“1、2……(或1.1.1、2.1.1……)”,四级标题用“(1)、(2)……
+ //(或1.1.1.1、2.1.1.1……)”,不再使用五级以下标题。两类标题不要混编。
+ set heading(depth: 4, numbering: if numbering == "一" {
+ numbly("{1:一}", "({2:一})", "{3}", "({4})")
+ } else { "1.1.1.1 "})
+ show heading: set text(weight: "regular")
+
+ // 章和节标题段前段后各空0.5行
+ // 行理解为当前行距,故在 "1.5倍行距" 的基准上再算一半,也即 "0.75倍行距"
+ show heading.where(level: 1): set block(above: 1em * 120% * 0.75, below: 1em * 120% * 0.75)
+ show heading.where(level: 2): set block(above: 1em * 120% * 0.75, below: 1em * 120% * 0.75)
+
+ // 目录标题 黑体三号居中
+ // 正文各章标题 黑体三号居中
+ // 参考文献标题 黑体三号居中
+ // 致谢、附录标题 黑体三号居中
+ show heading.where(level: 1): set text(font: 字体.黑体, size: 字号.三号)
+ show heading.where(level: 1): set align(center)
+
+ // 正文各节一级标题 黑体四号左对齐
+ show heading.where(level: 2): set text(font: 字体.黑体, size: 字号.四号)
+
+ // 正文各节二级及以下标题 宋体小四号加粗左对齐空两格
+ show heading.where(level: 3): set text(font: 字体.宋体, size: 字号.小四, weight: "bold")
+ show heading.where(level: 4): set text(font: 字体.宋体, size: 字号.小四, weight: "bold")
+ show heading.where(level: 3): it => pad(left: 2em, it)
+ show heading.where(level: 4): it => pad(left: 2em, it)
+
+ // 遇到一级标题重置图、表、公式编号计数
+ show heading: i-figured.reset-counters
+ show figure: i-figured.show-figure
+ show math.equation: i-figured.show-equation
+
+ // 图题、表题 宋体五号
+ show figure.caption: set text(font: 字体.宋体, size: 字号.五号)
+
+ // 标题放置在表格上方
+ show figure.where(kind: table): set figure.caption(position: top)
+
+ // 脚注、尾注 宋体小五号
+ show footnote.entry: set text(font: 字体.宋体, size: 字号.小五)
+
+ // 注释:毕业论文(设计)中有个别名词或情况需要解释时,可加注说明。注释采用脚注或尾注,
+ // 应根据注释的先后顺序编排序号。注释序号以“①、②”等数字形式标示在正文中被注释词条的
+ // 右上角,脚注或尾注内容中的序号应与被注释词条序号保持一致。
+ show footnote: set footnote(numbering: circle_numbers)
+
+ // 毕业论文应按以下顺序装订和存档:
+ // 封面->扉页->学术诚信声明->摘要->目录->正文->参考文献(->附录)->致谢。
+ if pages.cover {
+ cover(info: thesis-info)
+ pagebreak(weak: true, to: if twoside { "odd" })
+ }
+
+ titlepage(info: thesis-info)
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ declaration()
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ // 摘要开始至绪论之前以大写罗马数字(Ⅰ,Ⅱ,Ⅲ…)单独编连续码
+ // 页眉与页脚 宋体五号居中
+ set page(header: context {
+ set text(font: 字体.宋体, size: 字号.五号, stroke: sysucolor.green)
+ set align(center)
+ let loc = here()
+ let cur-heading = current-heading(level: 1, loc)
+ let first-level-heading = heading-display(active-heading(level: 1, loc))
+
+ if cur-heading != none {
+ thesis-info.title.join("")
+ } else if not twoside or calc.rem(loc.page(), 2) == 1 {
+ first-level-heading
+ } else {
+ thesis-info.title.join("")
+ }
+ line(length: 200%, stroke: 0.1em + sysucolor.green);
+ })
+ set page(numbering: "I")
+ counter(page).update(1)
+
+ abstract-page()
+ pagebreak(weak: true, to: if twoside { "odd" })
+ abstract-en-page()
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ outline()
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ // 绪论开始至论文结尾,以阿拉伯数字(1,2,3…)编连续码
+ set page(numbering: "1")
+ counter(page).update(1)
+
+ // 正文段落按照中文惯例缩进两格
+ set par(first-line-indent: (amount: 2em, all: true))
+
+ show heading.where(level: 1): it => {
+ pagebreak(weak: true)
+ it
+ }
+
+ content
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ // 参考文献
+ {
+ // 参考文献内容 宋体五号
+ set text(font: 字体.宋体, size: 字号.五号)
+ bilingual-bibliography(bibliography: bibliography, full: true)
+ }
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ // 附录
+ if pages.appendix {
+ appendix-part()
+ pagebreak(weak: true, to: if twoside { "odd" })
+ }
+
+ // 致谢
+ acknowledgement-page()
+ pagebreak(weak: true, to: if twoside { "odd" })
+}
+
+// 以下为校对用测试 preview 页面
+#show: doc.with(
+ bibliography: bibliography.with("/template/ref.bib"),
+ pages: (
+ appendix: true
+ )
+)
+
+
+// 正文各部分的标题应简明扼要,不使用标点符号。
+= 第某章
+== 节标题
+=== 小节标题
+==== 四级标题
+写一下测试的内容 @chapter1-img,章节标题 @chapter1[("第一章")]
+
+#figure(
+ image("/template/images/sysu_logo.svg", width: 20%),
+ caption: [图片测试],
+)
+
+// #show: appendix
+= 第一章
+== 节标题
+=== 小节标题
+==== 四级标题
+在附录中引用图片 @appendix-img, 以及附录章节标题 @appendix[#numbering("附录A")]
+
+#figure(
+ image("/template/images/sysu_logo.svg", width: 20%),
+ caption: [图片测试],
+)
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/titlepage.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/titlepage.typ
new file mode 100644
index 0000000000..87cbf26978
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/bachelor/titlepage.typ
@@ -0,0 +1,128 @@
+#import "/utils/datetime-display.typ": datetime-display
+#import "/utils/style.typ": 字号, 字体
+
+// 扉页
+// 内容包括论文中英文题目、学生姓名、学号、院系、专业、指导教师(姓名及职称)等信息。
+#let titlepage(
+ info: (:),
+ // 其他参数
+ stoke-width: 0.5pt,
+ min-title-lines: 2,
+ info-inset: (x: 0pt, bottom: 1pt),
+ info-key-width: 72pt,
+ info-key-font: "黑体",
+ info-value-font: "宋体",
+ column-gutter: -3pt,
+ row-gutter: 11.5pt,
+) = {
+ assert(type(info.title) == array)
+ assert(type(info.author) == dictionary)
+
+ info.title = info.title + range(min-title-lines - info.title.len()).map((it) => " ")
+ if type(info.submit-date) == datetime {
+ info.submit-date = datetime-display(info.submit-date)
+ }
+
+ // 内置辅助函数
+ let info-key(
+ font: 字体.at(info-key-font, default: "黑体"),
+ size: 字号.三号,
+ body,
+ ) = {
+ rect(
+ width: 100%,
+ inset: info-inset,
+ stroke: none,
+ text(
+ font: font,
+ size: size,
+ body,
+ ),
+ )
+ }
+
+ let info-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.三号,
+ key,
+ body,
+ ) = {
+ set align(center)
+ rect(
+ width: 100%,
+ inset: info-inset,
+ stroke: (bottom: stoke-width + black),
+ text(
+ font: font,
+ size: size,
+ bottom-edge: "descender",
+ body,
+ ),
+ )
+ }
+
+ let info-long-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.三号,
+ key,
+ body,
+ ) = {
+ grid.cell(colspan: 3,
+ info-value(
+ font: font,
+ size: size,
+ key,
+ body,
+ )
+ )
+ }
+
+ let info-short-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.三号,
+ key,
+ body
+ ) = {
+ info-value(
+ font: font,
+ size: size,
+ key,
+ body,
+ )
+ }
+
+ // 正式渲染
+ v(30pt)
+
+ set align(center + horizon)
+ for part in info.title {
+ text(size: 字号.二号, font: 字体.黑体, weight: "bold")[ #part ]
+ linebreak()
+ }
+ v(2em)
+ for part-en in info.title-en {
+ text(size: 字号.二号, weight: "bold")[ #part-en ]
+ linebreak()
+ }
+
+ // 学生与指导老师信息
+ set align(center + bottom)
+ block(width: 75%, grid(
+ columns: (info-key-width, 1fr, info-key-width, 1fr),
+ column-gutter: column-gutter,
+ row-gutter: row-gutter,
+ info-key("姓 名"),
+ info-long-value("author", info.author.name),
+ info-key("学 号"),
+ info-long-value("student-id", info.author.sno),
+ info-key("院 系"),
+ info-long-value("department", info.author.department),
+ info-key("专 业"),
+ info-long-value("major", info.author.major),
+ info-key("指导教师"),
+ info-long-value("supervisor", info.supervisor.join(" ")),
+ ))
+ v(2em)
+
+ text(font: 字体.黑体, size: 字号.四号)[#info.submit-date]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/abstract-en.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/abstract-en.typ
new file mode 100644
index 0000000000..9c537e6a65
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/abstract-en.typ
@@ -0,0 +1,49 @@
+// 利用 state 捕获摘要参数,并通过 context 传递给渲染函数
+#import "/utils/style.typ": 字体, 字号
+#let contents(..titles) = context titles.named().at(text.lang)
+
+#let abstract-en-keywords = state("keywords-en", (
+ "Sun Yat-sen University",
+ "thesis",
+ "specification",
+))
+#let abstract-en-content = state("abstract-en", [
+ 英文摘要及关键词内容应与中文摘要及关键词内容相同。中英文摘要及其关键词各置一页内。
+ The English abstract and its keywords should be the same as the Chinese one.
+ Both Chinese and English should be in seperated pages.
+])
+#let abstract-en(
+ keywords: (),
+ body,
+) = {
+ context abstract-en-keywords.update(keywords)
+ context abstract-en-content.update(body)
+}
+
+// 英文摘要页
+#let abstract-en-page() = {
+ // 英文摘要内容 Times New Roman小四号
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ // 英文摘要标题 Times New Roman加粗三号全部大写
+ show heading.where(level: 1): set text(
+ font: 字体.宋体,
+ size: 字号.三号,
+ weight: "bold",
+ )
+
+ // 摘要标题不编号
+ show heading.where(level: 1): set heading(numbering: none)
+
+ [
+ = #contents(zh: "ABSTRACT", en: "Abstract (In English)")
+
+ #context abstract-en-content.final()
+
+ #v(1em)
+
+ // 摘要正文下方另起一行顶格打印“关键词”款项,后加冒号,多个关键词以逗号分隔。
+ // (标题“Keywords”加粗)
+ *Keywords:* #context abstract-en-keywords.final().join(", ")
+ ]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/abstract.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/abstract.typ
new file mode 100644
index 0000000000..ff8427137d
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/abstract.typ
@@ -0,0 +1,46 @@
+// 利用 state 捕获摘要参数,并通过 context 传递给渲染函数
+#import "/utils/style.typ": 字体, 字号
+#let contents(..titles) = context titles.named().at(text.lang)
+
+#let abstract-keywords = state("keywords", (
+ "中山大学",
+ "论文",
+ "学位论文",
+ "规范",
+))
+#let abstract-content = state("abstract", [
+ 摘要应概括论文的主要信息,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。摘要内容一般应包括研究目的、内容、方法、成果和结论,要突出论文的创造性成果或新见解,不要与绪论相混淆。语言力求精练、准确,以300-500字为宜。关键词是供检索用的主题词条,应体现论文特色,具有语义性,在论文中有明确的出处,并应尽量采用《汉语主题词表》或各专业主题词表提供的规范词。关键词与摘要应在同一页,在摘要的下方另起一行注明,一般列3-5个,按词条的外延层次排列(外延大的排在前面)。
+])
+#let abstract(
+ keywords: (),
+ body,
+) = {
+ context abstract-keywords.update(keywords)
+ context abstract-content.update(body)
+}
+
+// 中文摘要页
+#let abstract-page() = {
+ // 中文摘要内容 宋体小四号
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ // 中文摘要标题 黑体三号居中
+ show heading.where(level: 1): set text(font: 字体.黑体, size: 字号.三号)
+
+ // 摘要标题不编号
+ show heading.where(level: 1): set heading(numbering: none)
+
+ [
+ = #contents(zh: "摘要", en: "Abstract (In Chinese)")
+
+ #set par(first-line-indent: (amount: 2em, all: true))
+ #context abstract-content.final()
+
+ #v(1em)
+
+ // 摘要正文下方另起一行顶格打印“关键词”款项,后加冒号,多个关键词以逗号分隔。
+ // (标题“关键词”加粗)
+ #set par(first-line-indent: 0em)
+ *关键词:*#context abstract-keywords.final().join(",")
+ ]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/acknowledgement.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/acknowledgement.typ
new file mode 100644
index 0000000000..3712cb9cc7
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/acknowledgement.typ
@@ -0,0 +1,36 @@
+// 利用 state 捕获摘要参数,并通过 context 传递给渲染函数
+#import "/utils/style.typ": 字体, 字号
+
+#let contents(..titles) = context titles.named().at(text.lang)
+
+// 致谢内容
+#let acknowledgement-content = state("acknowledgement", [
+ 致谢应以简短的文字对课题研究与论文撰写过程中曾直接给予帮助的人员(例如指导教师、答疑教师及其他人员)表达自己的谢意,这不仅是一种礼貌,也是对他人劳动的尊重,是治学者应当遵循的学术规范。内容限一页。
+])
+
+#let acknowledgement(
+ body,
+) = {
+ context acknowledgement-content.update(body)
+}
+
+#let acknowledgement-page() = {
+ // 致谢、附录内容 宋体小四号
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ // 致谢、附录标题 黑体三号居中
+ show heading.where(level: 1): set text(font: 字体.黑体, size: 字号.三号)
+
+ // 致谢标题不编号
+ show heading.where(level: 1): set heading(numbering: none)
+
+ [
+ = #contents(zh: "致谢", en: "Acknowledgements")
+
+ #set par(first-line-indent: (amount: 2em, all: true))
+ #context acknowledgement-content.final()
+
+ #v(1em)
+
+ ]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/appendix.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/appendix.typ
new file mode 100644
index 0000000000..4c616ce82a
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/appendix.typ
@@ -0,0 +1,53 @@
+// 利用 state 捕获摘要参数,并通过 context 传递给渲染函数
+#import "/utils/style.typ": 字体, 字号
+#import "@preview/numbly:0.1.0": numbly
+
+#import "@preview/i-figured:0.2.4"
+
+#let appendix-content = state("appendix", [
+ = 附录要求
+ 对于一些不宜放在正文中的重要支撑材料,可编入毕业论文的附录中,包括某些重要的原始数据、详细数学推导、程序全文及其说明、复杂的图表、设计图纸等一系列需要补充提供的说明材料。如果毕业论文中引用的实例、数据资料,实验结果等符号较多时,为了节约篇幅,便于读者查阅,可以编写一个符号说明,注明符号代表的意义。附录的篇幅不宜太多,一般不超过正文。此项不是必需项,空缺时可以省略。
+])
+
+#let appendix(
+ body,
+) = {
+ context appendix-content.update(body)
+}
+
+#let appendix-part() = {
+ // 致谢、附录内容 宋体小四号
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ // 附录标题中不需要分隔中英文
+ show heading: set text(cjk-latin-spacing: none)
+ set heading(outlined: false)
+ show heading.where(level: 1): set heading(outlined: true, numbering: none)
+
+ // 致谢、附录标题 黑体三号居中
+ show heading.where(level: 1): it => {
+ counter(heading).step()
+ set text(font: 字体.黑体, size: 字号.三号)
+ set align(center)
+ it.body
+ }
+
+ // 目录仅展示附录章标题
+ // 论文附录依次用大写字母“附录A、附录B、附录C……”表示,附录内的分级序号可采用“附A1、
+ // 附A1.1、附A1.1.1”等表示,图、表、公式均依此类推为“图A1、表A1、式A1”等。
+ set heading(numbering: numbly(
+ "附录{1:A}", // use {level:format} to specify the format
+ "附{1:A}{2}.", // if format is not specified, arabic numbers will be used
+ "附{1:A}{2}.{3}.", // here, we only want the 3rd level
+ "附{1:A}{2}.{3}.{4}",
+ ))
+
+
+ show figure: i-figured.show-figure.with(numbering: "A.1")
+ show math.equation: i-figured.show-equation.with(numbering: "(A.1)")
+
+ // 重置 heading 计数
+ counter(heading).update(0)
+
+ context appendix-content.final()
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/contents.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/contents.typ
new file mode 100644
index 0000000000..de4c43db29
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/contents.typ
@@ -0,0 +1,47 @@
+#import "/utils/style.typ": 字体, 字号
+// #import "@preview/cuti:0.3.0": show-cn-fakebold
+// #show: show-cn-fakebold
+
+#let contents-page(twoside: false) = {
+ show outline.entry: it => {
+ if text.lang == "zh" {
+ if it.element.numbering != none and it.element.level == 1 {
+ strong(link(
+ it.element.location(),
+ it.indented("第" + it.prefix() + "章", it.inner()),
+ ))
+ } else if it.element.level == 1 {
+ strong(it)
+ } else {
+ it
+ }
+ }
+
+ if text.lang == "en" {
+ if it.element.numbering != none and it.element.level == 1 {
+ strong(link(
+ it.element.location(),
+ it.indented("Chapter " + it.prefix(), it.inner()),
+ ))
+ } else if it.element.level == 1 {
+ strong(it)
+ } else {
+ it
+ }
+ }
+ }
+
+
+ outline()
+ pagebreak(weak: true, to: if twoside { "odd" })
+ {
+ set text(lang: "en")
+ show heading.where(level: 1): it => {
+ show text: set text(font: "Times New Roman", weight: "bold")
+ it
+ }
+ outline()
+ }
+ pagebreak(weak: true, to: if twoside { "odd" })
+}
+
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/cover.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/cover.typ
new file mode 100644
index 0000000000..1c1075c6fe
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/cover.typ
@@ -0,0 +1,155 @@
+#import "/utils/datetime-display.typ": datetime-display
+#import "/utils/style.typ": sysucolor, 字体, 字号
+
+// 封面
+#let cover(
+ info: (:),
+ // 其他参数
+ stoke-width: 0.5pt,
+ min-title-lines: 2,
+ info-inset: (x: 0pt, bottom: 1pt),
+ info-key-width: 72pt,
+ info-key-font: "黑体",
+ info-value-font: "宋体",
+ column-gutter: -3pt,
+ row-gutter: 11.5pt,
+ bold-info-keys: ("title",),
+ bold-level: "bold",
+) = {
+ assert(type(info.title) == array)
+ assert(type(info.author) == dictionary)
+
+ info.title = (
+ info.title + range(min-title-lines - info.title.len()).map(it => " ")
+ )
+ if type(info.submit-date) == datetime {
+ info.submit-date = datetime-display(info.submit-date)
+ }
+
+ // 内置辅助函数
+ let info-key(
+ font: 字体.at(info-key-font, default: "黑体"),
+ size: 字号.小三,
+ body,
+ ) = {
+ rect(
+ width: 100%,
+ inset: info-inset,
+ stroke: none,
+ text(
+ font: font,
+ size: size,
+ body,
+ ),
+ )
+ }
+
+ let info-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.小三,
+ key,
+ body,
+ ) = {
+ set align(center)
+ rect(
+ width: 100%,
+ inset: info-inset,
+ stroke: (bottom: stoke-width + black),
+ text(
+ font: font,
+ size: size,
+ weight: if (key in bold-info-keys) { bold-level } else { "regular" },
+ bottom-edge: "descender",
+ body,
+ ),
+ )
+ }
+
+ let info-long-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.小三,
+ key,
+ body,
+ ) = {
+ grid.cell(
+ colspan: 3,
+ info-value(
+ font: font,
+ size: size,
+ key,
+ body,
+ ),
+ )
+ }
+
+ let info-short-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.小三,
+ key,
+ body,
+ ) = {
+ info-value(
+ font: font,
+ size: size,
+ key,
+ body,
+ )
+ }
+
+ // 正式渲染
+ // 居中对齐
+ set align(center)
+
+ // 封面校徽
+ // 使用校方官方 VI 系统的 logo,来源:https://home3.sysu.edu.cn/sysuvi/index.html
+ image("/assets/vi/sysu_logo.svg", width: 3cm)
+
+ text(
+ size: 字号.小初,
+ font: 字体.宋体,
+ weight: "bold",
+ fill: sysucolor.green,
+ )[博士学位论文]
+ v(-2em)
+ line(length: 200%, stroke: 0.12cm + sysucolor.green)
+ v(-0.8em)
+ line(length: 200%, stroke: 0.05cm + sysucolor.green)
+ v(1.5cm)
+
+ // 论文题目
+ h(0.7cm)
+ block(width: 100%, grid(
+ columns: (25%, 1fr, 75%, 1fr),
+ column-gutter: column-gutter,
+ row-gutter: row-gutter,
+ info-key(size: 字号.二号, "题目:"),
+ ..info
+ .title
+ .map(s => info-long-value(size: 字号.二号, font: 字体.黑体, "title", s))
+ .intersperse(info-key(size: 字号.二号, " ")),
+ ))
+ v(2.7cm)
+
+ // 学生与指导老师信息
+ set align(center + bottom)
+ block(width: 75%, grid(
+ columns: (info-key-width, 1fr, info-key-width, 1fr),
+ column-gutter: column-gutter,
+ row-gutter: row-gutter,
+ info-key("姓 名"),
+ info-long-value("author", info.author.name),
+ info-key("学 号"),
+ info-long-value("student-id", info.author.sno),
+
+ info-key("院 系"),
+ info-long-value("department", info.author.department),
+ info-key("专 业"),
+ info-long-value("major", info.author.major),
+
+ info-key("指导教师"),
+ info-long-value("supervisor", info.supervisor.join(" ")),
+ ))
+ v(2em)
+
+ text(font: 字体.黑体, size: 字号.小四)[#info.submit-date]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/declaration.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/declaration.typ
new file mode 100644
index 0000000000..50b33f5639
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/declaration.typ
@@ -0,0 +1,25 @@
+#import "/utils/style.typ": 字号, 字体
+
+// 学术声明页
+// 参照 [中山大学本科生毕业论文(设计)写作与印制规范 2020年发](https://spa.sysu.edu.cn/zh-hans/article/1744) 电子档的示例设置格式
+#let declaration() = {
+ align(center, text(font: 字体.黑体, size: 字号.三号)[学术诚信声明])
+
+ set text(font: 字体.宋体, size: 字号.小四)
+
+ par(justify: true, first-line-indent: 2em)[
+ 本人郑重声明:所呈交的毕业论文(设计),是本人在导师的指导下,独立进行研究工作所取得的成果。除文中已经注明引用的内容外,本论文(设计)不包含任何其他个人或集体已经发表或撰写过的作品成果。对本论文(设计)的研究做出重要贡献的个人和集体,均已在文中以明确方式标明。本论文(设计)的知识产权归属于培养单位。本人完全意识到本声明的法律结果由本人承担。
+ ]
+ v(2em)
+
+ align(right + top,
+ box(
+ grid(
+ columns: (auto, auto),
+ gutter: 2em,
+ "作者签名:", "",
+ "日" + h(2em) + "期:", h(2.5em) + text("年") + h(2em) + text("月") + h(2em) + text("日")
+ )
+ )
+ )
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/lib.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/lib.typ
new file mode 100644
index 0000000000..0e1d688e07
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/lib.typ
@@ -0,0 +1,301 @@
+#import "/specifications/postgraduate/cover.typ": cover
+#import "/specifications/postgraduate/titlepage.typ": titlepage
+#import "/specifications/postgraduate/declaration.typ": declaration
+#import "/specifications/postgraduate/abstract.typ": abstract, abstract-page
+#import "/specifications/postgraduate/abstract-en.typ": abstract-en, abstract-en-page
+#import "/specifications/postgraduate/appendix.typ": appendix, appendix-part
+#import "/specifications/postgraduate/acknowledgement.typ": acknowledgement, acknowledgement-page
+#import "/specifications/postgraduate/contents.typ": contents-page
+
+#import "/utils/bilingual-bibliography.typ": bilingual-bibliography
+#import "/utils/custom-heading.typ": active-heading, current-heading, heading-display-postgraduate
+#import "/utils/style.typ": 字体, 字号
+
+#import "@preview/numbly:0.1.0": numbly
+#import "@preview/numblex:0.1.1": circle_numbers
+#import "@preview/i-figured:0.2.4"
+
+#let contents(..titles) = context titles.named().at(text.lang)
+
+// 中山大学本科生毕业论文(设计)写作与印制规范
+// 参考规范: https://spa.sysu.edu.cn/zh-hans/article/1744
+#let doc(
+ // 毕业论文基本信息
+ thesis-info: (
+ // 论文标题,将展示在封面、扉页与页眉上
+ // 多行标题请使用数组传入 `("thesis title", "with part next line")`,或使用换行符:`"thesis title\nwith part next line"`
+ title: ("博士学位论文", "写作与印制规范(2020-)"),
+ title-en: ("The Specification of Writting and Printing", "for SYSU thesis"),
+ // 论文作者信息:学号、姓名、院系、专业、指导老师
+ author: (
+ sno: "1xxxxxxx",
+ name: "张三",
+ grade: "2024",
+ department: "某学院",
+ major: "某专业",
+ ),
+ // 指导老师信息,以`("name", "title")` 数组方式传入
+ supervisor: ("李四", "教授"),
+ // 提交日期,默认为论文 PDF 生成日期
+ submit-date: datetime.today(),
+ discipline: "工学",
+ degree: "博士",
+ ),
+ // 参考文献来源
+ bibliography: none,
+ // 控制页面是否渲染
+ pages: (
+ // 封面可能由学院统一打印提供,因此可以不渲染
+ cover: false,
+ // 附录部分为可选。设置为 true 后,会在参考文献部分与致谢部分之间插入附录部分。
+ appendix: false,
+ ),
+ // 论文内文各大部分的标题用“一、二…… (或1、2……)”, 次级标题为“(一)、(二)……(或
+ // 1.1、2.1……)”,三级标题用“1、2……(或1.1.1、2.1.1……)”,四级标题用“(1)、(2)……
+ //(或1.1.1.1、2.1.1.1……)”,不再使用五级以下标题。两类标题不要混编。
+ numbering: none,
+ // 双面模式,会加入空白页,便于打印
+ twoside: false,
+ // 论文正文信息,包括绪论、主体、结论
+ content,
+) = {
+ // 论文信息参数处理。要求必须传递,且符合规格的参数
+ assert(type(thesis-info) == dictionary)
+ assert(type(thesis-info.title) == array or type(thesis-info.title) == str)
+ assert(
+ type(thesis-info.title-en) == array or type(thesis-info.title-en) == str,
+ )
+ // 论文信息默认参数。函数传入参数会完全覆盖参数值,因此需要提供默认参数补充。
+ // 彩蛋:如果论文参数不传递作者参数,那么论文就会被署名论文模板作者
+ let default-author = (
+ sno: "13xxxx87",
+ name: "Sunny Huang",
+ grade: "2013",
+ department: "数据科学与计算机学院",
+ major: "软件工程",
+ )
+ thesis-info.author = thesis-info.at("author", default: default-author)
+
+ let default-thesis-info = (
+ title: ("博士学位论文", "写作与印制规范"),
+ title-en: ("The Specification of Writting and Printing", "for SYSU thesis"),
+ supervisor: ("李四", "教授"),
+ submit-date: datetime.today(),
+ )
+ thesis-info = default-thesis-info + thesis-info
+
+ // 论文渲染控制参数处理。设置可选页面的默认设置项
+ let default-pages = (
+ cover: true,
+ appendix: false,
+ )
+ pages = default-pages + pages
+
+ // 文档元数据处理
+ if type(thesis-info.title) == str {
+ thesis-info.title = thesis-info.title.split("\n")
+ }
+ if type(thesis-info.title-en) == str {
+ thesis-info.title-en = thesis-info.title-en.split("\n")
+ }
+
+ set document(
+ title: thesis-info.title.join(""),
+ author: thesis-info.author.name,
+ // keywords: thesis-info.abstract.keywords,
+ )
+
+ // 纸张大小:A4。页边距:上边距25 mm,下边距20 mm,左右边距均为30 mm。
+ set page(paper: "a4", margin: (top: 25mm, bottom: 20mm, x: 30mm))
+
+ // 行距:1.5倍行距
+ // 行距理解为 word 默认行距(1em * 120%)的1.5倍,由于目前尚未实现 [line-height 模
+ // 型],故换算成行间距(leading)
+ //
+ // [line-height 模型]: https://github.com/typst/typst/issues/4224
+ set par(leading: 1em * 120% * 1.5 - 1em)
+
+ // 目录内容 宋体小四号
+ // 正文内容 宋体小四号
+ // 致谢、附录内容 宋体小四号
+ set text(lang: "zh", font: 字体.宋体, size: 字号.小四)
+
+ // 论文内文各大部分的标题用“一、二…… (或1、2……)”, 次级标题为“(一)、(二)……(或
+ // 1.1、2.1……)”,三级标题用“1、2……(或1.1.1、2.1.1……)”,四级标题用“(1)、(2)……
+ //(或1.1.1.1、2.1.1.1……)”,不再使用五级以下标题。两类标题不要混编。
+ set heading(depth: 4, numbering: if numbering == "一" {
+ numbly("{1:一}", "({2:一})", "{3}", "({4})")
+ } else { "1.1.1.1 " })
+ show heading: set text(weight: "regular")
+
+ // 章和节标题段前段后各空0.5行
+ // 行理解为当前行距,故在 "1.5倍行距" 的基准上再算一半,也即 "0.75倍行距"
+ show heading.where(level: 1): set block(
+ above: 1em * 120% * 0.75,
+ below: 1em * 120% * 0.75,
+ )
+ show heading.where(level: 2): set block(
+ above: 1em * 120% * 0.75,
+ below: 1em * 120% * 0.75,
+ )
+
+ // 目录标题 黑体三号居中
+ // 正文各章标题 黑体三号居中
+ // 参考文献标题 黑体三号居中
+ // 致谢、附录标题 黑体三号居中
+ show heading.where(level: 1): it => {
+ set text(font: 字体.黑体, size: 字号.三号)
+ set align(center)
+ heading-display-postgraduate(it)
+ }
+
+ // 正文各节一级标题 黑体四号左对齐
+ show heading.where(level: 2): set text(font: 字体.黑体, size: 字号.四号)
+
+ // 正文各节二级及以下标题 宋体小四号加粗左对齐空两格
+ show heading.where(level: 3): set text(
+ font: 字体.宋体,
+ size: 字号.小四,
+ weight: "bold",
+ )
+ show heading.where(level: 4): set text(
+ font: 字体.宋体,
+ size: 字号.小四,
+ weight: "bold",
+ )
+ show heading.where(level: 3): it => pad(left: 2em, it)
+ show heading.where(level: 4): it => pad(left: 2em, it)
+
+ // 遇到一级标题重置图、表、公式编号计数
+ show heading: i-figured.reset-counters
+ show figure: i-figured.show-figure
+ show math.equation: i-figured.show-equation
+
+ // 图题、表题 宋体五号
+ show figure.caption: set text(font: 字体.宋体, size: 字号.五号)
+
+ // 标题放置在表格上方
+ show figure.where(kind: table): set figure.caption(position: top)
+
+ // 脚注、尾注 宋体小五号
+ show footnote.entry: set text(font: 字体.宋体, size: 字号.小五)
+
+ // 注释:毕业论文(设计)中有个别名词或情况需要解释时,可加注说明。注释采用脚注或尾注,
+ // 应根据注释的先后顺序编排序号。注释序号以“①、②”等数字形式标示在正文中被注释词条的
+ // 右上角,脚注或尾注内容中的序号应与被注释词条序号保持一致。
+ show footnote: set footnote(numbering: circle_numbers)
+
+ // 毕业论文应按以下顺序装订和存档:
+ // 封面->扉页->学术诚信声明->摘要->目录->正文->参考文献(->附录)->致谢。
+ if pages.cover {
+ cover(info: thesis-info)
+ pagebreak(weak: true, to: if twoside { "odd" })
+ }
+
+ titlepage(info: thesis-info)
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ declaration()
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ // 摘要开始至绪论之前以大写罗马数字(Ⅰ,Ⅱ,Ⅲ…)单独编连续码
+ // 页眉与页脚 宋体五号居中
+ set page(header: context {
+ set text(font: 字体.宋体, size: 字号.五号)
+ set align(center)
+ let loc = here()
+ let cur-heading = current-heading(level: 1, loc)
+ let first-level-heading = heading-display-postgraduate(active-heading(
+ level: 1,
+ loc,
+ ))
+
+ if cur-heading != none {
+ heading-display-postgraduate(current-heading(level: 1, loc))
+ } else if calc.rem(loc.page(), 2) == 0 {
+ [中山大学] + thesis-info.discipline + thesis-info.degree + [学位论文]
+ } else {
+ first-level-heading
+ }
+ stack(
+ line(length: 100%, stroke: 2pt),
+ v(2pt),
+ line(length: 100%, stroke: 1pt),
+ )
+ })
+ set page(numbering: "I")
+ counter(page).update(1)
+
+ abstract-page()
+ pagebreak(weak: true, to: if twoside { "odd" })
+ abstract-en-page()
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ contents-page()
+
+ // 绪论开始至论文结尾,以阿拉伯数字(1,2,3…)编连续码
+ set page(numbering: "1")
+ counter(page).update(1)
+
+ // 正文段落按照中文惯例缩进两格
+ set par(first-line-indent: (amount: 2em, all: true))
+
+ show heading.where(level: 1): it => {
+ pagebreak(weak: true)
+ it
+ }
+
+ content
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ // 参考文献
+ {
+ // 参考文献内容 宋体五号
+ set text(font: 字体.宋体, size: 字号.五号)
+ bilingual-bibliography(bibliography: bibliography, full: true)
+ }
+ pagebreak(weak: true, to: if twoside { "odd" })
+
+ // 附录
+ if pages.appendix {
+ appendix-part()
+ pagebreak(weak: true, to: if twoside { "odd" })
+ }
+
+ // 致谢
+ acknowledgement-page()
+ pagebreak(weak: true, to: if twoside { "odd" })
+}
+
+// 以下为校对用测试 preview 页面
+#show: doc.with(
+ bibliography: bibliography.with("/template/ref.bib"),
+ pages: (
+ appendix: true,
+ ),
+)
+
+
+// 正文各部分的标题应简明扼要,不使用标点符号。
+= 第某章
+== 节标题
+=== 小节标题
+==== 四级标题
+写一下测试的内容 @chapter1-img,章节标题 @chapter1[("第一章")]
+
+#figure(
+ image("/template/images/sysu_logo.svg", width: 20%),
+ caption: [图片测试],
+)
+
+// #show: appendix
+// = 第一章
+// == 节标题
+// === 小节标题
+// ==== 四级标题
+// 在附录中引用图片 @appendix-img, 以及附录章节标题 @appendix[#numbering("附录A")]
+
+// #figure(
+// image("/template/images/sysu_logo.svg", width: 20%),
+// caption: [图片测试],
+// )
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/titlepage.typ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/titlepage.typ
new file mode 100644
index 0000000000..87cbf26978
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/specifications/postgraduate/titlepage.typ
@@ -0,0 +1,128 @@
+#import "/utils/datetime-display.typ": datetime-display
+#import "/utils/style.typ": 字号, 字体
+
+// 扉页
+// 内容包括论文中英文题目、学生姓名、学号、院系、专业、指导教师(姓名及职称)等信息。
+#let titlepage(
+ info: (:),
+ // 其他参数
+ stoke-width: 0.5pt,
+ min-title-lines: 2,
+ info-inset: (x: 0pt, bottom: 1pt),
+ info-key-width: 72pt,
+ info-key-font: "黑体",
+ info-value-font: "宋体",
+ column-gutter: -3pt,
+ row-gutter: 11.5pt,
+) = {
+ assert(type(info.title) == array)
+ assert(type(info.author) == dictionary)
+
+ info.title = info.title + range(min-title-lines - info.title.len()).map((it) => " ")
+ if type(info.submit-date) == datetime {
+ info.submit-date = datetime-display(info.submit-date)
+ }
+
+ // 内置辅助函数
+ let info-key(
+ font: 字体.at(info-key-font, default: "黑体"),
+ size: 字号.三号,
+ body,
+ ) = {
+ rect(
+ width: 100%,
+ inset: info-inset,
+ stroke: none,
+ text(
+ font: font,
+ size: size,
+ body,
+ ),
+ )
+ }
+
+ let info-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.三号,
+ key,
+ body,
+ ) = {
+ set align(center)
+ rect(
+ width: 100%,
+ inset: info-inset,
+ stroke: (bottom: stoke-width + black),
+ text(
+ font: font,
+ size: size,
+ bottom-edge: "descender",
+ body,
+ ),
+ )
+ }
+
+ let info-long-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.三号,
+ key,
+ body,
+ ) = {
+ grid.cell(colspan: 3,
+ info-value(
+ font: font,
+ size: size,
+ key,
+ body,
+ )
+ )
+ }
+
+ let info-short-value(
+ font: 字体.at(info-value-font, default: "宋体"),
+ size: 字号.三号,
+ key,
+ body
+ ) = {
+ info-value(
+ font: font,
+ size: size,
+ key,
+ body,
+ )
+ }
+
+ // 正式渲染
+ v(30pt)
+
+ set align(center + horizon)
+ for part in info.title {
+ text(size: 字号.二号, font: 字体.黑体, weight: "bold")[ #part ]
+ linebreak()
+ }
+ v(2em)
+ for part-en in info.title-en {
+ text(size: 字号.二号, weight: "bold")[ #part-en ]
+ linebreak()
+ }
+
+ // 学生与指导老师信息
+ set align(center + bottom)
+ block(width: 75%, grid(
+ columns: (info-key-width, 1fr, info-key-width, 1fr),
+ column-gutter: column-gutter,
+ row-gutter: row-gutter,
+ info-key("姓 名"),
+ info-long-value("author", info.author.name),
+ info-key("学 号"),
+ info-long-value("student-id", info.author.sno),
+ info-key("院 系"),
+ info-long-value("department", info.author.department),
+ info-key("专 业"),
+ info-long-value("major", info.author.major),
+ info-key("指导教师"),
+ info-long-value("supervisor", info.supervisor.join(" ")),
+ ))
+ v(2em)
+
+ text(font: 字体.黑体, size: 字号.四号)[#info.submit-date]
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/template/images/sysu_logo.svg b/packages/preview/modern-sysu-thesis/0.4.1/template/images/sysu_logo.svg
new file mode 100644
index 0000000000..1c14f8ec98
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/template/images/sysu_logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/template/ref.bib b/packages/preview/modern-sysu-thesis/0.4.1/template/ref.bib
new file mode 100644
index 0000000000..ac49843ee2
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/template/ref.bib
@@ -0,0 +1,94 @@
+@book{蒋有绪1998,
+ title={中国森林群落分类及其群落学特征},
+ author={蒋有绪 and 郭泉水 and 马娟 and others},
+ year={1998},
+ publisher={科学出版社},
+ address={北京},
+ pages={11-12},
+}
+
+@inproceedings{中国力学学会1990,
+ title={第3届全国实验流体力学学术会议论文集},
+ author={中国力学学会},
+ year={1990},
+ address={天津},
+ publisher={**出版社},
+ pages={20-24}
+}
+
+@techreport{WHO1970,
+ title={World Health Organization. Factors Regulating the Immune Response: Report of WHO Scientific Group},
+ year={1970},
+ institution={WHO},
+ address={Geneva}
+}
+
+@phdthesis{张志祥1998,
+ author = {张志祥},
+ title = {间断动力系统的随机扰动及其在守恒律方程中的应用},
+ school = {北京大学数学学院},
+ address = {北京},
+ year = {1998},
+ pages = {50-55}
+}
+
+@patent{河北绿洲2001,
+ title={一种荒漠化地区生态植被综合培育种植方法:中国,01129210.5},
+ author={河北绿洲生态环境科技有限公司},
+ year={2001},
+ type={patent},
+ number={01129210.5},
+ note={2001-10-24[2002-05-28]},
+ url={http://211.152.9.47/sipoasp/zlijs/hyjs-yxnew. asp?recid=01129210.5&leixin}
+}
+
+@standard{GB/T2659-1986,
+ title = {世界各国和地区名称代码},
+ author = {国家标准局信息分类编码研究所},
+ year = {1986},
+ howpublished = {全国文献工作标准化技术委员会. 文献工作国家标准汇编:3.北京:中国标准出版社,1988:59-92.},
+ note = {GB/T 2659-1986}
+}
+
+
+@article{李炳穆2000,
+ title={理想的图书馆员和信息专家的素质与形象},
+ author={李炳穆},
+ journal={图书情报工作},
+ year={2000},
+ volume={2000},
+ number={2},
+ pages={5-8}
+}
+
+@article{丁文祥2000,
+ title={数字革命与竞争国际化},
+ author={丁文祥},
+ journal={中国青年报},
+ year={2000},
+ month={11-20},
+ number={15}
+}
+
+@article{江向东1999,
+ title={互联网环境下的信息处理与图书管理系统解决方案},
+ author={江向东},
+ journal={情报学报},
+ year={1999},
+ volume={18},
+ number={2},
+ pages={4},
+ note={2000-01-18},
+ url={http://www.chinainfo.gov.cn/periodical/gbxb/gbxb99/gbxb990203}
+}
+
+@article{CHRISTINE1998,
+ title={Plant physiology:plant biology in the Genome Era},
+ author={M CHRISTINE},
+ journal={Science},
+ year={1998},
+ volume={281},
+ pages={331-332},
+ note={1998-09-23},
+ url={http://www.sciencemag.org/cgi/collection/anatmorp}
+}
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/template/thesis.typ b/packages/preview/modern-sysu-thesis/0.4.1/template/thesis.typ
new file mode 100644
index 0000000000..55bf26883c
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/template/thesis.typ
@@ -0,0 +1,182 @@
+// 建议在正式编辑论文时,采用 typst.app 中的已发布版本模板
+#import "@preview/modern-sysu-thesis:0.4.1": bachelor as thesis
+
+// 仅供开发调试使用
+// #import "lib.typ": postgraduate as thesis
+#import thesis: abstract, acknowledgement, appendix, contents
+
+// 你首先应该安装 https://gitlab.com/sysu-gitlab/thesis-template/better-thesis/-/tree/main/fonts 里的所有字体,
+// 如果是 Web App 上编辑,你应该手动上传这些字体文件,否则不能正常使用「楷体」和「仿宋」,导致显示错误。
+
+#show: thesis.doc.with(
+ // 毕业论文基本信息
+ thesis-info: (
+ // 论文标题,将展示在封面、扉页与页眉上
+ // 多行标题请使用数组传入 `("thesis title", "with part next line")`,或使用换行符:`"thesis title\nwith part next line"`
+ title: ("基于 Typst 的", "中山大学学位论文模板"),
+ title-en: "A Typst Template for SYSU thesis",
+ // 论文作者信息:学号、姓名、院系、专业、指导老师
+ author: (
+ sno: "1xxxxxxx",
+ name: "张三",
+ grade: "2024",
+ department: "某学院",
+ major: "某专业",
+ ),
+ // 指导老师信息,以`("name", "title")` 数组方式传入
+ supervisor: ("李四", "教授"),
+ // 提交日期,默认为论文 PDF 生成日期
+ submit-date: datetime.today(),
+ discipline: "工学",
+ degree: "博士",
+ ),
+
+ // 参考文献来源
+ bibliography: bibliography.with("ref.bib"),
+
+ // 控制页面是否渲染
+ pages: (
+ // 封面可能由学院统一打印提供,因此可以不渲染
+ cover: false,
+ // 附录部分为可选。设置为 true 后,会在参考文献部分与致谢部分之间插入附录部分。
+ appendix: true,
+ ),
+
+ // 论文内文各大部分的标题用“一、二…… (或1、2……)”, 次级标题为“(一)、(二)……(或
+ // 1.1、2.1……)”,三级标题用“1、2……(或1.1.1、2.1.1……)”,四级标题用“(1)、(2)……
+ //(或1.1.1.1、2.1.1.1……)”,不再使用五级以下标题。两类标题不要混编。
+ // numbering: "一",
+
+ // 双面模式,会加入空白页,便于打印
+ twoside: false,
+)
+
+// 本科模板无需双语目录,不需要使用#contents函数,请自行删除并直接输入标题
+= #contents(zh: "导 论", en: "Introduction")
+
+== #contents(zh: "列表", en: "List")
+
+=== #contents(zh: "无序列表", en: "Unordered list")
+
+- 无序列表项一
+- 无序列表项二
+ - 无序子列表项一
+ - 无序子列表项二
+
+=== #contents(zh: "有序列表", en: "Ordered list")
+
++ 有序列表项一
++ 有序列表项二
+ + 有序子列表项一
+ + 有序子列表项二
+
+=== #contents(zh: "术语列表", en: "List of terms")
+
+/ 术语一: 术语解释
+/ 术语二: 术语解释
+
+== #contents(zh: "图表", en: "Figures")
+
+引用@tbl:timing,引用@tbl:timing-tlt,以及@fig:sysu-logo。引用图表时,表格和图片分别需要加上 `tbl:`和`fig:` 前缀才能正常显示编号。
+
+#align(center, (
+ stack(dir: ltr)[
+ #figure(
+ table(
+ align: center + horizon,
+ columns: 4,
+ [t], [1], [2], [3],
+ [y], [0.3s], [0.4s], [0.8s],
+ ),
+ caption: [常规表],
+ )
+ ][
+ #h(50pt)
+ ][
+ #figure(
+ table(
+ columns: 4,
+ stroke: none,
+ table.hline(),
+ [t], [1], [2], [3],
+ table.hline(stroke: .5pt),
+ [y], [0.3s], [0.4s], [0.8s],
+ table.hline(),
+ ),
+ caption: [三线表],
+ )
+ ]
+))
+
+#figure(
+ image("images/sysu_logo.svg", width: 20%),
+ caption: [图片测试],
+)
+
+
+== #contents(zh: "数学公式", en: "Mathematical formula")
+可以像 Markdown 一样写行内公式 $x + y$,以及带编号的行间公式:
+
+$ phi.alt := (1 + sqrt(5)) / 2 $
+
+引用数学公式需要加上 `eqt:` 前缀,则由@eqt:ratio,我们有:
+
+$ F_n = floor(1 / sqrt(5) phi.alt^n) $
+
+我们也可以通过 `<->` 标签来标识该行间公式不需要编号
+
+$ y = integral_1^2 x^2 dif x $ <->
+
+而后续数学公式仍然能正常编号。
+
+$ F_n = floor(1 / sqrt(5) phi.alt^n) $
+
+== #contents(zh: "参考文献", en: "References")
+
+可以像这样引用参考文献:图书#[@蒋有绪1998]和会议#[@中国力学学会1990]。
+
+== #contents(zh: "代码块", en: "Code block")
+
+代码块支持语法高亮。引用时需要加上 `lst:` @lst:code
+
+#figure(
+ ```py
+ def add(x, y):
+ return x + y
+ ```,
+ caption: [代码块],
+)
+
+
+= #contents(zh: "正 文", en: "Main body")
+
+== #contents(zh: "正文子标题", en: "Subtitle of main body")
+
+=== #contents(zh: "正文子子标题", en: "Subsubtitle of main body")
+
+正文内容
+
+// 附录
+#show: appendix
+
+= #contents(zh: "附录", en: "Appendix")
+
+== 附录章节题
+
+=== 附录子标题
+==== 附录子子标题
+
+附录内容,这里也可以加入图片,例如@fig:appendix-img。
+
+从正文内容里复制公式,以审查公式编号
+$ F_n = floor(1 / sqrt(5) phi.alt^n) $
+
+#figure(
+ image("images/sysu_logo.svg", width: 20%),
+ caption: [图片测试],
+)
+
+// 致谢
+#acknowledgement[
+ 感谢 NJU-LUG,感谢 NJUThesis LaTeX 模板。
+]
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/thumbnail.png b/packages/preview/modern-sysu-thesis/0.4.1/thumbnail.png
new file mode 100644
index 0000000000..aab41416da
Binary files /dev/null and b/packages/preview/modern-sysu-thesis/0.4.1/thumbnail.png differ
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/typst.toml b/packages/preview/modern-sysu-thesis/0.4.1/typst.toml
new file mode 100644
index 0000000000..19edb77612
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/typst.toml
@@ -0,0 +1,19 @@
+[package]
+name = "modern-sysu-thesis"
+version = "0.4.1"
+entrypoint = "lib.typ"
+repository = "https://gitlab.com/sysu-gitlab/thesis-template/better-thesis"
+authors = [
+ "howardlau1999 <@howardlau1999>",
+ "Sunny Huang <@huangjj27>",
+ "chaos <@debeetle>",
+]
+license = "MIT"
+description = "中山大学学位论文 Typst 模板,A Typst template for SYSU thesis"
+keywords = ["SYSU", "thesis", "typst"]
+categories = ["thesis"]
+
+[template]
+path = "template"
+entrypoint = "thesis.typ"
+thumbnail = "thumbnail.png"
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/bilingual-bibliography.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/bilingual-bibliography.typ
new file mode 100644
index 0000000000..9765c82d9b
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/bilingual-bibliography.typ
@@ -0,0 +1,159 @@
+// Authors: csimide, OrangeX4
+// Tested only on GB-7714-2015-Numeric
+#let contents(..titles) = context titles.named().at(text.lang)
+#let bilingual-bibliography(
+ bibliography: none,
+ title: contents(zh: "参考文献", en: "References"),
+ full: false,
+ style: "gb-7714-2015-numeric",
+ mapping: (:),
+) = {
+ assert(
+ bibliography != none,
+ message: "请传入带有 source 的 bibliography 函数。",
+ )
+
+ // Please fill in the remaining mapping table here
+ mapping = (
+ //"等": "et al",
+ "卷": "Vol.",
+ "册": "Bk.",
+ // "译": "tran",
+ // "等译": "et al. tran",
+ // 注: 请见下方译者数量判断部分。
+ ) + mapping
+
+
+ let to-string(content) = {
+ if content.has("text") {
+ content.text
+ } else if content.has("children") {
+ content.children.map(to-string).join("")
+ } else if content.has("child") {
+ to-string(content.child)
+ } else if content.has("body") {
+ to-string(content.body)
+ } else if content == [ ] {
+ " "
+ }
+ }
+
+ show grid.cell.where(x: 1): it => {
+ // 后续的操作是对 string 进行的。
+ let ittext = to-string(it)
+ // 判断是否为中文文献:去除特定词组后,仍有至少两个连续汉字。
+ let pureittext = ittext.replace(
+ regex("[等卷册和版本章期页篇译间者(不详)]"),
+ "",
+ )
+ if pureittext.find(regex("\p{sc=Hani}{2,}")) != none {
+ ittext
+ } else {
+ // 若不是中文文献,进行替换
+ // 第xxx卷、第xxx册的情况:变为 Vol. XXX 或 Bk. XXX。
+ let reptext = ittext
+ reptext = reptext.replace(
+ regex("(第\s?)?\d+\s?[卷册]"),
+ itt => {
+ if itt.text.contains("卷") {
+ "Vol. "
+ } else {
+ "Bk. "
+ }
+ itt.text.find(regex("\d+"))
+ },
+ )
+
+ // 第xxx版/第xxx本的情况:变为 1st ed 格式。
+ reptext = reptext.replace(
+ regex("(第\s?)?\d+\s?[版本]"),
+ itt => {
+ let num = itt.text.find(regex("\d+"))
+ num
+ if num.clusters().len() == 2 and num.clusters().first() == "1" {
+ "th"
+ } else {
+ (
+ "1": "st",
+ "2": "nd",
+ "3": "rd",
+ ).at(num.clusters().last(), default: "th")
+ }
+ " ed"
+ },
+ )
+
+ // 译者数量判断:单数时需要用 trans,复数时需要用 tran 。
+ // 注:
+ // 1. 目前判断译者数量的方法非常草率,有逗号就是多个作者。但是在部分 GB/T 7714-2015 方言中,姓名中可以含有逗号。
+ // 2. 在 GB/T 7714-2015 原文中有 `等译`(P15 10.1.3 小节 示例 1-[1]),但未给出相应的英文缩写翻译。
+ // 3. CSL 社区库内的 GB/T 7714-2015 会使用 `等, 译` 和 `et al., tran` 的写法。为了保证统一性,这里会译作不带逗号的版本,即 `et al. tran`
+ // 如果工作不正常,可以考虑换为简单关键词替换,即注释这段情况,取消 13 行 mapping 内 `译` 条目的注释。
+ reptext = reptext.replace(
+ regex("\].+?译"),
+ itt => {
+ // 我想让上面这一行匹配变成非贪婪的,但加问号后没啥效果?
+ if itt.text.replace(regex(",\s?译"), "").find(",") != none {
+ itt.text.replace(regex(",?\s?译"), " tran")
+ } else {
+ itt.text.replace(regex(",?\s?译"), " trans")
+ }
+ },
+ )
+
+ // `等` 特殊处理:`等`后方接内容也需要译作 `et al.`,如 `等译` 需要翻译为 `et al. trans`
+ reptext = reptext.replace(
+ regex("等."),
+ itt => {
+ "et al."
+ // 如果原文就是 `等.`,则仅需简单替换,不需要额外处理
+ // 如果原文 `等` 后没有跟随英文标点,则需要补充一个空格
+ if not (
+ itt.text.last()
+ in (
+ ".",
+ ",",
+ ";",
+ ":",
+ "[",
+ "]",
+ "/",
+ "\\",
+ "<",
+ ">",
+ "?",
+ "(",
+ ")",
+ " ",
+ "\"",
+ "'",
+ )
+ ) {
+ " "
+ }
+ // 原文有英文句号时不需要重复句号,否则需要将匹配到的最后一个字符吐回来
+ if not itt.text.last() == "." {
+ itt.text.last()
+ }
+ },
+ )
+
+ // 其他情况:直接替换
+ reptext = reptext.replace(
+ regex("\p{sc=Hani}+"),
+ itt => {
+ mapping.at(itt.text, default: itt.text)
+ // 注意:若替换功能工作良好,应该不会出现 `default` 情形
+ },
+ )
+ reptext
+ }
+ }
+
+ set text(lang: "zh")
+ bibliography(
+ title: title,
+ full: full,
+ style: style,
+ )
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/custom-heading.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/custom-heading.typ
new file mode 100644
index 0000000000..3aee64d4f7
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/custom-heading.typ
@@ -0,0 +1,65 @@
+// 展示一个标题
+#let heading-display-postgraduate(it) = {
+ if it != none {
+ if it.has("numbering") and it.numbering != none {
+ [第]
+ numbering(it.numbering, ..counter(heading).at(it.location()))
+ [章 ]
+ }
+ it.body
+ } else {
+ ""
+ }
+}
+
+#let heading-display(it) = {
+ if it != none {
+ if it.has("numbering") and it.numbering != none {
+ numbering(it.numbering, ..counter(heading).at(it.location()))
+ [ ]
+ }
+ it.body
+ } else {
+ ""
+ }
+}
+
+// 获取当前激活的 heading,参数 prev 用于标志优先使用之前页面的 heading
+#let active-heading(level: 1, prev: true, loc) = {
+ // 之前页面的标题
+ let prev-headings = query(selector(heading.where(level: level)).before(loc))
+ // 当前页面的标题
+ let cur-headings = query(
+ selector(heading.where(level: level)).after(loc),
+ ).filter(it => it.location().page() == loc.page())
+ if prev-headings.len() == 0 and cur-headings.len() == 0 {
+ return none
+ } else {
+ if prev {
+ if prev-headings.len() != 0 {
+ return prev-headings.last()
+ } else {
+ return cur-headings.first()
+ }
+ } else {
+ if cur-headings.len() != 0 {
+ return cur-headings.first()
+ } else {
+ return prev-headings.last()
+ }
+ }
+ }
+}
+
+// 获取当前页面的标题
+#let current-heading(level: 1, loc) = {
+ // 当前页面的标题
+ let cur-headings = query(
+ selector(heading.where(level: level)).after(loc),
+ ).filter(it => it.location().page() == loc.page())
+ if cur-headings.len() != 0 {
+ return cur-headings.first()
+ } else {
+ return none
+ }
+}
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/custom-numbering.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/custom-numbering.typ
new file mode 100644
index 0000000000..a5c88476a1
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/custom-numbering.typ
@@ -0,0 +1,30 @@
+// 一个简单的自定义 Numbering
+// 用法也简单,可以特殊设置一级等标题的样式,以及一个缺省值
+#let custom-numbering(base: 1, depth: 5, first-level: auto, second-level: auto, third-level: auto, format, ..args) = {
+ if (args.pos().len() > depth) {
+ return
+ }
+ if (first-level != auto and args.pos().len() == 1) {
+ if (first-level != "") {
+ numbering(first-level, ..args)
+ }
+ return
+ }
+ if (second-level != auto and args.pos().len() == 2) {
+ if (second-level != "") {
+ numbering(second-level, ..args)
+ }
+ return
+ }
+ if (third-level != auto and args.pos().len() == 3) {
+ if (third-level != "") {
+ numbering(third-level, ..args)
+ }
+ return
+ }
+ // default
+ if (args.pos().len() >= base) {
+ numbering(format, ..(args.pos().slice(base - 1)))
+ return
+ }
+}
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/custom-tablex.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/custom-tablex.typ
new file mode 100644
index 0000000000..29fe03bb0e
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/custom-tablex.typ
@@ -0,0 +1 @@
+#import "@preview/tablex:0.0.8": *
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/datetime-display.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/datetime-display.typ
new file mode 100644
index 0000000000..2012033950
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/datetime-display.typ
@@ -0,0 +1,9 @@
+// 显示中文日期
+#let datetime-display(date) = {
+ date.display("[year] 年 [month] 月 [day] 日")
+}
+
+// 显示英文日期
+#let datetime-en-display(date) = {
+ date.display("[month repr:short] [day], [year]")
+}
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/double-underline.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/double-underline.typ
new file mode 100644
index 0000000000..74e1dd5995
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/double-underline.typ
@@ -0,0 +1,11 @@
+// 双下划线
+#let double-underline(body) = style(styles => {
+ let size = measure(body, styles)
+ stack(
+ body,
+ v(3pt),
+ line(length: size.width),
+ v(2pt),
+ line(length: size.width),
+ )
+})
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/hline.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/hline.typ
new file mode 100644
index 0000000000..afd563c669
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/hline.typ
@@ -0,0 +1,4 @@
+// 一条水平横线
+#let hline() = {
+ line(length: 100%)
+}
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/invisible-heading.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/invisible-heading.typ
new file mode 100644
index 0000000000..f16fa80818
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/invisible-heading.typ
@@ -0,0 +1,5 @@
+// 用于创建一个不可见的标题,用于给 outline 加上短标题
+#let invisible-heading(..args) = {
+ set text(size: 0pt, fill: white)
+ heading(numbering: none, ..args)
+}
\ No newline at end of file
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/justify-text.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/justify-text.typ
new file mode 100644
index 0000000000..318027d131
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/justify-text.typ
@@ -0,0 +1,9 @@
+// 双端对其一段小文本,常用于表格的中文 key
+#let justify-text(with-tail: false, tail: ":", body) = {
+ if with-tail and tail != "" {
+ stack(dir: ltr, stack(dir: ltr, spacing: 1fr, ..body.split("").filter(it => it != "")), tail)
+ } else {
+ stack(dir: ltr, spacing: 1fr, ..body.split("").filter(it => it != ""))
+ }
+}
+
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/style.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/style.typ
new file mode 100644
index 0000000000..a2bdb44eb9
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/style.typ
@@ -0,0 +1,87 @@
+#let 字号 = (
+ 初号: 42pt,
+ 小初: 36pt,
+ 一号: 26pt,
+ 小一: 24pt,
+ 二号: 22pt,
+ 小二: 18pt,
+ 三号: 16pt,
+ 小三: 15pt,
+ 四号: 14pt,
+ 中四: 13pt,
+ 小四: 12pt,
+ 五号: 10.5pt,
+ 小五: 9pt,
+ 六号: 7.5pt,
+ 小六: 6.5pt,
+ 七号: 5.5pt,
+ 小七: 5pt,
+)
+
+#let 字体 = (
+ // 宋体,属于「有衬线字体」,一般可以等同于英文中的 Serif Font
+ // 这一行分别是「新罗马体(有衬线英文字体)」、「思源宋体(简体)」、「思源宋体」、「宋体(Windows)」、「宋体(MacOS)」
+ 宋体: (
+ (name: "Times New Roman", covers: "latin-in-cjk"),
+ "Source Han Serif SC",
+ "Source Han Serif",
+ "Noto Serif CJK SC",
+ "SimSun",
+ "Songti SC",
+ "STSongti",
+ ),
+
+ // 黑体,属于「无衬线字体」,一般可以等同于英文中的 Sans Serif Font
+ // 这一行分别是「Arial(无衬线英文字体)」、「思源黑体(简体)」、「思源黑体」、「黑体(Windows)」、「黑体(MacOS)」
+ 黑体: (
+ (name: "Arial", covers: "latin-in-cjk"),
+ "Source Han Sans HW SC",
+ "Source Han Sans",
+ "Noto Sans CJK SC",
+ "SimHei",
+ "Heiti SC",
+ "STHeiti",
+ ),
+
+ // 楷体
+ 楷体: (
+ (name: "Times New Roman", covers: "latin-in-cjk"),
+ "KaiTi",
+ "Kaiti SC",
+ "STKaiti",
+ "FZKai-Z03S",
+ "Noto Serif CJK SC",
+ ),
+
+ // 仿宋
+ 仿宋: (
+ (name: "Times New Roman", covers: "latin-in-cjk"),
+ "FangSong",
+ "FangSong SC",
+ "STFangSong",
+ "FZFangSong-Z02S",
+ "Noto Serif CJK SC",
+ ),
+
+ // 等宽字体,用于代码块环境,一般可以等同于英文中的 Monospaced Font
+ // 这一行分别是「Courier New(Windows 等宽英文字体)」、「思源等宽黑体(简体)」、「思源等宽黑体」、「黑体(Windows)」、「黑体(MacOS)」
+ 等宽: (
+ (name: "Courier New", covers: "latin-in-cjk"),
+ "Menlo",
+ "IBM Plex Mono",
+ "Source Han Sans HW SC",
+ "Source Han Sans HW",
+ "Noto Sans Mono CJK SC",
+ "SimHei",
+ "Heiti SC",
+ "STHeiti",
+ ),
+)
+
+// 定义中山大学规范颜色
+// 参考 http://home3.sysu.edu.cn/sysuvi/content/zaisheng/b/C-1-5.jpg
+#let sysucolor = (
+ green: cmyk(100%, 0%, 100%, 60%),
+ red: cmyk(30%, 100%, 100%, 50%),
+ black: cmyk(0%, 0%, 0%, 100%),
+)
diff --git a/packages/preview/modern-sysu-thesis/0.4.1/utils/unpairs.typ b/packages/preview/modern-sysu-thesis/0.4.1/utils/unpairs.typ
new file mode 100644
index 0000000000..6931e95bdb
--- /dev/null
+++ b/packages/preview/modern-sysu-thesis/0.4.1/utils/unpairs.typ
@@ -0,0 +1,8 @@
+// 将 pairs 数组转成 dict 字典
+#let unpairs(pairs) = {
+ let dict = (:)
+ for pair in pairs {
+ dict.insert(..pair)
+ }
+ dict
+}
\ No newline at end of file