-
Notifications
You must be signed in to change notification settings - Fork 0
/
lib.typ
306 lines (269 loc) · 8.62 KB
/
lib.typ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
// Dependencies
#import "@preview/physica:0.9.3": *
#import "@preview/cetz:0.2.2"
#import "@preview/whalogen:0.2.0": ce
// Global functions and variables
#let indent = h(1em)
// Author Metadata
#let author-meta(
..affiliation,
email: none,
alias: none,
address: none,
cofirst: false
) = {
let info = (
"affiliation": affiliation
)
if email != none {
info.insert("email", email)
}
if alias != none {
info.insert("name", alias)
}
if address != none {
info.insert("address", address)
}
if cofirst != none {
info.insert("cofirst", cofirst)
}
info // return info
}
// Title of Article
#let default-title(title) = {
show: block.with(width: 100%)
set align(left)
set text(font: "New Computer Modern Sans", weight: "bold", size: 12pt)
title
}
// Author Print
#let default-author(author) = {
h(0.5em)
set text(font: "New Computer Modern Sans", size: 12pt)
text(author.name)
super(author.insts.map(it => str(it+1)).join(","))
if author.corresponding {
footnote[
#if author.email != none {
[Electronic mail: #underline(author.email).]
}
]
}
if author.cofirst == "thefirst" {
footnote("cofirst-author-mark")
} else if author.cofirst == "cofirst" {
locate(loc => query(footnote.where(body: [cofirst-author-mark]), loc).last())
}
}
// Affiliation Print
#let default-affiliation(id, address) = {
h(0.5em)
set text(style: "italic", size: 12pt)
super([#(id+1)])
address
}
// Author info print
#let default-author-info(authors, affiliations) = {
{
show: block.with(width: 100%)
authors.map(it => default-author(it)).join(", ", last:text(font: "New Computer Modern Sans", size: 12pt)[, and])
}
let used_affiliations = authors.map(it => it.insts).flatten().dedup().map(it => affiliations.keys().at(it - 1))
{
show: block.with(width: 100%)
set par(leading: 0.4em)
used_affiliations.enumerate().map(((ik, key)) => {
default-affiliation(ik, affiliations.at(key))
}).join(linebreak())
}
}
// Abstract Print
#let default-abstract(abstract, keywords) = {
// Abstract and keyword block
if abstract != [] {
v(2em)
set text(font: "New Computer Modern", size: 12pt)
set par(justify: true, leading: 1.5em)
pad(left: 0.5em, right: 0.5em, [#indent #abstract])
pagebreak()
}
}
// Bibliography
#let default-bibliography(bib) = {
pagebreak()
align(left, text(size: 12pt, font: "New Computer Modern", weight: "bold")[References])
set bibliography(title: none, style: "american-physics-society")
bib
}
// Body of the text
#let default-body(body) = {
set text(font: "New Computer Modern", size: 12pt)
set par(
first-line-indent: 1em,
justify: true,
leading: 1.5em
)
show heading.where(level: 1): set heading(numbering: "I.")
show heading.where(level: 1): upper
show heading.where(level: 1): set text(size: 12pt)
show heading: set block(above: 2em, below: 2em)
//level 2
show heading.where(level: 2): set heading(numbering:( _ , last) => numbering("A.", last))
show heading.where(level: 2): set text(size: 12pt)
show heading: set block(above: 2em, below: 2em)
set footnote(numbering: "1")
// math numbering
show link: underline
show link: set text(font: "New Computer Modern Mono", fill: red)
set math.equation(numbering: "(1)")
body
}
#let article(
// Article's Title
title: "Article Title",
// A dictionary of authors.
// Dictionary keys are authors' names.
// Dictionary values are meta data of every author, including
// label(s) of affiliation(s), email, contact address,
// or a self-defined name (to avoid name conflicts).
// Once the email or address exists, the author(s) will be labelled
// as the corresponding author(s), and their address will show in footnotes.
//
// Example:
// (
// "Auther Name": (
// "affiliation": "affil-1",
// "email": "[email protected]", // Optional
// "address": "Mail address", // Optional
// "name": "Alias Name", // Optional
// "cofirst": false // Optional, identify whether this author is the co-first author
// )
// )
authors: ("Author Name": author-meta("affiliation-label")),
// A dictionary of affiliation.
// Dictionary keys are affiliations' labels.
// These labels show be constent with those used in authors' meta data.
// Dictionary values are addresses of every affiliation.
//
// Example:
// (
// "affiliation-label": "Institution Name, University Name, Road, Post Code, Country"
// )
affiliations: ("affiliation-label": "Affiliation address"),
// The paper's abstract.
abstract: [],
// The paper's keywords.
keywords: (),
// The bibliography. Accept value from the built-in `bibliography` function.
bib: none,
// Templates for the following parts:
// - `title`: how to show the title of this article.
// - `author-list`: how to show the list of the authors.
// - `author`: how to show each author's information.
// - `affiliation`: how to show the affiliations.
// - `abstract`: how to show the abstract and keywords.
// - `bibliography`: how to show the bibliography.
// - `body`: how to show main text.
// Please see below for more infomation.
template: (:),
// Paper's content
body
) = {
// Set document properties
set document(title: title, author: authors.keys())
show footnote.entry: it => [
#set par(hanging-indent: 0.54em)
#it.note #it.note.body
]
set footnote(numbering: "*")
show "cofirst-author-mark": [These authors contributed equally to this work.]
let template = (
title: default-title,
author-info: default-author-info,
abstract: default-abstract,
bibliography: default-bibliography,
body: default-body,
..template,
)
// Title block
(template.title)(title)
// set align(left)
// Restore affiliations' keys for looking up later
// to show superscript labels of affiliations for each author.
let inst_keys = affiliations.keys()
// Find co-fisrt authors
let cofirst_index = authors.values().enumerate().filter(
meta => "cofirst" in meta.at(1) and meta.at(1).at("cofirst") == true
).map(it => it.at(0))
let author_list = ()
// Authors and affiliations
// Authors' block
// Process the text for each author one by one
for (ai, au) in authors.keys().enumerate() {
let author_list_item = (
name: none,
insts: (),
corresponding: false,
cofirst: "no",
address: none,
email: none,
)
let au_meta = authors.at(au)
// Write auther's name
let aname = if au_meta.keys().contains("name") and au_meta.name != none {
au_meta.name
} else {
au
}
author_list_item.insert("name", aname)
// Get labels of author's affiliation
let au_inst_id = au_meta.affiliation.pos()
let au_inst_primary = ""
// Test whether the author belongs to multiple affiliations
if type(au_inst_id) == array {
// If the author belongs to multiple affiliations,
// record the first affiliation as the primary affiliation,
au_inst_primary = affiliations.at(au_inst_id.first())
// and convert each affiliation's label to index
let au_inst_index = au_inst_id.map(id => inst_keys.position(key => key == id))
// Output affiliation
author_list_item.insert("insts", au_inst_index)
} else if (type(au_inst_id) == str) {
// If the author belongs to only one affiliation,
// set this as the primary affiliation
au_inst_primary = affiliations.at(au_inst_id)
// convert the affiliation's label to index
let au_inst_index = inst_keys.position(key => key == au_inst_id)
// Output affiliation
author_list_item.insert("insts", (au_inst_index,))
}
// Corresponding author
if au_meta.keys().contains("email") or au_meta.keys().contains("address") {
author_list_item.insert("corresponding", true)
let address = if not au_meta.keys().contains("address") or au_meta.address == "" {
au_inst_primary
} else { au_meta.address }
author_list_item.insert("address", address)
let email = if au_meta.keys().contains("email") and au_meta.email != none {
au_meta.email
} else { none }
author_list_item.insert("email", email)
}
if cofirst_index.len() > 0 {
if ai == 0 {
author_list_item.insert("cofirst", "thefirst")
} else if cofirst_index.contains(ai) {
author_list_item.insert("cofirst", "cofirst")
}
}
author_list.push(author_list_item)
}
(template.author-info)(author_list, affiliations)
(template.abstract)(abstract, keywords)
show: template.body
body
// Display bibliography.
if bib != none {
(template.bibliography)(bib)
}
}