Virtual Package Examples

2026-02-28 · by Tola
virtual-packagestutorialtypst
Code + rendered examples for @tola/site, @tola/pages, and @tola/current

Tola injects sys.inputs and exposes them through Typst’s package mechanism. You use them with standard #import syntax, so site metadata, page indexes, and current-page context are available as regular Typst modules.

This design is extensible and customizable:

#import "@tola/site:0.0.0": info
#import "@tola/pages:0.0.0": pages

#let featured = pages().filter(p => p.at("featured", default: false))
Brand color: #info.extra.at("brand-color", default: "sky")
Featured count: #featured.len()

API Overview

PackageExports
@tola/site:0.0.0info
@tola/pages:0.0.0pages(), by-tag(tag), by-tags(..tags), all-tags()
@tola/current:0.0.0permalink, parent-permalink, path, filename, headings, links-to, linked-by, breadcrumbs, children, siblings, at-offset, prev, next, take-prev, take-next

Site Metadata API (@tola/site)

Read site metadata from `tola.toml`

Same pattern as README: import `info` and read `info.title`, `info.author`, and `info.extra`.

Typst Code
#import "@tola/site:0.0.0": info

Site: #info.title
Author: #info.author
Language: #info.language
Custom0: #info.extra.at("custom0", default: "<none>")
Custom1: #info.extra.at("custom1", default: "<none>")
Rendered Output
  • Site: Starter
  • Author: Tola
  • Language: en
  • Custom0: ABC
  • Custom1: XYZ

Common Info Fields

Page Query API (@tola/pages)

Recent Posts Query

Recent 5 posts

README example converted to a reusable list block.

Typst Code
#import "@tola/pages:0.0.0": pages

#let posts = (pages()
.filter(p => "/posts/" in p.permalink)
.filter(p => p.at("date", default: none) != none)
.sorted(key: p => p.date)
.rev())

#let recent = posts.slice(0, calc.min(5, posts.len()))

#for post in recent {
[- #link(post.permalink)[#post.title]]
}
Rendered Output

Pinned Ordering Strategy

Pinned posts + stable date grouping

Avoid mixed-type sort keys by splitting pinned pages into date/non-date groups.

Typst Code
#import "@tola/pages:0.0.0": pages

#let pinned = pages().filter(p => p.at("pinned", default: false))
#let with-date = (pinned
.filter(p => p.at("date", default: none) != none)
.sorted(key: p => p.date)
.rev())
#let without-date = pinned.filter(p => p.at("date", default: none) == none)

#let ordered = with-date + without-date
Rendered Output

Tag Query Helpers

Tag query helpers: `by-tag`, `by-tags`, `all-tags`

Covers the helper APIs exported by `@tola/pages:0.0.0`.

Typst Code
#import "@tola/pages:0.0.0": by-tag, by-tags, all-tags

#let tutorial = by-tag("tutorial")
#let virtual-and-tutorial = by-tags("virtual-packages", "tutorial")
#let tags = all-tags()
Rendered Output
  • tutorial: 3 posts
  • virtual-packages + tutorial: 1 post
  • tags: baseline, demo-data, feature, head, html, math, placeholder, seo, showcase, tutorial, typst, virtual-packages

Current Page API (@tola/current)

Context Fields

Current page context (`permalink`, `parent-permalink`, `path`, `filename`, `headings`)

Use permalink-based context values in templates for breadcrumbs, TOC, and layout decisions.

Typst Code
#import "@tola/current:0.0.0": current-permalink, parent-permalink, path, filename, headings

Current permalink: #current-permalink
Parent permalink: #parent-permalink
Source path: #path
Filename: #filename
Heading count: #headings.len()
Rendered Output
  • permalink: /posts/virtual-packages/
  • parent-permalink: /posts/
  • path: posts/virtual-packages.typ
  • filename: virtual-packages.typ
  • headings: 15

Filename-Derived Metadata

Extract date-like prefix from `filename`

Pattern from README: works for filenames like `2025_02_25_my-post.typ`.

Typst Code
#import "@tola/current:0.0.0": path, filename

#let file = filename.replace(".typ", "")
#let parts = file.split("_")
#let auto-date = if parts.len() >= 4 {
parts.slice(0, 3).join("-")
} else {
none
}
Rendered Output
  • source path: posts/virtual-packages.typ
  • filename: virtual-packages.typ
  • derived date: <none>
  • derived slug: virtual-packages

Hierarchy Navigation

Prev/next + breadcrumbs + hierarchy helpers

Navigation helpers from `@tola/current` for section pages and article pages.

Typst Code
#import "@tola/pages:0.0.0": pages
#import "@tola/current:0.0.0": prev, next, breadcrumbs, children, siblings

#let all = pages()
#let dated-posts = all
.filter(p => "/posts/" in p.permalink and p.date != none)
.sorted(key: p => p.date)

#let prev-page = prev(dated-posts)
#let next-page = next(dated-posts)
#let crumbs = breadcrumbs(all, include-root: true)
#let direct-children = children(all)
#let same-level = siblings(all)
Rendered Output

Home / posts / Virtual Package Examples

  • stats: children = 0, siblings = 6, links-to = 0, linked-by = 0

Offset Navigation Window

Offset helpers: `at-offset`, `take-prev`, `take-next`

Build navigation windows around the current page without manual index math.

Typst Code
#import "@tola/pages:0.0.0": pages
#import "@tola/current:0.0.0": at-offset, take-prev, take-next

#let dated = (pages()
.filter(p => "/posts/" in p.permalink and p.date != none)
.sorted(key: p => p.date))

#let two-back = at-offset(dated, -2)
#let two-forward = at-offset(dated, 2)
#let previous = take-prev(dated, n: 2)
#let next = take-next(dated, n: 2)
Rendered Output

Page Metadata Contract

Standard Fields

Each entry from pages() is page metadata and includes common keys like:

Custom Fields

Any custom metadata fields you provide: