feat(run-liners): initial implementation

This commit is contained in:
swaits committed 2025-01-07 22:52:47 -07:00
1 parent df889d8d72
commit 5d8eb4763e
15 files changed
+1028

No files matched your search

Binary file not shown.
+472
View File
@@ -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!