Typst-Snippets/lapreprint.typ

399 lines
12 KiB
Plaintext

#import "@preview/i-figured:0.2.3"
#let count-words(it) = {
let fn = repr(it.func())
if fn == "sequence" { it.children.map(count-words).sum() }
else if fn == "heading" { count-words(it.body) }
else if fn == "figure" { count-words(it.caption.body) }
else if fn == "text" { it.text.split().len() }
else if fn in ("styled") { count-words(it.child) }
else if fn in ("highlight", "item", "strong", "link") { count-words(it.body) }
else if fn == "equation" { 1 }
else { 0 }
}
#let lapreprint(
// The paper's title.
title: "Paper Title",
subtitle: none,
// An array of authors. For each author you can specify a name, orcid, and affiliations.
// affiliations should be content, e.g. "1", which is shown in superscript and should match the affiliations list.
// Everything but but the name is optional.
authors: (),
// This is the affiliations list. Include an id and `name` in each affiliation. These are shown below the authors.
affiliations: (),
// The paper's abstract. Can be omitted if you don't have one.
abstract: none,
// The short-title is shown in the running header
short-title: none,
// The short-citation is shown in the running header, if set to auto it will show the author(s) and the year in APA format.
short-citation: auto,
// The venue is show in the footer
venue: none,
// An image path that is shown in the top right of the page. Can also be content.
logo: none,
// A DOI link, shown in the header on the first page. Should be just the DOI, e.g. `10.10123/123456` ,not a URL
doi: none,
heading-numbering: "1.a.i",
// Show an Open Access badge on the first page, and support open science, default is true, because that is what the default should be.
open-access: true,
// A list of keywords to display after the abstract
keywords: (),
// The "kind" of the content, e.g. "Original Research", this is shown as the title of the margin content on the first page.
kind: none,
// Content to put on the margin of the first page
// Should be a list of dicts with `title` and `content`
margin: (),
paper-size: "us-letter",
// A color for the theme of the document
theme: blue.darken(30%),
// Date published, for example, when you publish your preprint to an archive server.
// To hide the date, set this to `none`. You can also supply a list of dicts with `title` and `date`.
date: datetime.today(),
// Feel free to change this, the font applies to the whole document
font-face: "Noto Sans",
// The path to a bibliography file if you want to cite some external works.
bibliography-file: none,
bibliography-style: "apa",
// The outline
outline-show: true,
outline-depth: 2,
// Language of the document
lang: "en",
// The paper's content.
body
) = {
/* Logos */
let orcidSvg = ```<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 24 24"> <path fill="#AECD54" d="M21.8,12c0,5.4-4.4,9.8-9.8,9.8S2.2,17.4,2.2,12S6.6,2.2,12,2.2S21.8,6.6,21.8,12z M8.2,5.8c-0.4,0-0.8,0.3-0.8,0.8s0.3,0.8,0.8,0.8S9,7,9,6.6S8.7,5.8,8.2,5.8z M10.5,15.4h1.2v-6c0,0-0.5,0,1.8,0s3.3,1.4,3.3,3s-1.5,3-3.3,3s-1.9,0-1.9,0H10.5v1.1H9V8.3H7.7v8.2h2.9c0,0-0.3,0,3,0s4.5-2.2,4.5-4.1s-1.2-4.1-4.3-4.1s-3.2,0-3.2,0L10.5,15.4z"/></svg>```.text
let spacer = text(fill: gray)[#h(8pt) | #h(8pt)]
let dates;
if (type(date) == "datetime") {
dates = ((title: "Published", date: date),)
}else if (type(date) == "dictionary") {
dates = (date,)
} else {
dates = date
}
date = dates.at(0).date
// Create a short-citation, e.g. Cockett et al., 2023
let year = if (date != none) { ", " + date.display("[year]") }
if (short-citation == auto and authors.len() == 1) {
short-citation = authors.at(0).name.split(" ").last() + year
} else if (short-citation == auto and authors.len() == 2) {
short-citation = authors.at(0).name.split(" ").last() + " & " + authors.at(1).name.split(" ").last() + year
} else if (short-citation == auto and authors.len() > 2) {
short-citation = authors.at(0).name.split(" ").last() + " " + emph("et al.") + year
}
// Set document metadata.
set document(title: title, author: authors.map(author => author.name))
if short-title == none { short-title = title }
set page(
paper-size,
margin: (left: 20%, bottom: 1.5cm),
header: locate(loc => {
if(loc.page() == 1) {
let headers = (
if (open-access) {smallcaps[Open Access]},
if (doi != none) { link("https://doi.org/" + doi, "https://doi.org/" + doi)}
)
return align(left, text(size: 8pt, fill: gray, headers.filter(header => header != none).join(spacer)))
} else {
return align(right, text(size: 8pt, fill: gray.darken(50%),
(short-title, short-citation).join(spacer)
))
}
}),
footer: block(
width: 100%,
stroke: (top: 1pt + gray),
inset: (top: 8pt, right: 2pt),
[
#grid(columns: (75%, 25%),
align(left, text(size: 9pt, fill: gray.darken(50%),
(
if(venue != none) {emph(venue)},
if(date != none) {
if (lang == "en") {
date.display("[month repr:short] [day], [year]")
} else {
[#date.year() 年 #date.month() 月 #date.day() 日]
}
}
).filter(t => t != none).join(spacer)
)),
align(right)[
#text(
size: 9pt, fill: gray.darken(50%)
)[
#counter(page).display() of #locate((loc) => {counter(page).final(loc).first()})
]
]
)
]
)
)
// Set the body font.
set text(font: font-face, size: 10pt)
// Configure lists.
set enum(indent: 10pt, body-indent: 9pt)
set list(indent: 10pt, body-indent: 9pt)
// Configure i-figured
show figure: i-figured.show-figure
show figure.where(
kind: table
): set figure.caption(position: top)
show math.equation: i-figured.show-equation
// Configure Reference Link
show link: it => [#text(fill: theme)[#it]]
show ref: it => [#text(fill: theme)[#it]]
show ref: it => {
let el = it.element
if (el != none) {
let fn = repr(el.func())
if (fn == "equation") {link(
it.target,
if (lang == "en") {"Eq."} else {"式 "} +
numbering(
el.numbering,
..counter(math.equation).at(el.location())
)
)} else if (fn == "heading") {link(
it.target,
if (lang == "en") {"Section "} else {"第 "} +
numbering(
el.numbering,
..counter(heading).at(el.location())
) + if (lang == "zh") {" 节"}
)}
else { it }
} else {it}
}
// Configure headings.
set heading(numbering: heading-numbering)
show heading: it => locate(loc => {
// Find out the final number of the heading counter.
let levels = counter(heading).at(loc)
set text(10pt, weight: 400)
if it.level == 1 [
// First-level headings are centered smallcaps.
// We don't want to number of the acknowledgment section.
#let is-ack = it.body in ([Acknowledgment], [Acknowledgement])
// #set align(center)
#set text(if is-ack { 10pt } else { 12pt })
#show: smallcaps
#v(20pt, weak: true)
#if it.numbering != none and not is-ack {
numbering(heading-numbering, ..levels)
h(7pt, weak: true)
}
#it.body
#v(13.75pt, weak: true)
#for kind in (image, table, raw) {
counter(figure.where(kind: "i-figured-" + repr(kind))).update(0)
}
#counter(math.equation).update(0)
] else if it.level == 2 [
// Second-level headings are run-ins.
#set par(first-line-indent: 0pt)
#v(10pt, weak: true)
#if it.numbering != none {
numbering(heading-numbering, ..levels)
h(7pt, weak: true)
}
#it.body
#v(10pt, weak: true)
] else if it.level == 3 [
#set par(first-line-indent: 0pt)
#v(10pt, weak: true)
#if it.numbering != none {
numbering(heading-numbering, ..levels)
}
#it.body
#v(10pt, weak: true)
] else [
// Fourth level headings are run-ins too, but different.
#set par(first-line-indent: 0pt)
#if it.level >= 4 {
numbering(heading-numbering, ..levels)
}
#it.body
]
})
if (logo != none) {
place(
top,
dx: -33%,
float: false,
box(
width: 27%,
{
if (type(logo) == "content") {
logo
} else {
image(logo, width: 100%)
}
},
),
)
}
// Title and subtitle
box(inset: (bottom: 2pt), text(17pt, weight: "bold", fill: theme, title))
if subtitle != none {
parbreak()
box(text(14pt, fill: gray.darken(30%), subtitle))
}
// Authors and affiliations
linebreak()
if authors.len() > 0 {
box(inset: (y: 10pt), {
authors.map(author => {
text(11pt, weight: "semibold", author.name)
h(1pt)
if "affiliations" in author {
super(author.affiliations)
}
if "orcid" in author {
link("https://orcid.org/" + author.orcid)[#box(height: 1.1em, baseline: 13.5%)[#image.decode(orcidSvg)]]
}
}).join(", ", last: ", and ")
})
}
if affiliations.len() > 0 {
linebreak()
box(inset: (bottom: 10pt), {
affiliations.map(affiliation => {
super(affiliation.id)
h(1pt)
affiliation.name
}).join(", ")
})
}
place(
left + bottom,
dx: -25%,
dy: -10pt,
box(width: 22%, {
if (kind != none) {
show par: set block(spacing: 0em)
text(11pt, fill: theme, weight: "semibold", smallcaps(kind))
parbreak()
}
if (dates != none) {
let formatted-dates
grid(columns: (40%, 60%), gutter: 7pt,
..dates.zip(range(dates.len())).map((formatted-dates) => {
let d = formatted-dates.at(0);
let i = formatted-dates.at(1);
return (
if (i == 0){
strong[#text(size: 7pt, fill: theme, d.title)]
} else {
text(size: 7pt, fill: theme, d.title)
},
if (lang == "en") {
text(size: 7pt, d.date.display("[month repr:short] [day], [year]"))
} else {[
#set text(7pt)
#d.date.year()-#d.date.month()-#d.date.day()
]}
)
}).flatten()
)
}
v(2em)
grid(columns: 1, gutter: 2em, ..margin.map(side => {
text(size: 7pt, {
if ("title" in side) {
text(fill: theme, weight: "bold", side.title)
[\ ]
}
set enum(indent: 0.1em, body-indent: 0.25em)
set list(indent: 0.1em, body-indent: 0.25em)
side.content
})
}))
}),
)
let abstracts
if (type(abstract) == "content") {
abstracts = (title: "Abstract", content: abstract)
} else {
abstracts = abstract
}
if abstracts != none {
box(inset: (top: 16pt, bottom: 16pt), stroke: (top: 1pt + gray, bottom: 1pt + gray), {
abstracts.map(abs => {
set par(justify: true)
text(fill: theme, weight: "semibold", size: 9pt, abs.title)
parbreak()
abs.content
}).join(parbreak())
})
if (keywords.len() > 0) {
text(size: 9pt, {
if (lang == "en") {
text(fill: theme, weight: "semibold", "Keywords")
} else {
text(fill: theme, weight: "semibold", "关键词")
}
h(8pt)
keywords.join(", ")
})
}
v(10pt)
}
if (outline-show) {outline(
title: if (lang == "en") {"Content"} else {"目录"},
indent: 2em,
depth: outline-depth,
)}
pagebreak()
// Display the paper's contents.
show par: set block(spacing: 1.5em)
set page(
margin: (left: auto, bottom: 1.5cm),
)
// show: rest => {
// let n = count-words(rest)
// if (lang == "en") {
// rest + align(right, [(#n words)])
// } else {
// rest + align(right, [(#n 字)])
// }
// }
body
if (bibliography-file != none) {
show bibliography: set text(8pt)
bibliography(bibliography-file, title: text(10pt, "References"), style: bibliography-style)
}
}