@janga/norna 0.7.26 → 0.7.27
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/README.md +16 -9
- package/bin/norna-cli.mjs +2 -2
- package/package.json +1 -1
- package/schemas/category.schema.json +4 -4
- package/schemas/config.schema.json +65 -65
- package/schemas/content-frontmatter.schema.json +8 -8
- package/schemas/page-theme.schema.json +26 -26
- package/schemas/sitewide-content.schema.json +18 -18
- package/schemas/theme.schema.json +237 -237
- package/scripts/add-site-node.mjs +1 -1
- package/scripts/lib/documentation-links.mjs +33 -2
- package/scripts/lib/documentation-routes.json +222 -0
- package/scripts/lib/page-model.mjs +22 -0
- package/scripts/lib/schema-definitions.mjs +3 -3
- package/scripts/lib/schema-editor-metadata.mjs +1 -1
- package/src/components/PageAliasRedirect.astro +44 -3
- package/src/content.config.ts +5 -8
- package/src/lib/sitePages.ts +4 -18
- package/src/styles/content.css +3 -2
- package/starters/basic/README.md +1 -1
|
@@ -246,6 +246,6 @@ console.log(`${action} ${kind} "${title}" at ${toDisplayPath(destination)}.`);
|
|
|
246
246
|
if (kind === 'page') {
|
|
247
247
|
console.log(`URL: /${pagePath}/`);
|
|
248
248
|
} else {
|
|
249
|
-
console.log('This navigation category has no page
|
|
249
|
+
console.log('This navigation category has no authored content page. Norna generates its destination from the child pages.');
|
|
250
250
|
console.log(`Child URL prefix: /${pagePath}/`);
|
|
251
251
|
}
|
|
@@ -1,8 +1,39 @@
|
|
|
1
1
|
import packageJson from '../../package.json' with { type: 'json' };
|
|
2
|
+
import routes from './documentation-routes.json' with { type: 'json' };
|
|
3
|
+
|
|
4
|
+
const websiteRoot = 'https://janga.github.io/norna/reference/';
|
|
5
|
+
const repositoryRoot = 'https://github.com/janga/norna/blob/';
|
|
6
|
+
|
|
7
|
+
// Release tags through 0.7.26 contain the reference under docs/. Newer tags
|
|
8
|
+
// contain its single authored source in the documentation site's page tree.
|
|
9
|
+
export const usesLegacyReference = (version) => {
|
|
10
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(version ?? '');
|
|
11
|
+
if (!match) return false;
|
|
12
|
+
const [major, minor, patch] = match.slice(1).map(Number);
|
|
13
|
+
return major === 0 && (minor < 7 || (minor === 7 && patch <= 26));
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const referenceDestination = (file, anchor) => {
|
|
17
|
+
const target = routes.legacy[`${file}#${anchor}`] ?? routes.legacy[file];
|
|
18
|
+
if (!target) throw new Error(`Unknown documentation destination: ${file}${anchor ? `#${anchor}` : ''}`);
|
|
19
|
+
const [route, targetAnchor] = target.split('#');
|
|
20
|
+
const source = routes.sources[route];
|
|
21
|
+
if (!source) throw new Error(`Missing documentation source for ${route}`);
|
|
22
|
+
return { route, source, anchor: targetAnchor, url: websiteRoot + target };
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const documentationLinkForVersion = (version, label, file, anchor) => {
|
|
26
|
+
const destination = referenceDestination(file, anchor);
|
|
27
|
+
const reference = version ? `v${version}` : 'main';
|
|
28
|
+
const source = usesLegacyReference(version)
|
|
29
|
+
? `docs/${file}${anchor ? `#${anchor}` : ''}`
|
|
30
|
+
: `${destination.source}${destination.anchor ? `#${destination.anchor}` : ''}`;
|
|
31
|
+
const sourceLabel = version ? `Norna ${version} source reference` : 'Reference source';
|
|
32
|
+
return `[${label} (current)](${destination.url})\n\n[${sourceLabel}](${repositoryRoot}${reference}/${source})`;
|
|
33
|
+
};
|
|
2
34
|
|
|
3
35
|
export const documentationRef = `v${packageJson.version}`;
|
|
4
|
-
export const documentationRoot = `https://github.com/janga/norna/blob/${documentationRef}/docs`;
|
|
5
36
|
|
|
6
37
|
export const documentationLink = (label, file, anchor) => (
|
|
7
|
-
|
|
38
|
+
documentationLinkForVersion(packageJson.version, label, file, anchor)
|
|
8
39
|
);
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sources": {
|
|
3
|
+
"site/files/": "site/pages/032-reference/pages/010-site/pages/010-files/content.md",
|
|
4
|
+
"site/pages/": "site/pages/032-reference/pages/010-site/pages/020-pages/content.md",
|
|
5
|
+
"site/urls/": "site/pages/032-reference/pages/010-site/pages/030-urls/content.md",
|
|
6
|
+
"site/metadata/": "site/pages/032-reference/pages/010-site/pages/040-metadata/content.md",
|
|
7
|
+
"site/images/": "site/pages/032-reference/pages/010-site/pages/050-images/content.md",
|
|
8
|
+
"site/public-files/": "site/pages/032-reference/pages/010-site/pages/060-public-files/content.md",
|
|
9
|
+
"site/requirements/": "site/pages/032-reference/pages/010-site/pages/070-requirements/content.md",
|
|
10
|
+
"configuration/site/": "site/pages/032-reference/pages/020-configuration/pages/010-site/content.md",
|
|
11
|
+
"configuration/language/": "site/pages/032-reference/pages/020-configuration/pages/020-language/content.md",
|
|
12
|
+
"configuration/navigation/": "site/pages/032-reference/pages/020-configuration/pages/030-navigation/content.md",
|
|
13
|
+
"configuration/search/": "site/pages/032-reference/pages/020-configuration/pages/040-search/content.md",
|
|
14
|
+
"configuration/source-links/": "site/pages/032-reference/pages/020-configuration/pages/050-source-links/content.md",
|
|
15
|
+
"configuration/theme/": "site/pages/032-reference/pages/020-configuration/pages/060-theme/content.md",
|
|
16
|
+
"configuration/presets/": "site/pages/032-reference/pages/020-configuration/pages/065-presets/content.md",
|
|
17
|
+
"configuration/palettes/": "site/pages/032-reference/pages/020-configuration/pages/070-palettes/content.md",
|
|
18
|
+
"configuration/appearance/": "site/pages/032-reference/pages/020-configuration/pages/080-appearance/content.md",
|
|
19
|
+
"configuration/layout/": "site/pages/032-reference/pages/020-configuration/pages/090-layout/content.md",
|
|
20
|
+
"configuration/images/": "site/pages/032-reference/pages/020-configuration/pages/100-images/content.md",
|
|
21
|
+
"configuration/typography/": "site/pages/032-reference/pages/020-configuration/pages/110-typography/content.md",
|
|
22
|
+
"configuration/sections/": "site/pages/032-reference/pages/020-configuration/pages/120-sections/content.md",
|
|
23
|
+
"configuration/shared-content/": "site/pages/032-reference/pages/020-configuration/pages/130-shared-content/content.md",
|
|
24
|
+
"content/markdown/": "site/pages/032-reference/pages/030-content/pages/010-markdown/content.md",
|
|
25
|
+
"content/structured-blocks/": "site/pages/032-reference/pages/030-content/pages/015-structured-blocks/content.md",
|
|
26
|
+
"content/images/": "site/pages/032-reference/pages/030-content/pages/020-images/content.md",
|
|
27
|
+
"content/cards/": "site/pages/032-reference/pages/030-content/pages/030-cards/content.md",
|
|
28
|
+
"content/child-lists/": "site/pages/032-reference/pages/030-content/pages/040-child-lists/content.md",
|
|
29
|
+
"content/callouts/": "site/pages/032-reference/pages/030-content/pages/050-callouts/content.md",
|
|
30
|
+
"content/tabs/": "site/pages/032-reference/pages/030-content/pages/060-tabs/content.md",
|
|
31
|
+
"content/details/": "site/pages/032-reference/pages/030-content/pages/070-details/content.md",
|
|
32
|
+
"content/tables/": "site/pages/032-reference/pages/030-content/pages/080-tables/content.md",
|
|
33
|
+
"content/code/": "site/pages/032-reference/pages/030-content/pages/090-code/content.md",
|
|
34
|
+
"content/sidenotes/": "site/pages/032-reference/pages/030-content/pages/100-sidenotes/content.md",
|
|
35
|
+
"content/footnotes/": "site/pages/032-reference/pages/030-content/pages/110-footnotes/content.md",
|
|
36
|
+
"commands/invocation/": "site/pages/032-reference/pages/040-commands/pages/010-invocation/content.md",
|
|
37
|
+
"commands/init/": "site/pages/032-reference/pages/040-commands/pages/020-init/content.md",
|
|
38
|
+
"commands/create/": "site/pages/032-reference/pages/040-commands/pages/030-create/content.md",
|
|
39
|
+
"commands/move/": "site/pages/032-reference/pages/040-commands/pages/040-move/content.md",
|
|
40
|
+
"commands/validate/": "site/pages/032-reference/pages/040-commands/pages/050-validate/content.md",
|
|
41
|
+
"commands/navigation/": "site/pages/032-reference/pages/040-commands/pages/055-navigation/content.md",
|
|
42
|
+
"commands/development/": "site/pages/032-reference/pages/040-commands/pages/060-development/content.md",
|
|
43
|
+
"commands/build/": "site/pages/032-reference/pages/040-commands/pages/070-build/content.md",
|
|
44
|
+
"commands/publishing/": "site/pages/032-reference/pages/040-commands/pages/080-publishing/content.md",
|
|
45
|
+
"commands/theme/": "site/pages/032-reference/pages/040-commands/pages/090-theme/content.md",
|
|
46
|
+
"commands/engine/": "site/pages/032-reference/pages/040-commands/pages/100-engine/content.md",
|
|
47
|
+
"commands/migration-audit/": "site/pages/032-reference/pages/040-commands/pages/110-migration-audit/content.md",
|
|
48
|
+
"reader/display/": "site/pages/032-reference/pages/050-reader/pages/010-display/content.md",
|
|
49
|
+
"reader/accessibility/": "site/pages/032-reference/pages/050-reader/pages/020-accessibility/content.md",
|
|
50
|
+
"workflows/editor/": "site/pages/032-reference/pages/060-workflows/pages/010-editor/content.md",
|
|
51
|
+
"workflows/editor-ai-suggestions/": "site/pages/032-reference/pages/060-workflows/pages/015-editor-ai-suggestions/content.md",
|
|
52
|
+
"workflows/publishing/": "site/pages/032-reference/pages/060-workflows/pages/020-publishing/content.md",
|
|
53
|
+
"workflows/embedded-publishing/": "site/pages/032-reference/pages/060-workflows/pages/030-embedded-publishing/content.md",
|
|
54
|
+
"workflows/upgrading/": "site/pages/032-reference/pages/060-workflows/pages/040-upgrading/content.md",
|
|
55
|
+
"workflows/legacy-source/": "site/pages/032-reference/pages/060-workflows/pages/050-legacy-source/content.md"
|
|
56
|
+
},
|
|
57
|
+
"legacy": {
|
|
58
|
+
"site-files.md": "site/files/",
|
|
59
|
+
"pages.md": "site/pages/",
|
|
60
|
+
"configuration.md": "configuration/site/",
|
|
61
|
+
"content.md": "content/markdown/",
|
|
62
|
+
"theme.md": "configuration/theme/",
|
|
63
|
+
"typography.md": "configuration/typography/",
|
|
64
|
+
"images-and-metadata.md": "site/images/",
|
|
65
|
+
"public-files.md": "site/public-files/",
|
|
66
|
+
"sitewide-content.md": "configuration/shared-content/",
|
|
67
|
+
"commands.md": "commands/invocation/",
|
|
68
|
+
"local-development.md": "commands/development/",
|
|
69
|
+
"requirements.md": "site/requirements/",
|
|
70
|
+
"publishing.md": "workflows/publishing/",
|
|
71
|
+
"upgrading.md": "workflows/upgrading/",
|
|
72
|
+
"editor-support.md": "workflows/editor/",
|
|
73
|
+
"client-javascript.md": "reader/accessibility/",
|
|
74
|
+
"presentation-guarantees.md": "reader/accessibility/",
|
|
75
|
+
"site-files.md#root-files": "site/files/#source-layout",
|
|
76
|
+
"site-files.md#page-hierarchy": "site/files/#page-folders",
|
|
77
|
+
"site-files.md#public-files": "site/public-files/",
|
|
78
|
+
"site-files.md#selecting-the-site-directory": "commands/invocation/#site-selection",
|
|
79
|
+
"site-files.md#versioned-files": "site/files/#generated-files",
|
|
80
|
+
"site-files.md#generated-files": "site/files/#generated-files",
|
|
81
|
+
"pages.md#homepage-and-top-level-entries": "site/pages/#page-or-category",
|
|
82
|
+
"pages.md#choose-a-section-page-or-category": "site/pages/#page-or-category",
|
|
83
|
+
"pages.md#review-an-existing-hierarchy": "commands/navigation/",
|
|
84
|
+
"pages.md#navigation-categories": "site/pages/#page-or-category",
|
|
85
|
+
"pages.md#opening-a-category-url": "site/pages/#opening-a-category-url",
|
|
86
|
+
"pages.md#reachable-content-and-stable-links": "site/pages/#opening-a-category-url",
|
|
87
|
+
"pages.md#nested-pages": "site/pages/#page-or-category",
|
|
88
|
+
"pages.md#directory-names-order-and-urls": "site/pages/#names-and-order",
|
|
89
|
+
"pages.md#preserve-old-page-urls": "site/urls/#keep-an-old-url",
|
|
90
|
+
"pages.md#move-or-reconcile-a-page": "commands/move/",
|
|
91
|
+
"pages.md#create-pages-and-categories": "commands/create/",
|
|
92
|
+
"pages.md#page-content": "content/markdown/",
|
|
93
|
+
"pages.md#navigation": "configuration/navigation/",
|
|
94
|
+
"pages.md#focus-reading": "reader/display/#focus-reading",
|
|
95
|
+
"pages.md#current-reading-position": "configuration/navigation/#orientation-and-long-trees",
|
|
96
|
+
"pages.md#page-images": "site/images/",
|
|
97
|
+
"pages.md#page-themes": "configuration/theme/#page-themes",
|
|
98
|
+
"configuration.md#url": "configuration/site/#public-url",
|
|
99
|
+
"configuration.md#language": "configuration/language/",
|
|
100
|
+
"configuration.md#what-the-setting-changes": "configuration/language/",
|
|
101
|
+
"configuration.md#choose-a-language-tag": "configuration/language/",
|
|
102
|
+
"configuration.md#supported-languages": "configuration/language/",
|
|
103
|
+
"configuration.md#search-and-translation-boundaries": "configuration/language/",
|
|
104
|
+
"configuration.md#edit-link": "configuration/source-links/",
|
|
105
|
+
"configuration.md#local-editor": "configuration/source-links/#destination-rules",
|
|
106
|
+
"configuration.md#remote-source-host": "configuration/source-links/#fields",
|
|
107
|
+
"configuration.md#navigation": "configuration/navigation/",
|
|
108
|
+
"configuration.md#navigationmode": "configuration/navigation/",
|
|
109
|
+
"configuration.md#one-page-sections": "configuration/navigation/",
|
|
110
|
+
"configuration.md#top-level-pages-top": "configuration/navigation/",
|
|
111
|
+
"configuration.md#child-pages-or-categories-tree": "configuration/navigation/",
|
|
112
|
+
"configuration.md#search": "configuration/search/",
|
|
113
|
+
"configuration.md#scrollbehavior": "configuration/site/#anchor-movement",
|
|
114
|
+
"configuration.md#publishing-discovery": "commands/publishing/",
|
|
115
|
+
"configuration.md#site-directory-selection": "commands/invocation/#site-selection",
|
|
116
|
+
"content.md#page-title-and-frontmatter": "site/metadata/",
|
|
117
|
+
"content.md#sections": "content/markdown/#page-title-and-sections",
|
|
118
|
+
"content.md#internal-links": "site/urls/",
|
|
119
|
+
"content.md#norna-blocks": "content/structured-blocks/",
|
|
120
|
+
"content.md#child-page-list": "content/child-lists/",
|
|
121
|
+
"content.md#image-stack": "content/images/#image-stack",
|
|
122
|
+
"content.md#image-carousel": "content/images/#image-carousel",
|
|
123
|
+
"content.md#card-list": "content/cards/",
|
|
124
|
+
"content.md#image-files": "site/images/",
|
|
125
|
+
"content.md#markdown-images": "content/markdown/#markdown-images",
|
|
126
|
+
"content.md#markdown-text": "content/markdown/#standard-syntax-and-extensions",
|
|
127
|
+
"content.md#semantic-callouts": "content/callouts/",
|
|
128
|
+
"content.md#tabs": "content/tabs/",
|
|
129
|
+
"content.md#details-disclosures": "content/details/",
|
|
130
|
+
"content.md#tables": "content/tables/",
|
|
131
|
+
"content.md#row-headings": "content/tables/#row-headings",
|
|
132
|
+
"content.md#sorting": "content/tables/#sorting",
|
|
133
|
+
"content.md#width-and-scrolling": "content/tables/#width-and-sticky-context",
|
|
134
|
+
"content.md#code-blocks": "content/code/",
|
|
135
|
+
"content.md#side-notes": "content/sidenotes/",
|
|
136
|
+
"content.md#reference-footnotes": "content/footnotes/",
|
|
137
|
+
"content.md#validation-and-sync": "commands/validate/",
|
|
138
|
+
"images-and-metadata.md#managed-source-images": "site/images/#source-files",
|
|
139
|
+
"images-and-metadata.md#managed-image-presentation": "configuration/images/",
|
|
140
|
+
"images-and-metadata.md#captions-for-tall-images": "configuration/images/#tall-captions-and-inspection",
|
|
141
|
+
"images-and-metadata.md#inspecting-detailed-images": "configuration/images/#tall-captions-and-inspection",
|
|
142
|
+
"images-and-metadata.md#markdown-images": "content/markdown/#markdown-images",
|
|
143
|
+
"images-and-metadata.md#generated-variants-and-static-svg": "site/images/#variants-and-svg",
|
|
144
|
+
"images-and-metadata.md#manifest": "site/images/#manifest-and-cache",
|
|
145
|
+
"images-and-metadata.md#metadata-behavior": "site/images/#credits-and-provenance",
|
|
146
|
+
"images-and-metadata.md#ai-generated-images": "site/images/#credits-and-provenance",
|
|
147
|
+
"images-and-metadata.md#github-actions-cache": "site/images/#manifest-and-cache",
|
|
148
|
+
"public-files.md#navigation-logo": "site/public-files/#recognized-files",
|
|
149
|
+
"public-files.md#browser-icons": "site/public-files/#recognized-files",
|
|
150
|
+
"public-files.md#social-sharing-image": "site/public-files/#social-previews",
|
|
151
|
+
"public-files.md#github-pages-custom-domain": "site/public-files/#downloads-and-hosting-files",
|
|
152
|
+
"public-files.md#generated-sitemap": "site/public-files/#generated-sitemap",
|
|
153
|
+
"public-files.md#generated-404-page": "site/public-files/#generated-404-page",
|
|
154
|
+
"public-files.md#other-static-files": "site/public-files/#downloads-and-hosting-files",
|
|
155
|
+
"public-files.md#generated-copy": "site/public-files/#preparation-and-reserved-paths",
|
|
156
|
+
"theme.md#theme-presets": "configuration/presets/",
|
|
157
|
+
"theme.md#choose-a-preset": "configuration/theme/#presets-and-root-overrides",
|
|
158
|
+
"theme.md#portfolio": "configuration/presets/#portfolio",
|
|
159
|
+
"theme.md#documentation": "configuration/presets/#documentation",
|
|
160
|
+
"theme.md#project": "configuration/presets/#project",
|
|
161
|
+
"theme.md#statement": "configuration/presets/#statement",
|
|
162
|
+
"theme.md#overrides": "configuration/theme/#presets-and-root-overrides",
|
|
163
|
+
"theme.md#export-a-preset": "commands/theme/#list-and-export-presets",
|
|
164
|
+
"theme.md#layout": "configuration/layout/",
|
|
165
|
+
"theme.md#image-sizing": "configuration/images/",
|
|
166
|
+
"theme.md#content-block-defaults": "content/cards/#width",
|
|
167
|
+
"theme.md#typography": "configuration/typography/",
|
|
168
|
+
"theme.md#palette-and-appearance": "configuration/palettes/",
|
|
169
|
+
"theme.md#palette": "configuration/palettes/",
|
|
170
|
+
"theme.md#appearance": "configuration/appearance/",
|
|
171
|
+
"theme.md#reader-display-controls": "reader/display/",
|
|
172
|
+
"theme.md#corners": "configuration/theme/#site-wide-settings",
|
|
173
|
+
"theme.md#section-backgrounds": "configuration/sections/",
|
|
174
|
+
"theme.md#page-themes": "configuration/theme/#page-themes",
|
|
175
|
+
"typography.md#typography-profiles": "configuration/typography/#font-profile-and-rhythm",
|
|
176
|
+
"typography.md#typography-rhythm": "configuration/typography/#font-profile-and-rhythm",
|
|
177
|
+
"typography.md#configuration-shape": "configuration/typography/#override-fields",
|
|
178
|
+
"typography.md#override-values": "configuration/typography/#override-fields",
|
|
179
|
+
"typography.md#page-text-width": "configuration/layout/",
|
|
180
|
+
"sitewide-content.md#logo": "configuration/shared-content/#logo",
|
|
181
|
+
"sitewide-content.md#banners": "configuration/shared-content/#banners",
|
|
182
|
+
"sitewide-content.md#footer": "configuration/shared-content/#footer",
|
|
183
|
+
"commands.md#cli-commands": "commands/invocation/#command-map",
|
|
184
|
+
"commands.md#starter-npm-scripts": "commands/invocation/#project-npm-scripts",
|
|
185
|
+
"commands.md#create-pages-and-categories": "commands/create/",
|
|
186
|
+
"commands.md#move-a-page": "commands/move/",
|
|
187
|
+
"commands.md#review-navigation-structure": "commands/navigation/",
|
|
188
|
+
"commands.md#command-summary": "commands/invocation/#command-map",
|
|
189
|
+
"local-development.md#start-local-preview": "commands/development/",
|
|
190
|
+
"local-development.md#test-on-a-phone": "commands/development/#lan-preview",
|
|
191
|
+
"local-development.md#manage-preview": "commands/development/#lifecycle-commands",
|
|
192
|
+
"local-development.md#when-startup-fails": "commands/development/#preparation-failures-and-stale-output",
|
|
193
|
+
"local-development.md#rebuild-stale-preview": "commands/development/#preparation-failures-and-stale-output",
|
|
194
|
+
"publishing.md#requirements": "workflows/publishing/",
|
|
195
|
+
"publishing.md#github-pages-workflow": "workflows/publishing/#configure-and-publish",
|
|
196
|
+
"publishing.md#publish-an-embedded-site-beside-another-static-build": "workflows/embedded-publishing/",
|
|
197
|
+
"publishing.md#deploy-an-already-committed-branch": "commands/publishing/#deploy-committed-sources",
|
|
198
|
+
"publishing.md#deploy-with-a-generated-commit": "commands/publishing/#build-and-create-a-commit",
|
|
199
|
+
"publishing.md#watch-a-deploy": "commands/publishing/#monitor-a-workflow",
|
|
200
|
+
"upgrading.md#before-changing-the-site": "workflows/upgrading/#establish-the-baseline",
|
|
201
|
+
"upgrading.md#safest-pre-10-migration": "workflows/upgrading/#older-source-models",
|
|
202
|
+
"upgrading.md#current-source-layout": "workflows/legacy-source/",
|
|
203
|
+
"upgrading.md#routine-engine-updates": "workflows/upgrading/#update-and-review",
|
|
204
|
+
"upgrading.md#validate-the-migration": "workflows/upgrading/#update-and-review",
|
|
205
|
+
"editor-support.md#install-the-extension": "workflows/editor/#install-and-verify",
|
|
206
|
+
"editor-support.md#what-you-see-in-vs-code": "workflows/editor/#install-and-verify",
|
|
207
|
+
"editor-support.md#requirements": "workflows/editor/#install-and-verify",
|
|
208
|
+
"editor-support.md#recognized-files": "workflows/editor/#recognized-files",
|
|
209
|
+
"editor-support.md#configuration-help": "workflows/editor/#suggestions-and-diagnostics",
|
|
210
|
+
"editor-support.md#markdown-and-image-help": "workflows/editor/#managed-images-and-quick-fixes",
|
|
211
|
+
"editor-support.md#refresh-after-an-engine-change": "workflows/editor/#refresh-and-troubleshoot",
|
|
212
|
+
"editor-support.md#troubleshooting": "workflows/editor/#refresh-and-troubleshoot",
|
|
213
|
+
"editor-support.md#turn-off-ai-suggestions-while-keeping-intellisense": "workflows/editor-ai-suggestions/",
|
|
214
|
+
"client-javascript.md#feature-contract": "reader/accessibility/#without-javascript",
|
|
215
|
+
"client-javascript.md#choosing-static-alternatives": "reader/accessibility/#without-javascript",
|
|
216
|
+
"presentation-guarantees.md#color-and-focus": "reader/accessibility/#color-focus-and-controls",
|
|
217
|
+
"presentation-guarantees.md#typography-and-reading-width": "reader/accessibility/#reading-and-reflow",
|
|
218
|
+
"presentation-guarantees.md#reflow-and-text-adaptation": "reader/accessibility/#reading-and-reflow",
|
|
219
|
+
"presentation-guarantees.md#controls-and-user-preferences": "reader/display/",
|
|
220
|
+
"presentation-guarantees.md#author-responsibilities": "reader/accessibility/#author-responsibilities"
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -94,6 +94,28 @@ export const decodePageDirectoryPath = (pageEntryPath, label = 'page entry path'
|
|
|
94
94
|
return pageDirectories.join('/pages/');
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
+
export const getSiteEntryPrefix = (siteDirLabel) => siteDirLabel
|
|
98
|
+
.replace(/^[./\\]+/, '')
|
|
99
|
+
.replace(/[^a-zA-Z0-9-]+/g, '-')
|
|
100
|
+
.replace(/^-+|-+$/g, '') || 'site';
|
|
101
|
+
|
|
102
|
+
const getPageEntryPrefix = (siteDirLabel) => `${getSiteEntryPrefix(siteDirLabel)}-page-`;
|
|
103
|
+
|
|
104
|
+
export const encodePageEntryId = (siteDirLabel, pageDirectoryPath) => (
|
|
105
|
+
`${getPageEntryPrefix(siteDirLabel)}${encodePageDirectoryPath(pageDirectoryPath)}`
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
export const decodePageEntryId = (siteDirLabel, entryId) => {
|
|
109
|
+
const prefix = getPageEntryPrefix(siteDirLabel);
|
|
110
|
+
if (!entryId.startsWith(prefix)) return null;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
return parsePageDirectoryPath(decodePageDirectoryPath(entryId.slice(prefix.length))).pageDirectory;
|
|
114
|
+
} catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
97
119
|
export const getPageDirectoryAncestors = (pageDirectoryPath) => {
|
|
98
120
|
const { pageDirectories } = parsePageDirectoryPath(pageDirectoryPath);
|
|
99
121
|
return pageDirectories.map((_, index) => (
|
|
@@ -209,7 +209,7 @@ const pageAlias = z.string().regex(
|
|
|
209
209
|
'Use an old site-relative Norna page URL such as "/guides/install/". Start and end with / and use lowercase letters, numbers, and single hyphens.',
|
|
210
210
|
).describe('Previous site-relative URL that permanently identifies this page.');
|
|
211
211
|
const pageMetadata = z.object({
|
|
212
|
-
description: z.string().min(1).optional().describe('
|
|
212
|
+
description: z.string().min(1).optional().describe('Page description used in metadata, social previews and generated child-page lists.'),
|
|
213
213
|
aliases: z.array(pageAlias)
|
|
214
214
|
.min(1)
|
|
215
215
|
.refine((values) => new Set(values).size === values.length, 'Page aliases must be unique within the page.')
|
|
@@ -275,7 +275,7 @@ const sitewideShape = {
|
|
|
275
275
|
};
|
|
276
276
|
|
|
277
277
|
const categoryShape = {
|
|
278
|
-
label: z.string().trim().min(1).describe('Navigation label for
|
|
278
|
+
label: z.string().trim().min(1).describe('Navigation label for a group of child pages without an authored page body.'),
|
|
279
279
|
};
|
|
280
280
|
|
|
281
281
|
export const schemaTopLevelKeys = Object.freeze({
|
|
@@ -290,7 +290,7 @@ export const schemaTopLevelKeys = Object.freeze({
|
|
|
290
290
|
export const configSchema = z.object(configShape).strict()
|
|
291
291
|
.describe('Technical settings for one Norna site. Additional pages cannot provide technical configuration.');
|
|
292
292
|
export const categorySchema = z.object(categoryShape).strict()
|
|
293
|
-
.describe('A
|
|
293
|
+
.describe('A navigation group without an authored page body. Opening its URL redirects when its first listed direct child is a page; otherwise it shows a generated child list.');
|
|
294
294
|
export const siteSchema = z.object(siteShape).strict()
|
|
295
295
|
.describe('Frontmatter for a homepage or additional page content.md file.');
|
|
296
296
|
export const themeVisualSchema = z.object(themeVisualShape).strict()
|
|
@@ -583,7 +583,7 @@ const addContentHelp = (jsonSchema) => {
|
|
|
583
583
|
]);
|
|
584
584
|
addHelp(jsonSchema, 'page.description', [
|
|
585
585
|
yamlExample('page:\n description: About this project.'),
|
|
586
|
-
'
|
|
586
|
+
'A page-specific description used in metadata and social previews. Generated child-page and category lists can show it beside the page title; it is not inserted into the page body.',
|
|
587
587
|
documentationLink('Page title and frontmatter reference', 'content.md', 'page-title-and-frontmatter'),
|
|
588
588
|
], ['About this project.']);
|
|
589
589
|
addHelp(jsonSchema, 'page.aliases', [
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { getCollection } from 'astro:content';
|
|
3
|
+
import { getPresentationCssVariables, resolveThemePresentation } from '../../scripts/lib/presentation.mjs';
|
|
2
4
|
import projectConfig from '../../scripts/lib/project-config.mjs';
|
|
3
5
|
import { getAbsolutePageUrl } from '../../scripts/lib/site-page-urls.mjs';
|
|
6
|
+
import { siteThemeLabel } from '../../scripts/lib/site-paths.mjs';
|
|
4
7
|
import { withBasePath } from '../lib/basePath';
|
|
8
|
+
import { getReaderPreferencesScript } from '../lib/readerPreferencesScript.mjs';
|
|
5
9
|
|
|
6
10
|
interface Props {
|
|
7
11
|
targetPathname: string;
|
|
@@ -13,23 +17,54 @@ const { targetPathname, targetTitle, categoryTitle } = Astro.props;
|
|
|
13
17
|
const { labels, lang } = projectConfig.locale;
|
|
14
18
|
const targetHref = withBasePath(projectConfig.site.basePath, targetPathname);
|
|
15
19
|
const canonicalUrl = getAbsolutePageUrl(projectConfig.site.url, targetPathname);
|
|
20
|
+
const [siteTheme] = await getCollection('theme');
|
|
21
|
+
if (!siteTheme) throw new Error(`${siteThemeLabel} is required. Add a root theme before building the site.`);
|
|
22
|
+
const presentation = resolveThemePresentation(siteTheme.data, siteThemeLabel);
|
|
23
|
+
const documentStyle = Object.entries(getPresentationCssVariables(presentation))
|
|
24
|
+
.map(([name, value]) => `${name}: ${value}`).join('; ');
|
|
25
|
+
const readerPreferencesScript = getReaderPreferencesScript({
|
|
26
|
+
...presentation.readerPreferences,
|
|
27
|
+
cookiePath: projectConfig.site.basePath,
|
|
28
|
+
});
|
|
16
29
|
---
|
|
17
30
|
|
|
18
31
|
<!doctype html>
|
|
19
|
-
<html lang={lang} data-pagefind-ignore="all">
|
|
32
|
+
<html lang={lang} data-pagefind-ignore="all" data-appearance={presentation.appearance.default} style={documentStyle}>
|
|
20
33
|
<head>
|
|
21
34
|
<meta charset="utf-8" />
|
|
22
35
|
<meta name="viewport" content="width=device-width" />
|
|
23
36
|
<meta name="robots" content="noindex, follow" />
|
|
24
|
-
<meta http-equiv="refresh" content={`0; url=${targetHref}`} />
|
|
25
37
|
<link rel="canonical" href={canonicalUrl} />
|
|
26
38
|
<title>{categoryTitle ?? labels.pageMoved}: {targetTitle}</title>
|
|
39
|
+
<meta name="theme-color" content={presentation.palette.page.backgroundColor} />
|
|
27
40
|
<style is:inline>
|
|
28
41
|
:root {
|
|
29
|
-
color-
|
|
42
|
+
--color-page: var(--palette-light-page-background);
|
|
43
|
+
--color-primary-text: var(--palette-light-primary-text);
|
|
44
|
+
--color-link-text: var(--palette-light-link-text);
|
|
45
|
+
color-scheme: light;
|
|
46
|
+
min-height: 100%;
|
|
47
|
+
background: var(--color-page);
|
|
48
|
+
color: var(--color-primary-text);
|
|
30
49
|
font-family: system-ui, sans-serif;
|
|
31
50
|
}
|
|
32
51
|
|
|
52
|
+
:root[data-appearance='dark'] {
|
|
53
|
+
--color-page: var(--palette-dark-page-background);
|
|
54
|
+
--color-primary-text: var(--palette-dark-primary-text);
|
|
55
|
+
--color-link-text: var(--palette-dark-link-text);
|
|
56
|
+
color-scheme: dark;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@media (prefers-color-scheme: dark) {
|
|
60
|
+
:root[data-appearance='system'] {
|
|
61
|
+
--color-page: var(--palette-dark-page-background);
|
|
62
|
+
--color-primary-text: var(--palette-dark-primary-text);
|
|
63
|
+
--color-link-text: var(--palette-dark-link-text);
|
|
64
|
+
color-scheme: dark;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
33
68
|
body {
|
|
34
69
|
margin: 0;
|
|
35
70
|
padding: 2rem;
|
|
@@ -39,7 +74,13 @@ const canonicalUrl = getAbsolutePageUrl(projectConfig.site.url, targetPathname);
|
|
|
39
74
|
max-width: 42rem;
|
|
40
75
|
margin-inline: auto;
|
|
41
76
|
}
|
|
77
|
+
|
|
78
|
+
a {
|
|
79
|
+
color: var(--color-link-text);
|
|
80
|
+
}
|
|
42
81
|
</style>
|
|
82
|
+
<script is:inline set:html={readerPreferencesScript} />
|
|
83
|
+
<meta http-equiv="refresh" content={`0; url=${targetHref}`} />
|
|
43
84
|
</head>
|
|
44
85
|
<body>
|
|
45
86
|
<main>
|
package/src/content.config.ts
CHANGED
|
@@ -9,17 +9,14 @@ import {
|
|
|
9
9
|
siteThemePath,
|
|
10
10
|
sitewideContentPath,
|
|
11
11
|
} from '../scripts/lib/site-paths.mjs';
|
|
12
|
-
import {
|
|
12
|
+
import { encodePageEntryId, getSiteEntryPrefix, parsePageDirectoryPath } from '../scripts/lib/page-model.mjs';
|
|
13
13
|
import {
|
|
14
14
|
siteSchema,
|
|
15
15
|
sitewideSchema,
|
|
16
16
|
themeVisualSchema,
|
|
17
17
|
} from '../scripts/lib/schema-definitions.mjs';
|
|
18
18
|
|
|
19
|
-
const
|
|
20
|
-
.replace(/^[./\\]+/, '')
|
|
21
|
-
.replace(/[^a-zA-Z0-9-]+/g, '-')
|
|
22
|
-
.replace(/^-+|-+$/g, '') || 'site'}-content`;
|
|
19
|
+
const siteEntryPrefix = getSiteEntryPrefix(siteDirLabel);
|
|
23
20
|
const emptyYamlMapping = (value: unknown) => value ?? {};
|
|
24
21
|
const siteThemeSchema = z.preprocess(emptyYamlMapping, themeVisualSchema);
|
|
25
22
|
const sitewideContentSchema = z.preprocess(emptyYamlMapping, sitewideSchema);
|
|
@@ -34,7 +31,7 @@ const site = defineCollection({
|
|
|
34
31
|
.split('/')
|
|
35
32
|
.filter((segment) => segment !== 'pages')
|
|
36
33
|
.join('/pages/');
|
|
37
|
-
return
|
|
34
|
+
return encodePageEntryId(siteDirLabel, parsePageDirectoryPath(pageDirectory, `page directory pages/${pageEntryDirectory}`).pageDirectory);
|
|
38
35
|
},
|
|
39
36
|
}),
|
|
40
37
|
schema: siteSchema,
|
|
@@ -44,7 +41,7 @@ const theme = defineCollection({
|
|
|
44
41
|
loader: glob({
|
|
45
42
|
pattern: basename(siteThemePath),
|
|
46
43
|
base: pathToFileURL(siteDir),
|
|
47
|
-
generateId: () => `${
|
|
44
|
+
generateId: () => `${siteEntryPrefix}-theme`,
|
|
48
45
|
}),
|
|
49
46
|
schema: siteThemeSchema,
|
|
50
47
|
});
|
|
@@ -53,7 +50,7 @@ const sitewide = defineCollection({
|
|
|
53
50
|
loader: glob({
|
|
54
51
|
pattern: basename(sitewideContentPath),
|
|
55
52
|
base: pathToFileURL(siteDir),
|
|
56
|
-
generateId: () => `${
|
|
53
|
+
generateId: () => `${siteEntryPrefix}-sitewide`,
|
|
57
54
|
}),
|
|
58
55
|
schema: sitewideContentSchema,
|
|
59
56
|
});
|
package/src/lib/sitePages.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { CollectionEntry } from 'astro:content';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { decodePageEntryId, parsePageDirectoryPath } from '../../scripts/lib/page-model.mjs';
|
|
4
4
|
import { parsePageMarkdown } from '../../scripts/lib/page-markdown.mjs';
|
|
5
5
|
import { readSiteFile } from '../../scripts/lib/site-content.mjs';
|
|
6
6
|
import { homePageDirectory } from '../../scripts/lib/site-conventions.mjs';
|
|
7
7
|
import { assertCategoryDestinationModel, createCategoryDestinationModel } from '../../scripts/lib/category-destinations.mjs';
|
|
8
8
|
import { getSiteStructure } from '../../scripts/lib/site-structure.mjs';
|
|
9
|
-
import { sitePagesDir, sitePagesLabel } from '../../scripts/lib/site-paths.mjs';
|
|
9
|
+
import { siteDirLabel, sitePagesDir, sitePagesLabel } from '../../scripts/lib/site-paths.mjs';
|
|
10
10
|
|
|
11
11
|
type SiteEntry = CollectionEntry<'site'>;
|
|
12
12
|
|
|
@@ -48,24 +48,10 @@ export type SiteCategory = SiteNodeBase & {
|
|
|
48
48
|
|
|
49
49
|
export type SiteNode = SitePage | SiteCategory;
|
|
50
50
|
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
const stripPageIdPrefix = (id: string) => {
|
|
54
|
-
const markerIndex = id.lastIndexOf(pageIdMarker);
|
|
55
|
-
if (markerIndex === -1) return null;
|
|
56
|
-
|
|
57
|
-
const candidate = id.slice(markerIndex + pageIdMarker.length);
|
|
58
|
-
try {
|
|
59
|
-
return parsePageDirectoryPath(decodePageDirectoryPath(candidate)).pageDirectory;
|
|
60
|
-
} catch {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const isHomePageEntry = (entry: SiteEntry) => stripPageIdPrefix(entry.id) === homePageDirectory;
|
|
51
|
+
export const isHomePageEntry = (entry: SiteEntry) => decodePageEntryId(siteDirLabel, entry.id) === homePageDirectory;
|
|
66
52
|
|
|
67
53
|
export const getPageDirectory = (entry: SiteEntry) => {
|
|
68
|
-
const pageDirectory =
|
|
54
|
+
const pageDirectory = decodePageEntryId(siteDirLabel, entry.id);
|
|
69
55
|
if (!pageDirectory) throw new Error(`Page entry "${entry.id}" has no valid page directory.`);
|
|
70
56
|
return pageDirectory;
|
|
71
57
|
};
|
package/src/styles/content.css
CHANGED
|
@@ -983,8 +983,9 @@ ul {
|
|
|
983
983
|
padding: 0.78rem 0.9rem;
|
|
984
984
|
background: var(--color-code-background) !important;
|
|
985
985
|
color: var(--color-code-text);
|
|
986
|
-
font-
|
|
987
|
-
|
|
986
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
987
|
+
font-size: 0.875rem;
|
|
988
|
+
line-height: 1.43;
|
|
988
989
|
text-align: left;
|
|
989
990
|
}
|
|
990
991
|
|
package/starters/basic/README.md
CHANGED
|
@@ -61,5 +61,5 @@ Use `npm run norna:engine:version` to inspect the installed engine and
|
|
|
61
61
|
`npm run norna:engine:update` to update it.
|
|
62
62
|
|
|
63
63
|
Start with the [illustrated Getting Started guide](https://janga.github.io/norna/getting-started/install-norna/).
|
|
64
|
-
Use the [
|
|
64
|
+
Use the [Norna reference](https://janga.github.io/norna/reference/)
|
|
65
65
|
for exact file contracts, syntax, commands, and publishing behavior.
|