473 lines
10 KiB
Typst
473 lines
10 KiB
Typst
#import "/lib.typ": *
|
||
|
||
#import "@preview/codly:1.1.1": *
|
||
#import "@preview/codly-languages:0.1.1": *
|
||
#show: codly-init.with()
|
||
#codly(languages: codly-languages)
|
||
|
||
#set page(width: 8.5in, height: 11in, margin: 1in, numbering: "1",
|
||
header: [#h(1fr) Version: `0.1.0`])
|
||
#set par(justify: true)
|
||
#show raw.where(block: true): set text(size:7pt)
|
||
|
||
#let easy-typography(
|
||
body-size: 10pt,
|
||
body-font: "Source Serif Pro",
|
||
heading-font: "Source Sans Pro",
|
||
paper: none,
|
||
margin: none,
|
||
body
|
||
) = {
|
||
// Constants
|
||
let heading-above-max = 1.25em
|
||
let heading-above-min = 0.75em
|
||
let heading-below-max = 0.65em
|
||
let heading-below-min = 0.52em
|
||
let heading-size-max = 1.10em
|
||
let heading-size-min = 1.00em
|
||
let body-weight = "light"
|
||
let line-spacing = 1.25
|
||
let paragraph-spacing = 2.00
|
||
|
||
// Optional page setup
|
||
if paper != none {
|
||
set page(paper: paper)
|
||
}
|
||
if margin != none {
|
||
set page(margin: margin)
|
||
}
|
||
|
||
// Paragraphs
|
||
set par(
|
||
leading: line-spacing * 0.5em,
|
||
spacing: paragraph-spacing * 0.5em,
|
||
justify: true,
|
||
linebreaks: "optimized",
|
||
)
|
||
|
||
// Body text
|
||
set text(
|
||
font: body-font,
|
||
fallback: false,
|
||
style: "normal",
|
||
weight: body-weight,
|
||
stretch: 100%,
|
||
size: body-size,
|
||
tracking: 0pt,
|
||
spacing: 100% + 0pt,
|
||
baseline: 0pt,
|
||
overhang: true,
|
||
hyphenate: true,
|
||
kerning: true,
|
||
ligatures: true,
|
||
number-type: "lining",
|
||
)
|
||
|
||
// Top-heavy easing function for heading sizes/spacing:
|
||
// - max = biggest size (H1), min = smallest size (H5), level in [1..5]
|
||
// - sqrt(t) => gives biggest decrease at top, gentlest at bottom
|
||
let compute-size(max, min, level) = {
|
||
if level <= 1 {
|
||
max
|
||
} else if level >= 5 {
|
||
min
|
||
} else {
|
||
let t = (level - 1) / 4
|
||
max - (max - min) * calc.sqrt(t)
|
||
}
|
||
}
|
||
|
||
// Heading weight logic
|
||
let compute-weight(level) = {
|
||
if level <= 1 {
|
||
"bold"
|
||
} else if level == 2 {
|
||
"semibold"
|
||
} else if level == 3 {
|
||
"medium"
|
||
} else {
|
||
"regular"
|
||
}
|
||
}
|
||
|
||
// Show headings using computed size/spacing values
|
||
show heading: it => block(
|
||
breakable: false,
|
||
sticky: true,
|
||
above: compute-size(heading-above-max, heading-above-min, it.level),
|
||
below: compute-size(heading-below-max, heading-below-min, it.level),
|
||
text(
|
||
font: heading-font,
|
||
size: compute-size(heading-size-max, heading-size-min, it.level),
|
||
weight: compute-weight(it.level),
|
||
it
|
||
)
|
||
)
|
||
|
||
// Finally, render the body
|
||
body
|
||
}
|
||
|
||
#show: easy-typography
|
||
|
||
#text(
|
||
size: 3em,
|
||
weight: "black",
|
||
font: "Source Sans Pro",
|
||
[`run-liners`: User Manual]
|
||
)
|
||
|
||
#v(1fr)
|
||
|
||
#outline(depth: 1)
|
||
|
||
#pagebreak()
|
||
|
||
|
||
#set heading(numbering: "1.1.")
|
||
|
||
= Introduction
|
||
|
||
This package provides a set of functions that create “run-in” lists and enumerations, following guidelines similar to the *Chicago Manual of Style*. You can produce run-in enumerations, bullet lists, terms/definitions, or verses, all joined in a single line with flexible separators and optional words like “and,” “or,” or _none_ (i.e. omit a coordinator).
|
||
|
||
We’ll illustrate each function using
|
||
#run-in-terms(
|
||
coordinator: "and",
|
||
([the left column], [a `typst` block containing the Typst code you’d write]),
|
||
([the right column], [the rendered result]),
|
||
).
|
||
|
||
= `run-in-enum`: Run-in numbered lists
|
||
`run-in-enum` is typically used for run-in enumerations like “(1) apple, (2) banana, and (3) cherry.” It offers these parameters:
|
||
|
||
- *`separator`*: Defaults to `"auto"` (which tries to detect commas and switch to semicolons).
|
||
- *`coordinator`*: The word or phrase before the last item—defaults to `"and"`, can be `"or"`, `"and/or"`, or `none`.
|
||
- *`numbering-pattern`*: A pattern like `"(1)"`, `"(A)"`, or any format the `numbering()` call supports.
|
||
- *`numbering-formatter`*: A function that can style or transform the generated number.
|
||
|
||
|
||
|
||
== Example: Basic Three-Item Enumeration
|
||
|
||
#columns(2)[
|
||
```typst
|
||
#run-in-enum(
|
||
[Apple],
|
||
[Banana],
|
||
[Cherry]
|
||
)
|
||
```
|
||
#colbreak()
|
||
|
||
#run-in-enum(
|
||
[Apple],
|
||
[Banana],
|
||
[Cherry]
|
||
)
|
||
]
|
||
|
||
This example uses *all defaults*:
|
||
- `separator: "auto"` → because there’s no comma in the content, it uses commas.
|
||
- `coordinator: "and"` → puts “and” before the last item.
|
||
- `numbering-pattern: "(1)"` → “(1) (2) (3)”
|
||
- `numbering-formatter: (it) => [#it]` → no special styling.
|
||
|
||
|
||
|
||
== Example: Coordinator = none, 4 Items, Comma in content
|
||
|
||
If one of your items contains `[text, with comma]`, the `auto` separator chooses `"; "`.
|
||
|
||
#columns(2)[
|
||
```typst
|
||
#run-in-enum(
|
||
coordinator: none,
|
||
[Item One],
|
||
[Item Two, comma here],
|
||
[Item Three],
|
||
[Item Four]
|
||
)
|
||
```
|
||
#colbreak()
|
||
|
||
#run-in-enum(
|
||
coordinator: none,
|
||
[Item One],
|
||
[Item Two, comma here],
|
||
[Item Three],
|
||
[Item Four]
|
||
)
|
||
]
|
||
|
||
Notice it used semicolons because of comma detection, *and* no coordinator word (because `coordinator: none`).
|
||
|
||
== Example: Custom Numbering Pattern & Styling
|
||
|
||
#block(breakable: false)[
|
||
You can change `numbering-pattern` to `"(A)"` or `"(i)"` and style the numbers with `numbering-formatter`.
|
||
|
||
#columns(2)[
|
||
```typst
|
||
#run-in-enum(
|
||
numbering-pattern: "(A)",
|
||
numbering-formatter: (txt) => [#strong(txt)],
|
||
[Alpha],
|
||
[Beta],
|
||
[Gamma]
|
||
)
|
||
```
|
||
#colbreak()
|
||
|
||
#run-in-enum(
|
||
numbering-pattern: "(A)",
|
||
numbering-formatter: (txt) => [#strong(txt)],
|
||
[Alpha],
|
||
[Beta],
|
||
[Gamma]
|
||
)
|
||
]
|
||
Here, `(A)`, `(B)`, `(C)` appear in *bold*.
|
||
]
|
||
|
||
== Example: Single Item & Two Items Edge Cases
|
||
|
||
When only one item is present, no separator or coordinator is used. With two items, you’ll see just one separator plus “and/or/or” (depending on coordinator).
|
||
|
||
#columns(2)[
|
||
```typst
|
||
// Single item:
|
||
#run-in-enum([LoneItem])
|
||
```
|
||
#colbreak()
|
||
#run-in-enum([LoneItem])
|
||
]
|
||
#columns(2)[
|
||
```typst
|
||
// Two items:
|
||
#run-in-enum([First], [Second])
|
||
```
|
||
#colbreak()
|
||
#run-in-enum([First], [Second])
|
||
]
|
||
#columns(2)[
|
||
|
||
```typst
|
||
// Two items, no coordinator:
|
||
#run-in-enum(coordinator: none, [First], [Second])
|
||
```
|
||
#colbreak()
|
||
#run-in-enum(coordinator: none, [First], [Second])
|
||
]
|
||
#columns(2)[
|
||
|
||
```typst
|
||
// Three items:
|
||
#run-in-enum([First], [Second], [Third])
|
||
```
|
||
#colbreak()
|
||
#run-in-enum([First], [Second], [Third])
|
||
]
|
||
#columns(2)[
|
||
|
||
```typst
|
||
// Three items, no coordinator:
|
||
#run-in-enum(coordinator: none, [First], [Second], [Third])
|
||
```
|
||
#colbreak()
|
||
#run-in-enum(coordinator: none, [First], [Second], [Third])
|
||
]
|
||
|
||
|
||
|
||
= `run-in-list`: Run-in bullet points
|
||
`run-in-list` behaves like `run-in-enum` but uses a *bullet (or any marker)* before each item. The rest of the logic is the same—`separator`, `coordinator`, etc.
|
||
See the “run-in-enum” section for *how `auto` detection* and *`coordinator`* work.
|
||
|
||
|
||
|
||
== Example1: Default Bullets
|
||
#columns(2)[
|
||
```typst
|
||
#run-in-list(
|
||
[Apple],
|
||
[Banana],
|
||
[Cherry]
|
||
)
|
||
```
|
||
#colbreak()
|
||
|
||
#run-in-list(
|
||
[Apple],
|
||
[Banana],
|
||
[Cherry]
|
||
)
|
||
]
|
||
|
||
You get bullets `[•]` for each item by default.
|
||
|
||
== Example: Custom Marker, Coordinator = 'or'
|
||
|
||
#block(breakable: false)[
|
||
#columns(2)[
|
||
```typst
|
||
#run-in-list(
|
||
coordinator: "or",
|
||
marker: [#sym.ballot.check],
|
||
[First],
|
||
[Second],
|
||
[Third, comma item]
|
||
)
|
||
```
|
||
#colbreak()
|
||
|
||
#run-in-list(
|
||
coordinator: "or",
|
||
marker: [#sym.ballot.check],
|
||
[First],
|
||
[Second],
|
||
[Third, comma item]
|
||
)
|
||
]
|
||
Because of the comma, it uses semicolons. The coordinator is now `"or"`.
|
||
]
|
||
|
||
= `run-in-terms`: Run-in term definitions
|
||
|
||
`run-in-terms` is for run-in *terms and definitions*. By default, each term is *bold* (`[#strong(term)]`) followed by the definition, and you still get the same *separator* and *coordinator* logic as in `run-in-enum`.
|
||
|
||
== Example: Three Terms, No Coordinator
|
||
|
||
#columns(2)[
|
||
```typst
|
||
#run-in-terms(
|
||
coordinator: none,
|
||
(
|
||
([Goal], [Summarize the prior research]),
|
||
([Methods], [Outline the approach]),
|
||
([Outcome], [Analyze the results])
|
||
)
|
||
)
|
||
```
|
||
#colbreak()
|
||
#run-in-terms(
|
||
coordinator: none,
|
||
([Goal], [Summarize the prior research]),
|
||
([Methods], [Outline the approach]),
|
||
([Outcome], [Analyze the results])
|
||
)
|
||
]
|
||
|
||
See how no “and” or “or” appears. It detects commas if they exist.
|
||
|
||
|
||
|
||
== Example: Custom Term Formatter
|
||
#columns(2)[
|
||
```typst
|
||
#run-in-terms(
|
||
term-formatter: (txt) => [#underline(txt)],
|
||
([Key], [Value 1]),
|
||
([Another Key], [Value 2])
|
||
)
|
||
```
|
||
#colbreak()
|
||
#run-in-terms(
|
||
term-formatter: (txt) => [#underline(txt)],
|
||
([Key], [Value 1]),
|
||
([Another Key], [Value 2])
|
||
)
|
||
]
|
||
|
||
Each term is underlined, with a colon after the term.
|
||
|
||
|
||
|
||
= `run-in-verse`: Run-in poetry lines
|
||
`run-in-verse` simply joins lines (verses) with a given *separator* (default: `[ /~]`), and no coordinator. It’s much simpler since you typically don’t want “and” in between lines of poetry.
|
||
|
||
== Example: Default Verse Joining
|
||
#columns(2)[
|
||
```typst
|
||
#run-in-verse(
|
||
[Line 1],
|
||
[Line 2],
|
||
[Line 3]
|
||
)
|
||
```
|
||
#colbreak()
|
||
#run-in-verse(
|
||
[Line 1],
|
||
[Line 2],
|
||
[Line 3]
|
||
)
|
||
]
|
||
|
||
== Example: Custom Separator
|
||
|
||
#block(breakable: false)[
|
||
#columns(2)[
|
||
```typst
|
||
// Overriding the default with a comma + space
|
||
#run-in-verse(
|
||
separator: ", ",
|
||
[Line A],
|
||
[Line B],
|
||
[Line C]
|
||
)
|
||
```
|
||
#colbreak()
|
||
#run-in-verse(
|
||
separator: ", ",
|
||
[Line A],
|
||
[Line B],
|
||
[Line C]
|
||
)
|
||
]
|
||
]
|
||
|
||
= Direct `run-in-join`
|
||
All these functions ultimately call *`run-in-join`*, which you can use yourself if you want to create custom transformations. You supply:
|
||
|
||
1. *`separator`* (or `"auto"` for comma detection).
|
||
2. *`coordinator`* or `none`.
|
||
3. A *spread* of content items (`..content`).
|
||
|
||
|
||
|
||
== Example: Using `run-in-join` Directly
|
||
#columns(2)[
|
||
```typst
|
||
#run-in-join(
|
||
coordinator: "and/or",
|
||
[First item],
|
||
[Second item],
|
||
[Third item, comma triggers semicolon],
|
||
[Final item]
|
||
)
|
||
```
|
||
#colbreak()
|
||
#run-in-join(
|
||
coordinator: "and/or",
|
||
[First item],
|
||
[Second item],
|
||
[Third item, comma triggers semicolon],
|
||
[Final item]
|
||
)
|
||
]
|
||
|
||
You can see that it inserts semicolons (auto detection) and “and/or” before the last item.
|
||
|
||
|
||
|
||
= Conclusion
|
||
That’s your tour of the *run-in* functions! Remember:
|
||
- If you want enumerations with `(1)` or `(A)` prefixes, use *`run-in-enum`*.
|
||
- For bullet lists, use *`run-in-list`*.
|
||
- For term–definition pairs, *`run-in-terms`*.
|
||
- For verse lines, *`run-in-verse`*.
|
||
- Or just call *`run-in-join`* yourself for custom needs.
|
||
|
||
Explore different *separators* (like `[ /~]`, `", "`, or `"; "`) and *coordinators* (`"and"`, `"or"`, `"none"`, etc.) to get the exact run-in style your text requires.
|
||
|
||
Happy Typst-ing!
|