Skip to content

Commit e56a583

Browse files
authored
modern-hkust-thesis:0.1.0 (typst#3151)
1 parent 4b73387 commit e56a583

File tree

12 files changed

+851
-0
lines changed

12 files changed

+851
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 jlu625
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
Typst is a next-generation typesetting system, designed as a modern alternative to LaTeX. Written in Rust, it offers the advantages of user-friendly syntax and fast compilation.
2+
3+
This template was created by me for my own graduation project, and it meets [all the formatting requirements of HKUST-GZ](https://fytgs.hkust-gz.edu.cn/wp-content/uploads/2025/09/Guidelines-on-Thesis-Preparation.pdf).
4+
If you find it useful, you can [buy me a ☕️ coffee here](https://www.buymeacoffee.com/jwangl5). Thanks! ☺️
5+
If you encounter any issues, feel free to open a ticket in the issue tracker.
6+
Contributions are also welcome.
7+
8+
---
9+
10+
### Usage
11+
12+
+ You can use `vscode` and its plugins `Tinymist` to setup environment easily. Just download, then ready to use.
13+
14+
+ Clone this repo to your local directory,
15+
```git
16+
git clone http://gitlab.hkust-gz.edu.cn/jlu625/typst-thesis-template.git
17+
```
18+
19+
Or directly import this template from `@preview` package name domain.
20+
```typst
21+
#import "@preview/modern-hkust-thesis:0.1.0": thesis
22+
```
23+
24+
+ Open the folder with vscode, then you could modify the `sample.typ` file to finish your thesis.
25+
26+
+ I have already written enough comments in sample file to make sure you could understand how to modify the text with your own info, feel free to modify the text and preview what you got (shortcut key `ctrl+k v`).
27+
28+
+ If you have problems in using `typst`, you can read [official documents here](https://typst.app/docs/).
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#import "@preview/titleize:0.1.1": titlecase
2+
3+
#let stringify(text) = {
4+
if type(text) == str {
5+
return text
6+
}
7+
if "text" in text.fields() {
8+
return text.text
9+
}
10+
panic("Cannot stringify")
11+
}
12+
13+
#let get(short) = {
14+
let key = stringify(short)
15+
let entry = state("abbr", (:)).get().at(key, default:none)
16+
return (key, entry)
17+
}
18+
19+
#let warn(short) = [*(?? #short ??)*]
20+
21+
#let style-default(short) = {
22+
let val = if text.weight <= "medium" { 15% } else { 30% }
23+
set text(fill: black.lighten(val))
24+
show: strong
25+
short
26+
}
27+
28+
#let space-default = sym.space.nobreak.narrow
29+
30+
#let mark-first(key, dct) = {
31+
if not dct.frst { return }
32+
dct.frst=false
33+
state("abbr").update(it=>{
34+
it.insert(key, dct)
35+
return it
36+
})
37+
}
38+
39+
#let mark-used(key, dct) = {
40+
if dct.list { return }
41+
dct.list = true
42+
state("abbr").update(it=>{
43+
it.insert(key, dct)
44+
return it
45+
})
46+
}
47+
48+
/// add single entry
49+
#let add(short, ..entry) = context {
50+
let long = entry.at(0)
51+
let plural = entry.at(1, default:none)
52+
let (key, entry) = get(short)
53+
if entry == none { // do not update blindly, it'd reset the counter
54+
state("abbr").update(it => {
55+
let item = (
56+
l: long,
57+
pl: plural,
58+
lbl: label(short + sym.hyph.point + long),
59+
frst: true,
60+
list: false,
61+
)
62+
it.insert(short, item)
63+
return it
64+
})
65+
}
66+
}
67+
68+
/// add list of entries
69+
#let make(..lst) = for (..abbr) in lst.pos() { add(..abbr) }
70+
71+
/// add abbreviations from csv file
72+
#let load(..filename, delimiter:",") = {
73+
let notempty(s) = { return s != "" }
74+
let entries = read(..filename).split("\n")
75+
.filter(notempty)
76+
.map(entry => csv(bytes(entry),delimiter:delimiter)
77+
.flatten().map(str.trim).filter(notempty)
78+
)
79+
make(..entries)
80+
}
81+
82+
/// short form of abbreviation with link
83+
#let s(short) = context {
84+
let (key, dct) = get(short)
85+
if dct == none { return warn(short) }
86+
mark-used(key, dct)
87+
let styleit = state("abbr-style", style-default).get()
88+
if query(dct.lbl).len() != 0 {
89+
link(dct.lbl, styleit(key))
90+
} else {
91+
styleit(key)
92+
}
93+
}
94+
95+
/// long form of abbreviation
96+
#let l(short) = context {
97+
let (key, dct) = get(short)
98+
if dct == none { return warn(short) }
99+
mark-first(key, dct)
100+
dct.l
101+
state("abbr-space", space-default).get()
102+
sym.paren.l
103+
sym.zwj
104+
s(key)
105+
sym.zwj
106+
sym.paren.r
107+
}
108+
109+
/// long form _only_
110+
#let lo(short) = context {
111+
let dct = get(short).at(1)
112+
if dct == none { return warn(short) }
113+
dct.l
114+
}
115+
116+
/// automatic short/long form
117+
#let a(short) = context {
118+
let (key, dct) = get(short)
119+
if dct == none { return warn(short); }
120+
if dct.frst { l(key) }
121+
else { s(key) }
122+
}
123+
124+
/// short form plural
125+
#let pls(short) = context {
126+
let styleit = state("abbr-style", style-default).get()
127+
[#s(short)#styleit[s]]
128+
}
129+
130+
/// long form plural
131+
#let pll(short) = context {
132+
let (key, dct) = get(short)
133+
if dct == none { return warn(short) }
134+
mark-first(key, dct)
135+
if dct.pl != none {
136+
dct.pl
137+
} else {
138+
[#dct.l\s]
139+
}
140+
state("abbr-space", space-default).get()
141+
sym.paren.l
142+
sym.zwj
143+
pls(key)
144+
sym.zwj
145+
sym.paren.r
146+
}
147+
148+
/// long form plural _only_
149+
#let pllo(short) = context {
150+
let dct = get(short).at(1)
151+
if dct == none { return warn(short) }
152+
if dct.pl != none {
153+
dct.pl
154+
} else {
155+
[#dct.l\s]
156+
}
157+
}
158+
159+
/// automatic short/long form plural
160+
#let pla(short) = context {
161+
let (key, dct) = get(short)
162+
if dct == none { return warn(short); }
163+
if dct.frst { pll(key) }
164+
else { pls(key) }
165+
}
166+
167+
/// create list of abbreviations
168+
#let list(
169+
title: [List of Abbreviations],
170+
col: 2,
171+
) = context {
172+
let lst = state("abbr", (:)).final().pairs()
173+
.filter(it => it.at(1).list)
174+
.map(pair => (s: pair.at(0), l: titlecase(pair.at(1).l), lbl: pair.at(1).lbl))
175+
.sorted(key: it => it.s)
176+
if lst.len() == 0 { return }
177+
let styleit = state("abbr-style", style-default).get()
178+
let make-entry(e) = (styleit[#e.s #e.lbl], e.l)
179+
if col == 2 {
180+
let n = int(lst.len()/2)
181+
let last = if calc.odd(lst.len()) {lst.remove(n)}
182+
lst = lst.slice(0, n).zip(lst.slice(n)).flatten()
183+
if last != none { lst.push(last) }
184+
} else if col != 1 {
185+
panic("abbr.list only supports 1 or 2 columns")
186+
}
187+
heading(numbering: none, title)
188+
columns(col)[
189+
#table(
190+
columns: (auto, 1fr),
191+
stroke:none,
192+
..for entry in lst { make-entry(entry) }
193+
)
194+
]
195+
196+
}
197+
198+
/// configure styling of abbreviations
199+
#let config(style: auto, space-char: sym.space.nobreak.narrow) = {
200+
state("abbr-style", style-default).update(it => {
201+
if style == auto {
202+
return style-default
203+
}
204+
return style
205+
})
206+
state("abbr-space", space-default).update(it => space-char)
207+
}

0 commit comments

Comments
 (0)