feat(run-liners): initial implementation
This commit is contained in:
15 files changed
+1028
No files matched your search
Binary file not shown.
@@ -0,0 +1,472 @@
|
||||
#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!
|
||||
Reference in new issue
Block a user