@janga/norna 0.7.25 → 0.7.26
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 +3 -2
- package/astro.config.mjs +26 -12
- package/bin/norna-cli.mjs +12 -0
- package/package.json +14 -5
- package/schemas/card-list.schema.json +121 -0
- package/schemas/category.schema.json +2 -2
- package/schemas/config.schema.json +306 -32
- package/schemas/content-frontmatter.schema.json +7 -7
- package/schemas/image-carousel.schema.json +43 -0
- package/schemas/image-stack.schema.json +43 -0
- package/schemas/manifest.json +6 -1
- package/schemas/page-theme.schema.json +26 -26
- package/schemas/sitewide-content.schema.json +18 -18
- package/schemas/theme.schema.json +237 -262
- package/scripts/dev-local.mjs +24 -2
- package/scripts/generate-schemas.mjs +15 -3
- package/scripts/lib/category-destinations.mjs +48 -0
- package/scripts/lib/code-fence-metadata.mjs +14 -37
- package/scripts/lib/content-tabs.mjs +155 -0
- package/scripts/lib/details-headings.mjs +58 -0
- package/scripts/lib/docusaurus-migration-audit.mjs +603 -0
- package/scripts/lib/editor-language-service.mjs +238 -116
- package/scripts/lib/locale-registry.mjs +597 -0
- package/scripts/lib/locales/az-Latn.mjs +78 -0
- package/scripts/lib/locales/be.mjs +78 -0
- package/scripts/lib/locales/bg.mjs +78 -0
- package/scripts/lib/locales/bs.mjs +78 -0
- package/scripts/lib/locales/ca.mjs +78 -0
- package/scripts/lib/locales/cnr.mjs +78 -0
- package/scripts/lib/locales/cs.mjs +78 -0
- package/scripts/lib/locales/da.mjs +78 -0
- package/scripts/lib/locales/de.mjs +78 -0
- package/scripts/lib/locales/el.mjs +78 -0
- package/scripts/lib/locales/en.mjs +78 -0
- package/scripts/lib/locales/es.mjs +78 -0
- package/scripts/lib/locales/et.mjs +78 -0
- package/scripts/lib/locales/fi.mjs +78 -0
- package/scripts/lib/locales/fil.mjs +78 -0
- package/scripts/lib/locales/fr.mjs +78 -0
- package/scripts/lib/locales/ga.mjs +78 -0
- package/scripts/lib/locales/ha.mjs +78 -0
- package/scripts/lib/locales/hr.mjs +78 -0
- package/scripts/lib/locales/hu.mjs +78 -0
- package/scripts/lib/locales/id.mjs +78 -0
- package/scripts/lib/locales/is.mjs +78 -0
- package/scripts/lib/locales/it.mjs +78 -0
- package/scripts/lib/locales/jv.mjs +78 -0
- package/scripts/lib/locales/lb.mjs +78 -0
- package/scripts/lib/locales/lt.mjs +78 -0
- package/scripts/lib/locales/lv.mjs +78 -0
- package/scripts/lib/locales/mk.mjs +78 -0
- package/scripts/lib/locales/mt.mjs +78 -0
- package/scripts/lib/locales/nb.mjs +78 -0
- package/scripts/lib/locales/nl.mjs +78 -0
- package/scripts/lib/locales/nn.mjs +78 -0
- package/scripts/lib/locales/pcm.mjs +78 -0
- package/scripts/lib/locales/pl.mjs +78 -0
- package/scripts/lib/locales/pt.mjs +78 -0
- package/scripts/lib/locales/ro.mjs +78 -0
- package/scripts/lib/locales/ru.mjs +78 -0
- package/scripts/lib/locales/sk.mjs +78 -0
- package/scripts/lib/locales/sl.mjs +78 -0
- package/scripts/lib/locales/sq.mjs +78 -0
- package/scripts/lib/locales/sr-Cyrl.mjs +78 -0
- package/scripts/lib/locales/sr-Latn.mjs +78 -0
- package/scripts/lib/locales/sv.mjs +78 -0
- package/scripts/lib/locales/sw.mjs +78 -0
- package/scripts/lib/locales/tr.mjs +78 -0
- package/scripts/lib/locales/uk.mjs +78 -0
- package/scripts/lib/locales/vi.mjs +78 -0
- package/scripts/lib/markdown-links.mjs +4 -25
- package/scripts/lib/markdown-notes-render-plugin.mjs +75 -0
- package/scripts/lib/markdown-notes.mjs +165 -0
- package/scripts/lib/norna-markdown-blocks.mjs +32 -447
- package/scripts/lib/norna-markdown-render-plugin.mjs +4 -0
- package/scripts/lib/page-aliases.mjs +12 -1
- package/scripts/lib/page-markdown.mjs +63 -16
- package/scripts/lib/page-move-plan.mjs +22 -5
- package/scripts/lib/pagefind-translations.mjs +620 -0
- package/scripts/lib/presentation-contract.mjs +6 -1
- package/scripts/lib/presentation.mjs +29 -30
- package/scripts/lib/project-config.mjs +2 -173
- package/scripts/lib/schema-definitions.mjs +3 -10
- package/scripts/lib/schema-editor-metadata.mjs +22 -43
- package/scripts/lib/schema-value-definitions.mjs +4 -8
- package/scripts/lib/semantic-callouts.mjs +4 -2
- package/scripts/lib/site-content.mjs +4 -2
- package/scripts/lib/site-link-graph.mjs +16 -6
- package/scripts/lib/site-navigation-tree.mjs +0 -11
- package/scripts/lib/sitemap.mjs +5 -3
- package/scripts/lib/structured-blocks.mjs +108 -0
- package/scripts/lib/table-render-plugin.mjs +46 -3
- package/scripts/lib/table-row-headers.mjs +218 -0
- package/scripts/lib/theme-presets.mjs +3 -10
- package/scripts/lib/yaml-config.mjs +2 -6
- package/scripts/migrate-check.mjs +19 -0
- package/scripts/sync-content-sections.mjs +39 -10
- package/scripts/sync-site-public.mjs +7 -1
- package/src/components/CodeBlockCopyScript.astro +47 -5
- package/src/components/ContentBlocks.astro +39 -0
- package/src/components/ContentTabsScript.astro +60 -0
- package/src/components/DisplaySettings.astro +17 -19
- package/src/components/NavigationPageTree.astro +1 -1
- package/src/components/NoteNavigationScript.astro +4 -0
- package/src/components/PageAliasRedirect.astro +5 -4
- package/src/components/SearchNavigationScript.astro +4 -0
- package/src/components/SearchPage.astro +43 -2
- package/src/components/SectionNavigationScript.astro +43 -11
- package/src/components/SiteBreadcrumbs.astro +1 -1
- package/src/components/SiteNavigation.astro +29 -20
- package/src/components/SitePage.astro +40 -15
- package/src/components/SiteSection.astro +5 -81
- package/src/components/SiteTreeNavigation.astro +2 -2
- package/src/components/TableOverflowScript.astro +386 -58
- package/src/components/TopPageMenu.astro +47 -0
- package/src/components/TreeNavigationScript.astro +10 -3
- package/src/layouts/BaseLayout.astro +8 -12
- package/src/lib/navigationFollowing.ts +142 -0
- package/src/lib/noteNavigation.ts +50 -0
- package/src/lib/searchNavigation.ts +107 -0
- package/src/lib/sectionContent.ts +20 -90
- package/src/lib/siteNavigation.ts +0 -5
- package/src/lib/sitePages.ts +13 -2
- package/src/lib/table-sort-tooltip.ts +109 -0
- package/src/pages/[...slug].astro +16 -6
- package/src/styles/content.css +394 -132
- package/src/styles/foundations.css +9 -0
- package/src/styles/media.css +5 -0
- package/src/styles/navigation.css +63 -74
- package/src/styles/page-layout.css +7 -0
- package/src/styles/responsive.css +2 -7
|
@@ -87,16 +87,16 @@ const presentationPalettes = Object.freeze({
|
|
|
87
87
|
modes: Object.freeze({
|
|
88
88
|
light: createPaletteMode({
|
|
89
89
|
appearance: 'light',
|
|
90
|
-
page: { backgroundColor: '#
|
|
90
|
+
page: { backgroundColor: '#e8f1f8', textColor: '#202932' },
|
|
91
91
|
surfaces: {
|
|
92
|
-
base: { backgroundColor: '#
|
|
92
|
+
base: { backgroundColor: '#e8f1f8', textColor: '#202932' },
|
|
93
93
|
soft: { backgroundColor: '#e4eaf0', textColor: '#202932' },
|
|
94
94
|
emphasis: { backgroundColor: '#d3dee8', textColor: '#202932' },
|
|
95
95
|
},
|
|
96
|
-
frame: { backgroundColor: '#
|
|
96
|
+
frame: { backgroundColor: '#e8f1f8', textColor: '#202932' },
|
|
97
97
|
css: {
|
|
98
98
|
surface: '#e9eef2',
|
|
99
|
-
muted: '#
|
|
99
|
+
muted: '#56636f',
|
|
100
100
|
soft: '#d5dfe7',
|
|
101
101
|
accent: '#2a5877',
|
|
102
102
|
border: 'rgb(32 41 50 / 16%)',
|
|
@@ -127,13 +127,13 @@ const presentationPalettes = Object.freeze({
|
|
|
127
127
|
modes: Object.freeze({
|
|
128
128
|
light: createPaletteMode({
|
|
129
129
|
appearance: 'light',
|
|
130
|
-
page: { backgroundColor: '#
|
|
130
|
+
page: { backgroundColor: '#e3f1eb', textColor: '#203631' },
|
|
131
131
|
surfaces: {
|
|
132
|
-
base: { backgroundColor: '#
|
|
132
|
+
base: { backgroundColor: '#e3f1eb', textColor: '#203631' },
|
|
133
133
|
soft: { backgroundColor: '#dce9e4', textColor: '#203631' },
|
|
134
134
|
emphasis: { backgroundColor: '#c8ddd5', textColor: '#203631' },
|
|
135
135
|
},
|
|
136
|
-
frame: { backgroundColor: '#
|
|
136
|
+
frame: { backgroundColor: '#e3f1eb', textColor: '#203631' },
|
|
137
137
|
css: {
|
|
138
138
|
surface: '#e3ece8',
|
|
139
139
|
muted: '#536560',
|
|
@@ -167,16 +167,16 @@ const presentationPalettes = Object.freeze({
|
|
|
167
167
|
modes: Object.freeze({
|
|
168
168
|
light: createPaletteMode({
|
|
169
169
|
appearance: 'light',
|
|
170
|
-
page: { backgroundColor: '#
|
|
170
|
+
page: { backgroundColor: '#f0e8f8', textColor: '#2e2736' },
|
|
171
171
|
surfaces: {
|
|
172
|
-
base: { backgroundColor: '#
|
|
172
|
+
base: { backgroundColor: '#f0e8f8', textColor: '#2e2736' },
|
|
173
173
|
soft: { backgroundColor: '#ebe4f1', textColor: '#2e2736' },
|
|
174
174
|
emphasis: { backgroundColor: '#ddd3e8', textColor: '#2e2736' },
|
|
175
175
|
},
|
|
176
|
-
frame: { backgroundColor: '#
|
|
176
|
+
frame: { backgroundColor: '#f0e8f8', textColor: '#2e2736' },
|
|
177
177
|
css: {
|
|
178
178
|
surface: '#eee8f3',
|
|
179
|
-
muted: '#
|
|
179
|
+
muted: '#655b6c',
|
|
180
180
|
soft: '#ded5e7',
|
|
181
181
|
accent: '#604678',
|
|
182
182
|
border: 'rgb(46 39 54 / 16%)',
|
|
@@ -207,13 +207,13 @@ const presentationPalettes = Object.freeze({
|
|
|
207
207
|
modes: Object.freeze({
|
|
208
208
|
light: createPaletteMode({
|
|
209
209
|
appearance: 'light',
|
|
210
|
-
page: { backgroundColor: '#
|
|
210
|
+
page: { backgroundColor: '#fdf6e3', textColor: '#272522' },
|
|
211
211
|
surfaces: {
|
|
212
|
-
base: { backgroundColor: '#
|
|
212
|
+
base: { backgroundColor: '#fdf6e3', textColor: '#272522' },
|
|
213
213
|
soft: { backgroundColor: '#ebe5d9', textColor: '#272522' },
|
|
214
214
|
emphasis: { backgroundColor: '#ded4c5', textColor: '#272522' },
|
|
215
215
|
},
|
|
216
|
-
frame: { backgroundColor: '#
|
|
216
|
+
frame: { backgroundColor: '#fdf6e3', textColor: '#272522' },
|
|
217
217
|
css: {
|
|
218
218
|
surface: '#f0ebe1',
|
|
219
219
|
muted: '#6b655b',
|
|
@@ -247,13 +247,13 @@ const presentationPalettes = Object.freeze({
|
|
|
247
247
|
modes: Object.freeze({
|
|
248
248
|
light: createPaletteMode({
|
|
249
249
|
appearance: 'light',
|
|
250
|
-
page: { backgroundColor: '#
|
|
250
|
+
page: { backgroundColor: '#fbf1c7', textColor: '#34291c' },
|
|
251
251
|
surfaces: {
|
|
252
|
-
base: { backgroundColor: '#
|
|
252
|
+
base: { backgroundColor: '#fbf1c7', textColor: '#34291c' },
|
|
253
253
|
soft: { backgroundColor: '#eadbb8', textColor: '#34291c' },
|
|
254
254
|
emphasis: { backgroundColor: '#d8c18c', textColor: '#34291c' },
|
|
255
255
|
},
|
|
256
|
-
frame: { backgroundColor: '#
|
|
256
|
+
frame: { backgroundColor: '#fbf1c7', textColor: '#34291c' },
|
|
257
257
|
css: {
|
|
258
258
|
surface: '#efe2c4',
|
|
259
259
|
muted: '#6c5e4c',
|
|
@@ -287,13 +287,13 @@ const presentationPalettes = Object.freeze({
|
|
|
287
287
|
modes: Object.freeze({
|
|
288
288
|
light: createPaletteMode({
|
|
289
289
|
appearance: 'light',
|
|
290
|
-
page: { backgroundColor: '#
|
|
290
|
+
page: { backgroundColor: '#f8e9e7', textColor: '#3c2929' },
|
|
291
291
|
surfaces: {
|
|
292
|
-
base: { backgroundColor: '#
|
|
292
|
+
base: { backgroundColor: '#f8e9e7', textColor: '#3c2929' },
|
|
293
293
|
soft: { backgroundColor: '#ecdeda', textColor: '#3c2929' },
|
|
294
294
|
emphasis: { backgroundColor: '#ddc7c1', textColor: '#3c2929' },
|
|
295
295
|
},
|
|
296
|
-
frame: { backgroundColor: '#
|
|
296
|
+
frame: { backgroundColor: '#f8e9e7', textColor: '#3c2929' },
|
|
297
297
|
css: {
|
|
298
298
|
surface: '#f0e3e0',
|
|
299
299
|
muted: '#6d5558',
|
|
@@ -327,13 +327,13 @@ const presentationPalettes = Object.freeze({
|
|
|
327
327
|
modes: Object.freeze({
|
|
328
328
|
light: createPaletteMode({
|
|
329
329
|
appearance: 'light',
|
|
330
|
-
page: { backgroundColor: '#
|
|
330
|
+
page: { backgroundColor: '#eaf0da', textColor: '#263225' },
|
|
331
331
|
surfaces: {
|
|
332
|
-
base: { backgroundColor: '#
|
|
332
|
+
base: { backgroundColor: '#eaf0da', textColor: '#263225' },
|
|
333
333
|
soft: { backgroundColor: '#e1e6d2', textColor: '#263225' },
|
|
334
334
|
emphasis: { backgroundColor: '#cbd5b7', textColor: '#263225' },
|
|
335
335
|
},
|
|
336
|
-
frame: { backgroundColor: '#
|
|
336
|
+
frame: { backgroundColor: '#eaf0da', textColor: '#263225' },
|
|
337
337
|
css: {
|
|
338
338
|
surface: '#e7eadb',
|
|
339
339
|
muted: '#52604c',
|
|
@@ -367,16 +367,16 @@ const presentationPalettes = Object.freeze({
|
|
|
367
367
|
modes: Object.freeze({
|
|
368
368
|
light: createPaletteMode({
|
|
369
369
|
appearance: 'light',
|
|
370
|
-
page: { backgroundColor: '#
|
|
370
|
+
page: { backgroundColor: '#e8ebfa', textColor: '#25243a' },
|
|
371
371
|
surfaces: {
|
|
372
|
-
base: { backgroundColor: '#
|
|
372
|
+
base: { backgroundColor: '#e8ebfa', textColor: '#25243a' },
|
|
373
373
|
soft: { backgroundColor: '#e2e6f3', textColor: '#25243a' },
|
|
374
374
|
emphasis: { backgroundColor: '#d0d7eb', textColor: '#25243a' },
|
|
375
375
|
},
|
|
376
|
-
frame: { backgroundColor: '#
|
|
376
|
+
frame: { backgroundColor: '#e8ebfa', textColor: '#25243a' },
|
|
377
377
|
css: {
|
|
378
378
|
surface: '#e8eaf5',
|
|
379
|
-
muted: '#
|
|
379
|
+
muted: '#5b5d73',
|
|
380
380
|
soft: '#d5daec',
|
|
381
381
|
accent: '#3b568f',
|
|
382
382
|
border: 'rgb(37 36 58 / 16%)',
|
|
@@ -467,7 +467,6 @@ export const resolveThemePresentation = (theme, sourceLabel = 'theme.yaml') => {
|
|
|
467
467
|
const paletteName = normalizedTheme.palette ?? 'near-monochrome';
|
|
468
468
|
const palette = getPresentationPalette(paletteName);
|
|
469
469
|
const appearance = normalizedTheme.appearance ?? {};
|
|
470
|
-
const readerControls = normalizedTheme.readerControls ?? {};
|
|
471
470
|
const defaultAppearance = appearance.default ?? 'system';
|
|
472
471
|
if (!appearanceNames.includes(defaultAppearance)) {
|
|
473
472
|
throw new Error(`appearance.default must be one of ${appearanceNames.join(', ')} in ${sourceLabel}.`);
|
|
@@ -488,9 +487,9 @@ export const resolveThemePresentation = (theme, sourceLabel = 'theme.yaml') => {
|
|
|
488
487
|
},
|
|
489
488
|
readerPreferences: {
|
|
490
489
|
controls: {
|
|
491
|
-
appearance:
|
|
490
|
+
appearance: true,
|
|
492
491
|
readingWidth: true,
|
|
493
|
-
focusReading:
|
|
492
|
+
focusReading: false,
|
|
494
493
|
},
|
|
495
494
|
defaults: {
|
|
496
495
|
appearance: defaultAppearance,
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
siteThemeLabel,
|
|
15
15
|
} from './site-paths.mjs';
|
|
16
16
|
import { localEditorNames, normalizeEditLinkBaseUrl } from './edit-source-link.mjs';
|
|
17
|
+
import { resolveLocale } from './locale-registry.mjs';
|
|
17
18
|
import { readThemeConfig } from './theme-config.mjs';
|
|
18
19
|
import { resolveThemeConfig } from './theme-presets.mjs';
|
|
19
20
|
import { parseYamlConfig } from './yaml-config.mjs';
|
|
@@ -197,178 +198,6 @@ const readSiteUrl = (config) => {
|
|
|
197
198
|
return url;
|
|
198
199
|
};
|
|
199
200
|
|
|
200
|
-
const localeLabels = Object.freeze({
|
|
201
|
-
en: Object.freeze({
|
|
202
|
-
breadcrumb: 'Breadcrumb',
|
|
203
|
-
appearance: 'Appearance',
|
|
204
|
-
appearanceDark: 'Dark',
|
|
205
|
-
appearanceLight: 'Light',
|
|
206
|
-
appearanceSystem: 'System',
|
|
207
|
-
codeCopied: 'Copied',
|
|
208
|
-
codeCopyFailed: 'Could not copy code',
|
|
209
|
-
copyCode: 'Copy code',
|
|
210
|
-
calloutCaution: 'Caution',
|
|
211
|
-
calloutDanger: 'Danger',
|
|
212
|
-
calloutImportant: 'Important',
|
|
213
|
-
calloutNote: 'Note',
|
|
214
|
-
calloutTip: 'Tip',
|
|
215
|
-
calloutWarning: 'Warning',
|
|
216
|
-
closeNavigation: 'Close navigation',
|
|
217
|
-
editSource: 'Edit this page',
|
|
218
|
-
displaySettings: 'Display',
|
|
219
|
-
focusReading: 'Focus reading',
|
|
220
|
-
footnoteBackReference: 'Back to reference {reference}',
|
|
221
|
-
footnotes: 'Footnotes',
|
|
222
|
-
readingWidth: 'Reading width',
|
|
223
|
-
readingWidthNarrow: 'Narrow',
|
|
224
|
-
readingWidthStandard: 'Standard',
|
|
225
|
-
readingWidthWide: 'Wide',
|
|
226
|
-
resetDisplaySettings: 'Reset',
|
|
227
|
-
dismissBanner: 'Dismiss notice',
|
|
228
|
-
built: 'Built',
|
|
229
|
-
images: 'Images',
|
|
230
|
-
imageCarousel: 'image carousel',
|
|
231
|
-
imageInspection: 'Image inspection',
|
|
232
|
-
imageInspectionActualSize: 'Show actual size',
|
|
233
|
-
imageInspectionClose: 'Close image inspection',
|
|
234
|
-
imageInspectionFit: 'Fit image to window',
|
|
235
|
-
inspectImage: 'Inspect image: {description}',
|
|
236
|
-
navigationCollapsedAll: 'All navigation items collapsed.',
|
|
237
|
-
navigationCollapseAll: 'Collapse all',
|
|
238
|
-
navigationControls: 'Navigation tree controls',
|
|
239
|
-
navigationChildren: 'Child pages',
|
|
240
|
-
navigationExpandedAll: 'All navigation items expanded.',
|
|
241
|
-
navigationExpandAll: 'Expand all',
|
|
242
|
-
navigationFilter: 'Filter pages and groups',
|
|
243
|
-
navigationFilterEmpty: 'No matching pages or groups. The current page remains available.',
|
|
244
|
-
navigationFilterMatches: 'Matching navigation items: {count}',
|
|
245
|
-
navigationLocatedCurrent: 'Current page located.',
|
|
246
|
-
navigationLocateCurrent: 'Locate current page',
|
|
247
|
-
navigationMenu: 'Menu',
|
|
248
|
-
nextImage: 'Next image',
|
|
249
|
-
nextPage: 'Next page',
|
|
250
|
-
note: 'Note',
|
|
251
|
-
openInVsCode: 'Open in VS Code',
|
|
252
|
-
notFound: 'Page not found',
|
|
253
|
-
notFoundText: 'The requested page does not exist or may have moved.',
|
|
254
|
-
pageMoved: 'Page moved',
|
|
255
|
-
pageMovedText: 'This address now identifies',
|
|
256
|
-
pageNavigation: 'Page contents',
|
|
257
|
-
pageSequence: 'Page sequence',
|
|
258
|
-
pageSections: 'Sections',
|
|
259
|
-
previousImage: 'Previous image',
|
|
260
|
-
previousPage: 'Previous page',
|
|
261
|
-
returnHome: 'Go to the homepage',
|
|
262
|
-
search: 'Search',
|
|
263
|
-
searchDescription: 'Search the published content on this site.',
|
|
264
|
-
searchLoading: 'Loading search…',
|
|
265
|
-
searchNoScript: 'Search requires JavaScript. Use the page navigation when JavaScript is unavailable.',
|
|
266
|
-
searchUnavailable: 'Search is unavailable. During local work, run norna build:local to create or refresh the search index.',
|
|
267
|
-
siteBanners: 'Site notices',
|
|
268
|
-
siteNavigation: 'Pages',
|
|
269
|
-
skipToContent: 'Skip to content',
|
|
270
|
-
tableColumns: 'Table columns',
|
|
271
|
-
tableNextColumns: 'Show next columns',
|
|
272
|
-
tableOverflowDescription: 'More table columns are available horizontally.',
|
|
273
|
-
tablePreviousColumns: 'Show previous columns',
|
|
274
|
-
}),
|
|
275
|
-
sv: Object.freeze({
|
|
276
|
-
breadcrumb: 'Brödsmulor',
|
|
277
|
-
appearance: 'Utseende',
|
|
278
|
-
appearanceDark: 'Mörkt',
|
|
279
|
-
appearanceLight: 'Ljust',
|
|
280
|
-
appearanceSystem: 'System',
|
|
281
|
-
codeCopied: 'Kopierat',
|
|
282
|
-
codeCopyFailed: 'Kunde inte kopiera koden',
|
|
283
|
-
copyCode: 'Kopiera kod',
|
|
284
|
-
calloutCaution: 'Var försiktig',
|
|
285
|
-
calloutDanger: 'Fara',
|
|
286
|
-
calloutImportant: 'Viktigt',
|
|
287
|
-
calloutNote: 'Notera',
|
|
288
|
-
calloutTip: 'Tips',
|
|
289
|
-
calloutWarning: 'Varning',
|
|
290
|
-
closeNavigation: 'Stäng navigationen',
|
|
291
|
-
editSource: 'Redigera den här sidan',
|
|
292
|
-
displaySettings: 'Visning',
|
|
293
|
-
focusReading: 'Fokuserad läsning',
|
|
294
|
-
footnoteBackReference: 'Tillbaka till referens {reference}',
|
|
295
|
-
footnotes: 'Fotnoter',
|
|
296
|
-
readingWidth: 'Textbredd',
|
|
297
|
-
readingWidthNarrow: 'Smal',
|
|
298
|
-
readingWidthStandard: 'Standard',
|
|
299
|
-
readingWidthWide: 'Bred',
|
|
300
|
-
resetDisplaySettings: 'Återställ',
|
|
301
|
-
dismissBanner: 'Stäng meddelande',
|
|
302
|
-
built: 'Byggd',
|
|
303
|
-
images: 'Bilder',
|
|
304
|
-
imageCarousel: 'bildkarusell',
|
|
305
|
-
imageInspection: 'Bildgranskning',
|
|
306
|
-
imageInspectionActualSize: 'Visa faktisk storlek',
|
|
307
|
-
imageInspectionClose: 'Stäng bildgranskning',
|
|
308
|
-
imageInspectionFit: 'Anpassa bilden till fönstret',
|
|
309
|
-
inspectImage: 'Granska bild: {description}',
|
|
310
|
-
navigationCollapsedAll: 'Alla navigationsposter har fällts ihop.',
|
|
311
|
-
navigationCollapseAll: 'Fäll ihop alla',
|
|
312
|
-
navigationControls: 'Kontroller för navigationsträdet',
|
|
313
|
-
navigationChildren: 'Undersidor',
|
|
314
|
-
navigationExpandedAll: 'Alla navigationsposter har fällts ut.',
|
|
315
|
-
navigationExpandAll: 'Fäll ut alla',
|
|
316
|
-
navigationFilter: 'Filtrera sidor och grupper',
|
|
317
|
-
navigationFilterEmpty: 'Inga sidor eller grupper matchar. Den aktuella sidan är fortfarande tillgänglig.',
|
|
318
|
-
navigationFilterMatches: 'Matchande navigationsposter: {count}',
|
|
319
|
-
navigationLocatedCurrent: 'Den aktuella sidan har hittats.',
|
|
320
|
-
navigationLocateCurrent: 'Hitta aktuell sida',
|
|
321
|
-
navigationMenu: 'Meny',
|
|
322
|
-
nextImage: 'Nästa bild',
|
|
323
|
-
nextPage: 'Nästa sida',
|
|
324
|
-
note: 'Not',
|
|
325
|
-
openInVsCode: 'Öppna i VS Code',
|
|
326
|
-
notFound: 'Sidan hittades inte',
|
|
327
|
-
notFoundText: 'Den begärda sidan finns inte eller kan ha flyttats.',
|
|
328
|
-
pageMoved: 'Sidan har flyttats',
|
|
329
|
-
pageMovedText: 'Den här adressen identifierar nu',
|
|
330
|
-
pageNavigation: 'Sidinnehåll',
|
|
331
|
-
pageSequence: 'Sidföljd',
|
|
332
|
-
pageSections: 'Avsnitt',
|
|
333
|
-
previousImage: 'Föregående bild',
|
|
334
|
-
previousPage: 'Föregående sida',
|
|
335
|
-
returnHome: 'Gå till startsidan',
|
|
336
|
-
search: 'Sök',
|
|
337
|
-
searchDescription: 'Sök i det publicerade innehållet på webbplatsen.',
|
|
338
|
-
searchLoading: 'Laddar sökning…',
|
|
339
|
-
searchNoScript: 'Sökning kräver JavaScript. Använd sidnavigeringen när JavaScript inte är tillgängligt.',
|
|
340
|
-
searchUnavailable: 'Sökningen är inte tillgänglig. Kör norna build:local under lokalt arbete för att skapa eller uppdatera sökindexet.',
|
|
341
|
-
siteBanners: 'Meddelanden',
|
|
342
|
-
siteNavigation: 'Sidor',
|
|
343
|
-
skipToContent: 'Hoppa till innehållet',
|
|
344
|
-
tableColumns: 'Tabellkolumner',
|
|
345
|
-
tableNextColumns: 'Visa nästa kolumner',
|
|
346
|
-
tableOverflowDescription: 'Fler tabellkolumner är tillgängliga i sidled.',
|
|
347
|
-
tablePreviousColumns: 'Visa föregående kolumner',
|
|
348
|
-
}),
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
const readLocale = (config) => {
|
|
352
|
-
const lang = config.language ?? 'en';
|
|
353
|
-
|
|
354
|
-
if (typeof lang !== 'string' || !/^[a-zA-Z]{2,3}(?:-[a-zA-Z0-9]+)*$/.test(lang.trim())) {
|
|
355
|
-
throw new Error(`language must be a valid language tag such as "en" or "sv" in ${siteConfigLabel}.`);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const normalizedLang = lang.trim();
|
|
359
|
-
const languageKey = normalizedLang.toLowerCase().split('-')[0];
|
|
360
|
-
const labels = localeLabels[languageKey];
|
|
361
|
-
|
|
362
|
-
if (!labels) {
|
|
363
|
-
throw new Error(`language "${normalizedLang}" has no built-in Norna UI text. Supported languages: ${Object.keys(localeLabels).join(', ')}.`);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return Object.freeze({
|
|
367
|
-
lang: normalizedLang,
|
|
368
|
-
labels,
|
|
369
|
-
});
|
|
370
|
-
};
|
|
371
|
-
|
|
372
201
|
const rawConfig = assertObject(siteConfig, 'config YAML');
|
|
373
202
|
const rawTheme = assertObject(themeConfig, 'theme YAML', siteThemeLabel);
|
|
374
203
|
const siteUrl = readSiteUrl(rawConfig);
|
|
@@ -609,7 +438,7 @@ export const projectConfig = Object.freeze({
|
|
|
609
438
|
'instant',
|
|
610
439
|
),
|
|
611
440
|
}),
|
|
612
|
-
locale:
|
|
441
|
+
locale: resolveLocale(rawConfig.language, siteConfigLabel),
|
|
613
442
|
});
|
|
614
443
|
|
|
615
444
|
export default projectConfig;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'astro/zod';
|
|
2
2
|
import { localEditorNames } from './edit-source-link.mjs';
|
|
3
3
|
import { imagePresentationNames } from './image-presentation.mjs';
|
|
4
|
+
import { supportedLocaleTagPattern } from './locale-registry.mjs';
|
|
4
5
|
import { navigationModeNames } from './navigation-model.mjs';
|
|
5
6
|
import { presentationPaletteNames } from './presentation-palette-metadata.mjs';
|
|
6
7
|
import { themePresetNames } from './theme-presets.mjs';
|
|
@@ -25,13 +26,6 @@ const themeAppearance = z.object({
|
|
|
25
26
|
(value) => value.default !== undefined,
|
|
26
27
|
'Specify default.',
|
|
27
28
|
).describe('Site-wide initial appearance. The default is system.');
|
|
28
|
-
const readerControls = z.object({
|
|
29
|
-
appearance: z.boolean().optional().describe('Show an Appearance control that lets readers choose System, Light, or Dark.'),
|
|
30
|
-
focusReading: z.boolean().optional().describe('Show a Focus reading control that lets readers hide navigation, breadcrumbs, and the footer. Sites with tree navigation always show this control.'),
|
|
31
|
-
}).strict().refine(
|
|
32
|
-
(value) => value.appearance !== undefined || value.focusReading !== undefined,
|
|
33
|
-
'Specify appearance, focusReading, or both.',
|
|
34
|
-
).describe('Optional controls for the site-wide Display panel.');
|
|
35
29
|
const spacingDensity = z.enum(['compact', 'normal', 'airy']).describe('Coordinated spacing density. Omit this to use the selected preset.');
|
|
36
30
|
const contentSpacing = z.enum(['compact', 'normal', 'spacious']).describe('Vertical spacing between page sections and structured content blocks.');
|
|
37
31
|
const backgroundPattern = z.enum(['uniform', 'alternating', 'accented']).describe('How coordinated backgrounds are assigned to H2 sections. Non-uniform patterns are unavailable with tree navigation.');
|
|
@@ -196,7 +190,7 @@ const themeBlocks = z.object({
|
|
|
196
190
|
'Specify cardList.',
|
|
197
191
|
).describe('Optional site-wide defaults for structured Norna content blocks.');
|
|
198
192
|
const configNavigation = z.object({
|
|
199
|
-
mode: navigationMode.optional().describe('
|
|
193
|
+
mode: navigationMode.optional().describe('How Norna presents the discovered page and heading hierarchy. Omit this to select automatic.'),
|
|
200
194
|
}).strict().describe('Site-wide navigation behavior.');
|
|
201
195
|
const themeSections = z.object({
|
|
202
196
|
backgroundPattern: backgroundPattern.optional().describe('Section background pattern. Alternating and accented create full-width bands with sections or top navigation; tree navigation requires uniform.'),
|
|
@@ -244,7 +238,7 @@ const sitewideFooter = z.object({
|
|
|
244
238
|
|
|
245
239
|
const configShape = {
|
|
246
240
|
url: z.string().url().describe('Absolute public URL for the built site.'),
|
|
247
|
-
language: z.string().regex(
|
|
241
|
+
language: z.string().regex(supportedLocaleTagPattern).optional().describe('Site language tag selecting one complete built-in Norna interface language; the default is en.'),
|
|
248
242
|
editLink: editLink.optional(),
|
|
249
243
|
navigation: configNavigation.optional(),
|
|
250
244
|
search: z.boolean().optional().default(false).describe('Generate a static site search page and Pagefind index. The default is false.'),
|
|
@@ -259,7 +253,6 @@ const siteShape = {
|
|
|
259
253
|
const themeVisualShape = {
|
|
260
254
|
preset: themePreset.optional().describe('Complete visual starting point. Add only the overrides the site actually needs.'),
|
|
261
255
|
appearance: themeAppearance.optional(),
|
|
262
|
-
readerControls: readerControls.optional(),
|
|
263
256
|
corners: cornerTreatment.optional().describe('Site-wide corner treatment. Omit this to use the selected preset.'),
|
|
264
257
|
layout: themeLayout.optional(),
|
|
265
258
|
images: themeImages.optional(),
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { documentationLink } from './documentation-links.mjs';
|
|
2
|
+
import {
|
|
3
|
+
localeDefinitions,
|
|
4
|
+
supportedQualifiedLocaleTagPatternSource,
|
|
5
|
+
} from './locale-registry.mjs';
|
|
2
6
|
import { presentationPaletteNames } from './presentation-palette-metadata.mjs';
|
|
3
7
|
import { getSchemaValueDefinition } from './schema-value-definitions.mjs';
|
|
4
8
|
|
|
@@ -105,20 +109,21 @@ const addValueDescriptions = (schema) => {
|
|
|
105
109
|
const addLanguageSuggestions = (jsonSchema) => {
|
|
106
110
|
const language = jsonSchema.properties?.language;
|
|
107
111
|
if (!language) throw new Error('Generated config schema has no language property.');
|
|
108
|
-
const definition = getSchemaValueDefinition(['en', 'sv']);
|
|
109
112
|
language.default = 'en';
|
|
110
|
-
language.examples = ['en', 'sv', 'en-GB', '
|
|
113
|
+
language.examples = ['en', 'sv', 'es', 'el', 'uk', 'sr-Cyrl', 'en-GB', 'pt-BR'];
|
|
111
114
|
language.oneOf = [
|
|
112
|
-
...
|
|
113
|
-
const:
|
|
114
|
-
title:
|
|
115
|
-
description:
|
|
115
|
+
...localeDefinitions.map(({ tag, name, nativeName, script, requiresScript }) => ({
|
|
116
|
+
const: tag,
|
|
117
|
+
title: nativeName === name ? name : `${nativeName} — ${name}`,
|
|
118
|
+
description: requiresScript
|
|
119
|
+
? `Use Norna's built-in ${name} interface text in the ${script} script.`
|
|
120
|
+
: `Use Norna's built-in ${name} interface text.`,
|
|
116
121
|
})),
|
|
117
122
|
{
|
|
118
123
|
type: 'string',
|
|
119
|
-
pattern:
|
|
120
|
-
title: 'Regional
|
|
121
|
-
description: '
|
|
124
|
+
pattern: supportedQualifiedLocaleTagPatternSource,
|
|
125
|
+
title: 'Regional or script-qualified tag',
|
|
126
|
+
description: 'Add a region to a supported language, such as en-GB, pt-BR, or sr-Cyrl-RS. Norna preserves the complete tag in generated HTML.',
|
|
122
127
|
},
|
|
123
128
|
];
|
|
124
129
|
};
|
|
@@ -156,9 +161,9 @@ const addConfigHelp = (jsonSchema) => {
|
|
|
156
161
|
], ['https://example.com/', 'https://owner.github.io/repository-name/']);
|
|
157
162
|
addHelp(jsonSchema, 'language', [
|
|
158
163
|
yamlExample('language: en-GB'),
|
|
159
|
-
'Sets the
|
|
164
|
+
'Sets the language of the complete site and selects the matching built-in Norna interface text. Regional tags are preserved. The default is `en`; editorial Markdown is not translated.',
|
|
160
165
|
documentationLink('Language reference', 'configuration.md', 'language'),
|
|
161
|
-
], ['en', 'sv', 'en-GB', '
|
|
166
|
+
], ['en', 'sv', 'es', 'el', 'uk', 'sr-Cyrl', 'en-GB', 'pt-BR']);
|
|
162
167
|
addHelp(jsonSchema, 'editLink', [
|
|
163
168
|
yamlExample('editLink:\n localEditor: vscode\n baseUrl: https://github.com/owner/repository/edit/main/'),
|
|
164
169
|
'Links each rendered page to its `content.md` source. A loopback development preview uses the explicitly selected local editor; published output and LAN previews use the optional remote base URL. Specify either destination or both.',
|
|
@@ -188,19 +193,19 @@ const addConfigHelp = (jsonSchema) => {
|
|
|
188
193
|
], ['vscode']);
|
|
189
194
|
addHelp(jsonSchema, 'navigation', [
|
|
190
195
|
yamlExample('navigation:\n mode: automatic'),
|
|
191
|
-
'
|
|
192
|
-
documentationLink('Navigation reference', '
|
|
196
|
+
'Chooses how Norna presents the discovered page and heading hierarchy. Keep `automatic` unless the site deliberately needs to retain one presentation as its structure changes.',
|
|
197
|
+
documentationLink('Navigation setting reference', 'configuration.md', 'navigation'),
|
|
193
198
|
]);
|
|
194
199
|
addHelp(jsonSchema, 'search', [
|
|
195
200
|
yamlExample('search: true'),
|
|
196
|
-
'Generates a localized `/search/` page and a static Pagefind index during each build. Search is off by default
|
|
201
|
+
'Generates a localized `/search/` page and a static Pagefind index during each build. Search is off by default. Only the search page loads the search engine and index; a small navigation script remembers where readers opened it.',
|
|
197
202
|
documentationLink('Search reference', 'configuration.md', 'search'),
|
|
198
203
|
], [true, false]);
|
|
199
204
|
addFieldHelp(
|
|
200
205
|
jsonSchema,
|
|
201
206
|
'navigation.mode',
|
|
202
207
|
'navigation:\n mode: automatic',
|
|
203
|
-
'
|
|
208
|
+
'configuration.md',
|
|
204
209
|
'navigation',
|
|
205
210
|
['automatic', 'sections', 'top', 'tree'],
|
|
206
211
|
);
|
|
@@ -278,7 +283,7 @@ const addThemeHelp = (jsonSchema) => {
|
|
|
278
283
|
], presentationPaletteNames);
|
|
279
284
|
addHelp(jsonSchema, 'appearance', [
|
|
280
285
|
yamlExample('appearance:\n default: system'),
|
|
281
|
-
'Selects the initial Appearance. Omit this setting to follow the visitor\'s system preference.
|
|
286
|
+
'Selects the initial Appearance. The Appearance choice is always available in the site-wide Display panel. Omit this setting to follow the visitor\'s system preference.',
|
|
282
287
|
documentationLink('Appearance', 'theme.md', 'appearance'),
|
|
283
288
|
]);
|
|
284
289
|
addFieldHelp(jsonSchema, 'appearance.default', 'appearance:\n default: system', 'theme.md', 'appearance', ['system', 'light', 'dark']);
|
|
@@ -289,32 +294,6 @@ const addThemeHelp = (jsonSchema) => {
|
|
|
289
294
|
file: 'theme.md',
|
|
290
295
|
anchor: 'appearance',
|
|
291
296
|
})]);
|
|
292
|
-
addHelp(jsonSchema, 'readerControls', [
|
|
293
|
-
yamlExample('readerControls:\n appearance: true\n focusReading: true'),
|
|
294
|
-
'Choose which optional controls readers can use in the site-wide Display panel.',
|
|
295
|
-
'`appearance: true` lets readers choose System, Light, or Dark. `focusReading: true` lets them hide navigation, breadcrumbs, and the footer while reading.',
|
|
296
|
-
'Reading width is always included. Sites with tree navigation always include Focus reading, even when it is not enabled here.',
|
|
297
|
-
documentationLink('Reader Display controls', 'theme.md', 'reader-display-controls'),
|
|
298
|
-
]);
|
|
299
|
-
for (const [propertyPath, example] of [
|
|
300
|
-
['readerControls.appearance', 'readerControls:\n appearance: true'],
|
|
301
|
-
['readerControls.focusReading', 'readerControls:\n focusReading: true'],
|
|
302
|
-
]) {
|
|
303
|
-
addFieldHelp(
|
|
304
|
-
jsonSchema,
|
|
305
|
-
propertyPath,
|
|
306
|
-
example,
|
|
307
|
-
'theme.md',
|
|
308
|
-
'reader-display-controls',
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
addSnippets(jsonSchema, 'readerControls', [schemaSnippet({
|
|
312
|
-
label: 'Configure the Display panel',
|
|
313
|
-
body: 'readerControls:\n appearance: ${1:true}\n focusReading: ${2:true}',
|
|
314
|
-
description: 'Show optional Appearance and Focus reading controls. Reading width is already included, and tree navigation always includes Focus reading.',
|
|
315
|
-
file: 'theme.md',
|
|
316
|
-
anchor: 'reader-display-controls',
|
|
317
|
-
})]);
|
|
318
297
|
addHelp(jsonSchema, 'sections', [
|
|
319
298
|
yamlExample('sections:\n backgroundPattern: alternating'),
|
|
320
299
|
'Chooses whether H2 section backgrounds stay uniform, alternate between two backgrounds or move from base to soft to emphasis and back through soft. Non-uniform patterns are available with sections and top navigation; tree navigation requires uniform.',
|
|
@@ -628,7 +607,7 @@ const addContentHelp = (jsonSchema) => {
|
|
|
628
607
|
const addCategoryHelp = (jsonSchema) => {
|
|
629
608
|
jsonSchema.markdownDescription = [
|
|
630
609
|
yamlExample('label: Guides'),
|
|
631
|
-
'`category.yaml`
|
|
610
|
+
'`category.yaml` groups child pages without editorial content. Its URL opens the first listed direct page, or a generated child list when the first child is a category.',
|
|
632
611
|
documentationLink('Navigation category reference', 'pages.md', 'navigation-categories'),
|
|
633
612
|
].join('\n\n');
|
|
634
613
|
addHelp(jsonSchema, 'label', [
|
|
@@ -23,14 +23,10 @@ export const schemaValueDefinitions = Object.freeze([
|
|
|
23
23
|
smooth: option('Browser smooth', 'Use the browser\'s native smooth scrolling for anchor navigation.'),
|
|
24
24
|
}),
|
|
25
25
|
definition(['automatic', 'sections', 'top', 'tree'], {
|
|
26
|
-
automatic: option('Automatic', 'Choose
|
|
27
|
-
sections: option('Sections', '
|
|
28
|
-
top: option('Top', '
|
|
29
|
-
tree: option('Tree', '
|
|
30
|
-
}),
|
|
31
|
-
definition(['en', 'sv'], {
|
|
32
|
-
en: option('English', 'Use Norna\'s built-in English interface text.'),
|
|
33
|
-
sv: option('Swedish', 'Use Norna\'s built-in Swedish interface text.'),
|
|
26
|
+
automatic: option('Automatic', 'Choose one site-wide navigation presentation from the listed page hierarchy. This is the default.'),
|
|
27
|
+
sections: option('Sections', 'Keep a one-page site title and its H2 sections in sticky page navigation.'),
|
|
28
|
+
top: option('Top', 'Keep top-level pages in the global row and give the current page section navigation when needed.'),
|
|
29
|
+
tree: option('Tree', 'Keep top-level areas global and add a persistent left page tree. Deep branches can add a right H2/H3 contents rail.'),
|
|
34
30
|
}),
|
|
35
31
|
definition(['vscode'], {
|
|
36
32
|
vscode: option('Visual Studio Code', 'Open the current page source in the locally installed Visual Studio Code application.'),
|
|
@@ -62,6 +62,7 @@ const formatDiagnostic = ({ code, fix, label, line, message, offset }) => ({
|
|
|
62
62
|
line,
|
|
63
63
|
message: `${label} line ${line}: ${message}`,
|
|
64
64
|
offset,
|
|
65
|
+
severity: 'error',
|
|
65
66
|
});
|
|
66
67
|
|
|
67
68
|
export const getSemanticCalloutDiagnostics = (tree, options = {}) => {
|
|
@@ -101,7 +102,8 @@ export const getSemanticCalloutDiagnostics = (tree, options = {}) => {
|
|
|
101
102
|
issue = {
|
|
102
103
|
code: 'unknown-semantic-callout-type',
|
|
103
104
|
message: `Unknown semantic callout type "${marker.rawType}".`,
|
|
104
|
-
fix: `Use one of: ${semanticCalloutTypes.join(', ')}.`,
|
|
105
|
+
fix: `Use one of: ${semanticCalloutTypes.join(', ')}. The block will remain a neutral blockquote until then.`,
|
|
106
|
+
severity: 'warning',
|
|
105
107
|
};
|
|
106
108
|
} else if (marker.title) {
|
|
107
109
|
issue = {
|
|
@@ -117,7 +119,7 @@ export const getSemanticCalloutDiagnostics = (tree, options = {}) => {
|
|
|
117
119
|
};
|
|
118
120
|
}
|
|
119
121
|
|
|
120
|
-
if (issue) diagnostics.push(formatDiagnostic({ ...issue, label, line, offset }));
|
|
122
|
+
if (issue) diagnostics.push({ ...formatDiagnostic({ ...issue, label, line, offset }), severity: issue.severity ?? 'error' });
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
for (const child of node.children ?? []) visit(child, nextBlockquoteDepth);
|
|
@@ -67,7 +67,6 @@ const knownNestedFrontmatterKeys = new Set([
|
|
|
67
67
|
'palette',
|
|
68
68
|
'preset',
|
|
69
69
|
'profile',
|
|
70
|
-
'readerControls',
|
|
71
70
|
'readingWidth',
|
|
72
71
|
'rhythm',
|
|
73
72
|
'sectionGap',
|
|
@@ -171,7 +170,10 @@ export const validateFrontmatterStructure = (frontmatter, addIssue, {
|
|
|
171
170
|
fix = fileKind === 'page theme'
|
|
172
171
|
? 'Remove "colorMode:" from this page theme. Set "appearance:" in the root theme.yaml when an override is needed.'
|
|
173
172
|
: 'Replace "colorMode:" with "appearance:".';
|
|
174
|
-
} else if (fileKind === '
|
|
173
|
+
} else if ((fileKind === 'theme' || fileKind === 'page theme') && key === 'readerControls') {
|
|
174
|
+
message = `Frontmatter line ${lineNumber}: Theme setting "readerControls" was removed. Appearance and reading width are always available; Focus reading follows tree navigation.`;
|
|
175
|
+
fix = 'Remove "readerControls:". Use "appearance.default" for the initial Appearance; reading width is always available and tree navigation provides Focus reading.';
|
|
176
|
+
} else if (fileKind === 'page theme' && ['preset', 'appearance', 'corners', 'palette', 'typography'].includes(key)) {
|
|
175
177
|
message = `Frontmatter line ${lineNumber}: page themes may not define site-wide visual identity through "${key}".`;
|
|
176
178
|
fix = `Move "${key}:" to the root theme.yaml. Page themes may set only layout.textWidth, layout.contentSpacing, images, and sections.backgroundPattern.`;
|
|
177
179
|
} else if ((fileKind === 'theme' || fileKind === 'page theme') && ['logo', 'site'].includes(key)) {
|