Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
138566c506
|
||
|
|
fd4b7ceed6
|
No files matched your search
@@ -1,27 +1,13 @@
|
||||
image: alpine/edge
|
||||
packages:
|
||||
- git
|
||||
|
||||
secrets:
|
||||
- 88cce185-d2ec-4573-9546-e33f36f79bbf
|
||||
|
||||
environment:
|
||||
# repo and user names on both sr.ht and github
|
||||
REPO: typst-collection
|
||||
USER: swaits
|
||||
|
||||
sources:
|
||||
- git+ssh://git@git.sr.ht/~swaits/typst-collection
|
||||
tasks:
|
||||
- fetch-all-branches: |
|
||||
cd "$HOME/$REPO"
|
||||
git fetch origin '+refs/heads/*:refs/heads/*' '+refs/tags/*:refs/tags/*' --prune
|
||||
|
||||
- get-github-public-key: |
|
||||
ssh-keyscan -t rsa github.com >> "$HOME/.ssh/known_hosts"
|
||||
|
||||
- add-github-remote: |
|
||||
cd "$HOME/$REPO"
|
||||
git remote add github "git@github.com:$USER/$REPO.git"
|
||||
|
||||
- mirror-to-github: |
|
||||
cd "$HOME/$REPO"
|
||||
cd ~/typst-collection
|
||||
ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
|
||||
# Explicitly fetch all branches & tags
|
||||
git fetch origin '+refs/heads/*:refs/heads/*' '+refs/tags/*:refs/tags/*' --prune
|
||||
git remote add github git@github.com:swaits/typst-collection.git
|
||||
git push --mirror github
|
||||
@@ -11,8 +11,6 @@ links below to their main page.
|
||||
- [**codly-languages**](https://typst.app/universe/package/codly-languages): A
|
||||
set of language configurations for use with
|
||||
[codly](https://typst.app/universe/package/codly).
|
||||
- [easy-typography](https://typst.app/universe/package/easy-typography): Sets up
|
||||
sensible typography defaults.
|
||||
- [**glossy**](https://typst.app/universe/package/glossy): A very simple
|
||||
glossary system with easily customizable output.
|
||||
- [**rfc-vibe**](https://typst.app/universe/package/rfc-vibe): Bring RFC language
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
tests/**/out/
|
||||
tests/**/diff/
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Stephen Waits <steve@waits.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,65 +0,0 @@
|
||||
# Easy Typography for Typst
|
||||
|
||||
A Typst package that simplifies professional typography by providing sensible
|
||||
defaults and easy customization options. Focus on your content while ensuring
|
||||
beautiful, readable documents.
|
||||
|
||||
## Features
|
||||
|
||||
- 🎨 Precise heading scale with clear hierarchy
|
||||
- 📏 Optimal line height and paragraph spacing
|
||||
- 📖 Professional text justification and hyphenation
|
||||
- ⚖️ Balanced vertical rhythm throughout
|
||||
- ⚡ Simple configuration with reasonable defaults
|
||||
|
||||
## Usage
|
||||
|
||||
Basic usage with default settings:
|
||||
|
||||
```typst
|
||||
#import "@preview/easy-typography:0.1.0": *
|
||||
#show: easy-typography
|
||||
|
||||
= Your Document Title
|
||||
Your content here...
|
||||
```
|
||||
|
||||
Customized usage with specific fonts:
|
||||
|
||||
```typst
|
||||
#show: easy-typography.with(
|
||||
fonts: (
|
||||
heading: "Source Sans Pro",
|
||||
body: "Source Serif Pro"
|
||||
),
|
||||
body-size: 11pt,
|
||||
paper: "a4",
|
||||
margin: 2cm
|
||||
)
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
- `body-size`: Base size for body text (default: 10pt)
|
||||
- `fonts`: Dictionary specifying heading and body fonts
|
||||
- `heading`: Font for headings (default: "Libertinus Sans")
|
||||
- `body`: Font for body text (default: "Libertinus Serif")
|
||||
- `paper`: Paper size setting (optional)
|
||||
- `margin`: Page margin setting (optional)
|
||||
|
||||
## Example Output
|
||||
|
||||
The package automatically handles:
|
||||
|
||||
- Heading sizes with natural visual hierarchy (H1-H5)
|
||||
- Optimal spacing between elements
|
||||
- Professional text justification
|
||||
- Smart hyphenation
|
||||
- Consistent vertical rhythm
|
||||
|
||||
See the [example output](thumbnail.png) for more information and a complete
|
||||
example.
|
||||
|
||||
## License
|
||||
|
||||
MIT License - See [LICENSE](LICENSE) for details.
|
||||
@@ -1 +0,0 @@
|
||||
#import "src/main.typ": easy-typography
|
||||
@@ -1,29 +0,0 @@
|
||||
// Constants
|
||||
|
||||
// space above H1
|
||||
#let heading-above-max = 1.25em
|
||||
|
||||
// space above H5
|
||||
#let heading-above-min = 0.80em
|
||||
|
||||
// space below H1
|
||||
#let heading-below-max = 0.65em
|
||||
|
||||
// space below H5
|
||||
#let heading-below-min = 0.55em
|
||||
|
||||
// font size for H1
|
||||
#let heading-size-max = 1.10em
|
||||
|
||||
// font size for H5
|
||||
#let heading-size-min = 1.00em
|
||||
|
||||
// default text weight -- light is best for reading, and printers are fine with
|
||||
// it these days
|
||||
#let body-weight = "light"
|
||||
|
||||
// line spacing -- tight; efficient but still readable with good fonts
|
||||
#let line-spacing = 1.30
|
||||
|
||||
// paragraph spacing -- defaults to a double-space
|
||||
#let paragraph-spacing = 1.70
|
||||
@@ -1,102 +0,0 @@
|
||||
#import "constants.typ": *
|
||||
|
||||
/// The main function for easy typography setup.
|
||||
///
|
||||
/// - body-size (): The size of body text (default 10pt).
|
||||
/// - fonts (): A dictionary specifying heading/body fonts.
|
||||
/// - paper (str): The paper size to use (none to skip).
|
||||
/// - margin (): Margin for the page (none to skip).
|
||||
/// -> content
|
||||
#let easy-typography(
|
||||
body-size: 10pt,
|
||||
fonts: (heading: "Libertinus Sans", body: "Libertinus Serif"),
|
||||
paper: none,
|
||||
margin: none,
|
||||
body
|
||||
) = {
|
||||
// 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: fonts.body,
|
||||
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-width: "proportional",
|
||||
// number-type: "lining", // commented: intentionally left up to the font to choose
|
||||
)
|
||||
|
||||
show table: set text(number-width: "tabular")
|
||||
|
||||
/// Top-heavy easing function for heading sizes/spacing.
|
||||
///
|
||||
/// `sqrt(t)` gives biggest decrease at top, gentlest at bottom.
|
||||
///
|
||||
/// - max (length): Biggest size (H1)
|
||||
/// - min (length): Smallest size (H5)
|
||||
/// - level (length): From 1 to 5
|
||||
/// -> length
|
||||
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: fonts.heading,
|
||||
size: compute-size(heading-size-max, heading-size-min, it.level),
|
||||
weight: compute-weight(it.level),
|
||||
it
|
||||
)
|
||||
)
|
||||
|
||||
// Finally, render the body
|
||||
body
|
||||
}
|
||||
|
Before Width: | Height: | Size: 769 KiB |
@@ -1,125 +0,0 @@
|
||||
#import "/lib.typ": *
|
||||
|
||||
#import "@preview/codly:1.2.0": *
|
||||
#import "@preview/codly-languages:0.1.1": *
|
||||
#show: codly-init.with()
|
||||
#codly(languages: codly-languages)
|
||||
|
||||
#show: easy-typography.with(
|
||||
fonts: (heading: "Source Sans 3", body: "Source Serif 4"),
|
||||
)
|
||||
|
||||
= Introducing Easy Typography
|
||||
|
||||
#set heading(numbering: (..nums) => {
|
||||
numbering("1.1.", ..nums.pos().slice(1))
|
||||
})
|
||||
|
||||
The `easy-typography` package transforms complex typographic decisions into
|
||||
simple choices, letting you focus on your content while ensuring professional
|
||||
results. By adjusting the settings to match your specific needs, you can refine
|
||||
the aesthetic or adapt your layout for everything from casual reading to formal
|
||||
publication.
|
||||
|
||||
== Core Typography Features
|
||||
|
||||
The package manages:
|
||||
|
||||
#columns(2)[
|
||||
- Precise heading scale with a clear hierarchy
|
||||
- Optimal line height and paragraph spacing
|
||||
#colbreak()
|
||||
- Professional text justification and hyphenation
|
||||
- Balanced vertical rhythm throughout
|
||||
]
|
||||
|
||||
These features ensure that your document is both visually appealing and easy to
|
||||
read.
|
||||
|
||||
=== Type Formatting
|
||||
|
||||
This package automatically adjusts line spacing, paragraph spacing, and
|
||||
justification to maintain a clean layout. Headings are also carefully weighted
|
||||
to balance them against the body text, so you can focus on content rather than
|
||||
tweaking spacing and sizing. Standard formatting like *bold* and _italic_
|
||||
integrates seamlessly with `easy-typography`'s approach.
|
||||
|
||||
=== Heading Levels
|
||||
|
||||
The heading scale gracefully steps down, ensuring that each level remains
|
||||
distinct yet consistent. Behind the scenes, `easy-typography` calculates the
|
||||
ideal size for each heading, preserving a cohesive visual hierarchy as your
|
||||
document gets deeper. This approach supports manuals, academic papers, and any
|
||||
long-form text where structure matters. It also helps in shorter documents,
|
||||
guaranteeing a crisp layout with minimal effort.
|
||||
|
||||
== Why Typography Matters
|
||||
|
||||
Good typography isn't just about aesthetics. It's about effective communication.
|
||||
Well-designed text:
|
||||
|
||||
#columns(2)[
|
||||
- Improves reading comprehension
|
||||
- Reduces eye strain
|
||||
- Maintains reader engagement
|
||||
#colbreak()
|
||||
- Establishes visual hierarchy
|
||||
- Conveys professionalism
|
||||
]
|
||||
|
||||
Notice how this document's typography enhances readability. The justified text,
|
||||
proper hyphenation, and optimized line breaks create a clean, professional
|
||||
appearance. With each heading level, the user can quickly scan and digest
|
||||
important information.
|
||||
|
||||
== Example Usage and Output
|
||||
|
||||
#set heading(numbering: none)
|
||||
#show raw.where(block: true): set text(size: 7pt)
|
||||
|
||||
#grid(
|
||||
columns: (55%, auto),
|
||||
gutter: 1.0em,
|
||||
[
|
||||
// code
|
||||
```typst
|
||||
#import "@preview/easy-typography:0.1.0": *
|
||||
#show: easy-typography.with(
|
||||
fonts: (
|
||||
heading: "Source Sans Pro",
|
||||
body: "Source Serif Pro"
|
||||
),
|
||||
)
|
||||
|
||||
#lorem(6)
|
||||
= Level One
|
||||
#lorem(6)
|
||||
== Level Two
|
||||
#lorem(6)
|
||||
=== Level Three
|
||||
#lorem(6)
|
||||
==== Level Four
|
||||
#lorem(6)
|
||||
===== Level Five
|
||||
#lorem(6)
|
||||
```
|
||||
],
|
||||
box(
|
||||
stroke: 0.5pt + silver,
|
||||
inset: 0.5em,
|
||||
radius: 0.2em,
|
||||
[
|
||||
#lorem(6)
|
||||
= Level One
|
||||
#lorem(6)
|
||||
== Level Two
|
||||
#lorem(6)
|
||||
=== Level Three
|
||||
#lorem(6)
|
||||
==== Level Four
|
||||
#lorem(6)
|
||||
===== Level Five
|
||||
#lorem(6)
|
||||
]
|
||||
) // box
|
||||
)
|
||||
|
Before Width: | Height: | Size: 306 KiB |
@@ -1,10 +0,0 @@
|
||||
[package]
|
||||
name = "easy-typography"
|
||||
version = "0.1.0"
|
||||
entrypoint = "lib.typ"
|
||||
authors = ["Stephen Waits <steve@waits.net>"]
|
||||
license = "MIT"
|
||||
description = "Sets up sensible typography defaults."
|
||||
keywords = ["easy", "typography", "defaults"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
exclude = ["thumbnail.png", "tests"]
|
||||
@@ -41,7 +41,7 @@ different goals:
|
||||
### Import the package
|
||||
|
||||
```typst
|
||||
#import "@preview/glossy:0.5.1": *
|
||||
#import "@preview/glossy:0.4.1": *
|
||||
```
|
||||
|
||||
### Defining Glossary Terms
|
||||
@@ -186,9 +186,8 @@ Display the glossary using the `glossary()` function:
|
||||
|
||||
```typst
|
||||
#glossary(
|
||||
title: "Web Development Glossary", // Optional: defaults to Glossary theme:
|
||||
my-theme, // Optional: defaults to theme-academic
|
||||
sort: true, // Optional: whether or not to sort the glossary
|
||||
title: "Web Development Glossary", // Optional: defaults to Glossary
|
||||
theme: my-theme, // Optionaal: defaults to theme-twocol
|
||||
ignore-case: false, // Optional: ignore case when sorting terms
|
||||
groups: ("Web") // Optional: Filter to specific groups
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
// Returns:
|
||||
// dictionary: Normalized dictionary with all expected keys populated
|
||||
//
|
||||
// Panics:
|
||||
// Throws:
|
||||
// - If 'short' key is missing when using normal (non-abbreviated) syntax
|
||||
// - If 'short' value is not a string
|
||||
// - If 'short' value is an empty string
|
||||
@@ -97,7 +97,7 @@
|
||||
// Returns:
|
||||
// dictionary: The glossary entry associated with the key
|
||||
//
|
||||
// Panics:
|
||||
// Throws:
|
||||
// - If the key does not exist in the glossary
|
||||
//
|
||||
#let __get_entry(key) = {
|
||||
@@ -153,7 +153,7 @@
|
||||
//
|
||||
// Parameters:
|
||||
// key (string): The glossary entry key
|
||||
//
|
||||
//
|
||||
// Returns:
|
||||
// boolean: If the term is visible in the glossary (and the label is unique)
|
||||
//
|
||||
@@ -187,7 +187,7 @@
|
||||
// content: The fully formatted term, including optional article, capitalization,
|
||||
// usage tracking metadata, and the chosen form (short, long, or both).
|
||||
//
|
||||
#let __gls(key, modifiers: array, format-term: function, show-term: function, term-links: true) = {
|
||||
#let __gls(key, modifiers: array, show-term: function, term-links: true) = {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Check for illegal modifier combinations
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -248,6 +248,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
// get_term(mode): Returns the appropriate term string based on the mode.
|
||||
// mode is one of "short", "long", or "both".
|
||||
// - "short": Returns the short form.
|
||||
// - "long": Returns the long form.
|
||||
// - "both": Returns "Long form (short form)".
|
||||
// We rely on prior logic to ensure that when mode = "both" or "long", a long form is available.
|
||||
let get_term = (mode) => {
|
||||
let short_form = pluralize_term(entry.short, entry.plural)
|
||||
let long_form = pluralize_term(entry.long, entry.longplural) // none safe here
|
||||
if mode == "short" {
|
||||
// Just the short form.
|
||||
short_form
|
||||
} else if mode == "long" {
|
||||
// Just the long form.
|
||||
long_form
|
||||
} else {
|
||||
// mode == "both": "Long form (short form)".
|
||||
long_form + " (" + short_form + ")"
|
||||
}
|
||||
}
|
||||
|
||||
// get_article(mode): Returns the appropriate article string based on the mode.
|
||||
// - If wants_article is false, returns an empty string.
|
||||
// - If mode is "short", return the short article.
|
||||
@@ -316,33 +337,19 @@
|
||||
// Determine mode using the helper function
|
||||
let mode = determine_mode(wants_both, wants_long, wants_short, is_first_use, long_available)
|
||||
|
||||
// Pluralize (if requested)
|
||||
let short-form = pluralize_term(entry.short, entry.plural)
|
||||
let long-form = pluralize_term(entry.long, entry.longplural) // `none` safe here
|
||||
|
||||
// Apply format-term() to get the term
|
||||
let formatted-term = format-term(mode, short-form, long-form)
|
||||
if type(formatted-term) != "string" {
|
||||
// This is because we still need to capitalize the term, and we cannot do
|
||||
// that with content, thus requiring a string here.
|
||||
// TODO: consider if we want to capitalize *before* this. First intuition is
|
||||
// "no".
|
||||
panic("Your cutsom format-term() function must return a string.")
|
||||
}
|
||||
|
||||
// Get the article, then capitalize either the article or term (if requested)
|
||||
let (article, term) = capitalize_term(get_article(mode), formatted-term)
|
||||
// Get the article and term for the chosen mode, then apply capitalization if requested
|
||||
let (article, term) = capitalize_term(get_article(mode), get_term(mode))
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Construct and return the final output
|
||||
// ---------------------------------------------------------------------------
|
||||
context {
|
||||
let linked-term = if term-links and __has_glossary_entry(key) {
|
||||
link(label(key), term)
|
||||
let text = if term-links and __has_glossary_entry(key) {
|
||||
link(label(key), term)
|
||||
} else {
|
||||
term
|
||||
}
|
||||
[#article#show-term(linked-term)#metadata(term)#__term_label(key)]
|
||||
[#article#show-term(text)#metadata(term)#__term_label(key)]
|
||||
// |^^^^^^^|^^^^^^^^^ |^^^^^^^^ |^^^^^^^^^^^^
|
||||
// \_art. | | |
|
||||
// \_ apply user formatting function to the term
|
||||
@@ -377,48 +384,7 @@
|
||||
})
|
||||
.dedup(key: ((loc, page)) => page) // deduplicate by page
|
||||
.map(((loc, page)) => link(loc, page)) // create links
|
||||
.join(", ")
|
||||
}
|
||||
|
||||
// Formats a term string based on the specified mode.
|
||||
//
|
||||
// Given mode, long-form, and short-form, this function returns the formatted
|
||||
// term based on the mode. When mode is ...
|
||||
//
|
||||
// - "short" -> returns "short-form"
|
||||
// - "long" -> returns "long-form"
|
||||
// - "both" -> returns "short-form (long-form)"
|
||||
//
|
||||
// Parameters:
|
||||
// mode (string): The mode in which to format the term. Possible values are "short", "long", or "both".
|
||||
// short-form (string): The short form of the term.
|
||||
// long-form (string): The long form of the term.
|
||||
//
|
||||
// Returns:
|
||||
// string: The formatted term based on the specified mode.
|
||||
//
|
||||
#let __default-format-term(mode, short-form, long-form) = {
|
||||
if mode == "short" {
|
||||
short-form
|
||||
} else if mode == "long" {
|
||||
long-form
|
||||
} else {
|
||||
// mode assumed to be "both"
|
||||
long-form + " (" + short-form + ")"
|
||||
}
|
||||
}
|
||||
|
||||
// Styles a term to control its display in a document.
|
||||
//
|
||||
// Parameters:
|
||||
// term-body (content'ish): the unstyled output from __gls()
|
||||
//
|
||||
// Returns:
|
||||
// content: display ready content (assumed based on `term-body`)
|
||||
//
|
||||
#let __default-show-term(term-body) = {
|
||||
// Default: just render it like normal text
|
||||
term-body
|
||||
.join(", ")
|
||||
}
|
||||
|
||||
// Initializes the glossary system and sets up term reference handling.
|
||||
@@ -441,13 +407,12 @@
|
||||
// Returns:
|
||||
// content: Processed document content with glossary functionality enabled
|
||||
//
|
||||
// Panics:
|
||||
// Throws:
|
||||
// - If entries parameter is not a dictionary
|
||||
//
|
||||
#let init-glossary(
|
||||
entries,
|
||||
format-term: __default-format-term,
|
||||
show-term: __default-show-term,
|
||||
show-term: (term-body) => term-body,
|
||||
term-links: true,
|
||||
body
|
||||
) = context {
|
||||
@@ -458,7 +423,6 @@
|
||||
let checked-entry = z.parse(entry, dict-schema, scope: ("dictionary entry",))
|
||||
checked-entries.insert(checked-key, checked-entry)
|
||||
}
|
||||
let checked-format-term = z.parse(show-term, z.function(), scope: ("format-term",))
|
||||
let checked-show-term = z.parse(show-term, z.function(), scope: ("show-term",))
|
||||
let checked-body = z.parse(body, z.content(), scope: ("body",))
|
||||
|
||||
@@ -493,7 +457,7 @@
|
||||
// Now see if this is an actual glossary term key
|
||||
if __has_entry(key) {
|
||||
// Found in dictionary, render via __gls()
|
||||
__gls(key, modifiers: modifiers.map(lower), format-term: format-term, show-term: show-term, term-links: term-links)
|
||||
__gls(key, modifiers: modifiers.map(lower), show-term: show-term, term-links: term-links)
|
||||
} else {
|
||||
// Not one of ours, so just pass it through
|
||||
r
|
||||
@@ -535,13 +499,12 @@
|
||||
// Returns:
|
||||
// content: Formatted glossary content
|
||||
//
|
||||
// Panics:
|
||||
// Throws:
|
||||
// - If a requested group doesn't exist
|
||||
//
|
||||
#let glossary(
|
||||
title: "Glossary",
|
||||
theme: theme-academic,
|
||||
sort: true,
|
||||
theme: theme-twocol,
|
||||
ignore-case: false,
|
||||
groups: (),
|
||||
) = context {
|
||||
@@ -596,24 +559,20 @@
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add non-empty groups to output
|
||||
if current_entries.len() > 0 {
|
||||
group = if group == none { "" } else { group }
|
||||
|
||||
|
||||
// sort entries by case insensitivity if requested
|
||||
let sorted_entries = if sort {
|
||||
current_entries
|
||||
// 1. create array of tuples with (lower [if ignore-case], entry)
|
||||
.map(e => { if ignore-case { (lower(e.short), e) } else { (e.short, e) } })
|
||||
// 2. sort the tuples (by first element then second)
|
||||
.sorted() // NOTE: sorted() is NOT language-aware
|
||||
// 3. strip away the tuple's first element, leaving an array of entries
|
||||
.map(t => t.last())
|
||||
} else {
|
||||
current_entries
|
||||
}
|
||||
|
||||
let sorted_entries = current_entries
|
||||
// 1. create array of tuples with (lower [if ignore-case], entry)
|
||||
.map(e => { if ignore-case { (lower(e.short), e) } else { (e.short, e) } })
|
||||
// 2. sort the tuples (by first element then second)
|
||||
.sorted() // NOTE: sorted() is NOT language-aware
|
||||
// 3. strip away the tuple's first element, leaving an array of entries
|
||||
.map(t => t.last())
|
||||
|
||||
// add entries to this group's output map
|
||||
output.insert(group, sorted_entries)
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 MiB |
@@ -1,208 +0,0 @@
|
||||
#import "/lib.typ": *
|
||||
|
||||
#let myGlossary = (
|
||||
html: (
|
||||
short: "HTML",
|
||||
long: "Hypertext Markup Language",
|
||||
description: "A standard language for creating web pages",
|
||||
group: "Web"),
|
||||
css: (
|
||||
short: "CSS",
|
||||
long: "Cascading Style Sheets",
|
||||
description: "A language used for describing the presentation of a document",
|
||||
group: "Web"),
|
||||
tps: (
|
||||
short: "TPS",
|
||||
long: "test procedure specification",
|
||||
description: "A document on how to run all the test procedures"),
|
||||
concise: "Concise syntax!",
|
||||
shortonly: (
|
||||
short: "shortonly!!!"),
|
||||
unused: "Unused term, which shouldn't print in the glossary."
|
||||
)
|
||||
|
||||
#set page(width: 6.5in, height: auto, margin: 1em)
|
||||
|
||||
#let test-content = {
|
||||
table(
|
||||
columns: 3,
|
||||
table.header(
|
||||
[`short`], [`long`], [`both`],
|
||||
),
|
||||
|
||||
[@html:short], [@html:long], [@html:both],
|
||||
[@css:short], [@css:long], [@css:both],
|
||||
[@tps:short], [@tps:long], [@tps:both],
|
||||
[@concise:short], [@concise:long], [@concise:both],
|
||||
[@shortonly:short], [@shortonly:long], [@shortonly:both],
|
||||
|
||||
table.hline(stroke: 2pt),
|
||||
|
||||
[@html:short:cap], [@html:long:cap], [@html:both:cap],
|
||||
[@a:css:short], [@a:css:long], [@a:css:both],
|
||||
[@tps:short:pl], [@tps:long:pl], [@tps:both:pl],
|
||||
[@concise:a:cap:short], [@concise:a:cap:long], [@concise:a:cap:both],
|
||||
[@an:shortonly:short], [@an:shortonly:long], [@an:shortonly:both],
|
||||
)
|
||||
|
||||
[@a:tps:cap is @tps:def.]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
#let format-basic(mode, short-form, long-form) = {
|
||||
if mode == "short" {
|
||||
short-form
|
||||
} else if mode == "long" {
|
||||
long-form
|
||||
} else {
|
||||
long-form + " (" + short-form + ")"
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-basic)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
#let format-reverse(mode, short-form, long-form) = {
|
||||
if mode == "short" {
|
||||
short-form
|
||||
} else if mode == "long" {
|
||||
long-form
|
||||
} else {
|
||||
short-form + " [" + long-form + "]"
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-reverse)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
#let format-uppercase-short(mode, short-form, long-form) = {
|
||||
let short-up = upper(short-form);
|
||||
if mode == "short" {
|
||||
short-up
|
||||
} else if mode == "long" {
|
||||
long-form
|
||||
} else {
|
||||
long-form + " (" + short-up + ")"
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-uppercase-short)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
#let format-prefix-suffix(mode, short-form, long-form) = {
|
||||
if mode == "short" {
|
||||
"Term: " + short-form + "."
|
||||
} else if mode == "long" {
|
||||
"Term: " + long-form + "."
|
||||
} else {
|
||||
"Term: " + long-form + " (" + short-form + ")."
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-prefix-suffix)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
#let format-conditional-separator(mode, short-form, long-form) = {
|
||||
let separator = if short-form.len() > 4 { " / " } else { ", " };
|
||||
let has_long = long-form != none and long-form != "";
|
||||
|
||||
if mode == "short" {
|
||||
short-form
|
||||
} else if mode == "long" {
|
||||
if has_long { long-form } else { short-form }
|
||||
} else {
|
||||
if has_long {
|
||||
long-form + separator + short-form
|
||||
} else {
|
||||
short-form
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-conditional-separator)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// 1. Braces and Labels
|
||||
// Idea: Use different bracket styles and labels based on the mode.
|
||||
#let format-braces(mode, short-form, long-form) = {
|
||||
if mode == "short" {
|
||||
"{" + short-form + "}"
|
||||
} else if mode == "long" {
|
||||
"[" + long-form + "]"
|
||||
} else {
|
||||
long-form + " <" + short-form + ">"
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-braces)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// 2. Mode-Based Prefix
|
||||
// Idea: Add a prefix indicating the mode, and then show the term(s).
|
||||
#let format-mode-prefix(mode, short-form, long-form) = {
|
||||
let prefix = if mode == "short" { "S:" } else if mode == "long" { "L:" } else { "B:" };
|
||||
if mode == "short" {
|
||||
prefix + short-form
|
||||
} else if mode == "long" {
|
||||
prefix + long-form
|
||||
} else {
|
||||
prefix + long-form + " & " + short-form
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-mode-prefix)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// 3. Conditional Fallback for Missing Long
|
||||
// Idea: If no long-form is provided, use the short-form in all cases.
|
||||
#let format-fallback-long(mode, short-form, long-form) = {
|
||||
let has_long = long-form != none and long-form != "";
|
||||
if mode == "short" {
|
||||
short-form
|
||||
} else if mode == "long" {
|
||||
if has_long { long-form } else { short-form }
|
||||
} else {
|
||||
if has_long { long-form + " (" + short-form + ")" } else { short-form }
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-fallback-long)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// 4. Uppercase Both Terms in Both Mode
|
||||
// Idea: Always uppercase for both mode, normal otherwise.
|
||||
#let format-uppercase-both(mode, short-form, long-form) = {
|
||||
if mode == "short" {
|
||||
short-form
|
||||
} else if mode == "long" {
|
||||
long-form
|
||||
} else {
|
||||
upper(long-form) + " (" + upper(short-form) + ")"
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-uppercase-both)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// 5. Append Length Info
|
||||
// Idea: In both mode, append the length of each string.
|
||||
#let format-length-info(mode, short-form, long-form) = {
|
||||
let s_len = str(short-form.len())
|
||||
let l_len = if long-form != none and long-form != "" { str(long-form.len()) } else { "0" }
|
||||
|
||||
if mode == "short" {
|
||||
short-form + " [len:" + s_len + "]"
|
||||
} else if mode == "long" {
|
||||
long-form + " [len:" + l_len + "]"
|
||||
} else {
|
||||
long-form + " (" + short-form + ") [L:" + l_len + ", S:" + s_len + "]"
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-length-info)[#test-content]
|
||||
|
||||
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 76 KiB |
@@ -1,23 +0,0 @@
|
||||
first:
|
||||
short: "DAL"
|
||||
long: "first"
|
||||
|
||||
second:
|
||||
short: "cab"
|
||||
long: "second"
|
||||
|
||||
third:
|
||||
short: "delta"
|
||||
long: "third"
|
||||
|
||||
fourth:
|
||||
short: "COO"
|
||||
long: "fourth"
|
||||
|
||||
fifth:
|
||||
short: "cuckoo"
|
||||
long: "fifth"
|
||||
|
||||
sixth:
|
||||
short: "ČR"
|
||||
long: "sixth"
|
||||
|
Before Width: | Height: | Size: 183 KiB |
@@ -1,13 +0,0 @@
|
||||
#import "/lib.typ":*
|
||||
|
||||
#show: init-glossary.with(yaml("glossary.yml"))
|
||||
|
||||
@first, @second, @third, @fourth, @fifth, @sixth
|
||||
|
||||
#glossary(ignore-case: false, sort: true)
|
||||
#line(length: 20em)
|
||||
#glossary(ignore-case: true, sort: true)
|
||||
#line(length: 20em)
|
||||
#glossary(ignore-case: false, sort: false)
|
||||
#line(length: 20em)
|
||||
#glossary(ignore-case: true, sort: false)
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "glossy"
|
||||
version = "0.5.1"
|
||||
version = "0.4.1"
|
||||
entrypoint = "lib.typ"
|
||||
authors = ["Stephen Waits <steve@waits.net>"]
|
||||
license = "MIT"
|
||||
|
||||