@heroiclands/package-build 23.13.0 → 24.0.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 +36 -0
- package/README.md +2 -1
- package/assets/preview/gitea.ini +12 -7
- package/assets/styles/content-base.css +150 -1
- package/bin/content-commands.mjs +356 -210
- package/bin/package-build.mjs +3 -2
- package/ci/check-banners.mjs +7 -7
- package/config.mjs +21 -6
- package/content-config.mjs +199 -80
- package/docs/api.md +93 -72
- package/docs/authoring/links-and-markup.md +316 -78
- package/docs/commands.md +244 -78
- package/docs/configuration.md +210 -102
- package/docs/content-format.md +2 -2
- package/docs/diagnostics.md +2 -2
- package/docs/getting-started.md +1 -1
- package/docs/guides/icons.md +1 -1
- package/docs/guides/module-project.md +5 -8
- package/docs/guides/release-and-deploy.md +2 -2
- package/docs/guides/site.md +112 -23
- package/docs/guides/system-project.md +1 -1
- package/docs/guides/writing-in-invented-scripts.md +1247 -0
- package/docs/index.md +1 -0
- package/docs/project-setup.md +28 -30
- package/docs/reference/format-details.md +589 -308
- package/docs/reference/note-types.md +40 -10
- package/docs/reference/theme-pages.md +127 -108
- package/docs/source-preview.md +15 -1
- package/engine/asset-shipping.mjs +22 -10
- package/engine/base-compiler.mjs +62 -104
- package/engine/changelog-lint.mjs +1 -1
- package/engine/content-address.mjs +1 -1
- package/engine/content-alerts.mjs +8 -4
- package/engine/content-blocks.mjs +26 -11
- package/engine/content-embeds.mjs +1 -1
- package/engine/content-expand.mjs +376 -0
- package/engine/content-figures.mjs +13 -6
- package/engine/content-format.yaml +8 -0
- package/engine/content-glyphs.mjs +213 -0
- package/engine/content-images.mjs +6 -7
- package/engine/content-links.mjs +3 -3
- package/engine/content-lint.mjs +1 -1
- package/engine/content-render.mjs +453 -0
- package/engine/content-scripts.mjs +326 -27
- package/engine/content-spans.mjs +4 -1
- package/engine/content-styles.mjs +91 -0
- package/engine/content-symbols.mjs +186 -0
- package/engine/content-verse.mjs +6 -18
- package/engine/core-report.mjs +169 -0
- package/engine/core-vocabulary.mjs +208 -0
- package/engine/dictionary-html.mjs +119 -0
- package/engine/field-reference.mjs +1 -1
- package/engine/frontmatter-lint.mjs +1 -1
- package/engine/heading-attributes.mjs +89 -0
- package/engine/helpers.mjs +61 -101
- package/engine/homepage.mjs +17 -29
- package/engine/html-minify.mjs +70 -0
- package/engine/index.mjs +8 -5
- package/engine/language-rows.mjs +8 -2
- package/engine/language-terms.mjs +115 -14
- package/engine/language-words.mjs +12 -0
- package/engine/logographic.mjs +255 -0
- package/engine/map-lexicon.mjs +221 -25
- package/engine/map-places.mjs +5 -4
- package/engine/markdown-expressions.mjs +0 -2
- package/engine/markdownlint-run.mjs +9 -3
- package/engine/markup-validation.mjs +21 -0
- package/engine/metre-declaration.mjs +134 -0
- package/engine/note-matter.mjs +2 -2
- package/engine/note-vocabulary.mjs +187 -3
- package/engine/pdf-build.mjs +68 -133
- package/engine/pdf-render.mjs +102 -44
- package/engine/post-fields.mjs +157 -0
- package/engine/preview-index.mjs +130 -0
- package/engine/preview-source.mjs +450 -0
- package/engine/project-init.mjs +5 -12
- package/engine/prose-config.mjs +3 -3
- package/engine/run-words.mjs +3 -2
- package/engine/script-emphasis-terms.mjs +38 -0
- package/engine/script-emphasis.mjs +295 -0
- package/engine/script-font-delivery.mjs +4 -4
- package/engine/site-build.mjs +259 -314
- package/engine/site-config.mjs +26 -238
- package/engine/site-files.mjs +175 -0
- package/engine/site-index.mjs +9 -4
- package/engine/site-preview.mjs +50 -523
- package/engine/site-render.mjs +593 -0
- package/engine/site-root.mjs +22 -13
- package/engine/site-search.mjs +161 -0
- package/engine/site-serve.mjs +273 -0
- package/engine/site-theme-banner.mjs +154 -0
- package/engine/site-theme-urls.mjs +125 -0
- package/engine/site-theme.mjs +926 -0
- package/engine/text-maps.mjs +57 -10
- package/engine/typographer.mjs +248 -0
- package/engine/verse-metre.mjs +357 -0
- package/engine/wikilink-syntax.mjs +29 -47
- package/engine/wikilinks.mjs +758 -279
- package/engine/word-forms.mjs +39 -24
- package/engine/word-rows.mjs +12 -2
- package/engine/word-terms.mjs +29 -4
- package/manifest.mjs +3 -4
- package/package.json +10 -7
- package/{hugo-theme → site-theme}/data/banners.yaml +6 -10
- package/site-theme/layouts/base.hbs +31 -0
- package/site-theme/layouts/blog-list.hbs +30 -0
- package/site-theme/layouts/blog-post.hbs +40 -0
- package/site-theme/layouts/home.hbs +35 -0
- package/site-theme/layouts/list.hbs +20 -0
- package/site-theme/layouts/not-found.hbs +31 -0
- package/site-theme/layouts/page.hbs +7 -0
- package/site-theme/partials/copy-buttons.hbs +37 -0
- package/site-theme/partials/draft-notice.hbs +5 -0
- package/site-theme/partials/exturl.hbs +2 -0
- package/{hugo-theme/layouts/partials/footer.html → site-theme/partials/footer.hbs} +10 -7
- package/site-theme/partials/header.hbs +44 -0
- package/site-theme/partials/hero-banner.hbs +11 -0
- package/site-theme/partials/infobox-entry.hbs +2 -0
- package/site-theme/partials/infobox-section.hbs +31 -0
- package/site-theme/partials/infobox-value.hbs +2 -0
- package/site-theme/partials/infobox.hbs +18 -0
- package/site-theme/partials/list-members.hbs +9 -0
- package/site-theme/partials/nav-links.hbs +5 -0
- package/site-theme/partials/page-body.hbs +48 -0
- package/site-theme/partials/page-list.hbs +14 -0
- package/site-theme/partials/related.hbs +24 -0
- package/site-theme/partials/search-meta.hbs +6 -0
- package/site-theme/partials/search-names.hbs +2 -0
- package/site-theme/partials/search.hbs +52 -0
- package/site-theme/partials/tags.hbs +4 -0
- package/site-theme/partials/toc.hbs +7 -0
- package/{hugo-theme → site-theme}/static/css/style.css +14 -0
- package/stage.mjs +1 -2
- package/types/config.d.mts +8 -4
- package/types/content-config.d.mts +15 -15
- package/types/engine/asset-shipping.d.mts +5 -2
- package/types/engine/base-compiler.d.mts +20 -2
- package/types/engine/content-address.d.mts +1 -1
- package/types/engine/content-alerts.d.mts +8 -2
- package/types/engine/content-blocks.d.mts +11 -4
- package/types/engine/content-expand.d.mts +288 -0
- package/types/engine/content-figures.d.mts +11 -3
- package/types/engine/content-glyphs.d.mts +85 -0
- package/types/engine/content-images.d.mts +6 -7
- package/types/engine/content-links.d.mts +1 -1
- package/types/engine/content-render.d.mts +199 -0
- package/types/engine/content-scripts.d.mts +62 -0
- package/types/engine/content-spans.d.mts +1 -1
- package/types/engine/content-styles.d.mts +33 -0
- package/types/engine/content-symbols.d.mts +35 -0
- package/types/engine/core-report.d.mts +45 -0
- package/types/engine/core-vocabulary.d.mts +53 -0
- package/types/engine/dictionary-html.d.mts +8 -0
- package/types/engine/field-reference.d.mts +1 -1
- package/types/engine/heading-attributes.d.mts +20 -0
- package/types/engine/helpers.d.mts +3 -10
- package/types/engine/homepage.d.mts +11 -24
- package/types/engine/html-minify.d.mts +9 -0
- package/types/engine/index.d.mts +2 -1
- package/types/engine/language-terms.d.mts +24 -2
- package/types/engine/logographic.d.mts +45 -0
- package/types/engine/map-lexicon.d.mts +48 -8
- package/types/engine/map-places.d.mts +8 -0
- package/types/engine/markdown-expressions.d.mts +0 -2
- package/types/engine/metre-declaration.d.mts +39 -0
- package/types/engine/pdf-render.d.mts +6 -2
- package/types/engine/post-fields.d.mts +44 -0
- package/types/engine/preview-index.d.mts +72 -0
- package/types/engine/preview-source.d.mts +51 -0
- package/types/engine/script-emphasis-terms.d.mts +21 -0
- package/types/engine/script-emphasis.d.mts +84 -0
- package/types/engine/script-font-delivery.d.mts +4 -4
- package/types/engine/site-build.d.mts +71 -113
- package/types/engine/site-config.d.mts +14 -134
- package/types/engine/site-files.d.mts +73 -0
- package/types/engine/site-index.d.mts +11 -3
- package/types/engine/site-preview.d.mts +15 -19
- package/types/engine/site-render.d.mts +171 -0
- package/types/engine/site-root.d.mts +12 -4
- package/types/engine/site-search.d.mts +54 -0
- package/types/engine/site-serve.d.mts +44 -0
- package/types/engine/site-theme-banner.d.mts +51 -0
- package/types/engine/site-theme-urls.d.mts +60 -0
- package/types/engine/site-theme.d.mts +127 -0
- package/types/engine/text-maps.d.mts +17 -3
- package/types/engine/typographer.d.mts +11 -0
- package/types/engine/verse-metre.d.mts +131 -0
- package/types/engine/wikilink-syntax.d.mts +30 -48
- package/types/engine/wikilinks.d.mts +330 -14
- package/types/engine/word-forms.d.mts +3 -2
- package/types/manifest.d.mts +3 -4
- package/types/stage.d.mts +1 -2
- package/types/vendor/markdownlint.d.mts +8 -0
- package/vendor/markdownlint.mjs +20388 -0
- package/engine/web-wikilinks.mjs +0 -594
- package/hugo-theme/layouts/404.html +0 -85
- package/hugo-theme/layouts/_default/baseof.html +0 -67
- package/hugo-theme/layouts/_default/list.html +0 -139
- package/hugo-theme/layouts/_default/single.html +0 -4
- package/hugo-theme/layouts/blog/list.html +0 -54
- package/hugo-theme/layouts/blog-post/single.html +0 -36
- package/hugo-theme/layouts/index.html +0 -75
- package/hugo-theme/layouts/partials/banner-url.html +0 -141
- package/hugo-theme/layouts/partials/cdn-url.html +0 -36
- package/hugo-theme/layouts/partials/dictionary-lists.html +0 -58
- package/hugo-theme/layouts/partials/draft-notice.html +0 -41
- package/hugo-theme/layouts/partials/draft-state.html +0 -26
- package/hugo-theme/layouts/partials/header.html +0 -35
- package/hugo-theme/layouts/partials/hero-banner.html +0 -85
- package/hugo-theme/layouts/partials/infobox/entry.html +0 -18
- package/hugo-theme/layouts/partials/infobox/items.html +0 -26
- package/hugo-theme/layouts/partials/infobox/section.html +0 -56
- package/hugo-theme/layouts/partials/infobox/value.html +0 -43
- package/hugo-theme/layouts/partials/infobox.html +0 -57
- package/hugo-theme/layouts/partials/page-body.html +0 -152
- package/hugo-theme/layouts/partials/related.html +0 -138
- package/hugo-theme/layouts/partials/search.html +0 -84
- package/hugo-theme/layouts/partials/site-url.html +0 -32
- package/hugo-theme/layouts/partials/tags.html +0 -30
- package/hugo-theme/layouts/partials/toc.html +0 -28
- package/hugo-theme/layouts/partials/warn-missing-banner.html +0 -3
- package/hugo-theme/layouts/shortcodes/cartouche.html +0 -64
- package/hugo-theme/layouts/shortcodes/exturl.html +0 -12
- package/hugo-theme/layouts/shortcodes/glyph.html +0 -43
- package/hugo-theme/layouts/shortcodes/pagelist.html +0 -63
- package/hugo-theme/theme.toml +0 -11
- package/types/engine/web-wikilinks.d.mts +0 -107
- /package/{hugo-theme → site-theme}/data/banner-kinds.yaml +0 -0
- /package/{hugo-theme → site-theme}/static/css/sohl-icons.css +0 -0
- /package/{hugo-theme → site-theme}/static/fonts/game-icons-kb.woff2 +0 -0
- /package/{hugo-theme → site-theme}/static/img/banners/takheperu-hieroglyphs.svg +0 -0
- /package/{hugo-theme → site-theme}/static/img/cartouches/takheperu.svg +0 -0
- /package/{hugo-theme → site-theme}/static/js/inline-spoilers.js +0 -0
package/engine/word-forms.mjs
CHANGED
|
@@ -38,6 +38,11 @@
|
|
|
38
38
|
* the root as its `replaces` says, or whole where it states none. A
|
|
39
39
|
* participle closing on an agreement ending agrees.
|
|
40
40
|
*
|
|
41
|
+
* A word's `variants` are known forms as written, and each takes the rules
|
|
42
|
+
* its word takes: the plural rule, the verb pattern, the suffixes, agreement
|
|
43
|
+
* and participles. A word's own stated `plural` belongs to its citation form
|
|
44
|
+
* alone.
|
|
45
|
+
*
|
|
41
46
|
* The mapped-run word check ({@link module:engine/run-words}) and
|
|
42
47
|
* `package-build lexicon --derived` both read {@link derivedForms}, so what
|
|
43
48
|
* the command lists is what the check accepts.
|
|
@@ -279,8 +284,9 @@ function participleForms(citation, participles) {
|
|
|
279
284
|
*/
|
|
280
285
|
|
|
281
286
|
/**
|
|
282
|
-
* Every form the language's rules derive from its lexicon words,
|
|
283
|
-
* `data.words` order, each once, leaving out a
|
|
287
|
+
* Every form the language's rules derive from its lexicon words, and each
|
|
288
|
+
* declared variant of a word, in `data.words` order, each once, leaving out a
|
|
289
|
+
* form that is a lexicon word.
|
|
284
290
|
*
|
|
285
291
|
* @param {Record<string, any>|undefined} data - The language note's `data`.
|
|
286
292
|
* @returns {DerivedForm[]} The forms.
|
|
@@ -304,30 +310,39 @@ export function derivedForms(data) {
|
|
|
304
310
|
seen.add(folded);
|
|
305
311
|
out.push({ form: folded, word });
|
|
306
312
|
};
|
|
307
|
-
const folded = foldWord(word.form);
|
|
308
313
|
const base = parseWordClass(word.class).base;
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
if (verbs && base === "v")
|
|
312
|
-
for (const { ending } of verbs.endings)
|
|
313
|
-
add(verbForm(folded, foldWord(ending), replaces));
|
|
314
|
-
const attaching = suffixes.filter(
|
|
315
|
-
({ classes }) => classes === undefined || (base !== undefined && classes.has(base)),
|
|
314
|
+
const variants = listOf(word.variants).filter(
|
|
315
|
+
(variant) => typeof variant === "string" && variant.trim() !== "",
|
|
316
316
|
);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
317
|
+
for (const [at, written] of [word.form, ...variants].entries()) {
|
|
318
|
+
const folded = foldWord(written);
|
|
319
|
+
if (at > 0) add(written);
|
|
320
|
+
const plural =
|
|
321
|
+
at === 0 ? pluralOf(word, grammar)
|
|
322
|
+
: base === "n" ? pluralByRule(written, grammar)
|
|
323
|
+
: null;
|
|
324
|
+
if (plural) add(plural);
|
|
325
|
+
if (verbs && base === "v")
|
|
326
|
+
for (const { ending } of verbs.endings)
|
|
327
|
+
add(verbForm(folded, foldWord(ending), replaces));
|
|
328
|
+
const attaching = suffixes.filter(
|
|
329
|
+
({ classes }) => classes === undefined || (base !== undefined && classes.has(base)),
|
|
330
|
+
);
|
|
331
|
+
if (attaching.length)
|
|
332
|
+
for (const [stem] of written.matchAll(WORD)) {
|
|
333
|
+
const one = foldWord(stem);
|
|
334
|
+
for (const { suffix, replaces: closing } of attaching)
|
|
335
|
+
add(attach(one, suffix, closing));
|
|
336
|
+
}
|
|
337
|
+
if (agreement && base !== undefined && agreement.classes.has(base))
|
|
338
|
+
for (const form of agreeingForms(folded, agreement, grammar)) add(form);
|
|
339
|
+
if (participles && base === "v")
|
|
340
|
+
for (const participle of participleForms(folded, participles)) {
|
|
341
|
+
add(participle);
|
|
342
|
+
if (agreement)
|
|
343
|
+
for (const form of agreeingForms(participle, agreement, grammar)) add(form);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
331
346
|
}
|
|
332
347
|
return out;
|
|
333
348
|
}
|
package/engine/word-rows.mjs
CHANGED
|
@@ -69,8 +69,18 @@ export const WORD_COLUMNS = Object.freeze([
|
|
|
69
69
|
/** Every column of the `glossary` relation, in order. */
|
|
70
70
|
export const GLOSSARY_COLUMNS = Object.freeze(["note", "position", ...GLOSSARY_ENTRY_KEYS]);
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* The affix's own keys an affix row carries: all but `native`, its writings
|
|
74
|
+
* under a logographic map, which `package-build lexicon` resolves.
|
|
75
|
+
*/
|
|
76
|
+
const AFFIX_ROW_KEYS = Object.freeze(AFFIX_KEYS.filter((key) => key !== "native"));
|
|
77
|
+
|
|
72
78
|
/** Every column of the `affixes` relation, in order. */
|
|
73
|
-
export const AFFIX_COLUMNS = Object.freeze([
|
|
79
|
+
export const AFFIX_COLUMNS = Object.freeze([
|
|
80
|
+
...WORD_IDENTITY_COLUMNS,
|
|
81
|
+
...AFFIX_ROW_KEYS,
|
|
82
|
+
"written",
|
|
83
|
+
]);
|
|
74
84
|
|
|
75
85
|
/** Every column of the `fields` relation, in order. */
|
|
76
86
|
export const FIELD_COLUMNS = Object.freeze([...WORD_IDENTITY_COLUMNS, ...FIELD_KEYS]);
|
|
@@ -322,7 +332,7 @@ function languageListRows(records, list, keys) {
|
|
|
322
332
|
* @returns {object[]} One row per affix, in record then entry order.
|
|
323
333
|
*/
|
|
324
334
|
export function affixRows(records) {
|
|
325
|
-
return languageListRows(records, "affixes",
|
|
335
|
+
return languageListRows(records, "affixes", AFFIX_ROW_KEYS).map((row) => ({
|
|
326
336
|
...row,
|
|
327
337
|
written: row.zero === true ? ZERO_AFFIX : row.form,
|
|
328
338
|
}));
|
package/engine/word-terms.mjs
CHANGED
|
@@ -126,7 +126,8 @@ export const WORD_NATIVE_FIELDS = Object.freeze([
|
|
|
126
126
|
required: true,
|
|
127
127
|
shape: "the word in the script, as the map's characters",
|
|
128
128
|
describe:
|
|
129
|
-
"The word as the script writes it, where the map's rows would write it otherwise
|
|
129
|
+
"The word as the script writes it, where the map's rows would write it otherwise, " +
|
|
130
|
+
"or as a logographic map writes it.",
|
|
130
131
|
}),
|
|
131
132
|
]);
|
|
132
133
|
|
|
@@ -150,7 +151,7 @@ export const WORD_FIELDS = Object.freeze([
|
|
|
150
151
|
entries: Object.freeze({ kind: "string", shape: "a form, bare" }),
|
|
151
152
|
describe:
|
|
152
153
|
"The word's other forms, such as a long form beside a short one; a marked use of " +
|
|
153
|
-
"one cites the word.",
|
|
154
|
+
"one cites the word, and a mapped run accepts it and the forms the language's rules derive from it.",
|
|
154
155
|
}),
|
|
155
156
|
Object.freeze({
|
|
156
157
|
name: "name_sort",
|
|
@@ -191,6 +192,15 @@ export const WORD_FIELDS = Object.freeze([
|
|
|
191
192
|
describe:
|
|
192
193
|
"The meaning, in brief; a list states one sense per entry, which a dictionary numbers.",
|
|
193
194
|
}),
|
|
195
|
+
Object.freeze({
|
|
196
|
+
name: "concept",
|
|
197
|
+
kind: "string-or-list",
|
|
198
|
+
shape: "a core concept's id, or a list of them",
|
|
199
|
+
entries: Object.freeze({ kind: "string", shape: "a core concept's id" }),
|
|
200
|
+
describe:
|
|
201
|
+
"The core concepts the word serves, each an `id` of a `data.concepts` list. The " +
|
|
202
|
+
"core report counts the word toward them.",
|
|
203
|
+
}),
|
|
194
204
|
Object.freeze({
|
|
195
205
|
name: "source",
|
|
196
206
|
kind: "map",
|
|
@@ -250,8 +260,10 @@ export const WORD_FIELDS = Object.freeze([
|
|
|
250
260
|
fields: WORD_NATIVE_FIELDS,
|
|
251
261
|
}),
|
|
252
262
|
describe:
|
|
253
|
-
"The word's native form under a map
|
|
254
|
-
"
|
|
263
|
+
"The word's native form under a map. Under a map that spells by its rows it is " +
|
|
264
|
+
"stated only where the rows spell the word differently, and the word's derived " +
|
|
265
|
+
"forms are spelled by the rows; under a logographic map it is the word's writing, " +
|
|
266
|
+
"which its derived forms and the words built on it are written from.",
|
|
255
267
|
}),
|
|
256
268
|
]);
|
|
257
269
|
|
|
@@ -411,6 +423,19 @@ export const AFFIX_FIELDS = Object.freeze([
|
|
|
411
423
|
shape: "a tone pattern, such as `L`",
|
|
412
424
|
describe: "The tone pattern the affix carries, written as a word's `tones` is.",
|
|
413
425
|
}),
|
|
426
|
+
Object.freeze({
|
|
427
|
+
name: "native",
|
|
428
|
+
kind: "list",
|
|
429
|
+
shape: "a list of `{ map, font?, text }`",
|
|
430
|
+
entries: Object.freeze({
|
|
431
|
+
kind: "map",
|
|
432
|
+
shape: "a map — `{ map, font?, text }`",
|
|
433
|
+
fields: WORD_NATIVE_FIELDS,
|
|
434
|
+
}),
|
|
435
|
+
describe:
|
|
436
|
+
"The affix's writing under a logographic map, which a word whose `built` names the " +
|
|
437
|
+
"affix is written with.",
|
|
438
|
+
}),
|
|
414
439
|
]);
|
|
415
440
|
|
|
416
441
|
/** The keys of {@link WORD_FIELD_FIELDS}, in declared order. */
|
package/manifest.mjs
CHANGED
|
@@ -121,10 +121,9 @@ export const HOMEPAGE_ORIGIN = "https://www.heroiclands.org";
|
|
|
121
121
|
* to drift — and the one that drifts is this one, because nothing fetches `url`
|
|
122
122
|
* the way Foundry fetches `manifest`, so a wrong value is never reported.
|
|
123
123
|
*
|
|
124
|
-
*
|
|
125
|
-
* source: it
|
|
126
|
-
*
|
|
127
|
-
* repository keeps its site configuration.
|
|
124
|
+
* `package.json`'s `homepage` says the same thing, and is deliberately not the
|
|
125
|
+
* source: reading it would mean the packaging half depending on the site's
|
|
126
|
+
* configuration.
|
|
128
127
|
*
|
|
129
128
|
* @param {string} contentPackage - The package's content-package name.
|
|
130
129
|
* @returns {string} The homepage URL, with its trailing slash.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "24.0.0",
|
|
4
4
|
"description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -123,17 +123,18 @@
|
|
|
123
123
|
"engine",
|
|
124
124
|
"githooks",
|
|
125
125
|
"hm3",
|
|
126
|
-
"hugo-theme",
|
|
127
126
|
"index.mjs",
|
|
128
127
|
"lang.mjs",
|
|
129
128
|
"manifest.mjs",
|
|
130
129
|
"markdownlint-config.mjs",
|
|
131
130
|
"prettier-config.mjs",
|
|
132
131
|
"release.mjs",
|
|
132
|
+
"site-theme",
|
|
133
133
|
"sohl",
|
|
134
134
|
"stage.mjs",
|
|
135
135
|
"templates.mjs",
|
|
136
|
-
"types"
|
|
136
|
+
"types",
|
|
137
|
+
"vendor"
|
|
137
138
|
],
|
|
138
139
|
"dependencies": {
|
|
139
140
|
"@duckdb/node-api": "^1.5.5-r.4",
|
|
@@ -152,6 +153,7 @@
|
|
|
152
153
|
"flesch": "^2.0.1",
|
|
153
154
|
"glob": "^13.0.6",
|
|
154
155
|
"handlebars": "^4.7.10",
|
|
156
|
+
"highlight.js": "^11.12.0",
|
|
155
157
|
"ignore": "^7.0.12",
|
|
156
158
|
"js-yaml": "^5.5.0",
|
|
157
159
|
"jsonc-parser": "^3.3.1",
|
|
@@ -160,7 +162,6 @@
|
|
|
160
162
|
"markdown-it": "^15.0.0",
|
|
161
163
|
"markdown-it-deflist": "^4.0.0",
|
|
162
164
|
"markdown-it-footnote": "^4.0.0",
|
|
163
|
-
"markdownlint": "^0.42.0",
|
|
164
165
|
"minimatch": "^10.2.6",
|
|
165
166
|
"pagefind": "^1.5.2",
|
|
166
167
|
"prettier": "^3.9.6",
|
|
@@ -173,7 +174,6 @@
|
|
|
173
174
|
"retext-simplify": "^8.0.0",
|
|
174
175
|
"retext-stringify": "^4.0.0",
|
|
175
176
|
"sharp": "^0.35.4",
|
|
176
|
-
"smol-toml": "^1.8.0",
|
|
177
177
|
"ssh2-sftp-client": "^12.1.1",
|
|
178
178
|
"syllable": "^5.0.1",
|
|
179
179
|
"typescript": "^6.0.3",
|
|
@@ -185,6 +185,8 @@
|
|
|
185
185
|
"devDependencies": {
|
|
186
186
|
"@changesets/cli": "^3.0.0",
|
|
187
187
|
"@types/node": "^26.2.0",
|
|
188
|
+
"esbuild": "^0.28.2",
|
|
189
|
+
"markdownlint": "^0.42.0",
|
|
188
190
|
"npm-run-all": "^4.1.5",
|
|
189
191
|
"vitest": "^5.0.0"
|
|
190
192
|
},
|
|
@@ -193,7 +195,8 @@
|
|
|
193
195
|
"test:watch": "vitest",
|
|
194
196
|
"build": "node bin/package-build.mjs ci",
|
|
195
197
|
"deploy:npm": "node ci/publish-npm.mjs",
|
|
196
|
-
"prepack": "run-s build:types build:asset-index",
|
|
198
|
+
"prepack": "run-s build:vendor build:types build:asset-index",
|
|
199
|
+
"build:vendor": "node scripts/vendor-markdownlint.mjs",
|
|
197
200
|
"build:types": "tsc -p tsconfig.dts.json",
|
|
198
201
|
"build:asset-index": "node ci/emit-asset-index.mjs",
|
|
199
202
|
"format": "node ci/prettier.mjs --write",
|
|
@@ -210,7 +213,7 @@
|
|
|
210
213
|
"lint:content-format:fields": "node bin/package-build.mjs content-format fields --fields sohl && node bin/package-build.mjs content-format fields --fields hm3",
|
|
211
214
|
"changeset": "changeset",
|
|
212
215
|
"changeset:version": "changeset version && node bin/package-build.mjs changelog group && npm install --package-lock-only",
|
|
213
|
-
"prepare": "git config core.hooksPath .githooks || true",
|
|
216
|
+
"prepare": "(git config core.hooksPath .githooks || true) && (test ! -e scripts/vendor-markdownlint.mjs || npm run build:vendor)",
|
|
214
217
|
"build:deps": "node bin/package-build.mjs deps fetch"
|
|
215
218
|
},
|
|
216
219
|
"engines": {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Which banner images exist in the shared artwork set.
|
|
2
2
|
#
|
|
3
|
-
#
|
|
3
|
+
# The hero banner resolves a page's hero image to a path under
|
|
4
4
|
# `images/banners/`, and that path is emitted into a `background-image` with no
|
|
5
5
|
# way to test it: the artwork is served from the consuming site's
|
|
6
|
-
# `params.cdnBaseURL`, and
|
|
7
|
-
# So a banner that was never drawn would 404 in silence — the band
|
|
8
|
-
# with its title, palette and gradient intact and a dead image URL
|
|
9
|
-
# and nothing fails: not the build, not
|
|
6
|
+
# `params.cdnBaseURL`, and the build cannot ask a remote host whether a URL
|
|
7
|
+
# exists. So a banner that was never drawn would 404 in silence — the band
|
|
8
|
+
# renders with its title, palette and gradient intact and a dead image URL
|
|
9
|
+
# behind it, and nothing fails: not the build, not the deploy guard.
|
|
10
10
|
#
|
|
11
11
|
# This file is the declaration that replaces that missing test. A name listed
|
|
12
12
|
# here is asserted to exist; a resolved banner whose name is absent falls back
|
|
13
|
-
# to `default.webp` and
|
|
13
|
+
# to `default.webp` and the build warns once for it.
|
|
14
14
|
#
|
|
15
15
|
# It speaks for the names this theme resolves itself — a hand-authored
|
|
16
16
|
# `banner:` and the subtype defaults below. A note's own `data.banner` arrives
|
|
@@ -21,10 +21,6 @@
|
|
|
21
21
|
# (`ci/check-banners.mjs`, part of `npm run lint`) fetches every name below
|
|
22
22
|
# from a real asset host and fails on any non-200. Add a name here only after
|
|
23
23
|
# the file is published, or the check will say so.
|
|
24
|
-
#
|
|
25
|
-
# A consumer publishing its own artwork set overrides the whole list by
|
|
26
|
-
# shipping its own `data/banners.yaml` — Hugo reads the site's data directory
|
|
27
|
-
# in preference to the theme's.
|
|
28
24
|
|
|
29
25
|
# The asset root every name below is resolved under, and the name used when a
|
|
30
26
|
# resolved banner is not in `available`. Both are relative to the consuming
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
+
<title>{{head.title}}</title>
|
|
8
|
+
<meta name="description" content="{{head.description}}">
|
|
9
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
+
<link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Lora:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600&display=swap" rel="stylesheet">
|
|
12
|
+
<link rel="stylesheet" href="{{site.urls.style}}">
|
|
13
|
+
{{#if site.urls.scriptFonts}}
|
|
14
|
+
<link rel="stylesheet" href="{{site.urls.scriptFonts}}">
|
|
15
|
+
{{/if}}
|
|
16
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.3.1/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer">
|
|
17
|
+
<link rel="stylesheet" href="{{site.urls.icons}}">
|
|
18
|
+
<link rel="stylesheet" href="{{site.urls.code}}">
|
|
19
|
+
{{#if site.feed}}
|
|
20
|
+
<link rel="alternate" type="application/atom+xml" title="{{site.feed.title}}" href="{{site.feed.url}}">
|
|
21
|
+
{{/if}}
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
{{> header site}}
|
|
25
|
+
<main>
|
|
26
|
+
{{{body}}}
|
|
27
|
+
</main>
|
|
28
|
+
{{> footer site}}
|
|
29
|
+
{{> copy-buttons}}
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
2
|
+
{{#if hero}}
|
|
3
|
+
{{> hero-banner hero}}
|
|
4
|
+
{{/if}}
|
|
5
|
+
<article class="single">
|
|
6
|
+
<div class="single-content">
|
|
7
|
+
{{#if body}}
|
|
8
|
+
<div class="single-body">
|
|
9
|
+
{{{body}}}
|
|
10
|
+
</div>
|
|
11
|
+
{{/if}}
|
|
12
|
+
{{#if posts}}
|
|
13
|
+
<ul class="blog-list">
|
|
14
|
+
{{#each posts}}
|
|
15
|
+
<li class="blog-list-item">
|
|
16
|
+
{{#if date}}
|
|
17
|
+
<time class="blog-list-date" datetime="{{date.iso}}">{{date.text}}</time>
|
|
18
|
+
{{/if}}
|
|
19
|
+
<a class="blog-list-title" href="{{url}}">{{title}}</a>
|
|
20
|
+
{{#if preview}}
|
|
21
|
+
<p class="blog-list-desc">{{preview}}</p>
|
|
22
|
+
{{/if}}
|
|
23
|
+
</li>
|
|
24
|
+
{{/each}}
|
|
25
|
+
</ul>
|
|
26
|
+
{{else}}
|
|
27
|
+
<p class="page-list-empty">No posts yet.</p>
|
|
28
|
+
{{/if}}
|
|
29
|
+
</div>
|
|
30
|
+
</article>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
2
|
+
{{#if hero}}
|
|
3
|
+
{{> hero-banner hero}}
|
|
4
|
+
{{/if}}
|
|
5
|
+
{{#if article}}
|
|
6
|
+
<article class="single">
|
|
7
|
+
{{> search-meta article.search}}
|
|
8
|
+
<div class="single-content">
|
|
9
|
+
{{#if article.meta}}
|
|
10
|
+
<div class="single-meta blog-meta">
|
|
11
|
+
{{#if article.meta.series}}
|
|
12
|
+
<div class="blog-series">
|
|
13
|
+
<span class="blog-series-label">Series</span>
|
|
14
|
+
<span class="blog-series-name">{{article.meta.series}}</span>
|
|
15
|
+
</div>
|
|
16
|
+
{{/if}}
|
|
17
|
+
{{#if article.meta.date}}
|
|
18
|
+
<time class="single-date" datetime="{{article.meta.date.iso}}">{{article.meta.date.text}}</time>
|
|
19
|
+
{{/if}}
|
|
20
|
+
{{#if article.meta.tags}}
|
|
21
|
+
{{> tags article.meta.tags}}
|
|
22
|
+
{{/if}}
|
|
23
|
+
</div>
|
|
24
|
+
{{/if}}
|
|
25
|
+
|
|
26
|
+
{{#if article.content}}
|
|
27
|
+
<div class="single-body" data-pagefind-body>
|
|
28
|
+
{{{article.content}}}
|
|
29
|
+
</div>
|
|
30
|
+
{{/if}}
|
|
31
|
+
|
|
32
|
+
{{#if article.related}}
|
|
33
|
+
{{> related article.related}}
|
|
34
|
+
{{/if}}
|
|
35
|
+
{{#if article.nav}}
|
|
36
|
+
{{> nav-links article.nav}}
|
|
37
|
+
{{/if}}
|
|
38
|
+
</div>
|
|
39
|
+
</article>
|
|
40
|
+
{{/if}}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
2
|
+
{{#if isHomepage}}
|
|
3
|
+
{{#if hero}}
|
|
4
|
+
{{> hero-banner hero}}
|
|
5
|
+
{{/if}}
|
|
6
|
+
{{#if article}}
|
|
7
|
+
{{> page-body article}}
|
|
8
|
+
{{/if}}
|
|
9
|
+
{{else if grid}}
|
|
10
|
+
{{#if grid.hero}}
|
|
11
|
+
{{> hero-banner grid.hero}}
|
|
12
|
+
{{/if}}
|
|
13
|
+
{{#if grid.hasItems}}
|
|
14
|
+
<section class="home-sections">
|
|
15
|
+
<div class="home-featured">
|
|
16
|
+
{{#each grid.headings}}
|
|
17
|
+
<h2 class="home-section-title{{#if class}} home-section-title--{{class}}{{/if}}">{{title}}</h2>
|
|
18
|
+
{{/each}}
|
|
19
|
+
{{#each grid.cards}}
|
|
20
|
+
|
|
21
|
+
<div class="home-card{{#if key}} home-card--{{key}}{{/if}}">
|
|
22
|
+
{{#if imageUrl}}
|
|
23
|
+
<a href="{{url}}">
|
|
24
|
+
<img src="{{imageUrl}}" alt="{{alt}}" class="card-image">
|
|
25
|
+
</a>
|
|
26
|
+
{{/if}}
|
|
27
|
+
<h2><a href="{{url}}">{{title}}</a></h2>
|
|
28
|
+
<p>{{text}}</p>
|
|
29
|
+
<a href="{{url}}" class="card-button">More Info →</a>
|
|
30
|
+
</div>
|
|
31
|
+
{{/each}}
|
|
32
|
+
</div>
|
|
33
|
+
</section>
|
|
34
|
+
{{/if}}
|
|
35
|
+
{{/if}}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
2
|
+
{{#if hero}}
|
|
3
|
+
{{> hero-banner hero}}
|
|
4
|
+
{{/if}}
|
|
5
|
+
{{#if hasBody}}
|
|
6
|
+
<article class="single">
|
|
7
|
+
<div class="single-content">
|
|
8
|
+
<div class="single-body" data-pagefind-body>
|
|
9
|
+
{{{body}}}
|
|
10
|
+
</div>
|
|
11
|
+
{{> list-members}}
|
|
12
|
+
</div>
|
|
13
|
+
</article>
|
|
14
|
+
{{else if hasMembers}}
|
|
15
|
+
<article class="single">
|
|
16
|
+
<div class="single-content">
|
|
17
|
+
{{> list-members}}
|
|
18
|
+
</div>
|
|
19
|
+
</article>
|
|
20
|
+
{{/if}}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
2
|
+
<section class="hero hero-with-image" style="background-image: url('{{cssUrl heroUrl}}');">
|
|
3
|
+
<div class="hero-inner" data-pagefind-ignore>
|
|
4
|
+
<h1>Page not found</h1>
|
|
5
|
+
<p class="hero-tagline">{{tagline}} <code id="missing-path">the address you followed</code>.</p>
|
|
6
|
+
</div>
|
|
7
|
+
</section>
|
|
8
|
+
|
|
9
|
+
<article class="single">
|
|
10
|
+
<div class="single-content">
|
|
11
|
+
<div class="single-body">
|
|
12
|
+
<p>
|
|
13
|
+
The page may have been moved to another part of the
|
|
14
|
+
{{noun}}, or withdrawn along with the concept it described. Links
|
|
15
|
+
from older discussions, issues, and search results can outlive the
|
|
16
|
+
pages they point at.
|
|
17
|
+
</p>
|
|
18
|
+
{{#if links}}
|
|
19
|
+
<p>Start again from one of these:</p>
|
|
20
|
+
{{> page-list links}}
|
|
21
|
+
{{/if}}
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</article>
|
|
25
|
+
|
|
26
|
+
<script>
|
|
27
|
+
(function () {
|
|
28
|
+
var el = document.getElementById("missing-path");
|
|
29
|
+
if (el) el.textContent = window.location.pathname;
|
|
30
|
+
})();
|
|
31
|
+
</script>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
2
|
+
<script>
|
|
3
|
+
// Auto-enhance <span data-copy="URL"> elements with a clipboard copy button
|
|
4
|
+
document.querySelectorAll('[data-copy]').forEach(function(el) {
|
|
5
|
+
var url = el.getAttribute('data-copy');
|
|
6
|
+
el.classList.add('exturl');
|
|
7
|
+
|
|
8
|
+
// Wrap existing text in a code element if not already
|
|
9
|
+
if (!el.querySelector('.exturl-text')) {
|
|
10
|
+
var code = document.createElement('code');
|
|
11
|
+
code.className = 'exturl-text';
|
|
12
|
+
code.textContent = el.textContent;
|
|
13
|
+
el.textContent = '';
|
|
14
|
+
el.appendChild(code);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
var btn = document.createElement('button');
|
|
18
|
+
btn.className = 'exturl-copy';
|
|
19
|
+
btn.title = 'Copy URL to clipboard';
|
|
20
|
+
btn.setAttribute('aria-label', 'Copy URL to clipboard');
|
|
21
|
+
btn.innerHTML =
|
|
22
|
+
'<svg class="exturl-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
|
|
23
|
+
'<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>' +
|
|
24
|
+
'<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>' +
|
|
25
|
+
'</svg>' +
|
|
26
|
+
'<svg class="exturl-check" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">' +
|
|
27
|
+
'<polyline points="20 6 9 17 4 12"/>' +
|
|
28
|
+
'</svg>';
|
|
29
|
+
btn.addEventListener('click', function() {
|
|
30
|
+
navigator.clipboard.writeText(url).then(function() {
|
|
31
|
+
btn.classList.add('copied');
|
|
32
|
+
setTimeout(function() { btn.classList.remove('copied'); }, 1500);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
el.appendChild(btn);
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
2
|
+
<aside class="draft-notice">
|
|
3
|
+
<i class="fa-solid fa-circle-exclamation draft-notice-icon" aria-hidden="true"></i>
|
|
4
|
+
<p class="draft-notice-text"><strong class="draft-notice-label">Draft.</strong> <em>{{notice}}</em></p>
|
|
5
|
+
</aside>
|
|
@@ -1,31 +1,34 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
1
2
|
<footer class="site-footer" data-pagefind-ignore>
|
|
2
3
|
<div class="footer-inner">
|
|
3
4
|
<p class="footer-text">
|
|
4
|
-
© 2020–{{
|
|
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.{{
|
|
6
|
-
<a href="{{
|
|
5
|
+
© 2020–{{year}} Tom Rodriguez. Content under The World of Thalorna and Song of Heroic Lands is licensed under
|
|
6
|
+
<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.{{#if brand.licenseUrl}} See
|
|
7
|
+
<a href="{{brand.licenseUrl}}">License</a>.{{/if}}
|
|
7
8
|
</p>
|
|
8
9
|
<div class="footer-links">
|
|
9
10
|
<a href="https://creativecommons.org/licenses/by-sa/4.0/">
|
|
10
11
|
<img src="https://licensebuttons.net/l/by-sa/4.0/88x31.png" alt="CC BY-SA 4.0" class="cc-badge">
|
|
11
12
|
</a>
|
|
12
|
-
{{
|
|
13
|
-
<a href="{{
|
|
13
|
+
{{#if brand.discordUrl}}
|
|
14
|
+
<a href="{{brand.discordUrl}}">
|
|
14
15
|
<svg width="24" height="19" viewBox="0 0 71 55" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
15
16
|
<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
17
|
</svg>
|
|
17
18
|
Discord
|
|
18
19
|
</a>
|
|
19
|
-
{{
|
|
20
|
+
{{/if}}
|
|
20
21
|
</div>
|
|
21
22
|
</div>
|
|
22
23
|
</footer>
|
|
23
24
|
|
|
25
|
+
{{#if hasMenu}}
|
|
24
26
|
<script>
|
|
25
27
|
document.querySelector('.nav-toggle')?.addEventListener('click', function() {
|
|
26
28
|
document.querySelector('.site-nav').classList.toggle('open');
|
|
27
29
|
this.classList.toggle('open');
|
|
28
30
|
});
|
|
29
31
|
</script>
|
|
32
|
+
{{/if}}
|
|
30
33
|
|
|
31
|
-
<script src="{{
|
|
34
|
+
<script src="{{urls.spoilers}}" defer></script>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{{!-- SPDX-License-Identifier: GPL-3.0-or-later --}}
|
|
2
|
+
<header class="site-header" data-pagefind-ignore>
|
|
3
|
+
<div class="header-inner">
|
|
4
|
+
<a href="{{homeUrl}}" class="site-title">
|
|
5
|
+
{{#if brand.logoUrl}}
|
|
6
|
+
<img src="{{brand.logoUrl}}" alt="Heroic Lands" class="site-logo">
|
|
7
|
+
{{/if}}
|
|
8
|
+
<span class="title-main">Heroic Lands</span>
|
|
9
|
+
</a>
|
|
10
|
+
{{#if hasActions}}
|
|
11
|
+
<div class="header-actions">
|
|
12
|
+
{{#if hasMenu}}
|
|
13
|
+
<nav class="site-nav">
|
|
14
|
+
{{#each menu}}
|
|
15
|
+
{{#if hasChildren}}
|
|
16
|
+
<div class="nav-dropdown">
|
|
17
|
+
<a href="{{url}}" class="nav-link{{#if active}} active{{/if}}">
|
|
18
|
+
{{name}}
|
|
19
|
+
<svg class="dropdown-arrow" width="10" height="6" viewBox="0 0 10 6" fill="currentColor"><path d="M1 1l4 4 4-4"/></svg>
|
|
20
|
+
</a>
|
|
21
|
+
<div class="dropdown-menu">
|
|
22
|
+
{{#each children}}
|
|
23
|
+
<a href="{{url}}" class="dropdown-item">{{name}}</a>
|
|
24
|
+
{{/each}}
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
{{else}}
|
|
28
|
+
<a href="{{url}}" class="nav-link{{#if active}} active{{/if}}">{{name}}</a>
|
|
29
|
+
{{/if}}
|
|
30
|
+
{{/each}}
|
|
31
|
+
</nav>
|
|
32
|
+
{{/if}}
|
|
33
|
+
{{#if search}}
|
|
34
|
+
{{> search}}
|
|
35
|
+
{{/if}}
|
|
36
|
+
{{#if hasMenu}}
|
|
37
|
+
<button class="nav-toggle" aria-label="Toggle navigation">
|
|
38
|
+
<span></span><span></span><span></span>
|
|
39
|
+
</button>
|
|
40
|
+
{{/if}}
|
|
41
|
+
</div>
|
|
42
|
+
{{/if}}
|
|
43
|
+
</div>
|
|
44
|
+
</header>
|