152 lines
3.7 KiB
Plaintext
152 lines
3.7 KiB
Plaintext
// rPubs Book Template — main entry point
|
|
// Reads structured content from JSON and renders a complete pocket book.
|
|
// Works with any format file (A6, A7, digest, etc.)
|
|
|
|
#import "../lib/series-style.typ": apply-series-style, series-colors, series-fonts, series-rule, series-separator
|
|
|
|
#let data = json(sys.inputs.at("data-path"))
|
|
|
|
// Apply series typography
|
|
#show: apply-series-style
|
|
|
|
// --- Cover Page ---
|
|
#page(
|
|
numbering: none,
|
|
margin: (x: 15mm, y: 20mm),
|
|
fill: series-colors.cover-bg,
|
|
)[
|
|
#set text(fill: series-colors.cover-fg)
|
|
#v(1fr)
|
|
|
|
#align(center)[
|
|
#block(width: 100%)[
|
|
#set text(font: series-fonts.heading)
|
|
|
|
// Title
|
|
#text(size: 18pt, weight: "bold")[
|
|
#data.title
|
|
]
|
|
|
|
#if data.at("subtitle", default: none) != none {
|
|
v(0.3em)
|
|
text(size: 11pt, fill: series-colors.cover-fg.lighten(20%))[
|
|
#data.subtitle
|
|
]
|
|
}
|
|
|
|
#v(1em)
|
|
#line(length: 40%, stroke: 0.5pt + series-colors.cover-fg.darken(40%))
|
|
#v(1em)
|
|
|
|
// Author
|
|
#if data.at("author", default: none) != none {
|
|
text(size: 10pt)[
|
|
#data.author
|
|
]
|
|
}
|
|
]
|
|
]
|
|
|
|
#v(1fr)
|
|
|
|
#align(center)[
|
|
#text(size: 7pt, fill: series-colors.cover-fg.darken(40%))[
|
|
rpubs
|
|
]
|
|
]
|
|
]
|
|
|
|
// --- Table of Contents (if there are headings) ---
|
|
#let has-headings = data.sections.any(s => s.at("heading", default: none) != none)
|
|
#if has-headings {
|
|
page(numbering: none)[
|
|
#v(2em)
|
|
#text(font: series-fonts.heading, size: 12pt, weight: "bold", fill: series-colors.accent)[Contents]
|
|
#v(1em)
|
|
#series-rule()
|
|
#v(0.5em)
|
|
|
|
#for (i, section) in data.sections.enumerate() {
|
|
if section.at("heading", default: none) != none {
|
|
let level = section.at("level", default: 1)
|
|
let indent = (level - 1) * 1em
|
|
pad(left: indent)[
|
|
#text(size: 9pt)[#section.heading]
|
|
]
|
|
v(0.2em)
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
// --- Body Content ---
|
|
#for section in data.sections {
|
|
// Section heading
|
|
if section.at("heading", default: none) != none {
|
|
let level = section.at("level", default: 1)
|
|
if level == 1 {
|
|
heading(level: 1)[#section.heading]
|
|
} else if level == 2 {
|
|
heading(level: 2)[#section.heading]
|
|
} else {
|
|
heading(level: 3)[#section.heading]
|
|
}
|
|
}
|
|
|
|
// Content blocks
|
|
for item in section.at("blocks", default: ()) {
|
|
if item.type == "paragraph" {
|
|
par[#item.text]
|
|
} else if item.type == "quote" {
|
|
pad(left: 1em)[
|
|
#block(
|
|
inset: (left: 8pt, y: 4pt),
|
|
stroke: (left: 2pt + series-colors.accent),
|
|
)[
|
|
#set text(style: "italic", size: 8.5pt)
|
|
#item.text
|
|
#if item.at("attribution", default: none) != none {
|
|
v(0.2em)
|
|
align(right)[
|
|
#text(size: 7.5pt, fill: series-colors.muted)[— #item.attribution]
|
|
]
|
|
}
|
|
]
|
|
]
|
|
} else if item.type == "list" {
|
|
if item.at("ordered", default: false) {
|
|
enum(..item.items.map(entry => [#entry]))
|
|
} else {
|
|
list(..item.items.map(entry => [#entry]))
|
|
}
|
|
} else if item.type == "code" {
|
|
raw(block: true, lang: item.at("language", default: none), item.code)
|
|
} else if item.type == "separator" {
|
|
series-separator()
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Colophon (back page) ---
|
|
#pagebreak()
|
|
#v(1fr)
|
|
#series-rule()
|
|
#v(0.5em)
|
|
#set text(size: 7pt, fill: series-colors.muted)
|
|
|
|
#if data.at("title", default: none) != none [
|
|
*#data.title*
|
|
#if data.at("author", default: none) != none [ by #data.author]
|
|
#v(0.3em)
|
|
]
|
|
|
|
#[
|
|
Typeset with rPubs. \
|
|
Formatted for standardized pocket-book printing.
|
|
]
|
|
|
|
#v(0.5em)
|
|
#align(center)[
|
|
#text(size: 6pt)[rpubs · drop in a document · get a book]
|
|
]
|