@heroiclands/package-build 22.23.0 → 22.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +1 -0
- package/assets/styles/content-base.css +45 -0
- package/ci/check-banners.mjs +183 -0
- package/ci/ci-steps.mjs +21 -11
- package/docs/authoring/assets.md +15 -0
- package/docs/authoring/links-and-markup.md +69 -2
- package/docs/commands.md +18 -19
- package/docs/configuration.md +2 -6
- package/docs/content-format.md +9 -0
- package/docs/guides/module-project.md +2 -2
- package/docs/guides/site.md +41 -0
- package/docs/project-setup.md +4 -4
- package/docs/reference/format-details.md +3 -3
- package/docs/reference/theme-pages.md +496 -0
- package/engine/art-slots.mjs +2 -1
- package/engine/content-blocks.mjs +83 -14
- package/engine/content-figures.mjs +18 -3
- package/engine/content-poetry.mjs +61 -0
- package/engine/foreign-catalog.mjs +2 -1
- package/engine/helpers.mjs +5 -3
- package/engine/note-vocabulary.mjs +2 -1
- package/engine/pdf-build.mjs +1 -1
- package/engine/pdf-render.mjs +32 -2
- package/engine/rank-ladder.mjs +32 -0
- package/engine/site-config.mjs +19 -24
- package/hugo-theme/data/banners.yaml +69 -0
- package/hugo-theme/layouts/404.html +85 -0
- package/hugo-theme/layouts/_default/baseof.html +64 -0
- package/hugo-theme/layouts/_default/list.html +139 -0
- package/hugo-theme/layouts/_default/single.html +4 -0
- package/hugo-theme/layouts/blog/list.html +54 -0
- package/hugo-theme/layouts/blog-post/single.html +36 -0
- package/hugo-theme/layouts/index.html +75 -0
- package/hugo-theme/layouts/partials/banner-url.html +117 -0
- package/hugo-theme/layouts/partials/cdn-url.html +36 -0
- package/hugo-theme/layouts/partials/draft-notice.html +41 -0
- package/hugo-theme/layouts/partials/draft-state.html +26 -0
- package/hugo-theme/layouts/partials/footer.html +29 -0
- package/hugo-theme/layouts/partials/header.html +35 -0
- package/hugo-theme/layouts/partials/hero-banner.html +86 -0
- package/hugo-theme/layouts/partials/holdings/entry.html +21 -0
- package/hugo-theme/layouts/partials/holdings/kind-groups.html +71 -0
- package/hugo-theme/layouts/partials/holdings.html +61 -0
- package/hugo-theme/layouts/partials/infobox/entry.html +15 -0
- package/hugo-theme/layouts/partials/infobox/items.html +26 -0
- package/hugo-theme/layouts/partials/infobox/section.html +56 -0
- package/hugo-theme/layouts/partials/infobox/value.html +43 -0
- package/hugo-theme/layouts/partials/infobox.html +57 -0
- package/hugo-theme/layouts/partials/page-body.html +154 -0
- package/hugo-theme/layouts/partials/place-map.html +9 -0
- package/hugo-theme/layouts/partials/related.html +121 -0
- package/hugo-theme/layouts/partials/search.html +84 -0
- package/hugo-theme/layouts/partials/site-url.html +32 -0
- package/hugo-theme/layouts/partials/tags.html +30 -0
- package/hugo-theme/layouts/partials/toc.html +28 -0
- package/hugo-theme/layouts/partials/warn-missing-banner.html +3 -0
- package/hugo-theme/layouts/shortcodes/cartouche.html +64 -0
- package/hugo-theme/layouts/shortcodes/exturl.html +12 -0
- package/hugo-theme/layouts/shortcodes/glyph.html +43 -0
- package/hugo-theme/layouts/shortcodes/pagelist.html +63 -0
- package/hugo-theme/static/css/sohl-icons.css +57 -0
- package/hugo-theme/static/css/style.css +2982 -0
- package/hugo-theme/static/fonts/game-icons-kb.woff2 +0 -0
- package/hugo-theme/static/img/banners/takheperu-hieroglyphs.svg +1 -0
- package/hugo-theme/static/img/cartouches/takheperu.svg +1 -0
- package/hugo-theme/theme.toml +11 -0
- package/package.json +5 -2
- package/types/engine/art-slots.d.mts +2 -1
- package/types/engine/content-figures.d.mts +1 -0
- package/types/engine/content-poetry.d.mts +19 -0
- package/types/engine/helpers.d.mts +5 -3
- package/types/engine/rank-ladder.d.mts +8 -0
- package/types/engine/site-config.d.mts +9 -9
|
@@ -2648,7 +2648,7 @@ displays **Table 1** as a link.
|
|
|
2648
2648
|
optionally followed by a braced attribute block in the grammar a heading and
|
|
2649
2649
|
a named block take too. A line of `:::` alone closes it. Between the
|
|
2650
2650
|
two, the first `///` written alone on a line, read at the top level — outside
|
|
2651
|
-
any nested code fence — divides what the fence holds from its caption; a `///`
|
|
2651
|
+
any nested code or poetry fence — divides what the fence holds from its caption; a `///`
|
|
2652
2652
|
written inside a nested fence is content, not a divider. A second top-level
|
|
2653
2653
|
`///` is an error, naming the line: a figure holds one caption, so it carries
|
|
2654
2654
|
one `///` line.
|
|
@@ -2681,11 +2681,11 @@ note and is `a figure needs a closing :::`, also at the opening line, and
|
|
|
2681
2681
|
nothing after it is scanned as a second fence.
|
|
2682
2682
|
|
|
2683
2683
|
**The counter is derived, never authored.** The fence's contents decide which
|
|
2684
|
-
of
|
|
2684
|
+
of six counters it draws from — `Code`, `Table`, `Figure`, `Map`, `Poem`, `Prose` — read from
|
|
2685
2685
|
the first top-level block inside the fence: a table is `Table`; a fenced `sql`
|
|
2686
2686
|
block is `Table`, because its rendered output is one; any other fenced or
|
|
2687
2687
|
indented code block is `Code`; one or more pictures and nothing else is
|
|
2688
|
-
`Figure`; everything else is `Prose`. A table or
|
|
2688
|
+
`Figure`; a `:::poetry` fence as the first nonblank content is `Poem`; everything else is `Prose`. A poem, table or picture written outside any
|
|
2689
2689
|
`:::figure` fence draws no label and is counted nowhere. The website and a
|
|
2690
2690
|
Foundry journal number each counter within the note; the book numbers each
|
|
2691
2691
|
counter across the book in reading order.
|
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
---
|
|
2
|
+
shortcode: referencethemepages
|
|
3
|
+
name: { full: "What the theme draws" }
|
|
4
|
+
type: doc
|
|
5
|
+
subType: reference
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# What the theme draws
|
|
9
|
+
|
|
10
|
+
`package-build site` writes a page's front matter; the shared Hugo theme reads
|
|
11
|
+
it and draws the page around it. This reference describes that second half —
|
|
12
|
+
the infobox rail, the hero band, the holdings and related cards, the place
|
|
13
|
+
map, search, and the markup an image or a figure renders as — and names the
|
|
14
|
+
classes a consumer styles against.
|
|
15
|
+
|
|
16
|
+
**None of the sections below is an authoring instruction.** `infoboxes`,
|
|
17
|
+
`related`, `contains`, `held_by`, `holdings`, `map`, `package`, `slug`, `url`
|
|
18
|
+
and `title` cannot be written by a note at all: a note's top-level region is
|
|
19
|
+
closed and does not admit them, so each arrives already resolved by the time
|
|
20
|
+
the theme sees it. Read this page when a panel is missing or a class needs
|
|
21
|
+
styling. [Frontmatter](../authoring/frontmatter.md) and the
|
|
22
|
+
[note-type reference](note-types.md) describe what a note itself carries;
|
|
23
|
+
[what an emitted page carries](../guides/site.md#what-an-emitted-page-carries)
|
|
24
|
+
describes the keys the build writes from it.
|
|
25
|
+
|
|
26
|
+
## The infobox
|
|
27
|
+
|
|
28
|
+
The toolchain settles what each box holds and in what order — see
|
|
29
|
+
[the infobox](format-details.md#the-infobox) for the field semantics, the
|
|
30
|
+
three states a system box can say, and the four section layouts a box is
|
|
31
|
+
built from. On the website, `partials/infobox.html` draws the whole list by
|
|
32
|
+
switching on a section's `layout` and a value's `kind`, never on a note type
|
|
33
|
+
or a field name:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
---
|
|
37
|
+
infoboxes:
|
|
38
|
+
- id: note
|
|
39
|
+
kind: note
|
|
40
|
+
title: Profile
|
|
41
|
+
sections:
|
|
42
|
+
- id: profile
|
|
43
|
+
layout: rows
|
|
44
|
+
rows:
|
|
45
|
+
- label: Name
|
|
46
|
+
kind: text
|
|
47
|
+
value: Brànwâal Dôrgaar
|
|
48
|
+
- label: Affiliations
|
|
49
|
+
kind: links
|
|
50
|
+
value:
|
|
51
|
+
- text: The Silent Talon Company
|
|
52
|
+
url: /thalorna/affiliation-slntlncmpny/
|
|
53
|
+
- id: sohl
|
|
54
|
+
kind: system
|
|
55
|
+
system: sohl
|
|
56
|
+
title: SoHL
|
|
57
|
+
available: true
|
|
58
|
+
sections:
|
|
59
|
+
- id: attributes
|
|
60
|
+
label: Attributes
|
|
61
|
+
layout: grid
|
|
62
|
+
cells:
|
|
63
|
+
- label: STR
|
|
64
|
+
value: 14
|
|
65
|
+
- id: hm3
|
|
66
|
+
kind: system
|
|
67
|
+
system: hm3
|
|
68
|
+
title: HM3
|
|
69
|
+
available: false
|
|
70
|
+
sections: []
|
|
71
|
+
---
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Each layout draws under its own class:
|
|
75
|
+
|
|
76
|
+
| `layout` | drawn as |
|
|
77
|
+
| -------- | --------------------------------------------- |
|
|
78
|
+
| `rows` | `.info-profile-grid` |
|
|
79
|
+
| `grid` | `.info-attrs-grid` / `.info-attr` |
|
|
80
|
+
| `runin` | `.info-skill-line` / `.skill-cat` |
|
|
81
|
+
| `list` | `.info-mystical-list` / `.info-mystical-item` |
|
|
82
|
+
|
|
83
|
+
A `link` value renders as an anchor where the build reached the page, and as
|
|
84
|
+
its own words where it did not; a whole `number` is set with digit grouping.
|
|
85
|
+
|
|
86
|
+
**How the boxes are drawn.**
|
|
87
|
+
|
|
88
|
+
- Each box is a `<details>` disclosure, **open by default** — native,
|
|
89
|
+
accessible, no JavaScript. Closed, a box is one summary line, which is what
|
|
90
|
+
lets a note box and one box per system stack without burying the prose.
|
|
91
|
+
- The boxes sit in a **rail on wide screens and inline on narrow ones**. The
|
|
92
|
+
rail is written first in the markup, because the infobox is content
|
|
93
|
+
prepended before the prose: when the grid collapses, the boxes land above
|
|
94
|
+
the text they summarise.
|
|
95
|
+
- A page carrying boxes takes the `.single-with-sidebar` grid, and its
|
|
96
|
+
contents list — where it has more than three `<h2>`s — joins the foot of the
|
|
97
|
+
same rail. A page with a contents list and no boxes takes `.single-with-toc`
|
|
98
|
+
and its narrower column, exactly as before.
|
|
99
|
+
- **A box carries no image.** A picture is authored in the page body, where
|
|
100
|
+
its position in the prose governs what follows it.
|
|
101
|
+
- A system box with nothing to show carries a `statement`, drawn in place of
|
|
102
|
+
its sections — see
|
|
103
|
+
[the three states of a system box](format-details.md#the-three-states-of-a-system-box)
|
|
104
|
+
for which one applies and why.
|
|
105
|
+
|
|
106
|
+
A page whose front matter declares no `infoboxes:` renders no rail.
|
|
107
|
+
|
|
108
|
+
## The hero banner
|
|
109
|
+
|
|
110
|
+
Nearly every page opens with a hero band, and `partials/hero-banner.html`
|
|
111
|
+
decides what sits behind it. A page arrives with its hero image stated in one
|
|
112
|
+
of two ways, and the difference is who resolved it: a content page carries
|
|
113
|
+
`data.banner`, which the build resolved from the asset Address the note
|
|
114
|
+
declared into the address its asset host serves; a hand-authored page carries
|
|
115
|
+
a top-level `banner:`, which the theme resolves against `params.cdnBaseURL`
|
|
116
|
+
(see [`params.cdnBaseURL`](../configuration.md#what-a-consumer-must-supply)).
|
|
117
|
+
|
|
118
|
+
**Resolution order.**
|
|
119
|
+
|
|
120
|
+
1. `data.banner` — a note's own hero image, used exactly as given, because the
|
|
121
|
+
build resolved it against a real asset record and dropped one nothing
|
|
122
|
+
answered. A blank is a note naming no hero image on purpose and declines
|
|
123
|
+
one; an unset or `null` value carries on to the next step.
|
|
124
|
+
2. `banner:` at the top level. `none` (or `false`) declines a hero image; a
|
|
125
|
+
full URL is used as-is; anything else is a fragment under `images/`.
|
|
126
|
+
3. `images/banners/{subtype}.webp`, where the subtype is the page's `category`
|
|
127
|
+
for a `type: doc` page and its `type` otherwise.
|
|
128
|
+
4. `images/banners/default.webp` — when the page has no type, **and** whenever
|
|
129
|
+
the name picked by 2 or 3 is not in the declared inventory.
|
|
130
|
+
|
|
131
|
+
**Why step 4 is a declaration, not a test.** Hugo cannot ask a remote host
|
|
132
|
+
whether a URL exists, so a banner that was never drawn would 404 in silence —
|
|
133
|
+
the band renders with its title, palette and gradient intact behind a dead URL,
|
|
134
|
+
and nothing fails: not the build, not Hugo, not the deploy guard.
|
|
135
|
+
`data/banners.yaml` is the declaration that stands in for the test the
|
|
136
|
+
template cannot make. A name listed in its `available` is asserted to exist; a
|
|
137
|
+
resolved name that is absent falls back to `fallback`, and Hugo logs one
|
|
138
|
+
deduplicated warning naming the missing banner and the first page that wanted
|
|
139
|
+
it. The fallback applies only to a relative path landing directly in the
|
|
140
|
+
declared `dir` — an absolute URL, and a fragment pointing anywhere else under
|
|
141
|
+
`images/`, pass through untouched, because the theme has no inventory for
|
|
142
|
+
either and must not second-guess an address it cannot know about. A step 1
|
|
143
|
+
address is not checked for the same reason: the question has already been
|
|
144
|
+
answered upstream.
|
|
145
|
+
|
|
146
|
+
**One resolver.** The order above lives in `partials/banner-url.html`, which
|
|
147
|
+
returns a URL or an empty string; `hero-banner.html` calls it with the page's
|
|
148
|
+
subtype, for step 2.
|
|
149
|
+
|
|
150
|
+
**Keeping the inventory honest.** The lint check over `data/banners.yaml`
|
|
151
|
+
fetches every declared name from the asset host and fails on any non-200
|
|
152
|
+
response, so a name added optimistically is caught here rather than on a
|
|
153
|
+
published page. A consumer publishing its own artwork set replaces the whole
|
|
154
|
+
list by shipping its own `data/banners.yaml`, which Hugo reads in preference
|
|
155
|
+
to the theme's bundled one, and can run the same check against it.
|
|
156
|
+
|
|
157
|
+
**Declining a hero image.** `banner: none` on a hand-authored page, and a
|
|
158
|
+
blank `data.banner` on a note, render the band with no image at all — the
|
|
159
|
+
title, the palette and the `.hero-with-image` gradient, which is what gives
|
|
160
|
+
the band its presence. A package may have a standing editorial reason to
|
|
161
|
+
publish no imagery, and falling back to a default for those would substitute
|
|
162
|
+
artwork where the considered answer was "none". See
|
|
163
|
+
[images, icons, audio, and provenance](../authoring/assets.md) for how a note
|
|
164
|
+
declines one; the spelling differs from the hand-authored page's, and the two
|
|
165
|
+
are not interchangeable.
|
|
166
|
+
|
|
167
|
+
## The holdings card
|
|
168
|
+
|
|
169
|
+
`partials/holdings.html` renders a bordered card below the body and above the
|
|
170
|
+
Related card, holding up to three small tables. The build derives this front
|
|
171
|
+
matter from what every _other_ page says, so the three keys are refused in a
|
|
172
|
+
note and dropped if one carries them:
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
---
|
|
176
|
+
contains: [{ title: …, url: …, type: place, subType: … }] # places within this one
|
|
177
|
+
held_by: [{ title: …, url: …, type: affiliation, subType: … }] # affiliations holding this place
|
|
178
|
+
holdings: [{ title: …, url: …, type: place, subType: … }] # places this affiliation holds
|
|
179
|
+
---
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
A place page carries `contains` and/or `held_by`; an affiliation page carries
|
|
183
|
+
`holdings`. Each key is tested for independently — a page carrying none of the
|
|
184
|
+
three renders no card, and a page carrying one renders one table.
|
|
185
|
+
|
|
186
|
+
**`url` is absent for an entry with no page of its own** — a stub note with an
|
|
187
|
+
empty body, which still appears in the lists of the pages that name it. Such
|
|
188
|
+
an entry's title renders as plain text; every other entry renders as a link.
|
|
189
|
+
`partials/holdings/entry.html` carries the guard, the same one
|
|
190
|
+
`partials/infobox/entry.html` already applies to its own `{text, url}` shape.
|
|
191
|
+
|
|
192
|
+
**Within** (`contains`) and **Holdings** (`holdings`) list places, and each is
|
|
193
|
+
broken into groups by `subType`, in the closed order region, settlement, site,
|
|
194
|
+
structure, feature — a `subType` outside that order, or missing entirely,
|
|
195
|
+
groups last, alphabetically by its rendered label. **Held by** (`held_by`)
|
|
196
|
+
lists affiliations, whose kinds have no fixed hierarchy to group by, so it
|
|
197
|
+
stays one flat grid with the kind printed beside each name.
|
|
198
|
+
|
|
199
|
+
Every grid is `repeat(auto-fill, minmax(14em, 1fr))`, the one the Related card
|
|
200
|
+
uses, so a region with forty settlements stays scannable.
|
|
201
|
+
|
|
202
|
+
| class | drawn as |
|
|
203
|
+
| ----------------------- | -------------------------------------------------------------------- |
|
|
204
|
+
| `.holdings` | the card |
|
|
205
|
+
| `.holdings-table` | one of the three tables, label and body together |
|
|
206
|
+
| `.holdings-table-label` | "Within" / "Held by" / "Holdings" |
|
|
207
|
+
| `.holdings-table-grid` | the grid of entries (Held by; the innermost grid of Within/Holdings) |
|
|
208
|
+
| `.holdings-kind-group` | one kind's block within Within or Holdings |
|
|
209
|
+
| `.holdings-kind-label` | the kind label heading a group |
|
|
210
|
+
| `.holdings-entry-name` | an entry's title, linked or plain |
|
|
211
|
+
| `.holdings-entry-kind` | the kind printed beside a Held by entry |
|
|
212
|
+
|
|
213
|
+
A page whose front matter declares none of `contains`, `held_by` or
|
|
214
|
+
`holdings` renders no card at all.
|
|
215
|
+
|
|
216
|
+
## The place map
|
|
217
|
+
|
|
218
|
+
A place page with `map: from-<shortcode>.svg` displays a **From here** panel
|
|
219
|
+
between Holdings and Related. The map is a page-bundle SVG the build draws
|
|
220
|
+
from the place's authored borders and routes, and `map:` is not a key a note
|
|
221
|
+
may write. Its place names link to their pages. A page with no `map` value or
|
|
222
|
+
no matching bundle resource displays no panel.
|
|
223
|
+
|
|
224
|
+
The drawing fits the content column and scrolls horizontally when the
|
|
225
|
+
available width is narrow. The relevant classes are `.place-map`,
|
|
226
|
+
`.place-map-heading`, and `.place-map-drawing`.
|
|
227
|
+
|
|
228
|
+
## The related card
|
|
229
|
+
|
|
230
|
+
`partials/related.html` renders a bordered "Related" card below the body,
|
|
231
|
+
listing the pages connected to this one. The build emits this front matter on
|
|
232
|
+
every content page; what links to a page is a fact about every other page, so
|
|
233
|
+
an authored `related:` is refused and dropped:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
---
|
|
237
|
+
related:
|
|
238
|
+
backlinks: [{ title: …, url: …, type: … }] # pages that link here
|
|
239
|
+
mentions: [{ title: …, url: …, type: … }] # pages this page links to
|
|
240
|
+
---
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Both directions are merged into a single pool, deduped by `url`, and grouped
|
|
244
|
+
by the referenced page's `type`. Each group is a labelled block, its entries a
|
|
245
|
+
CSS grid (`repeat(auto-fill, minmax(14em, 1fr))`) that reflows its own column
|
|
246
|
+
count from the available width with no media query — two or three columns on
|
|
247
|
+
a desktop, one on a phone. An entry is the linked page title.
|
|
248
|
+
|
|
249
|
+
| class | drawn as |
|
|
250
|
+
| ---------------------- | ----------------------------------------- |
|
|
251
|
+
| `.related` | the card |
|
|
252
|
+
| `.related-heading` | the "Related" heading |
|
|
253
|
+
| `.related-group` | one type's block, label and grid together |
|
|
254
|
+
| `.related-group-label` | the type label heading a group |
|
|
255
|
+
| `.related-group-grid` | the grid of linked entries |
|
|
256
|
+
|
|
257
|
+
A page whose `related` carries neither list, or whose two lists are both
|
|
258
|
+
empty, renders no card at all.
|
|
259
|
+
|
|
260
|
+
## Images in note prose
|
|
261
|
+
|
|
262
|
+
The content renderer emits a `figure.note-image` for a Markdown image that
|
|
263
|
+
stands in its own paragraph. An image with no `size:` uses its natural width,
|
|
264
|
+
bounded by the content column. `size: small`, `medium`, `large`, and
|
|
265
|
+
`xlarge` set maximum widths of 64, 128, 256, and 512 CSS pixels. `size:
|
|
266
|
+
full-width` fills the content column; `.full-width` gives the figure the same
|
|
267
|
+
column width. When `.full-width` and a bounded size appear together, the
|
|
268
|
+
image keeps its named width inside the full-width figure. The image height
|
|
269
|
+
follows its aspect ratio.
|
|
270
|
+
|
|
271
|
+
A picture's declared role carries a maximum of its own, so pictures of one
|
|
272
|
+
kind draw at one measure across every page. `portrait` and `emblem` take half
|
|
273
|
+
the content column; `banner`, `plate`, and `map` take the whole of it. Each
|
|
274
|
+
slot is a maximum rather than a target: the drawn width is the smaller of the
|
|
275
|
+
slot and what the file's own pixels support, so a picture is never stretched
|
|
276
|
+
past the size it was made at. A named `size:` or `.full-width` overrides a
|
|
277
|
+
role's slot outright, and a vector — which states no pixel count — draws at
|
|
278
|
+
the slot. On a narrow column every slot opens to the full measure. The role
|
|
279
|
+
vocabulary is the one the content toolchain declares, and a role added there
|
|
280
|
+
fails this theme's own check until the slot table gives it a maximum.
|
|
281
|
+
|
|
282
|
+
`float: top-left` and `bottom-left` wrap prose to the right; `top-right` and
|
|
283
|
+
`bottom-right` wrap it to the left. `float: center` centers the figure without
|
|
284
|
+
wrapping. On narrow screens, figures remain in document order without text
|
|
285
|
+
wrapping. An image's label is alternative text, carried on the image itself
|
|
286
|
+
for a reader who cannot see it, and is not drawn beneath the picture. See
|
|
287
|
+
[figures and numbered references](../authoring/links-and-markup.md#figures-and-numbered-references)
|
|
288
|
+
for how an author writes `size`, `float` and a role.
|
|
289
|
+
|
|
290
|
+
## A numbered figure
|
|
291
|
+
|
|
292
|
+
A `:::figure` fence wraps a picture, a table, a listing, a map or a passage of
|
|
293
|
+
prose in a numbered, referable block. The content build decides which from
|
|
294
|
+
the fence's contents, counts each kind separately, and emits the block with
|
|
295
|
+
its label beneath whatever it holds:
|
|
296
|
+
|
|
297
|
+
```html
|
|
298
|
+
<div id="harbour-at-dusk" class="content-figure content-figure-figure">
|
|
299
|
+
<figure class="note-image note-image-role-map">…</figure>
|
|
300
|
+
<p class="content-figure-label">Figure 3: The harbour at dusk</p>
|
|
301
|
+
</div>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
The kind is `code`, `table`, `figure`, `map`, `poem` or `prose`, labelled **Code**,
|
|
305
|
+
**Table**, **Figure**, **Map**, **Poem** and **Prose**. Every kind is drawn alike — the
|
|
306
|
+
block carries the spacing, its contents add none of their own at the edges,
|
|
307
|
+
and the label reads as a caption rather than as another paragraph of the body
|
|
308
|
+
— so a kind added to the vocabulary arrives styled. A fence carrying an `id`
|
|
309
|
+
is a cross-reference target and takes the same scroll offset a heading does.
|
|
310
|
+
|
|
311
|
+
`border` is the one class an author may write on a fence, and it draws the
|
|
312
|
+
block as a boxed aside.
|
|
313
|
+
|
|
314
|
+
| class | drawn as |
|
|
315
|
+
| ------------------------ | ------------------------------------------ |
|
|
316
|
+
| `.content-figure` | the block |
|
|
317
|
+
| `.content-figure-<kind>` | the kind, for a consumer wanting one apart |
|
|
318
|
+
| `.content-figure-label` | the label, number and caption together |
|
|
319
|
+
| `.border` | the block as a boxed aside |
|
|
320
|
+
|
|
321
|
+
## Search
|
|
322
|
+
|
|
323
|
+
`params.search = true` renders a search box in the header; left unset (or
|
|
324
|
+
`false`), `partials/search.html` renders nothing. The box, and everything it
|
|
325
|
+
opens, is the theme's own — the index it reads is not.
|
|
326
|
+
|
|
327
|
+
**Where the index comes from.** `package-build site-root` writes a
|
|
328
|
+
[Pagefind](https://pagefind.app) index at `pagefind/` beside the rendered
|
|
329
|
+
pages, when `site.search` in `package-build.config.yaml` is left at its
|
|
330
|
+
default of `true` (see [`site.search`](../configuration.md#site) and
|
|
331
|
+
[`package-build site-root`](../commands.md#package-build-site-root)).
|
|
332
|
+
Pagefind's own UI — `pagefind-ui.js` and `pagefind-ui.css` — ships inside that
|
|
333
|
+
generated directory, so the theme carries no copy and is pinned to no
|
|
334
|
+
Pagefind version. Turning `params.search` on without `site.search` indexing
|
|
335
|
+
the site (or with it set `false`) shows an empty results box that never finds
|
|
336
|
+
anything — the two settings are independent, and a consumer sets both.
|
|
337
|
+
|
|
338
|
+
Both files are referenced the same way every other theme-bundled asset is —
|
|
339
|
+
`relURL`, the same resolution `"css/style.css" | relURL` uses in
|
|
340
|
+
`baseof.html` — so a package served under a prefix (`/thalorna/pagefind/…`)
|
|
341
|
+
finds its own index rather than another package's, and the theme carries no
|
|
342
|
+
address of its own.
|
|
343
|
+
|
|
344
|
+
**Why a header box and not a `/search/` page.** A site is its homepage and
|
|
345
|
+
its pages, with nothing generated between them — a results page would need a
|
|
346
|
+
consumer content file at that address, which the theme has no way to
|
|
347
|
+
conjure. Pagefind's own panel UI needs no page of its own: the header button
|
|
348
|
+
opens it in place.
|
|
349
|
+
|
|
350
|
+
**What is indexed.** `data-pagefind-body` on `.single-body` scopes indexing to
|
|
351
|
+
a page's prose; the theme's own chrome carries `data-pagefind-ignore` — the
|
|
352
|
+
header, the footer, the infobox rail, the table of contents, the Related
|
|
353
|
+
card, and the hero banner's title and tagline. `_default/single.html` also
|
|
354
|
+
tags every page with `data-pagefind-filter="type"` and
|
|
355
|
+
`data-pagefind-filter="package"`, read from the page's own `type` and
|
|
356
|
+
`package` front matter, so a search can be narrowed to one catalog or one
|
|
357
|
+
package without either value appearing in the page itself.
|
|
358
|
+
|
|
359
|
+
**Classes added:** `.site-search`, `.search-toggle`, `.search-panel`,
|
|
360
|
+
`.search-panel-inner`, and `.header-actions` (the header's nav/search/toggle
|
|
361
|
+
group). `.search-panel-inner` carries Pagefind's own `--pagefind-ui-*`
|
|
362
|
+
theming variables, set from the theme's own tokens so results match the
|
|
363
|
+
chrome around them.
|
|
364
|
+
|
|
365
|
+
## What a page, a homepage and a section landing carry
|
|
366
|
+
|
|
367
|
+
### A page
|
|
368
|
+
|
|
369
|
+
`_default/single.html` renders every page that is not the homepage: the hero,
|
|
370
|
+
the infobox rail, the body, any `related:` block, and prev/next links through
|
|
371
|
+
the page's own catalog.
|
|
372
|
+
|
|
373
|
+
**Emitted.** A note's page arrives with `title` (the note's name), `type`,
|
|
374
|
+
`subType`, `description` and `tags` already set, and `data.banner` resolved.
|
|
375
|
+
The form below is the hand-written one, which is what a blog post or a
|
|
376
|
+
curated landing carries: `title`, `date` and a top-level `banner:` are keys
|
|
377
|
+
the content build never writes, and a note's page therefore has no `date` and
|
|
378
|
+
no meta-line date at all.
|
|
379
|
+
|
|
380
|
+
```yaml
|
|
381
|
+
---
|
|
382
|
+
# A hand-written page. A note's page carries the emitted form instead.
|
|
383
|
+
title: Brànwâal Dôrgaar
|
|
384
|
+
type: being # the page's catalog — see "Prev/next" below
|
|
385
|
+
subType: character # a being's classification; shown as a plain label
|
|
386
|
+
banner: being/dorgaar.webp
|
|
387
|
+
date: 2024-03-01 # optional; shown in the page meta line
|
|
388
|
+
tags: [archetype, mercantyl] # optional; shown in the page meta line
|
|
389
|
+
---
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
- **`type`** is the page's catalog key, unless it is `doc` — prose rather than
|
|
393
|
+
a catalog of its own — in which case the key is `subType` (what the build
|
|
394
|
+
compiles from a note's classification) or, failing that, `category` (what a
|
|
395
|
+
hand-mounted documentation tree carries). A page with no `type` has no
|
|
396
|
+
catalog.
|
|
397
|
+
- **`date`**, **`tags`** — each optional and shown only when present, in a
|
|
398
|
+
meta line above the body. A tag links to `tags/<tag>/`.
|
|
399
|
+
- **`subType`** — shown as a plain label for `type: being` pages. It does not
|
|
400
|
+
create a tag or taxonomy term.
|
|
401
|
+
|
|
402
|
+
**The draft notice.** A page tagged `draft` states that its content is not
|
|
403
|
+
settled, at the head of the article — above the infobox rail and above the
|
|
404
|
+
prose, at every width. The tag is a state rather than a subject, so it is kept
|
|
405
|
+
out of the meta line's tag row and said here instead.
|
|
406
|
+
|
|
407
|
+
```html
|
|
408
|
+
<aside class="draft-notice">
|
|
409
|
+
<i class="fa-solid fa-circle-exclamation draft-notice-icon" aria-hidden="true"></i>
|
|
410
|
+
<p class="draft-notice-text"><strong class="draft-notice-label">Draft.</strong> <em>…</em></p>
|
|
411
|
+
</aside>
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
- **`params.notfound`** wording is separate; **`params.draftNotice`** replaces
|
|
415
|
+
the draft sentence above. The default reads _This entry is unfinished. What
|
|
416
|
+
it states may change, and nothing in it is settled._
|
|
417
|
+
- **`.draft-notice`**, **`.draft-notice-icon`**, **`.draft-notice-text`** and
|
|
418
|
+
**`.draft-notice-label`** are the classes a consumer styles against.
|
|
419
|
+
- The mark is Font Awesome, which `baseof.html` already loads; the sentence
|
|
420
|
+
reads on its own where it does not arrive.
|
|
421
|
+
- The sentence is an `em`: the label is the page's own voice naming the
|
|
422
|
+
state, and the sentence is the page speaking about itself.
|
|
423
|
+
- A page carrying the notice also carries **`.single-with-notice`** on its
|
|
424
|
+
article, which is what moves a two-column page's content and rail below it.
|
|
425
|
+
|
|
426
|
+
**Prev/next.** `.PrevInSection` / `.NextInSection` walk every page under the
|
|
427
|
+
site's content mount, since the build emits every note flat there rather than
|
|
428
|
+
filing it into a directory named for its catalog. A mount holding more than
|
|
429
|
+
one catalog narrows the walk to the pages sharing this page's catalog key, so
|
|
430
|
+
reading through the afflictions does not surface a skill; a mount holding a
|
|
431
|
+
single catalog is untouched, because `.PrevInSection` already walks exactly
|
|
432
|
+
that catalog there.
|
|
433
|
+
|
|
434
|
+
### The homepage
|
|
435
|
+
|
|
436
|
+
A package's home page is `content/_index.md`, mounted at the package's own
|
|
437
|
+
prefix. `layouts/index.html` selects between two shapes by what it carries.
|
|
438
|
+
|
|
439
|
+
**`type: homepage`** renders the page through the same structure a note gets
|
|
440
|
+
from `_default/single.html` — the hero from its `banner:`, then its body —
|
|
441
|
+
sharing the markup through `partials/page-body.html` so a homepage and a page
|
|
442
|
+
read as one family:
|
|
443
|
+
|
|
444
|
+
```yaml
|
|
445
|
+
---
|
|
446
|
+
type: homepage
|
|
447
|
+
title: Song of Heroic Lands # hero heading
|
|
448
|
+
description: A classless, skill-based fantasy system … # hero standfirst
|
|
449
|
+
|
|
450
|
+
# The hero image. The same `banner:` every other page in this theme uses,
|
|
451
|
+
# resolved by `partials/hero-banner.html` in the documented order and through
|
|
452
|
+
# `params.cdnBaseURL` — see "The hero banner" above. With none set, the
|
|
453
|
+
# subtype default lands on `images/banners/homepage.webp`, since the subtype
|
|
454
|
+
# default is keyed on the page's `type`. `banner: none` declines a hero image
|
|
455
|
+
# entirely.
|
|
456
|
+
banner: brand/sohl-banner.webp
|
|
457
|
+
---
|
|
458
|
+
Everything published for the system lives under this address …
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
The home page declares no `infoboxes:`, `related:`, `date:` or `tags:`, so
|
|
462
|
+
those pieces of a page stay silent.
|
|
463
|
+
|
|
464
|
+
**No `type` at all** — a site whose home page is a set of entry points into
|
|
465
|
+
everything it publishes — renders the featured grid documented under
|
|
466
|
+
[`params.home`](../configuration.md#what-a-consumer-must-supply).
|
|
467
|
+
|
|
468
|
+
### A section landing
|
|
469
|
+
|
|
470
|
+
**Hand-written.** `_default/list.html` renders whatever a consumer still
|
|
471
|
+
gives Hugo's `section`, `taxonomy` or `term` kinds to render — a
|
|
472
|
+
hand-curated landing at a real subdirectory, and Hugo's own tag pages. A
|
|
473
|
+
`package-build` site disables all three (`disableKinds`), so this layout
|
|
474
|
+
never runs for one; a site that keeps them enabled still needs a landing, and
|
|
475
|
+
this is it.
|
|
476
|
+
|
|
477
|
+
It opens with the hero and any authored body, then auto-lists the section's
|
|
478
|
+
members (`.Pages`) as a gap-filler: a member the body already links,
|
|
479
|
+
directly or transitively, is not repeated, and the rest appear under
|
|
480
|
+
"Orphaned Pages" when the body links some of them, or plainly when it links
|
|
481
|
+
none. A tag's term page lists the pages carrying it; the tag index itself
|
|
482
|
+
lists every tag with its page count.
|
|
483
|
+
|
|
484
|
+
```yaml
|
|
485
|
+
---
|
|
486
|
+
# content/projects/_index.md — a hand-curated landing, no `type:` at all
|
|
487
|
+
title: Projects
|
|
488
|
+
description: Foundry VTT systems, modules, and reference content …
|
|
489
|
+
---
|
|
490
|
+
Each section below has its own landing page.
|
|
491
|
+
|
|
492
|
+
# [Song of Heroic Lands](/projects/song-of-heroic-lands/)
|
|
493
|
+
…
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
A row is a linked title and, when the page carries one, its description.
|
package/engine/art-slots.mjs
CHANGED
|
@@ -43,7 +43,8 @@ const ART_TYPES = Object.freeze(["icon", "image"]);
|
|
|
43
43
|
* The four art slots, in the order the specification tabulates them.
|
|
44
44
|
*
|
|
45
45
|
* `banner` is the one that reaches no compiled document: it is the page's hero
|
|
46
|
-
* image, read by the site and by
|
|
46
|
+
* image, read by the site and by nothing else. The book's section plates read a
|
|
47
|
+
* banner of their own, from the book plan's `presentation.page.banner`.
|
|
47
48
|
* That is what `document: false` states, and it is why the inert-art check
|
|
48
49
|
* skips it — a key that is *meant* to reach no document is not an inert key.
|
|
49
50
|
*
|