feat: Typst lesson template with Jellyfin media frontmatter #9

Merged
sscoble merged 2 commits from issue-3-typst-template into main 2026-05-16 04:39:37 +00:00
2 changed files with 173 additions and 0 deletions

View file

@ -0,0 +1,83 @@
// example-lesson.typ — Complete example demonstrating the lesson template
// ============================================================
// Frontmatter:
// title: God's Creation: The Water Cycle
// grade: 3
// subject: Science
// date: 2026-01-15
// media: jellyfin://uuid-water-cycle, jellyfin://uuid-cloud-formation
// description: Learn how God designed water to move through His creation —
// evaporation, condensation, and precipitation working together to sustain life.
#import "lesson.typ": lesson-template, media-ref
#show: doc => lesson-template(
doc,
title: "God's Creation: The Water Cycle",
grade: "3",
subject: "Science",
date: "2026-01-15",
media: (
("uuid-water-cycle", "The Water Cycle Explained"),
("uuid-cloud-formation", "Cloud Formation and Weather"),
),
description: "Learn how God designed water to move through His creation — evaporation, condensation, and precipitation working together to sustain life on Earth.",
)
= What Is the Water Cycle?
Water is one of God's most amazing creations! The water cycle is how water moves
all around our planet. It never runs out — it just keeps going around and around.
There are four main steps: evaporation, condensation, precipitation, and collection.
== Evaporation
When the sun shines on oceans, lakes, and rivers, the water gets warm and turns
into a gas called *water vapor*. This gas rises up into the sky. You can't see it,
but it's there! Evaporation happens every day, especially on warm, sunny days.
== Condensation
When the water vapor goes high up where it's cold, it turns back into tiny water
droplets. These droplets come together to make clouds. Have you ever looked at
clouds and seen shapes? Those shapes are made of millions of tiny water droplets
sticking together!
== Precipitation
When the clouds get too heavy with water droplets, the water falls back down to
Earth. This is called *precipitation*. It can be:
- Rain — liquid water falling from the sky
- Snow — frozen crystals that fall in cold weather
- Sleet — tiny ice pellets that bounce when they land
- Hail — hard balls of ice that form in big storms
God sends precipitation to water the plants and fill the rivers, lakes, and oceans.
== Collection
The water that falls onto the ground collects in rivers, lakes, and oceans. Some
of it soaks into the ground and becomes *groundwater* — water stored underground
that plants can reach with their roots. Then the sun warms the water, and the
whole cycle starts all over again!
= Why Is the Water Cycle Important?
God designed the water cycle to do important work:
- Give plants the water they need to grow
- Provide fresh water for animals and people to drink
- Keep our rivers and lakes full of water
- Help control the temperature of our whole planet
- Clean the water naturally as it moves through the cycle
*"He causes the vapors to ascend from the ends of the earth; He makes lightning
for the rain; He brings the wind out of His treasuries."* — Psalm 135:7
= Think About It
1. What happens to water when the sun shines on a lake?
2. Why do clouds form high up in the sky?
3. What are the four types of precipitation?
4. How does the water cycle show God's care for His creation?

90
templates/lesson.typ Normal file
View file

@ -0,0 +1,90 @@
// lesson.typ — Typst template for homeschool lessons
// ============================================================
// This template produces clean, structured lesson documents.
// Designed to compile to HTML for rendering inside Jellyfin.
//
// Frontmatter convention (documented as comments at top of each lesson):
// // title: The Lesson Title
// // grade: 3
// // subject: Science
// // date: 2026-01-15
// // media: jellyfin://uuid-1, jellyfin://uuid-2
// // description: Short description of the lesson
//
// Usage:
// #import "lesson.typ": lesson-template, media-ref
// #show: doc => lesson-template(
// doc,
// title: "The Water Cycle",
// grade: "3",
// subject: "Science",
// date: "2026-01-15",
// media: (),
// description: "Learn about evaporation and condensation.",
// )
// Render a single Jellyfin media reference.
// Produces a <code data-lang="jellyfin-media"> element in HTML output
// that the Jellyfin plugin can parse and link to the player.
#let media-ref(id, title) = {
raw(lang: "jellyfin-media", id + "|" + title, block: false)
}
// Render a list of media references as a formatted section.
#let media-section(media-items) = {
if media-items.len() > 0 {
heading(level: 2)[Media]
for item in media-items {
list.item(media-ref(item.at(0), item.at(1)))
}
}
}
// The main lesson template.
// - body: The lesson content (passed via show rule)
// - title: Lesson title (string)
// - grade: Grade level (string, e.g. "3")
// - subject: Subject name (string)
// - date: Lesson date in YYYY-MM-DD format
// - media: Array of (id, title) pairs for linked Jellyfin media
// - description: Short description of the lesson
#let lesson-template(
body,
title: "Untitled Lesson",
grade: none,
subject: none,
date: none,
media: (),
description: none,
) = {
// Document metadata for PDF output
set document(title: title)
// Title — prominent heading
heading(level: 1, title)
// Metadata line: Grade X — Subject — Date
let meta-parts = ()
if grade != none { meta-parts.push([Grade ] + grade) }
if subject != none { meta-parts.push(subject) }
if date != none { meta-parts.push(date) }
if meta-parts.len() > 0 {
let sep = [ — ]
let meta-text = meta-parts.first()
for i in range(1, meta-parts.len()) {
meta-text += sep + meta-parts.at(i)
}
par(text(style: "italic", size: 0.9em, meta-text))
}
// Description paragraph
if description != none {
par([*Description:* ] + description)
}
// Lesson body content (renders user-authored sections, paragraphs, lists, etc.)
body
// Media references section — listed with identifiable jellyfin-media codes
media-section(media)
}