@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
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
Whether a page's note is an unfinished draft.
|
|
3
|
+
|
|
4
|
+
The `draft` tag is the authored signal, and it is the only one either side
|
|
5
|
+
can read: the content build asks it through its own single reader
|
|
6
|
+
(package-build/engine/note-vocabulary.mjs, `DRAFT_TAG`) and a theme cannot
|
|
7
|
+
import that, so the shared fact is the tag itself. It reaches the page
|
|
8
|
+
because the build copies a note's own front matter onto it.
|
|
9
|
+
|
|
10
|
+
It is spelled once, here. Two partials act on the state — the tag row leaves
|
|
11
|
+
it out of a page's subjects, and the notice states it — and a second literal
|
|
12
|
+
is how the two come apart.
|
|
13
|
+
|
|
14
|
+
Hugo's own reserved `draft: true` is a different thing entirely and is never
|
|
15
|
+
written by the build: a page carrying it is not rendered at all.
|
|
16
|
+
|
|
17
|
+
Context: the page. Returns "true" for a draft and "" for anything else, which
|
|
18
|
+
is what `if` reads.
|
|
19
|
+
*/ -}}
|
|
20
|
+
{{- $draft := false -}}
|
|
21
|
+
{{- range .Params.tags -}}
|
|
22
|
+
{{- if eq (lower .) "draft" -}}
|
|
23
|
+
{{- $draft = true -}}
|
|
24
|
+
{{- end -}}
|
|
25
|
+
{{- end -}}
|
|
26
|
+
{{- return $draft -}}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<footer class="site-footer" data-pagefind-ignore>
|
|
2
|
+
<div class="footer-inner">
|
|
3
|
+
<p class="footer-text">
|
|
4
|
+
© 2020–{{ now.Year }} Tom Rodriguez. Content under The World of Thalorna and Song of Heroic Lands is licensed under
|
|
5
|
+
<a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a>; all other content is © Tom Rodriguez, all rights reserved.{{ with .Site.Params.brand }}{{ with .licenseURL }} See
|
|
6
|
+
<a href="{{ . }}">License</a>.{{ end }}{{ end }}
|
|
7
|
+
</p>
|
|
8
|
+
<div class="footer-links">
|
|
9
|
+
<a href="https://creativecommons.org/licenses/by-sa/4.0/">
|
|
10
|
+
<img src="https://licensebuttons.net/l/by-sa/4.0/88x31.png" alt="CC BY-SA 4.0" class="cc-badge">
|
|
11
|
+
</a>
|
|
12
|
+
{{- with .Site.Params.brand }}{{ with .discordURL }}
|
|
13
|
+
<a href="{{ . }}">
|
|
14
|
+
<svg width="24" height="19" viewBox="0 0 71 55" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
15
|
+
<path d="M60.1 4.9A58.5 58.5 0 0045.4.2a.2.2 0 00-.2.1 40.8 40.8 0 00-1.8 3.7 54 54 0 00-16.2 0A39 39 0 0025.4.3a.2.2 0 00-.2-.1A58.4 58.4 0 0010.5 5a.2.2 0 00-.1 0A60 60 0 00.3 45.3a.2.2 0 000 .2 58.7 58.7 0 0017.7 9 .2.2 0 00.3-.1 42 42 0 003.6-5.9.2.2 0 00-.1-.3 38.6 38.6 0 01-5.5-2.6.2.2 0 01 0-.4c.4-.3.7-.6 1.1-.8a.2.2 0 01.2 0 41.9 41.9 0 0035.6 0 .2.2 0 01.2 0l1 .9a.2.2 0 010 .3 36.2 36.2 0 01-5.5 2.6.2.2 0 00-.1.4 47.1 47.1 0 003.6 5.8.2.2 0 00.2.1A58.5 58.5 0 0070.3 45.5a.2.2 0 000-.2A59.7 59.7 0 0060.2 5a.2.2 0 00-.1 0zM23.7 37.3c-3.5 0-6.4-3.2-6.4-7.1s2.8-7.1 6.4-7.1 6.5 3.2 6.4 7.1c0 3.9-2.8 7.1-6.4 7.1zm23.7 0c-3.5 0-6.4-3.2-6.4-7.1s2.8-7.1 6.4-7.1 6.5 3.2 6.4 7.1c0 3.9-2.8 7.1-6.4 7.1z"/>
|
|
16
|
+
</svg>
|
|
17
|
+
Discord
|
|
18
|
+
</a>
|
|
19
|
+
{{- end }}{{ end }}
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</footer>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
document.querySelector('.nav-toggle')?.addEventListener('click', function() {
|
|
26
|
+
document.querySelector('.site-nav').classList.toggle('open');
|
|
27
|
+
this.classList.toggle('open');
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<header class="site-header" data-pagefind-ignore>
|
|
2
|
+
<div class="header-inner">
|
|
3
|
+
<a href="{{ .Site.Home.RelPermalink }}" class="site-title">
|
|
4
|
+
{{- with .Site.Params.brand }}{{ with .logo }}
|
|
5
|
+
<img src="{{ partial "cdn-url.html" (dict "site" $.Site "path" .) }}" alt="Heroic Lands" class="site-logo">
|
|
6
|
+
{{- end }}{{ end }}
|
|
7
|
+
<span class="title-main">Heroic Lands</span>
|
|
8
|
+
</a>
|
|
9
|
+
<div class="header-actions">
|
|
10
|
+
<nav class="site-nav">
|
|
11
|
+
{{ range .Site.Menus.main }}
|
|
12
|
+
{{ if .HasChildren }}
|
|
13
|
+
<div class="nav-dropdown">
|
|
14
|
+
<a href="{{ .URL }}" class="nav-link{{ if $.IsMenuCurrent "main" . }} active{{ end }}">
|
|
15
|
+
{{ .Name }}
|
|
16
|
+
<svg class="dropdown-arrow" width="10" height="6" viewBox="0 0 10 6" fill="currentColor"><path d="M1 1l4 4 4-4"/></svg>
|
|
17
|
+
</a>
|
|
18
|
+
<div class="dropdown-menu">
|
|
19
|
+
{{ range .Children }}
|
|
20
|
+
<a href="{{ .URL }}" class="dropdown-item">{{ .Name }}</a>
|
|
21
|
+
{{ end }}
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
{{ else }}
|
|
25
|
+
<a href="{{ .URL }}" class="nav-link{{ if $.IsMenuCurrent "main" . }} active{{ end }}">{{ .Name }}</a>
|
|
26
|
+
{{ end }}
|
|
27
|
+
{{ end }}
|
|
28
|
+
</nav>
|
|
29
|
+
{{ partial "search.html" . }}
|
|
30
|
+
<button class="nav-toggle" aria-label="Toggle navigation">
|
|
31
|
+
<span></span><span></span><span></span>
|
|
32
|
+
</button>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</header>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
Hero banner partial.
|
|
3
|
+
|
|
4
|
+
Displays a full-width banner band (using the same .hero.hero-with-image
|
|
5
|
+
classes as the homepage) with a centered page title and description
|
|
6
|
+
above the content.
|
|
7
|
+
|
|
8
|
+
Every path below resolves through cdn-url.html against the consuming
|
|
9
|
+
site's `params.cdnBaseURL`; the theme names no host of its own.
|
|
10
|
+
|
|
11
|
+
The resolution itself lives in `banner-url.html`, which a derived landing card
|
|
12
|
+
calls too. The order is documented in both places because this is where a
|
|
13
|
+
reader looking at a banner starts; that partial is where it happens.
|
|
14
|
+
|
|
15
|
+
Banner image resolution order:
|
|
16
|
+
1. .Params.data.banner — a note's own hero image, which the content
|
|
17
|
+
build resolved from an asset Address into
|
|
18
|
+
the address its asset host serves. Used
|
|
19
|
+
exactly as given. A blank declines a hero
|
|
20
|
+
image; unset or `null` carries on.
|
|
21
|
+
2. .Params.banner — a hand-authored page's value. `none` (or
|
|
22
|
+
`false`) declines a hero image entirely —
|
|
23
|
+
see "Declining" below. A full URL is used
|
|
24
|
+
as-is; anything else is treated as a
|
|
25
|
+
fragment under images/.
|
|
26
|
+
3. images/banners/{subtype}.webp — subtype-specific default, where
|
|
27
|
+
subtype = category for type=doc pages,
|
|
28
|
+
otherwise type
|
|
29
|
+
4. images/banners/default.webp — used when the page has no type, *and*
|
|
30
|
+
whenever the name picked by 2 or 3 is not
|
|
31
|
+
in the declared inventory (see below).
|
|
32
|
+
|
|
33
|
+
Existence, and why step 4 is a declaration rather than a test.
|
|
34
|
+
The image is served from the consumer's asset host, and Hugo cannot ask a
|
|
35
|
+
remote host whether a URL exists — so a name that was never drawn would be
|
|
36
|
+
emitted unchecked and 404 in silence, the band rendering with its title,
|
|
37
|
+
palette and gradient intact behind a dead URL. `data/banners.yaml`
|
|
38
|
+
is the declaration that stands in for the test it cannot make: a resolved name
|
|
39
|
+
absent from `available` falls back to `fallback` and warns once. That file
|
|
40
|
+
documents how the list is kept honest (`npm run lint:banners` fetches every
|
|
41
|
+
name and fails on a non-200), and a consumer publishing its own artwork set
|
|
42
|
+
overrides the whole list by shipping its own `data/banners.yaml`.
|
|
43
|
+
|
|
44
|
+
The check applies only to a *relative* path resolving directly inside the
|
|
45
|
+
declared banner directory. An absolute URL, and a fragment pointing anywhere
|
|
46
|
+
else under images/, pass through untouched: the theme has no inventory for
|
|
47
|
+
either and must not second-guess an address it cannot know about. A step 1
|
|
48
|
+
address is not checked either — the build resolved it against a real asset
|
|
49
|
+
record, so the question has already been answered.
|
|
50
|
+
|
|
51
|
+
Declining a hero image.
|
|
52
|
+
`banner: none` on a hand-authored page, and a blank `data.banner` on a note,
|
|
53
|
+
render the band with no image at all — the title, the palette
|
|
54
|
+
and the .hero-with-image gradient, which is what gives the band its presence.
|
|
55
|
+
This is not the same as having no banner yet: a package may have a standing
|
|
56
|
+
editorial reason to publish no imagery, and the fan-material carve-outs do.
|
|
57
|
+
Falling back to a default for them would substitute artwork where the
|
|
58
|
+
considered answer was "none", so declining has to be sayable.
|
|
59
|
+
*/ -}}
|
|
60
|
+
|
|
61
|
+
{{- /* For narrative content (type=doc) the meaningful kind of page lives in
|
|
62
|
+
`category` — continent, region, polity, faith, lore, etc. — so prefer
|
|
63
|
+
that when picking a default banner. */ -}}
|
|
64
|
+
{{- $type := .Params.type | default "" -}}
|
|
65
|
+
{{- $subtype := cond (eq $type "doc") (.Params.category | default "") $type -}}
|
|
66
|
+
{{- if not $subtype }}{{ $subtype = "default" }}{{ end -}}
|
|
67
|
+
|
|
68
|
+
{{- /* The order above, the `none` decision and the declared-existence check
|
|
69
|
+
all live in `banner-url.html`, which a derived landing card calls too
|
|
70
|
+
(issue #41). A hero band always wants the subtype default; a card never
|
|
71
|
+
does. */ -}}
|
|
72
|
+
{{- $bannerURL := partial "banner-url.html" (dict
|
|
73
|
+
"site" .Site
|
|
74
|
+
"data" .Params.data
|
|
75
|
+
"banner" .Params.banner
|
|
76
|
+
"subtype" $subtype
|
|
77
|
+
"context" .RelPermalink) -}}
|
|
78
|
+
|
|
79
|
+
<section class="hero hero-with-image"{{ with $bannerURL }} style="background-image: url('{{ . }}');"{{ end }}>
|
|
80
|
+
<div class="hero-inner" data-pagefind-ignore>
|
|
81
|
+
<h1>{{ .Title }}</h1>
|
|
82
|
+
{{- with .Params.description }}
|
|
83
|
+
<p class="hero-tagline">{{ . }}</p>
|
|
84
|
+
{{- end }}
|
|
85
|
+
</div>
|
|
86
|
+
</section>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
One entry of a holdings list — `{title, url, type, subType}`, as
|
|
3
|
+
`@heroiclands/package-build` derives from `contains`, `held_by` and
|
|
4
|
+
`holdings` (see the "holdings card" section of the README).
|
|
5
|
+
|
|
6
|
+
`url` is absent for a stub: a note with an empty body, which carries its
|
|
7
|
+
facts into every list that names it but publishes no page of its own. The
|
|
8
|
+
build omits the key outright rather than writing `url: null` — confirmed by
|
|
9
|
+
stringifying a stub entry through the same `gray-matter`/`js-yaml` path the
|
|
10
|
+
build writes frontmatter with — but `with` guards both the same way, since
|
|
11
|
+
a missing map key and an empty string both read false. This is the same
|
|
12
|
+
guard `infobox/entry.html` already applies to its own `{text, url}` shape.
|
|
13
|
+
|
|
14
|
+
Takes `entry` and the `class` its medium gives it.
|
|
15
|
+
*/ -}}
|
|
16
|
+
{{- $entry := .entry -}}
|
|
17
|
+
{{- with $entry.url -}}
|
|
18
|
+
<a class="{{ $.class }}" href="{{ . }}">{{ $entry.title }}</a>
|
|
19
|
+
{{- else -}}
|
|
20
|
+
<span class="{{ $.class }}">{{ $entry.title }}</span>
|
|
21
|
+
{{- end -}}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
The kind-grouped body of a "Within" or "Holdings" table: its entries
|
|
3
|
+
broken into named groups by `subType`, in the closed order region,
|
|
4
|
+
settlement, site, structure, feature — the order a reader wants a place
|
|
5
|
+
hierarchy read in, not alphabetical. A `subType` outside that order, or
|
|
6
|
+
missing entirely, is grouped last, one group per remaining kind,
|
|
7
|
+
alphabetically by its `humanize`d label.
|
|
8
|
+
|
|
9
|
+
Each group is a CSS grid (`repeat(auto-fill, minmax(14em, 1fr))`, the same
|
|
10
|
+
the Related card uses) so a region with forty settlements stays scannable.
|
|
11
|
+
|
|
12
|
+
Takes the entries (a `HoldingsEntry` list). Renders nothing for an empty
|
|
13
|
+
list, so a caller can include it unconditionally once its own presence
|
|
14
|
+
check on the list has passed.
|
|
15
|
+
*/ -}}
|
|
16
|
+
{{- $entries := . -}}
|
|
17
|
+
{{- $kindOrder := slice "region" "settlement" "site" "structure" "feature" -}}
|
|
18
|
+
{{- $kindLabels := dict
|
|
19
|
+
"region" "Regions"
|
|
20
|
+
"settlement" "Settlements"
|
|
21
|
+
"site" "Sites"
|
|
22
|
+
"structure" "Structures"
|
|
23
|
+
"feature" "Features"
|
|
24
|
+
-}}
|
|
25
|
+
|
|
26
|
+
{{- /* Bucket entries by subType, defaulting an absent one to "". */ -}}
|
|
27
|
+
{{- $byKind := dict -}}
|
|
28
|
+
{{- range $entries -}}
|
|
29
|
+
{{- $kind := .subType | default "" -}}
|
|
30
|
+
{{- $existing := index $byKind $kind | default slice -}}
|
|
31
|
+
{{- $byKind = merge $byKind (dict $kind ($existing | append .)) -}}
|
|
32
|
+
{{- end -}}
|
|
33
|
+
|
|
34
|
+
{{- /* The closed order first. */ -}}
|
|
35
|
+
{{- $groups := slice -}}
|
|
36
|
+
{{- $seen := slice -}}
|
|
37
|
+
{{- range $kindOrder -}}
|
|
38
|
+
{{- $kind := . -}}
|
|
39
|
+
{{- with index $byKind $kind -}}
|
|
40
|
+
{{- $groups = $groups | append (dict "label" (index $kindLabels $kind) "entries" .) -}}
|
|
41
|
+
{{- $seen = $seen | append $kind -}}
|
|
42
|
+
{{- end -}}
|
|
43
|
+
{{- end -}}
|
|
44
|
+
|
|
45
|
+
{{- /* Anything else — a kind outside the closed set, or none at all —
|
|
46
|
+
grouped last, alphabetically by its rendered label. */ -}}
|
|
47
|
+
{{- $leftover := slice -}}
|
|
48
|
+
{{- range $kind, $group := $byKind -}}
|
|
49
|
+
{{- if not (in $seen $kind) -}}
|
|
50
|
+
{{- $label := humanize $kind -}}
|
|
51
|
+
{{- if eq $kind "" -}}{{- $label = "Other" -}}{{- end -}}
|
|
52
|
+
{{- $leftover = $leftover | append (dict "label" $label "entries" $group) -}}
|
|
53
|
+
{{- end -}}
|
|
54
|
+
{{- end -}}
|
|
55
|
+
{{- if $leftover -}}
|
|
56
|
+
{{- $leftover = sort $leftover "label" "asc" -}}
|
|
57
|
+
{{- range $leftover -}}
|
|
58
|
+
{{- $groups = $groups | append . -}}
|
|
59
|
+
{{- end -}}
|
|
60
|
+
{{- end -}}
|
|
61
|
+
|
|
62
|
+
{{- range $groups }}
|
|
63
|
+
<div class="holdings-kind-group">
|
|
64
|
+
<h4 class="holdings-kind-label">{{ .label }}</h4>
|
|
65
|
+
<ul class="holdings-table-grid">
|
|
66
|
+
{{- range .entries }}
|
|
67
|
+
<li>{{ partial "holdings/entry.html" (dict "entry" . "class" "holdings-entry-name") }}</li>
|
|
68
|
+
{{- end }}
|
|
69
|
+
</ul>
|
|
70
|
+
</div>
|
|
71
|
+
{{- end -}}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
Holdings card.
|
|
3
|
+
|
|
4
|
+
Three small tables, rendered after the body and before the Related card
|
|
5
|
+
(see `page-body.html`), from front matter `@heroiclands/package-build`
|
|
6
|
+
derives and a note never authors itself:
|
|
7
|
+
|
|
8
|
+
contains: [{ title, url, type, subType }] places sitting within this one
|
|
9
|
+
held_by: [{ title, url, type, subType }] affiliations holding this place
|
|
10
|
+
holdings: [{ title, url, type, subType }] places this affiliation holds
|
|
11
|
+
|
|
12
|
+
A place page carries `contains` and/or `held_by`; an affiliation page
|
|
13
|
+
carries `holdings`. Neither is checked here — presence of the key is the
|
|
14
|
+
only test, the same silent-disappear convention the Related card follows:
|
|
15
|
+
a page carrying none of the three renders no card at all.
|
|
16
|
+
|
|
17
|
+
`contains` and `holdings` list places, so each is broken into groups by
|
|
18
|
+
kind (`holdings/kind-groups.html`) — the towns together, the hamlets
|
|
19
|
+
together. `held_by` lists affiliations, whose kinds have no fixed
|
|
20
|
+
hierarchy to group by, so it stays one flat grid with the kind printed
|
|
21
|
+
beside each name instead of as a group heading.
|
|
22
|
+
|
|
23
|
+
An entry's `url` is absent for a stub — a note with an empty body, which
|
|
24
|
+
carries its facts into every list that names it but publishes no page of
|
|
25
|
+
its own. `holdings/entry.html` renders such an entry as plain text and
|
|
26
|
+
every other entry as a link — see it for the guard and how its correctness
|
|
27
|
+
was established.
|
|
28
|
+
*/ -}}
|
|
29
|
+
{{- $within := .Params.contains -}}
|
|
30
|
+
{{- $heldBy := .Params.held_by -}}
|
|
31
|
+
{{- $holds := .Params.holdings -}}
|
|
32
|
+
|
|
33
|
+
{{- if or $within $heldBy $holds -}}
|
|
34
|
+
<section class="holdings" data-pagefind-ignore>
|
|
35
|
+
{{- with $within }}
|
|
36
|
+
<div class="holdings-table">
|
|
37
|
+
<h3 class="holdings-table-label">Within</h3>
|
|
38
|
+
{{ partial "holdings/kind-groups.html" . }}
|
|
39
|
+
</div>
|
|
40
|
+
{{- end }}
|
|
41
|
+
{{- with $heldBy }}
|
|
42
|
+
<div class="holdings-table">
|
|
43
|
+
<h3 class="holdings-table-label">Held by</h3>
|
|
44
|
+
<ul class="holdings-table-grid">
|
|
45
|
+
{{- range . }}
|
|
46
|
+
<li>
|
|
47
|
+
{{- partial "holdings/entry.html" (dict "entry" . "class" "holdings-entry-name") -}}
|
|
48
|
+
{{- with .subType }}<span class="holdings-entry-kind"> ({{ humanize . }})</span>{{ end -}}
|
|
49
|
+
</li>
|
|
50
|
+
{{- end }}
|
|
51
|
+
</ul>
|
|
52
|
+
</div>
|
|
53
|
+
{{- end }}
|
|
54
|
+
{{- with $holds }}
|
|
55
|
+
<div class="holdings-table">
|
|
56
|
+
<h3 class="holdings-table-label">Holdings</h3>
|
|
57
|
+
{{ partial "holdings/kind-groups.html" . }}
|
|
58
|
+
</div>
|
|
59
|
+
{{- end }}
|
|
60
|
+
</section>
|
|
61
|
+
{{- end -}}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
One entry of a `runin` group or a `list` section.
|
|
3
|
+
|
|
4
|
+
An entry is `{text, url}`. It links when the build reached the page it
|
|
5
|
+
names, and keeps its words when it did not — a panel naming something this
|
|
6
|
+
site does not publish is better than a panel silently one entry short.
|
|
7
|
+
|
|
8
|
+
Takes `entry` and the `class` its medium gives it.
|
|
9
|
+
*/ -}}
|
|
10
|
+
{{- $entry := .entry -}}
|
|
11
|
+
{{- with $entry.url -}}
|
|
12
|
+
<a class="{{ $.class }}" href="{{ . }}">{{ $entry.text }}</a>
|
|
13
|
+
{{- else -}}
|
|
14
|
+
<span class="{{ $.class }}">{{ $entry.text }}</span>
|
|
15
|
+
{{- end -}}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
What one infobox section holds, whatever its layout.
|
|
3
|
+
|
|
4
|
+
A section carries its content under the key its layout names — `rows`,
|
|
5
|
+
`cells`, `groups` or `entries` — so one lookup answers "is there anything to
|
|
6
|
+
draw?" for every layout there is. Returns a slice, empty when there is
|
|
7
|
+
nothing.
|
|
8
|
+
|
|
9
|
+
Takes the section. Returns the items.
|
|
10
|
+
|
|
11
|
+
An unrecognised layout returns nothing and says so once: the four layouts
|
|
12
|
+
are a closed set, so a fifth means this theme is older than the content it
|
|
13
|
+
is drawing, and a silently dropped section is the expensive way to find out.
|
|
14
|
+
*/ -}}
|
|
15
|
+
{{- $section := . -}}
|
|
16
|
+
{{- $layout := $section.layout | default "" -}}
|
|
17
|
+
{{- $key := index (dict "rows" "rows" "grid" "cells" "runin" "groups" "list" "entries") $layout -}}
|
|
18
|
+
{{- $items := slice -}}
|
|
19
|
+
{{- with $key -}}
|
|
20
|
+
{{- with index $section . -}}
|
|
21
|
+
{{- $items = . -}}
|
|
22
|
+
{{- end -}}
|
|
23
|
+
{{- else -}}
|
|
24
|
+
{{- warnidf "infobox-unknown-layout" "infobox: section layout %q is not one of rows, grid, runin or list, so the section is not drawn. Upgrade @heroiclands/hugo-theme to a version that draws it." $layout -}}
|
|
25
|
+
{{- end -}}
|
|
26
|
+
{{- return $items -}}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
One infobox section, arranged the way its `layout` says.
|
|
3
|
+
|
|
4
|
+
Four layouts, a closed set, and the key a section carries its content under
|
|
5
|
+
is what names it:
|
|
6
|
+
|
|
7
|
+
rows — label/value pairs, one per line `rows`
|
|
8
|
+
grid — short label/value cells packed together `cells`
|
|
9
|
+
runin — groups of comma-joined entries `groups`
|
|
10
|
+
list — one entry per line `entries`
|
|
11
|
+
|
|
12
|
+
Takes the section.
|
|
13
|
+
|
|
14
|
+
**A value of `0` is a value.** Armour that stops nothing edged is a fact
|
|
15
|
+
about the armour, so a cell is printed as it comes rather than guarded with
|
|
16
|
+
`with`, which would drop a zero along with an absence.
|
|
17
|
+
*/ -}}
|
|
18
|
+
{{- $section := . -}}
|
|
19
|
+
{{- $layout := $section.layout | default "" -}}
|
|
20
|
+
{{- if eq $layout "rows" -}}
|
|
21
|
+
<dl class="info-profile-grid">
|
|
22
|
+
{{- range $section.rows }}
|
|
23
|
+
<dt>{{ .label }}</dt>
|
|
24
|
+
<dd>{{ partial "infobox/value.html" . }}</dd>
|
|
25
|
+
{{- end }}
|
|
26
|
+
</dl>
|
|
27
|
+
{{- else if eq $layout "grid" -}}
|
|
28
|
+
<div class="info-attrs-grid">
|
|
29
|
+
{{- range $section.cells }}
|
|
30
|
+
<div class="info-attr">
|
|
31
|
+
<span class="attr-label">{{ .label }}</span>
|
|
32
|
+
<span class="attr-value">{{ .value }}</span>
|
|
33
|
+
</div>
|
|
34
|
+
{{- end }}
|
|
35
|
+
</div>
|
|
36
|
+
{{- else if eq $layout "runin" -}}
|
|
37
|
+
{{- range $section.groups }}
|
|
38
|
+
<p class="info-skill-line">
|
|
39
|
+
{{- with .label }}<span class="skill-cat">{{ . }}:</span>{{ end }}
|
|
40
|
+
<span class="skill-entries">
|
|
41
|
+
{{- range $i, $entry := .entries -}}
|
|
42
|
+
{{- if $i }}, {{ end -}}
|
|
43
|
+
{{- partial "infobox/entry.html" (dict "entry" $entry "class" "skill-entry") -}}
|
|
44
|
+
{{- end -}}
|
|
45
|
+
</span>
|
|
46
|
+
</p>
|
|
47
|
+
{{- end }}
|
|
48
|
+
{{- else if eq $layout "list" -}}
|
|
49
|
+
<ul class="info-mystical-list">
|
|
50
|
+
{{- range $section.entries }}
|
|
51
|
+
<li class="info-mystical-item">
|
|
52
|
+
{{- partial "infobox/entry.html" (dict "entry" . "class" "mystical-name") -}}
|
|
53
|
+
</li>
|
|
54
|
+
{{- end }}
|
|
55
|
+
</ul>
|
|
56
|
+
{{- end -}}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
One row's value, drawn by its `kind`.
|
|
3
|
+
|
|
4
|
+
Five kinds, a closed set:
|
|
5
|
+
|
|
6
|
+
text — a string
|
|
7
|
+
number — a number
|
|
8
|
+
link — `{text, url}`
|
|
9
|
+
links — a list of those, comma-joined
|
|
10
|
+
list — a list of strings, comma-joined
|
|
11
|
+
|
|
12
|
+
Takes the row.
|
|
13
|
+
|
|
14
|
+
**A value of `0` is a value**, so a number is printed as it comes rather
|
|
15
|
+
than guarded with `with`, which would drop a zero along with an absence.
|
|
16
|
+
Anything the build did not classify is set as text, which is what an
|
|
17
|
+
unlabelled scalar is.
|
|
18
|
+
*/ -}}
|
|
19
|
+
{{- $kind := .kind | default "text" -}}
|
|
20
|
+
{{- if eq $kind "link" -}}
|
|
21
|
+
{{- partial "infobox/entry.html" (dict "entry" .value "class" "info-link") -}}
|
|
22
|
+
{{- else if eq $kind "links" -}}
|
|
23
|
+
{{- range $i, $entry := .value -}}
|
|
24
|
+
{{- if $i }}, {{ end -}}
|
|
25
|
+
{{- partial "infobox/entry.html" (dict "entry" $entry "class" "info-link") -}}
|
|
26
|
+
{{- end -}}
|
|
27
|
+
{{- else if eq $kind "list" -}}
|
|
28
|
+
{{- delimit .value ", " -}}
|
|
29
|
+
{{- else if eq $kind "number" -}}
|
|
30
|
+
{{- /* A whole number is grouped, so a population reads as 500,000 rather
|
|
31
|
+
than as a run of digits a reader has to count. Grouping is
|
|
32
|
+
typography and belongs to the medium; the number itself is the
|
|
33
|
+
build's. Anything that is not a plain integer — a measurement, or a
|
|
34
|
+
value the build did not classify — is set as written. */ -}}
|
|
35
|
+
{{- $digits := printf "%v" .value -}}
|
|
36
|
+
{{- if findRE `^-?[0-9]+$` $digits -}}
|
|
37
|
+
{{- lang.FormatNumberCustom 0 (int $digits) -}}
|
|
38
|
+
{{- else -}}
|
|
39
|
+
{{- .value -}}
|
|
40
|
+
{{- end -}}
|
|
41
|
+
{{- else -}}
|
|
42
|
+
{{- .value -}}
|
|
43
|
+
{{- end -}}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{{- /*
|
|
2
|
+
The infobox rail — every box a page declares, drawn in the order declared.
|
|
3
|
+
|
|
4
|
+
**The content is not decided here.** A page's `infoboxes:` front matter
|
|
5
|
+
carries an ordered list of boxes, each holding ordered sections, each holding
|
|
6
|
+
ordered rows, cells, groups or entries, already labelled. This partial and
|
|
7
|
+
the three under `infobox/` switch on a section's `layout` and a value's
|
|
8
|
+
`kind` and on nothing else — never on a note type, never on a field name.
|
|
9
|
+
That is what lets a field added to a type appear here with no edit.
|
|
10
|
+
|
|
11
|
+
A box is a `<details>` disclosure, open by default: native, accessible, and
|
|
12
|
+
no JavaScript. It is what lets several boxes stack for nothing — a note box
|
|
13
|
+
and one box per system are three summary lines when closed, rather than
|
|
14
|
+
three panels burying the prose.
|
|
15
|
+
|
|
16
|
+
Two kinds of box, and they answer emptiness differently:
|
|
17
|
+
|
|
18
|
+
- A **note box** with no section holding anything is not drawn. A heading
|
|
19
|
+
over nothing asserts a fact that is not there.
|
|
20
|
+
- A **system box** carries a `statement` where it has nothing to show, and
|
|
21
|
+
the statement is drawn in place of the sections. Which silence this is —
|
|
22
|
+
the system compiled no document, or it compiled one holding nothing the
|
|
23
|
+
profile has not already said — is decided by the build, because a reader
|
|
24
|
+
meeting one page cannot tell the two apart and neither can a template. A
|
|
25
|
+
system that does not map the note's type at all sends no box, and nothing
|
|
26
|
+
is drawn.
|
|
27
|
+
|
|
28
|
+
Returns an empty string when the page declares no box, so a caller can test
|
|
29
|
+
what comes back rather than reaching into the data itself.
|
|
30
|
+
*/ -}}
|
|
31
|
+
{{- range .Params.infoboxes -}}
|
|
32
|
+
{{- $box := . -}}
|
|
33
|
+
{{- $sections := slice -}}
|
|
34
|
+
{{- range $box.sections -}}
|
|
35
|
+
{{- if gt (len (partial "infobox/items.html" .)) 0 -}}
|
|
36
|
+
{{- $sections = $sections | append . -}}
|
|
37
|
+
{{- end -}}
|
|
38
|
+
{{- end -}}
|
|
39
|
+
{{- $system := eq ($box.kind | default "") "system" -}}
|
|
40
|
+
{{- if or $system (gt (len $sections) 0) }}
|
|
41
|
+
<details class="info-sidebar info-box{{ with $box.id }} info-box-{{ . }}{{ end }}" open data-pagefind-ignore>
|
|
42
|
+
<summary class="info-sidebar-title"><h2>{{ $box.title }}</h2></summary>
|
|
43
|
+
{{- with $box.statement }}
|
|
44
|
+
<p class="info-statement">{{ . }}</p>
|
|
45
|
+
{{- else }}
|
|
46
|
+
{{- range $sections }}
|
|
47
|
+
<section class="info-section{{ with .id }} info-section-{{ . }}{{ end }}">
|
|
48
|
+
{{- with .label }}
|
|
49
|
+
<h3 class="info-section-title">{{ . }}</h3>
|
|
50
|
+
{{- end }}
|
|
51
|
+
{{ partial "infobox/section.html" . }}
|
|
52
|
+
</section>
|
|
53
|
+
{{- end }}
|
|
54
|
+
{{- end }}
|
|
55
|
+
</details>
|
|
56
|
+
{{- end -}}
|
|
57
|
+
{{- end -}}
|