Compare commits

..
Author SHA1 Message Date
swaits d30225f4e6 feat(glossy): 0.1.2 2024-12-10 20:44:44 +00:00
swaits 347d44b5da feat(glossy): 0.1.1 2024-12-10 20:44:16 +00:00
6 changed files with 209 additions and 46 deletions

No files matched your search

+52 -5
View File
@@ -43,7 +43,7 @@ different goals:
### Import the package ### Import the package
```typst ```typst
#import "@preview/glossy:0.1.0": * #import "@preview/glossy:0.1.2": *
``` ```
@@ -86,6 +86,32 @@ Note that you could also load glossary entries from a data file using
[#json()](https://typst.app/docs/reference/data-loading/json/), or [#json()](https://typst.app/docs/reference/data-loading/json/), or
[similar](https://typst.app/docs/reference/data-loading/). [similar](https://typst.app/docs/reference/data-loading/).
For example, the above glossary could be in this YAML file:
```yaml
- key: html,
short: HTML,
long: Hypertext Markup Language,
description: A standard language for creating web pages,
group: Web
- key: css
short: CSS,
long: Cascading Style Sheets,
description: A stylesheet language used for describing the presentation of a document,
group: Web
- key: tps,
short: TPS,
long: test procedure specification
```
And then loaded during initialization as follows:
```typst
#show: init-glossary.with(yaml("glossary.yaml"))
```
### Using Glossary Terms in Your Document ### Using Glossary Terms in Your Document
Use glossary terms within your text using the `@reference` functionality in Use glossary terms within your text using the `@reference` functionality in
@@ -142,14 +168,34 @@ the title and specify a theme if desired:
#glossary(title: "Web Development Glossary", theme: my-theme, groups: ("Web")) #glossary(title: "Web Development Glossary", theme: my-theme, groups: ("Web"))
``` ```
### Themes See more on theming below in "Glossary Themes."
### Customizing the Output
#### Term usage in documents
You can control how terms are displayed when using the `@term` reference syntax
in your document by passing a custom function to `init-glossary` in the
`show-term` parameter.
For example, if you wanted all terms to be italicized, you could do this:
```typst
#let emph-term(body) = { emph(body) }
#show: init-glossary.with(myGlossary, show-term: emph-term)
// remainder of document follows
```
#### Glossary Themes
Customize the appearance of the glossary using themes. Each theme defines how Customize the appearance of the glossary using themes. Each theme defines how
sections, groups, and entries are displayed. sections, groups, and entries are displayed.
- **section**: This is a main glossary section. It contains multiple glossary groups. - **section**: This is a main glossary section. It contains multiple glossary groups.
- **group**: A group within the main glossary section. Contains multiple - **group**: A group within the main glossary section. Contains multiple
entries. Can be `none`. entries. Can be an empty string for terms with no group (`""`).
- **entry**: A single entry within a group. This is the actual term, and can - **entry**: A single entry within a group. This is the actual term, and can
include any of the fields in entry. Contains the following fields: include any of the fields in entry. Contains the following fields:
- `key`: The term key. (always present and unique) - `key`: The term key. (always present and unique)
@@ -166,8 +212,9 @@ Example of a minimal theme:
heading(level: 1, title) heading(level: 1, title)
body body
}, },
group: (name, body) => { group: (name, i, n, body) => {
if name != none and name != "" { // i is the group's index, n is total number of groups
if name != "" and n > 1 {
heading(level: 2, name) heading(level: 2, name)
} }
body body
Binary file not shown.
+120 -11
View File
@@ -1,6 +1,6 @@
// a minimal example, also listed in the README // a minimal example, also listed in the README
#import "@preview/glossy:0.1.0": * #import "@preview/glossy:0.1.2": *
#let myGlossary = ( #let myGlossary = (
(key: "html", short: "HTML", long: "Hypertext Markup Language", description: "A standard language for creating web pages", group: "Web"), (key: "html", short: "HTML", long: "Hypertext Markup Language", description: "A standard language for creating web pages", group: "Web"),
@@ -9,24 +9,45 @@
// Add more entries as needed // Add more entries as needed
) )
#show: init-glossary.with(myGlossary) #show: init-glossary.with(myGlossary, show-term: (body) => [#emph(body)])
#set heading(numbering: "1.1")
= Hello, `glossy`!
In modern web development, languages like @html and @css are essential. In modern web development, languages like @html and @css are essential.
Now make sure I get your @tps:short reports by 2pm! Now make sure I get your @tps:short reports by 2pm!
= Examples with modifiers
#table( #table(
columns: 2, columns: 2,
table.header([*Input*], [*Output*]), table.header([*Input*], [*Output*]),
[`@tps:short` ], [@tps:short], [`@tps:short` ], [@tps:short],
[`@tps:long` ], [@tps:long], [`@tps:long` ], [@tps:long],
[`@tps:both` ], [@tps:both], [`@tps:both` ], [@tps:both],
[`@tps:long:cap` ], [@tps:long:cap], [`@tps:long:cap` ], [@tps:long:cap],
[`@tps:long:pl` ], [@tps:long:pl], [`@tps:long:pl` ], [@tps:long:pl],
[`@tps:short:pl` ], [@tps:short:pl], [`@tps:short:pl` ], [@tps:short:pl],
[`@tps:both:pl:cap`], [@tps:both:pl:cap], [`@tps:both:pl:cap`], [@tps:both:pl:cap],
)
== Using conflicting modifiers (short, long, both)
These modifiers are semantically mutually exclusive, by they can be combined
syntactically. When multiple are used, `glossy` tries to make a smart choice on
which one to display.
#table(
columns: 2,
table.header([*Input*], [*Output*]),
[`@tps:short:long` ], [@tps:short:long],
[`@tps:short:both` ], [@tps:short:both],
[`@tps:long:both` ], [@tps:long:both],
[`@tps:short:long:both`], [@tps:short:long:both],
) )
#let my-theme = ( #let my-theme = (
@@ -34,8 +55,8 @@ Now make sure I get your @tps:short reports by 2pm!
heading(level: 1, title) heading(level: 1, title)
body body
}, },
group: (name, body) => { group: (name, i, n, body) => {
if name != none and name != "" { if name != "" and n > 1 {
heading(level: 2, name) heading(level: 2, name)
} }
body body
@@ -61,3 +82,91 @@ Now make sure I get your @tps:short reports by 2pm!
) )
#glossary(theme: my-theme) #glossary(theme: my-theme)
#glossary(title: "Glossary with just empty group", groups: ("",), theme: my-theme)
#glossary(title: "Glossary with just Web group", groups: ("Web",), theme: my-theme)
// a minimal example, also listed in the README
#import "@preview/glossy:0.1.2": *
#let myGlossary = (
(key: "html", short: "HTML", long: "Hypertext Markup Language", description: "A standard language for creating web pages", group: "Web"),
(key: "css", short: "CSS", long: "Cascading Style Sheets", description: "A language used for describing the presentation of a document", group: "Web"),
(key: "tps", short: "TPS", long: "test procedure specification"),
// Add more entries as needed
)
#show: init-glossary.with(myGlossary)
#set heading(numbering: "1.1")
= Hello, `glossy`!
In modern web development, languages like @html and @css are essential.
Now make sure I get your @tps:short reports by 2pm!
= Examples with modifiers
#table(
columns: 2,
table.header([*Input*], [*Output*]),
[`@tps:short` ], [@tps:short],
[`@tps:long` ], [@tps:long],
[`@tps:both` ], [@tps:both],
[`@tps:long:cap` ], [@tps:long:cap],
[`@tps:long:pl` ], [@tps:long:pl],
[`@tps:short:pl` ], [@tps:short:pl],
[`@tps:both:pl:cap`], [@tps:both:pl:cap],
)
== Using conflicting modifiers (short, long, both)
These modifiers are semantically mutually exclusive, by they can be combined
syntactically. When multiple are used, `glossy` tries to make a smart choice on
which one to display.
#table(
columns: 2,
table.header([*Input*], [*Output*]),
[`@tps:short:long` ], [@tps:short:long],
[`@tps:short:both` ], [@tps:short:both],
[`@tps:long:both` ], [@tps:long:both],
[`@tps:short:long:both` ], [@tps:short:long:both],
)
#let my-theme = (
section: (title, body) => {
heading(level: 1, title)
body
},
group: (name, i, n, body) => {
if name != "" and n > 1 {
heading(level: 2, name)
}
body
},
entry: (entry, i, n) => {
// i is the entry's index, n is total number of entries
let output = [#entry.short]
if entry.long != none {
output = [#output -- #entry.long]
}
if entry.description != none {
output = [#output: #entry.description]
}
block(
grid(
columns: (auto, 1fr, auto),
output,
repeat([#h(0.25em) . #h(0.25em)]),
entry.pages,
)
)
}
)
#glossary(theme: my-theme)
#glossary(title: "Glossary with just empty group", groups: ("",), theme: my-theme)
#glossary(title: "Glossary with just Web group", groups: ("Web",), theme: my-theme)
+35 -28
View File
@@ -128,35 +128,32 @@
if "cap" in modifiers { upper(term.first()) + term.slice(1) } else { term } if "cap" in modifiers { upper(term.first()) + term.slice(1) } else { term }
} }
// Helper: Format a term with pluralization and capitalization
let format_term = (term, plural) => {
capitalize_term(pluralize_term(term, plural))
}
// Helper: Select and format the displayed term (long, short, or both) // Helper: Select and format the displayed term (long, short, or both)
let select_term = (is_long_mode, use_both) => { let select_term = (is_long_mode, use_both) => {
// Derive pluralized and capitalized versions of the long and short forms // Derive pluralized and capitalized versions of the long and short forms
let long_form = capitalize_term(pluralize_term(entry.long, entry.longplural)) let short_form = format_term(entry.short, entry.plural)
let short_form = capitalize_term(pluralize_term(entry.short, entry.plural)) let long_form = if entry.long != none { format_term(entry.long, entry.longplural) } else { none }
// If "both" modifier is present, show both the long form and short form // Return logic for term selection:
if use_both { if use_both and long_form != none {
// If the long form exists, show "Long Form (Short Form)" // 1. If "both" is requested AND we have a long form available:
if long_form != none { // Show "Long Form (Short Form)"
[#long_form (#short_form)] [#long_form (#short_form)]
} } else if is_long_mode and long_form != none {
// Fallback: If no long form exists, just show the short form // 2. If long mode is requested AND we have a long form available:
else { // Show just the long form
[#short_form] [#long_form]
} } else {
} // 3. Fallback case - use short form when:
// If in "long mode", show the long form, fallback to short if long form is missing // - "both" was requested but no long form exists
else if is_long_mode { // - long mode was requested but no long form exists
if long_form != none { // - short form was explicitly requested
[#long_form] // - no specific mode was requested
}
// Fallback: if no long form, show short
else {
[#short_form]
}
}
// Default case: Just show the short form
else {
[#short_form] [#short_form]
} }
} }
@@ -218,7 +215,9 @@
// Main wrapper (usually used in a `#show: init-glossary`) which loads the // Main wrapper (usually used in a `#show: init-glossary`) which loads the
// entries passed in into our state. Furthermore, hooks into references so that // entries passed in into our state. Furthermore, hooks into references so that
// we can intercept term usage in a doc and label them appropriately. // we can intercept term usage in a doc and label them appropriately.
#let init-glossary(entries, body) = context { //
// Pass a function in `show-term(term-body)` to control how you display terms.
#let init-glossary(entries, show-term: (term-body) => term-body, body) = context {
for entry in __normalize_entries(entries) { for entry in __normalize_entries(entries) {
__add_entry(entry) __add_entry(entry)
} }
@@ -227,7 +226,7 @@
show ref: r => { show ref: r => {
let (key, ..modifiers) = str(r.target).split(":") let (key, ..modifiers) = str(r.target).split(":")
if __has_entry(key) { if __has_entry(key) {
__gls(key, modifiers: modifiers) show-term(__gls(key, modifiers: modifiers))
} else { } else {
r r
} }
@@ -296,7 +295,7 @@
} }
} }
if cur.len() > 0 { if cur.len() > 0 {
if g == "" { g = none } if g == none { g = "" }
output.insert(g, cur.sorted(key: e => e.short)) output.insert(g, cur.sorted(key: e => e.short))
} }
} }
@@ -305,16 +304,24 @@
// with no group)?? -- in this case should we just not use the theme.group() // with no group)?? -- in this case should we just not use the theme.group()
// function? // function?
// index for group because dictionary don't have enumerate()
let i_group = 0;
// render it using our theme // render it using our theme
(theme.section)( (theme.section)(
title, title,
// section body (all groups)
for (group, entries) in output { for (group, entries) in output {
(theme.group)( (theme.group)(
group, group,
i_group,
output.len(),
// group body (all entries)
for (i,e) in entries.enumerate() { for (i,e) in entries.enumerate() {
(theme.entry)(e, i, entries.len()) (theme.entry)(e, i, entries.len())
}, },
) )
i_group += 1
} }
) )
} }
+2 -2
View File
@@ -5,8 +5,8 @@
columns(2, body) columns(2, body)
}, },
group: (name, body) => { group: (name, i, n, body) => {
if name != none { if name != "" and n > 1 {
heading(level: 2, name) heading(level: 2, name)
} }
body body
Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 150 KiB