@janga/norna 0.7.8 → 0.7.10
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 +1 -1
- package/docs/README.md +18 -11
- package/docs/configuration.md +9 -54
- package/docs/content.md +6 -7
- package/docs/design/norna-diagram-design.md +158 -0
- package/docs/getting-started.md +18 -16
- package/docs/routes.md +7 -6
- package/docs/site-structure.md +4 -2
- package/docs/sitewide-content.md +74 -0
- package/docs/theme.md +61 -128
- package/docs/typography.md +45 -33
- package/examples/001-dog-shelter-single-page/README.md +9 -0
- package/examples/001-dog-shelter-single-page/site/config.mjs +27 -0
- package/examples/001-dog-shelter-single-page/site/content.md +38 -0
- package/examples/001-dog-shelter-single-page/site/images/what-we-do/dog-house.svg +25 -0
- package/examples/001-dog-shelter-single-page/site/images/you-can-help/heart.svg +13 -0
- package/examples/001-dog-shelter-single-page/site/public/favicon.svg +10 -0
- package/examples/001-dog-shelter-single-page/site/public/robots.txt +2 -0
- package/examples/001-dog-shelter-single-page/site/sitewide-content.md +6 -0
- package/examples/001-dog-shelter-single-page/site/theme.md +25 -0
- package/examples/002-dog-shelter-multi-page/README.md +9 -0
- package/examples/002-dog-shelter-multi-page/site/config.mjs +27 -0
- package/examples/002-dog-shelter-multi-page/site/content.md +12 -0
- package/examples/002-dog-shelter-multi-page/site/public/favicon.svg +10 -0
- package/examples/002-dog-shelter-multi-page/site/public/robots.txt +2 -0
- package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rex.svg +19 -0
- package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rover.svg +19 -0
- package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/route-content.md +30 -0
- package/examples/002-dog-shelter-multi-page/site/routes/020-adopt/route-content.md +12 -0
- package/examples/002-dog-shelter-multi-page/site/sitewide-content.md +6 -0
- package/examples/002-dog-shelter-multi-page/site/theme.md +25 -0
- package/examples/dog-gallery/.astro/collections/site.schema.json +776 -0
- package/examples/dog-gallery/.astro/collections/theme.schema.json +672 -0
- package/examples/dog-gallery/.astro/content-assets.mjs +4 -0
- package/examples/dog-gallery/.astro/content-modules.mjs +1 -0
- package/examples/dog-gallery/.astro/content.d.ts +175 -0
- package/examples/dog-gallery/.astro/data-store.json +1 -0
- package/examples/dog-gallery/.astro/dev-local.json +8 -0
- package/examples/dog-gallery/.astro/dev.json +13 -0
- package/examples/dog-gallery/.astro/dev.log +95 -0
- package/examples/dog-gallery/.astro/settings.json +5 -0
- package/examples/dog-gallery/.astro/types.d.ts +2 -0
- package/examples/dog-gallery/dist/_astro/GalleryGrid.astro_astro_type_script_index_0_lang.B0kxDyGz.js +1 -0
- package/examples/dog-gallery/dist/_astro/SitePage.DicGh_5N.css +1 -0
- package/examples/dog-gallery/dist/dog-care/index.html +15 -0
- package/examples/dog-gallery/dist/dog-shelter-logo.svg +14 -0
- package/examples/dog-gallery/dist/favicon.svg +7 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1536.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-960.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1920.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-3939.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1920.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-2400.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1600.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1920.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-2576.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1277.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1536.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-768.webp +0 -0
- package/examples/dog-gallery/dist/index.html +45 -0
- package/examples/dog-gallery/dist/robots.txt +2 -0
- package/examples/dog-gallery/node_modules/.vite/deps/_metadata.json +7 -7
- package/examples/dog-gallery/site/.norna/generated-images.json +8 -8
- package/examples/dog-gallery/site/config.mjs +0 -20
- package/examples/dog-gallery/site/content.md +4 -5
- package/examples/dog-gallery/site/public/logo.svg +14 -0
- package/examples/dog-gallery/site/sitewide-content.md +16 -0
- package/examples/dog-gallery/site/theme.md +13 -24
- package/examples/presentation/README.md +15 -0
- package/examples/presentation/site/.norna/generated-images.json +66 -0
- package/examples/presentation/site/config.mjs +29 -0
- package/examples/presentation/site/content.md +67 -0
- package/examples/presentation/site/public/robots.txt +2 -0
- package/examples/presentation/site/routes/010-presets/route-content.md +63 -0
- package/examples/presentation/site/routes/010-presets/theme.md +4 -0
- package/examples/presentation/site/routes/020-media/images/cards/card-carousel.svg +11 -0
- package/examples/presentation/site/routes/020-media/images/cards/card-stack.svg +9 -0
- package/examples/presentation/site/routes/020-media/images/cards/card-surfaces.svg +8 -0
- package/examples/presentation/site/routes/020-media/images/carousel/carousel-one.svg +8 -0
- package/examples/presentation/site/routes/020-media/images/carousel/carousel-three.svg +13 -0
- package/examples/presentation/site/routes/020-media/images/carousel/carousel-two.svg +8 -0
- package/examples/presentation/site/routes/020-media/images/stack/stack-one.svg +8 -0
- package/examples/presentation/site/routes/020-media/images/stack/stack-two.svg +9 -0
- package/examples/presentation/site/routes/020-media/route-content.md +77 -0
- package/examples/presentation/site/routes/020-media/theme.md +4 -0
- package/examples/presentation/site/routes/030-surfaces/route-content.md +44 -0
- package/examples/presentation/site/routes/030-surfaces/theme.md +7 -0
- package/examples/presentation/site/sitewide-content.md +6 -0
- package/examples/presentation/site/theme.md +43 -0
- package/examples/typography-presets/.astro/collections/routeTheme.schema.json +746 -0
- package/examples/typography-presets/.astro/collections/site.schema.json +59 -0
- package/examples/typography-presets/.astro/collections/sitewide.schema.json +114 -0
- package/examples/typography-presets/.astro/collections/theme.schema.json +770 -0
- package/examples/typography-presets/.astro/content-assets.mjs +4 -0
- package/examples/typography-presets/.astro/content-modules.mjs +1 -0
- package/examples/typography-presets/.astro/content.d.ts +183 -0
- package/examples/typography-presets/.astro/data-store.json +1 -0
- package/examples/typography-presets/.astro/dev-local.json +8 -0
- package/examples/typography-presets/.astro/dev.json +15 -0
- package/examples/typography-presets/.astro/dev.log +45 -0
- package/examples/typography-presets/.astro/settings.json +5 -0
- package/examples/typography-presets/.astro/types.d.ts +2 -0
- package/examples/typography-presets/node_modules/.vite/deps/_metadata.json +80 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro-D_GIpJIE.js +434 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro-D_GIpJIE.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
- package/examples/typography-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js +1534 -0
- package/examples/typography-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/embla-carousel.js +1389 -0
- package/examples/typography-presets/node_modules/.vite/deps/embla-carousel.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js +48 -0
- package/examples/typography-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/icons-RyebKi45.js +42 -0
- package/examples/typography-presets/node_modules/.vite/deps/icons-RyebKi45.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/package.json +3 -0
- package/examples/typography-presets/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
- package/examples/typography-presets/node_modules/.vite/deps/settings-DaU-gNnK.js +190 -0
- package/examples/typography-presets/node_modules/.vite/deps/settings-DaU-gNnK.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/toolbar-63PA619H.js +458 -0
- package/examples/typography-presets/node_modules/.vite/deps/toolbar-63PA619H.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js +1016 -0
- package/examples/typography-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/window-jPkpKVcy.js +32 -0
- package/examples/typography-presets/node_modules/.vite/deps/window-jPkpKVcy.js.map +1 -0
- package/examples/typography-presets/node_modules/.vite/deps/xray-BXCHpEJP.js +111 -0
- package/examples/typography-presets/node_modules/.vite/deps/xray-BXCHpEJP.js.map +1 -0
- package/examples/typography-presets/site/.norna/generated-images.json +290 -0
- package/examples/typography-presets/site/config.mjs +29 -0
- package/examples/typography-presets/site/content.md +16 -0
- package/examples/typography-presets/site/public/robots.txt +2 -0
- package/examples/typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/puppy-portrait.jpg +0 -0
- package/examples/typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/shepherd-portrait.jpg +0 -0
- package/examples/typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/white-puppy.jpg +0 -0
- package/examples/typography-presets/site/routes/010-quiet-gallery/route-content.md +34 -0
- package/examples/typography-presets/site/routes/010-quiet-gallery/theme.md +4 -0
- package/examples/typography-presets/site/routes/020-compact-gallery/images/compact-gallery/black-schnauzer.jpg +0 -0
- package/examples/typography-presets/site/routes/020-compact-gallery/images/compact-gallery/retriever-portrait.jpg +0 -0
- package/examples/typography-presets/site/routes/020-compact-gallery/images/compact-gallery/schnauzer-portrait.jpg +0 -0
- package/examples/typography-presets/site/routes/020-compact-gallery/route-content.md +33 -0
- package/examples/typography-presets/site/routes/020-compact-gallery/theme.md +4 -0
- package/examples/typography-presets/site/routes/030-text-forward/images/text-forward/boxer-portrait.jpg +0 -0
- package/examples/typography-presets/site/routes/030-text-forward/images/text-forward/grass-puppy.jpg +0 -0
- package/examples/typography-presets/site/routes/030-text-forward/images/text-forward/grey-street-dog.jpg +0 -0
- package/examples/typography-presets/site/routes/030-text-forward/route-content.md +34 -0
- package/examples/typography-presets/site/routes/030-text-forward/theme.md +4 -0
- package/examples/typography-presets/site/routes/040-statement/images/statement/black-pedigree.jpg +0 -0
- package/examples/typography-presets/site/routes/040-statement/images/statement/sheepdog-grass.jpg +0 -0
- package/examples/typography-presets/site/routes/040-statement/images/statement/sheepdog-wide.jpg +0 -0
- package/examples/typography-presets/site/routes/040-statement/route-content.md +34 -0
- package/examples/typography-presets/site/routes/040-statement/theme.md +4 -0
- package/examples/typography-presets/site/sitewide-content.md +14 -0
- package/examples/typography-presets/site/theme.md +43 -0
- package/fixtures/basic/site/config.mjs +0 -13
- package/fixtures/basic/site/sitewide-content.md +12 -0
- package/fixtures/basic/site/theme.md +2 -2
- package/fixtures/content-model-v2/site/content.md +2 -5
- package/fixtures/content-model-v2/site/theme.md +1 -3
- package/package.json +3 -2
- package/scripts/check-config.mjs +22 -1
- package/scripts/lib/frontmatter-yaml.mjs +28 -0
- package/scripts/lib/logo-assets.mjs +35 -0
- package/scripts/lib/norna-markdown-blocks.mjs +166 -0
- package/scripts/lib/presentation.mjs +104 -46
- package/scripts/lib/project-config.mjs +67 -105
- package/scripts/lib/site-content.mjs +26 -42
- package/scripts/lib/site-paths.mjs +2 -0
- package/scripts/lib/sitewide-config.mjs +34 -0
- package/scripts/lib/theme-config.mjs +72 -6
- package/scripts/lib/typography.mjs +20 -26
- package/scripts/show-typography.mjs +40 -147
- package/scripts/sync-content-sections.mjs +19 -14
- package/scripts/test-content-check.mjs +76 -14
- package/scripts/test-content-model-v2.mjs +154 -0
- package/scripts/test-engine-commands.mjs +3 -1
- package/scripts/test-package-check.mjs +78 -19
- package/scripts/test-temporary-visibility.mjs +19 -2
- package/src/components/CardList.astro +5 -2
- package/src/components/GalleryGrid.astro +37 -16
- package/src/components/SiteBanners.astro +100 -0
- package/src/components/SiteNavigation.astro +48 -31
- package/src/components/SitePage.astro +55 -13
- package/src/components/SiteSection.astro +194 -36
- package/src/content.config.ts +78 -48
- package/src/layouts/BaseLayout.astro +64 -14
- package/src/lib/routeThemes.ts +61 -0
- package/src/lib/sectionContent.ts +236 -44
- package/src/lib/sitePublicAssets.ts +1 -0
- package/src/styles/global.css +282 -93
- package/starters/basic/.github/workflows/deploy.yml +1 -1
- package/starters/basic/README.md +7 -6
- package/starters/basic/site/config.mjs +0 -13
- package/starters/basic/site/content.md +1 -1
- package/starters/basic/site/sitewide-content.md +14 -0
- package/starters/basic/site/theme.md +13 -24
- package/starters/project/.github/workflows/deploy.yml +1 -1
- package/starters/project/README.md +10 -8
- package/starters/project/site/config.mjs +0 -13
- package/starters/project/site/sitewide-content.md +14 -0
- package/starters/project/site/theme.md +3 -11
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
1
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
import { parseYamlMapping } from './frontmatter-yaml.mjs';
|
|
3
4
|
import {
|
|
4
5
|
splitSiteFile,
|
|
5
6
|
validateFrontmatterIndentation,
|
|
7
|
+
validateRouteThemeFrontmatterStructure,
|
|
6
8
|
validateThemeFrontmatterStructure,
|
|
7
9
|
} from './site-content.mjs';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
import {
|
|
11
|
+
siteRoutesDir,
|
|
12
|
+
siteRoutesLabel,
|
|
13
|
+
siteThemeLabel,
|
|
14
|
+
siteThemePath,
|
|
15
|
+
sitewideContentLabel,
|
|
16
|
+
} from './site-paths.mjs';
|
|
11
17
|
|
|
12
18
|
export const readThemeConfig = async () => {
|
|
13
19
|
const themeFile = await readFile(siteThemePath, 'utf8').catch((error) => {
|
|
14
20
|
if (error?.code === 'ENOENT') {
|
|
15
|
-
|
|
21
|
+
throw new Error(`${siteThemeLabel} is required. Create it before running Norna.`);
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
throw error;
|
|
@@ -30,5 +36,65 @@ export const readThemeConfig = async () => {
|
|
|
30
36
|
].join('\n'));
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
|
|
39
|
+
const config = parseYamlMapping(frontmatterBody);
|
|
40
|
+
if (Object.hasOwn(config, 'navigation')) {
|
|
41
|
+
throw new Error(`${siteThemeLabel} may not define navigation. Brand and logo belong in ${sitewideContentLabel}.`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return config;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const getRouteThemeFiles = async (directory, relativeDirectory = '') => {
|
|
48
|
+
const entries = await readdir(directory, { withFileTypes: true }).catch((error) => {
|
|
49
|
+
if (error?.code === 'ENOENT') return [];
|
|
50
|
+
throw error;
|
|
51
|
+
});
|
|
52
|
+
const files = [];
|
|
53
|
+
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
const relativePath = path.join(relativeDirectory, entry.name);
|
|
56
|
+
const absolutePath = path.join(directory, entry.name);
|
|
57
|
+
if (entry.isDirectory()) {
|
|
58
|
+
files.push(...await getRouteThemeFiles(absolutePath, relativePath));
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (entry.name === 'theme.md') {
|
|
63
|
+
files.push({
|
|
64
|
+
path: absolutePath,
|
|
65
|
+
label: `${siteRoutesLabel}/${relativePath.split(path.sep).join('/')}`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return files;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const validateRouteThemeFiles = async () => {
|
|
74
|
+
const files = await getRouteThemeFiles(siteRoutesDir);
|
|
75
|
+
const configs = [];
|
|
76
|
+
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
const source = await readFile(file.path, 'utf8');
|
|
79
|
+
const { frontmatter, frontmatterBody } = splitSiteFile(source, file.label);
|
|
80
|
+
const issues = [];
|
|
81
|
+
validateFrontmatterIndentation(frontmatter, (issue) => issues.push(issue));
|
|
82
|
+
validateRouteThemeFrontmatterStructure(frontmatter, (issue) => issues.push(issue));
|
|
83
|
+
|
|
84
|
+
if (issues.length > 0) {
|
|
85
|
+
throw new Error([
|
|
86
|
+
`${file.label} has invalid frontmatter.`,
|
|
87
|
+
...issues.map((issue) => `- ${issue.message}`),
|
|
88
|
+
].join('\n'));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const config = parseYamlMapping(frontmatterBody);
|
|
92
|
+
if (Object.hasOwn(config, 'navigation')) {
|
|
93
|
+
throw new Error(`${file.label} may not define navigation. Brand and logo belong in ${sitewideContentLabel}.`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
configs.push({ ...file, config });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return configs;
|
|
34
100
|
};
|
|
@@ -17,27 +17,32 @@ export const typographyPresets = {
|
|
|
17
17
|
h1: {
|
|
18
18
|
align: { desktop: 'left', mobile: 'left' },
|
|
19
19
|
size: 'medium',
|
|
20
|
+
weight: 400,
|
|
20
21
|
lineHeight: 1.04,
|
|
21
22
|
},
|
|
22
23
|
h2: {
|
|
23
24
|
align: { desktop: 'left', mobile: 'left' },
|
|
24
25
|
size: 'medium',
|
|
26
|
+
weight: 400,
|
|
25
27
|
lineHeight: 1.08,
|
|
26
28
|
},
|
|
27
29
|
h3: {
|
|
28
30
|
align: { desktop: 'left', mobile: 'left' },
|
|
29
31
|
size: 'medium',
|
|
32
|
+
weight: 500,
|
|
30
33
|
lineHeight: 1.35,
|
|
31
34
|
},
|
|
32
35
|
h4: {
|
|
33
36
|
align: { desktop: 'left', mobile: 'left' },
|
|
34
37
|
size: 'medium',
|
|
38
|
+
weight: 400,
|
|
35
39
|
lineHeight: 1.5,
|
|
36
40
|
},
|
|
37
41
|
},
|
|
38
42
|
body: {
|
|
39
43
|
align: { desktop: 'left', mobile: 'left' },
|
|
40
44
|
size: 'medium',
|
|
45
|
+
width: 'normal',
|
|
41
46
|
lineHeight: 1.5,
|
|
42
47
|
},
|
|
43
48
|
caption: {
|
|
@@ -51,27 +56,32 @@ export const typographyPresets = {
|
|
|
51
56
|
h1: {
|
|
52
57
|
align: { desktop: 'left', mobile: 'left' },
|
|
53
58
|
size: 'medium',
|
|
59
|
+
weight: 500,
|
|
54
60
|
lineHeight: 1.04,
|
|
55
61
|
},
|
|
56
62
|
h2: {
|
|
57
63
|
align: { desktop: 'left', mobile: 'left' },
|
|
58
64
|
size: 'medium',
|
|
65
|
+
weight: 500,
|
|
59
66
|
lineHeight: 1.08,
|
|
60
67
|
},
|
|
61
68
|
h3: {
|
|
62
69
|
align: { desktop: 'left', mobile: 'left' },
|
|
63
70
|
size: 'medium',
|
|
71
|
+
weight: 600,
|
|
64
72
|
lineHeight: 1.3,
|
|
65
73
|
},
|
|
66
74
|
h4: {
|
|
67
75
|
align: { desktop: 'left', mobile: 'left' },
|
|
68
76
|
size: 'medium',
|
|
77
|
+
weight: 500,
|
|
69
78
|
lineHeight: 1.42,
|
|
70
79
|
},
|
|
71
80
|
},
|
|
72
81
|
body: {
|
|
73
82
|
align: { desktop: 'left', mobile: 'left' },
|
|
74
83
|
size: 'medium',
|
|
84
|
+
width: 'wide',
|
|
75
85
|
lineHeight: 1.42,
|
|
76
86
|
},
|
|
77
87
|
caption: {
|
|
@@ -85,27 +95,32 @@ export const typographyPresets = {
|
|
|
85
95
|
h1: {
|
|
86
96
|
align: { desktop: 'left', mobile: 'left' },
|
|
87
97
|
size: 'medium',
|
|
98
|
+
weight: 500,
|
|
88
99
|
lineHeight: 1.06,
|
|
89
100
|
},
|
|
90
101
|
h2: {
|
|
91
102
|
align: { desktop: 'left', mobile: 'left' },
|
|
92
103
|
size: 'medium',
|
|
104
|
+
weight: 500,
|
|
93
105
|
lineHeight: 1.12,
|
|
94
106
|
},
|
|
95
107
|
h3: {
|
|
96
108
|
align: { desktop: 'left', mobile: 'left' },
|
|
97
109
|
size: 'medium',
|
|
110
|
+
weight: 500,
|
|
98
111
|
lineHeight: 1.35,
|
|
99
112
|
},
|
|
100
113
|
h4: {
|
|
101
114
|
align: { desktop: 'left', mobile: 'left' },
|
|
102
115
|
size: 'medium',
|
|
116
|
+
weight: 400,
|
|
103
117
|
lineHeight: 1.55,
|
|
104
118
|
},
|
|
105
119
|
},
|
|
106
120
|
body: {
|
|
107
121
|
align: { desktop: 'left', mobile: 'left' },
|
|
108
122
|
size: 'medium',
|
|
123
|
+
width: 'narrow',
|
|
109
124
|
lineHeight: 1.62,
|
|
110
125
|
},
|
|
111
126
|
caption: {
|
|
@@ -119,27 +134,32 @@ export const typographyPresets = {
|
|
|
119
134
|
h1: {
|
|
120
135
|
align: { desktop: 'left', mobile: 'left' },
|
|
121
136
|
size: 'medium',
|
|
137
|
+
weight: 600,
|
|
122
138
|
lineHeight: 1.02,
|
|
123
139
|
},
|
|
124
140
|
h2: {
|
|
125
141
|
align: { desktop: 'left', mobile: 'left' },
|
|
126
142
|
size: 'medium',
|
|
143
|
+
weight: 600,
|
|
127
144
|
lineHeight: 1.04,
|
|
128
145
|
},
|
|
129
146
|
h3: {
|
|
130
147
|
align: { desktop: 'left', mobile: 'left' },
|
|
131
148
|
size: 'medium',
|
|
149
|
+
weight: 600,
|
|
132
150
|
lineHeight: 1.18,
|
|
133
151
|
},
|
|
134
152
|
h4: {
|
|
135
153
|
align: { desktop: 'left', mobile: 'left' },
|
|
136
154
|
size: 'medium',
|
|
155
|
+
weight: 500,
|
|
137
156
|
lineHeight: 1.42,
|
|
138
157
|
},
|
|
139
158
|
},
|
|
140
159
|
body: {
|
|
141
160
|
align: { desktop: 'left', mobile: 'left' },
|
|
142
161
|
size: 'medium',
|
|
162
|
+
width: 'narrow',
|
|
143
163
|
lineHeight: 1.42,
|
|
144
164
|
},
|
|
145
165
|
caption: {
|
|
@@ -243,32 +263,6 @@ export const resolveTypographyConfig = (typography = defaultTypography) => {
|
|
|
243
263
|
};
|
|
244
264
|
};
|
|
245
265
|
|
|
246
|
-
export const resolveTypographyOverride = (baseResolved, typographyConfig) => {
|
|
247
|
-
if (typographyConfig?.preset || typographyConfig?.rhythm) {
|
|
248
|
-
return resolveTypographyConfig({
|
|
249
|
-
preset: typographyConfig.preset ?? baseResolved.preset,
|
|
250
|
-
rhythm: typographyConfig.rhythm ?? baseResolved.rhythm,
|
|
251
|
-
overrides: typographyConfig.overrides,
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (typographyConfig?.overrides) {
|
|
256
|
-
return {
|
|
257
|
-
preset: baseResolved.preset,
|
|
258
|
-
rhythm: baseResolved.rhythm,
|
|
259
|
-
values: mergeDeep(baseResolved.values, typographyConfig.overrides),
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return baseResolved;
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
export const resolveSectionTypography = (defaultTypographyConfig, sectionTypographyConfig) => {
|
|
267
|
-
const defaultResolved = resolveTypographyConfig(defaultTypographyConfig);
|
|
268
|
-
|
|
269
|
-
return resolveTypographyOverride(defaultResolved, sectionTypographyConfig);
|
|
270
|
-
};
|
|
271
|
-
|
|
272
266
|
const quoteString = (value) => typeof value === 'string' && !/^[a-z0-9.-]+$/i.test(value)
|
|
273
267
|
? JSON.stringify(value)
|
|
274
268
|
: value;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
import { findMap } from './lib/frontmatter-yaml.mjs';
|
|
3
4
|
import {
|
|
4
5
|
defaultTypography,
|
|
5
|
-
resolveTypographyOverride,
|
|
6
6
|
resolveTypographyConfig,
|
|
7
7
|
toYamlLines,
|
|
8
8
|
typographyPresets,
|
|
@@ -15,11 +15,13 @@ import {
|
|
|
15
15
|
splitSiteFile,
|
|
16
16
|
validateContentFrontmatterStructure,
|
|
17
17
|
validateFrontmatterIndentation,
|
|
18
|
+
validateRouteThemeFrontmatterStructure,
|
|
18
19
|
validateThemeFrontmatterStructure,
|
|
19
20
|
} from './lib/site-content.mjs';
|
|
20
21
|
import {
|
|
21
22
|
siteContentLabel,
|
|
22
23
|
siteContentPath,
|
|
24
|
+
siteRoutesDir,
|
|
23
25
|
siteThemeLabel,
|
|
24
26
|
siteThemePath,
|
|
25
27
|
} from './lib/site-paths.mjs';
|
|
@@ -30,30 +32,35 @@ const typographyValuePaths = [
|
|
|
30
32
|
['headings', 'h1', 'align', 'desktop'],
|
|
31
33
|
['headings', 'h1', 'align', 'mobile'],
|
|
32
34
|
['headings', 'h1', 'size'],
|
|
35
|
+
['headings', 'h1', 'weight'],
|
|
33
36
|
['headings', 'h1', 'lineHeight'],
|
|
34
37
|
['headings', 'h1', 'spacingBefore'],
|
|
35
38
|
['headings', 'h1', 'spacingAfter'],
|
|
36
39
|
['headings', 'h2', 'align', 'desktop'],
|
|
37
40
|
['headings', 'h2', 'align', 'mobile'],
|
|
38
41
|
['headings', 'h2', 'size'],
|
|
42
|
+
['headings', 'h2', 'weight'],
|
|
39
43
|
['headings', 'h2', 'lineHeight'],
|
|
40
44
|
['headings', 'h2', 'spacingBefore'],
|
|
41
45
|
['headings', 'h2', 'spacingAfter'],
|
|
42
46
|
['headings', 'h3', 'align', 'desktop'],
|
|
43
47
|
['headings', 'h3', 'align', 'mobile'],
|
|
44
48
|
['headings', 'h3', 'size'],
|
|
49
|
+
['headings', 'h3', 'weight'],
|
|
45
50
|
['headings', 'h3', 'lineHeight'],
|
|
46
51
|
['headings', 'h3', 'spacingBefore'],
|
|
47
52
|
['headings', 'h3', 'spacingAfter'],
|
|
48
53
|
['headings', 'h4', 'align', 'desktop'],
|
|
49
54
|
['headings', 'h4', 'align', 'mobile'],
|
|
50
55
|
['headings', 'h4', 'size'],
|
|
56
|
+
['headings', 'h4', 'weight'],
|
|
51
57
|
['headings', 'h4', 'lineHeight'],
|
|
52
58
|
['headings', 'h4', 'spacingBefore'],
|
|
53
59
|
['headings', 'h4', 'spacingAfter'],
|
|
54
60
|
['body', 'align', 'desktop'],
|
|
55
61
|
['body', 'align', 'mobile'],
|
|
56
62
|
['body', 'size'],
|
|
63
|
+
['body', 'width'],
|
|
57
64
|
['body', 'lineHeight'],
|
|
58
65
|
['body', 'paragraphSpacing'],
|
|
59
66
|
['caption', 'align', 'desktop'],
|
|
@@ -74,8 +81,6 @@ const rhythmValuePaths = new Set([
|
|
|
74
81
|
'body.paragraphSpacing',
|
|
75
82
|
'caption.spacingBefore',
|
|
76
83
|
]);
|
|
77
|
-
const countIndent = (line) => line.match(/^\s*/)?.[0].length ?? 0;
|
|
78
|
-
|
|
79
84
|
const isPlainObject = (value) => (
|
|
80
85
|
value !== null &&
|
|
81
86
|
typeof value === 'object' &&
|
|
@@ -156,19 +161,6 @@ const applyOverrideSources = (sources, typographyConfig, sourceLabel) => {
|
|
|
156
161
|
return sources;
|
|
157
162
|
};
|
|
158
163
|
|
|
159
|
-
const inheritedSources = (sources) => {
|
|
160
|
-
const inherited = structuredClone(sources);
|
|
161
|
-
|
|
162
|
-
for (const path of typographyValuePaths) {
|
|
163
|
-
setPath(inherited, path, {
|
|
164
|
-
...getPath(sources, path),
|
|
165
|
-
inherited: true,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return inherited;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
164
|
const resolveAnnotatedTypographyConfig = (typographyConfig, sourceLabel) => {
|
|
173
165
|
const resolved = resolveTypographyConfig(typographyConfig ?? defaultTypography);
|
|
174
166
|
const sources = applyOverrideSources(
|
|
@@ -193,126 +185,14 @@ const resolveAnnotatedTypographyConfig = (typographyConfig, sourceLabel) => {
|
|
|
193
185
|
};
|
|
194
186
|
};
|
|
195
187
|
|
|
196
|
-
const resolveAnnotatedTypographyOverride = (baseAnnotated, typographyConfig, sourceLabel) => {
|
|
197
|
-
if (typographyConfig?.preset || typographyConfig?.rhythm) {
|
|
198
|
-
const resolvedConfig = {
|
|
199
|
-
preset: typographyConfig.preset ?? baseAnnotated.resolved.preset,
|
|
200
|
-
rhythm: typographyConfig.rhythm ?? baseAnnotated.resolved.rhythm,
|
|
201
|
-
overrides: typographyConfig.overrides,
|
|
202
|
-
};
|
|
203
|
-
const resolved = resolveTypographyConfig(resolvedConfig);
|
|
204
|
-
const sources = applyOverrideSources(
|
|
205
|
-
defaultSources(resolved.preset, resolved.rhythm),
|
|
206
|
-
typographyConfig,
|
|
207
|
-
sourceLabel,
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
return {
|
|
211
|
-
preset: {
|
|
212
|
-
value: resolved.preset,
|
|
213
|
-
source: typographyConfig.preset ? sourceLabel : baseAnnotated.preset.source,
|
|
214
|
-
...(typographyConfig.preset ? {} : { inherited: true }),
|
|
215
|
-
},
|
|
216
|
-
rhythm: {
|
|
217
|
-
value: resolved.rhythm,
|
|
218
|
-
source: typographyConfig.rhythm ? sourceLabel : baseAnnotated.rhythm.source,
|
|
219
|
-
...(typographyConfig.rhythm ? {} : { inherited: true }),
|
|
220
|
-
},
|
|
221
|
-
resolved,
|
|
222
|
-
sources,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (typographyConfig?.overrides) {
|
|
227
|
-
const resolved = resolveTypographyOverride(baseAnnotated.resolved, typographyConfig);
|
|
228
|
-
const sources = applyOverrideSources(
|
|
229
|
-
inheritedSources(baseAnnotated.sources),
|
|
230
|
-
typographyConfig,
|
|
231
|
-
sourceLabel,
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
return {
|
|
235
|
-
preset: {
|
|
236
|
-
value: resolved.preset,
|
|
237
|
-
source: baseAnnotated.preset.source,
|
|
238
|
-
inherited: true,
|
|
239
|
-
},
|
|
240
|
-
rhythm: {
|
|
241
|
-
value: resolved.rhythm,
|
|
242
|
-
source: baseAnnotated.rhythm.source,
|
|
243
|
-
inherited: true,
|
|
244
|
-
},
|
|
245
|
-
resolved,
|
|
246
|
-
sources,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return {
|
|
251
|
-
preset: {
|
|
252
|
-
value: baseAnnotated.resolved.preset,
|
|
253
|
-
source: baseAnnotated.preset.source,
|
|
254
|
-
inherited: true,
|
|
255
|
-
},
|
|
256
|
-
rhythm: {
|
|
257
|
-
value: baseAnnotated.resolved.rhythm,
|
|
258
|
-
source: baseAnnotated.rhythm.source,
|
|
259
|
-
inherited: true,
|
|
260
|
-
},
|
|
261
|
-
resolved: baseAnnotated.resolved,
|
|
262
|
-
sources: inheritedSources(baseAnnotated.sources),
|
|
263
|
-
};
|
|
264
|
-
};
|
|
265
|
-
|
|
266
188
|
const formatAnnotatedTypography = (annotated) => ({
|
|
267
189
|
preset: annotated.preset,
|
|
268
190
|
rhythm: annotated.rhythm,
|
|
269
191
|
resolved: annotateResolvedValues(annotated.resolved, annotated.sources),
|
|
270
192
|
});
|
|
271
193
|
|
|
272
|
-
const getSectionMetadataBlocks = (lines) => {
|
|
273
|
-
const sectionsMap = findMap(lines, 'sections');
|
|
274
|
-
if (!sectionsMap) return new Map();
|
|
275
|
-
|
|
276
|
-
const sections = new Map();
|
|
277
|
-
let current = null;
|
|
278
|
-
|
|
279
|
-
for (let index = sectionsMap.index + 1; index < lines.length; index += 1) {
|
|
280
|
-
const line = lines[index];
|
|
281
|
-
if (!line.trim()) continue;
|
|
282
|
-
|
|
283
|
-
const indent = countIndent(line);
|
|
284
|
-
if (indent <= sectionsMap.indent) break;
|
|
285
|
-
|
|
286
|
-
const sectionMatch = line.match(/^\s{2}([a-z0-9-]+):(?:\s+.*)?\s*$/);
|
|
287
|
-
if (sectionMatch) {
|
|
288
|
-
if (current) current.end = index;
|
|
289
|
-
current = { id: sectionMatch[1], start: index, end: lines.length };
|
|
290
|
-
sections.set(current.id, current);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const sectionList = Array.from(sections.values());
|
|
295
|
-
const finalSection = sectionList.at(-1);
|
|
296
|
-
if (finalSection) {
|
|
297
|
-
const afterSections = lines.findIndex((line, index) => (
|
|
298
|
-
index > finalSection.start &&
|
|
299
|
-
line.trim() &&
|
|
300
|
-
countIndent(line) <= sectionsMap.indent
|
|
301
|
-
));
|
|
302
|
-
finalSection.end = afterSections === -1 ? lines.length : afterSections;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return sections;
|
|
306
|
-
};
|
|
307
|
-
|
|
308
194
|
const readThemeTypography = async () => {
|
|
309
|
-
const themeFile = await readFile(siteThemePath, 'utf8')
|
|
310
|
-
if (error?.code === 'ENOENT') {
|
|
311
|
-
return '---\n---\n';
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
throw error;
|
|
315
|
-
});
|
|
195
|
+
const themeFile = await readFile(siteThemePath, 'utf8');
|
|
316
196
|
const { frontmatter: themeFrontmatter, frontmatterBody: themeFrontmatterBody } = splitSiteFile(themeFile, siteThemeLabel);
|
|
317
197
|
const indentationIssues = [];
|
|
318
198
|
validateFrontmatterIndentation(themeFrontmatter, (issue) => indentationIssues.push(issue));
|
|
@@ -329,8 +209,35 @@ const readThemeTypography = async () => {
|
|
|
329
209
|
return resolveAnnotatedTypographyConfig(themeTypographyConfig ?? defaultTypography, siteThemeLabel);
|
|
330
210
|
};
|
|
331
211
|
|
|
332
|
-
const
|
|
333
|
-
|
|
212
|
+
const readRouteThemeTypography = async (contentFile, themeTypography) => {
|
|
213
|
+
if (contentFile.isHome) return themeTypography;
|
|
214
|
+
|
|
215
|
+
const routeThemePath = path.join(siteRoutesDir, contentFile.routeDirectory, 'theme.md');
|
|
216
|
+
const routeThemeLabel = `${contentFile.contentLabel.replace(/\/route-content\.md$/, '')}/theme.md`;
|
|
217
|
+
const routeThemeFile = await readFile(routeThemePath, 'utf8').catch((error) => {
|
|
218
|
+
if (error?.code === 'ENOENT') return null;
|
|
219
|
+
throw error;
|
|
220
|
+
});
|
|
221
|
+
if (!routeThemeFile) return themeTypography;
|
|
222
|
+
|
|
223
|
+
const { frontmatter, frontmatterBody } = splitSiteFile(routeThemeFile, routeThemeLabel);
|
|
224
|
+
const indentationIssues = [];
|
|
225
|
+
validateFrontmatterIndentation(frontmatter, (issue) => indentationIssues.push(issue));
|
|
226
|
+
validateRouteThemeFrontmatterStructure(frontmatter, (issue) => indentationIssues.push(issue));
|
|
227
|
+
if (indentationIssues.length > 0) {
|
|
228
|
+
throw new Error([
|
|
229
|
+
`Cannot inspect typography because ${routeThemeLabel} has invalid frontmatter.`,
|
|
230
|
+
...indentationIssues.map((issue) => `- ${issue.message}`),
|
|
231
|
+
].join('\n'));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const lines = frontmatterBody.split(/\r?\n/);
|
|
235
|
+
const typographyConfig = findMap(lines, 'typography', 0, lines.length, 0)?.value;
|
|
236
|
+
return resolveAnnotatedTypographyConfig(typographyConfig ?? defaultTypography, routeThemeLabel);
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const readPageTypography = async (contentFile, siteThemeTypography) => {
|
|
240
|
+
const { frontmatter, body } = await readSiteFile(contentFile.contentPath, contentFile.contentLabel);
|
|
334
241
|
const indentationIssues = [];
|
|
335
242
|
validateFrontmatterIndentation(frontmatter, (issue) => indentationIssues.push(issue));
|
|
336
243
|
validateContentFrontmatterStructure(frontmatter, (issue) => indentationIssues.push(issue));
|
|
@@ -341,27 +248,13 @@ const readPageTypography = async (contentFile, themeTypography) => {
|
|
|
341
248
|
].join('\n'));
|
|
342
249
|
}
|
|
343
250
|
|
|
344
|
-
const
|
|
345
|
-
const pagePresentation = findMap(lines, 'presentation', 0, lines.length, 0);
|
|
346
|
-
const pageTypographyConfig = pagePresentation
|
|
347
|
-
? findMap(lines, 'typography', pagePresentation.index + 1, pagePresentation.nextIndex)?.value
|
|
348
|
-
: null;
|
|
349
|
-
const pageTypography = resolveAnnotatedTypographyOverride(themeTypography, pageTypographyConfig ?? undefined, contentFile.contentLabel);
|
|
350
|
-
const sectionMetadataBlocks = getSectionMetadataBlocks(lines);
|
|
251
|
+
const pageTypography = await readRouteThemeTypography(contentFile, siteThemeTypography);
|
|
351
252
|
const sections = getBodySections(body).sections
|
|
352
253
|
.filter((section) => section.id)
|
|
353
254
|
.map((section) => {
|
|
354
|
-
const metadata = sectionMetadataBlocks.get(section.id);
|
|
355
|
-
const presentation = metadata
|
|
356
|
-
? findMap(lines, 'presentation', metadata.start + 1, metadata.end)
|
|
357
|
-
: null;
|
|
358
|
-
const typography = presentation
|
|
359
|
-
? findMap(lines, 'typography', presentation.index + 1, presentation.nextIndex)?.value
|
|
360
|
-
: null;
|
|
361
|
-
|
|
362
255
|
return {
|
|
363
256
|
id: section.id,
|
|
364
|
-
typography:
|
|
257
|
+
typography: pageTypography,
|
|
365
258
|
};
|
|
366
259
|
});
|
|
367
260
|
|
|
@@ -5,6 +5,7 @@ import { stdin as input, stdout as output } from 'node:process';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
7
|
import {
|
|
8
|
+
extractInlineNoteDiagnostics,
|
|
8
9
|
extractMarkdownImageReferences,
|
|
9
10
|
extractNornaMarkdownBlockDiagnostics,
|
|
10
11
|
getNornaBlockImageReferences,
|
|
@@ -12,10 +13,9 @@ import {
|
|
|
12
13
|
import {
|
|
13
14
|
getBodySections,
|
|
14
15
|
getContentFiles,
|
|
15
|
-
getFrontmatterInlineStyleNames,
|
|
16
16
|
getFrontmatterSections,
|
|
17
17
|
getImageCandidatesByName,
|
|
18
|
-
|
|
18
|
+
getDeprecatedInlineStyleReferences,
|
|
19
19
|
readSiteFile,
|
|
20
20
|
readThemeFile,
|
|
21
21
|
toPosixPath,
|
|
@@ -400,10 +400,6 @@ try {
|
|
|
400
400
|
}
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
const themeInlineStyleNames = themeFrontmatter
|
|
404
|
-
? getFrontmatterInlineStyleNames(themeFrontmatter)
|
|
405
|
-
: new Set();
|
|
406
|
-
|
|
407
403
|
const contentFiles = await getContentFiles();
|
|
408
404
|
const allImageFiles = [];
|
|
409
405
|
const contentFileContexts = [];
|
|
@@ -462,6 +458,17 @@ for (const contentFile of contentFiles) {
|
|
|
462
458
|
});
|
|
463
459
|
blockResultsBySectionId.set(section.id, blockResults);
|
|
464
460
|
|
|
461
|
+
const inlineNoteResults = extractInlineNoteDiagnostics(section.text, {
|
|
462
|
+
label: contentFile.contentLabel,
|
|
463
|
+
lineOffset: bodyLineOffset + section.line - 1,
|
|
464
|
+
});
|
|
465
|
+
for (const error of inlineNoteResults.errors) {
|
|
466
|
+
addSectionIssue(contentFile, section, {
|
|
467
|
+
severity: 'error',
|
|
468
|
+
message: error.message,
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
465
472
|
for (const reference of getNornaBlockImageReferences(blockResults.blocks)) {
|
|
466
473
|
const expectedPath = getExpectedImagePath(contentFile, section.id, reference.image);
|
|
467
474
|
addExpectedReference(globalExpectedReferencesByPath, expectedPath, { contentFile, section, reference });
|
|
@@ -498,14 +505,12 @@ for (const context of contentFileContexts) {
|
|
|
498
505
|
}
|
|
499
506
|
}
|
|
500
507
|
|
|
501
|
-
for (const styleName of new Set(
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
});
|
|
508
|
-
}
|
|
508
|
+
for (const styleName of new Set(getDeprecatedInlineStyleReferences(body))) {
|
|
509
|
+
addContentIssue(contentFile, {
|
|
510
|
+
severity: 'error',
|
|
511
|
+
message: `Inline color style ".${styleName}" is no longer supported in ${contentFile.contentLabel}.`,
|
|
512
|
+
fix: 'Use standard Markdown emphasis, a blockquote, or a semantic Norna block instead of color syntax.',
|
|
513
|
+
});
|
|
509
514
|
}
|
|
510
515
|
|
|
511
516
|
for (const section of sections) {
|