@janga/norna 0.7.2 → 0.7.3
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 -16
- package/bin/norna-cli.mjs +12 -7
- package/docs/README.md +10 -11
- package/docs/commands.md +8 -8
- package/docs/configuration.md +13 -145
- package/docs/content.md +17 -15
- package/docs/design/command-organization.md +55 -55
- package/docs/design/site-examples-structure.md +2 -2
- package/docs/engine-development.md +5 -5
- package/docs/getting-started.md +19 -26
- package/docs/images-and-metadata.md +1 -1
- package/docs/local-development.md +2 -2
- package/docs/publishing.md +1 -1
- package/docs/routes.md +2 -2
- package/docs/site-structure.md +8 -7
- package/docs/theme.md +149 -7
- package/docs/typography.md +47 -28
- package/examples/dog-gallery/.astro/collections/site.schema.json +802 -0
- package/examples/dog-gallery/.astro/collections/theme.schema.json +714 -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 +49 -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.BFHZm5UG.css +1 -0
- package/examples/dog-gallery/dist/dog-care/index.html +15 -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 +43 -0
- package/examples/dog-gallery/dist/robots.txt +2 -0
- package/examples/dog-gallery/node_modules/.vite/deps/_metadata.json +74 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro-D_GIpJIE.js +434 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro-D_GIpJIE.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
- package/examples/dog-gallery/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/audit-DM9Hkl5B.js +1534 -0
- package/examples/dog-gallery/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/highlight-DnZ1ULOL.js +48 -0
- package/examples/dog-gallery/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/icons-RyebKi45.js +42 -0
- package/examples/dog-gallery/node_modules/.vite/deps/icons-RyebKi45.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/package.json +3 -0
- package/examples/dog-gallery/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
- package/examples/dog-gallery/node_modules/.vite/deps/settings-DaU-gNnK.js +190 -0
- package/examples/dog-gallery/node_modules/.vite/deps/settings-DaU-gNnK.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/toolbar-63PA619H.js +458 -0
- package/examples/dog-gallery/node_modules/.vite/deps/toolbar-63PA619H.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/ui-library--bkcNSYz.js +1016 -0
- package/examples/dog-gallery/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/window-jPkpKVcy.js +32 -0
- package/examples/dog-gallery/node_modules/.vite/deps/window-jPkpKVcy.js.map +1 -0
- package/examples/dog-gallery/node_modules/.vite/deps/xray-BXCHpEJP.js +111 -0
- package/examples/dog-gallery/node_modules/.vite/deps/xray-BXCHpEJP.js.map +1 -0
- package/examples/dog-gallery/site/config.mjs +12 -42
- package/examples/dog-gallery/site/content.md +27 -5
- package/examples/dog-gallery/site/routes/dog-care/route-content.md +17 -3
- package/examples/dog-gallery/site/theme.md +85 -26
- package/fixtures/basic/site/config.mjs +2 -22
- package/fixtures/basic/site/content.md +1 -1
- package/fixtures/basic/site/theme.md +7 -3
- package/package.json +3 -3
- package/scripts/check-config.mjs +3 -3
- package/scripts/deploy-site.mjs +3 -3
- package/scripts/init-site.mjs +10 -8
- package/scripts/lib/frontmatter-yaml.mjs +85 -0
- package/scripts/lib/presentation.mjs +10 -11
- package/scripts/lib/project-config.mjs +91 -45
- package/scripts/lib/site-content.mjs +20 -2
- package/scripts/lib/theme-config.mjs +34 -0
- package/scripts/lib/typography.mjs +100 -20
- package/scripts/show-typography.mjs +58 -154
- package/scripts/sync-content-sections.mjs +6 -6
- package/scripts/test-content-check.mjs +3 -4
- package/scripts/test-engine-commands.mjs +2 -2
- package/scripts/test-package-check.mjs +17 -16
- package/scripts/test-temporary-visibility.mjs +2 -3
- package/src/components/SitePage.astro +2 -3
- package/src/components/SiteSection.astro +39 -5
- package/src/content.config.ts +60 -2
- package/src/layouts/BaseLayout.astro +17 -0
- package/src/styles/global.css +54 -50
- package/starters/basic/README.md +10 -15
- package/starters/basic/package.json +2 -2
- package/starters/basic/site/config.mjs +3 -24
- package/starters/basic/site/content.md +40 -7
- package/starters/basic/site/theme.md +110 -17
- package/starters/project/.github/workflows/deploy.yml +65 -0
- package/starters/project/README.md +72 -0
- package/starters/project/package-lock.json +4296 -0
- package/starters/project/package.json +35 -0
- package/starters/project/site/config.mjs +43 -0
- package/starters/project/site/content.md +88 -0
- package/starters/project/site/public/robots.txt +2 -0
- package/starters/project/site/routes/guide/route-content.md +58 -0
- package/starters/project/site/theme.md +15 -0
|
@@ -7,11 +7,31 @@ export const typographyPresetNames = [
|
|
|
7
7
|
|
|
8
8
|
export const typographyPresets = {
|
|
9
9
|
'quiet-gallery': {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
headings: {
|
|
11
|
+
h1: {
|
|
12
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
13
|
+
size: 'large',
|
|
14
|
+
lineHeight: 1.04,
|
|
15
|
+
spacing: '0.55em',
|
|
16
|
+
},
|
|
17
|
+
h2: {
|
|
18
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
19
|
+
size: 'medium',
|
|
20
|
+
lineHeight: 1.08,
|
|
21
|
+
spacing: '0.65em',
|
|
22
|
+
},
|
|
23
|
+
h3: {
|
|
24
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
25
|
+
size: 'small',
|
|
26
|
+
lineHeight: 1.35,
|
|
27
|
+
spacing: '0.9rem',
|
|
28
|
+
},
|
|
29
|
+
h4: {
|
|
30
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
31
|
+
size: 'medium',
|
|
32
|
+
lineHeight: 1.5,
|
|
33
|
+
spacing: '0.85rem',
|
|
34
|
+
},
|
|
15
35
|
},
|
|
16
36
|
body: {
|
|
17
37
|
align: { desktop: 'left', mobile: 'left' },
|
|
@@ -27,11 +47,31 @@ export const typographyPresets = {
|
|
|
27
47
|
},
|
|
28
48
|
},
|
|
29
49
|
'compact-gallery': {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
headings: {
|
|
51
|
+
h1: {
|
|
52
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
53
|
+
size: 'large',
|
|
54
|
+
lineHeight: 1.04,
|
|
55
|
+
spacing: '0.45em',
|
|
56
|
+
},
|
|
57
|
+
h2: {
|
|
58
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
59
|
+
size: 'medium',
|
|
60
|
+
lineHeight: 1.08,
|
|
61
|
+
spacing: '0.45em',
|
|
62
|
+
},
|
|
63
|
+
h3: {
|
|
64
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
65
|
+
size: 'small',
|
|
66
|
+
lineHeight: 1.3,
|
|
67
|
+
spacing: '0.75rem',
|
|
68
|
+
},
|
|
69
|
+
h4: {
|
|
70
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
71
|
+
size: 'medium',
|
|
72
|
+
lineHeight: 1.42,
|
|
73
|
+
spacing: '0.6rem',
|
|
74
|
+
},
|
|
35
75
|
},
|
|
36
76
|
body: {
|
|
37
77
|
align: { desktop: 'left', mobile: 'left' },
|
|
@@ -47,11 +87,31 @@ export const typographyPresets = {
|
|
|
47
87
|
},
|
|
48
88
|
},
|
|
49
89
|
'text-forward': {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
90
|
+
headings: {
|
|
91
|
+
h1: {
|
|
92
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
93
|
+
size: 'large',
|
|
94
|
+
lineHeight: 1.06,
|
|
95
|
+
spacing: '0.65em',
|
|
96
|
+
},
|
|
97
|
+
h2: {
|
|
98
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
99
|
+
size: 'medium',
|
|
100
|
+
lineHeight: 1.12,
|
|
101
|
+
spacing: '0.8em',
|
|
102
|
+
},
|
|
103
|
+
h3: {
|
|
104
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
105
|
+
size: 'small',
|
|
106
|
+
lineHeight: 1.35,
|
|
107
|
+
spacing: '1rem',
|
|
108
|
+
},
|
|
109
|
+
h4: {
|
|
110
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
111
|
+
size: 'medium',
|
|
112
|
+
lineHeight: 1.55,
|
|
113
|
+
spacing: '0.85rem',
|
|
114
|
+
},
|
|
55
115
|
},
|
|
56
116
|
body: {
|
|
57
117
|
align: { desktop: 'left', mobile: 'left' },
|
|
@@ -67,11 +127,31 @@ export const typographyPresets = {
|
|
|
67
127
|
},
|
|
68
128
|
},
|
|
69
129
|
statement: {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
130
|
+
headings: {
|
|
131
|
+
h1: {
|
|
132
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
133
|
+
size: 'xlarge',
|
|
134
|
+
lineHeight: 1.02,
|
|
135
|
+
spacing: '0.45em',
|
|
136
|
+
},
|
|
137
|
+
h2: {
|
|
138
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
139
|
+
size: 'large',
|
|
140
|
+
lineHeight: 1.04,
|
|
141
|
+
spacing: '0.5em',
|
|
142
|
+
},
|
|
143
|
+
h3: {
|
|
144
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
145
|
+
size: 'medium',
|
|
146
|
+
lineHeight: 1.18,
|
|
147
|
+
spacing: '0.85rem',
|
|
148
|
+
},
|
|
149
|
+
h4: {
|
|
150
|
+
align: { desktop: 'left', mobile: 'left' },
|
|
151
|
+
size: 'medium',
|
|
152
|
+
lineHeight: 1.42,
|
|
153
|
+
spacing: '0.75rem',
|
|
154
|
+
},
|
|
75
155
|
},
|
|
76
156
|
body: {
|
|
77
157
|
align: { desktop: 'left', mobile: 'left' },
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { findMap } from './lib/frontmatter-yaml.mjs';
|
|
2
3
|
import {
|
|
3
4
|
defaultTypography,
|
|
4
5
|
resolveTypographyOverride,
|
|
@@ -23,76 +24,40 @@ import {
|
|
|
23
24
|
|
|
24
25
|
const mode = process.argv[2] ?? 'show';
|
|
25
26
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const typographyValuePaths = [
|
|
28
|
+
['headings', 'h1', 'align', 'desktop'],
|
|
29
|
+
['headings', 'h1', 'align', 'mobile'],
|
|
30
|
+
['headings', 'h1', 'size'],
|
|
31
|
+
['headings', 'h1', 'lineHeight'],
|
|
32
|
+
['headings', 'h1', 'spacing'],
|
|
33
|
+
['headings', 'h2', 'align', 'desktop'],
|
|
34
|
+
['headings', 'h2', 'align', 'mobile'],
|
|
35
|
+
['headings', 'h2', 'size'],
|
|
36
|
+
['headings', 'h2', 'lineHeight'],
|
|
37
|
+
['headings', 'h2', 'spacing'],
|
|
38
|
+
['headings', 'h3', 'align', 'desktop'],
|
|
39
|
+
['headings', 'h3', 'align', 'mobile'],
|
|
40
|
+
['headings', 'h3', 'size'],
|
|
41
|
+
['headings', 'h3', 'lineHeight'],
|
|
42
|
+
['headings', 'h3', 'spacing'],
|
|
43
|
+
['headings', 'h4', 'align', 'desktop'],
|
|
44
|
+
['headings', 'h4', 'align', 'mobile'],
|
|
45
|
+
['headings', 'h4', 'size'],
|
|
46
|
+
['headings', 'h4', 'lineHeight'],
|
|
47
|
+
['headings', 'h4', 'spacing'],
|
|
48
|
+
['body', 'align', 'desktop'],
|
|
49
|
+
['body', 'align', 'mobile'],
|
|
50
|
+
['body', 'size'],
|
|
51
|
+
['body', 'lineHeight'],
|
|
52
|
+
['body', 'paragraphSpacing'],
|
|
53
|
+
['caption', 'align', 'desktop'],
|
|
54
|
+
['caption', 'align', 'mobile'],
|
|
55
|
+
['caption', 'size'],
|
|
56
|
+
['caption', 'lineHeight'],
|
|
57
|
+
['caption', 'spacing'],
|
|
58
|
+
];
|
|
34
59
|
const countIndent = (line) => line.match(/^\s*/)?.[0].length ?? 0;
|
|
35
60
|
|
|
36
|
-
const parseScalar = (rawValue) => {
|
|
37
|
-
const value = rawValue.trim();
|
|
38
|
-
|
|
39
|
-
if (/^-?\d+(?:\.\d+)?$/.test(value)) return Number(value);
|
|
40
|
-
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
41
|
-
return value.slice(1, -1);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return value;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const parseMapping = (lines, startIndex, baseIndent) => {
|
|
48
|
-
const value = {};
|
|
49
|
-
let index = startIndex;
|
|
50
|
-
|
|
51
|
-
while (index < lines.length) {
|
|
52
|
-
const line = lines[index];
|
|
53
|
-
if (!line.trim() || line.trim().startsWith('#')) {
|
|
54
|
-
index += 1;
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const indent = countIndent(line);
|
|
59
|
-
if (indent <= baseIndent) break;
|
|
60
|
-
if (line.trim().startsWith('- ')) break;
|
|
61
|
-
|
|
62
|
-
const match = line.trim().match(/^([a-zA-Z][a-zA-Z0-9-]*):(?:\s+(.*))?$/);
|
|
63
|
-
if (!match) break;
|
|
64
|
-
|
|
65
|
-
const [, key, rawValue] = match;
|
|
66
|
-
if (rawValue === undefined) {
|
|
67
|
-
const parsed = parseMapping(lines, index + 1, indent);
|
|
68
|
-
value[key] = parsed.value;
|
|
69
|
-
index = parsed.nextIndex;
|
|
70
|
-
} else {
|
|
71
|
-
value[key] = parseScalar(rawValue);
|
|
72
|
-
index += 1;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return { value, nextIndex: index };
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const findMap = (lines, label, parentStart = 0, parentEnd = lines.length, requiredIndent = null) => {
|
|
80
|
-
for (let index = parentStart; index < parentEnd; index += 1) {
|
|
81
|
-
const line = lines[index];
|
|
82
|
-
const match = line.match(/^(\s*)([a-zA-Z][a-zA-Z0-9-]*):\s*$/);
|
|
83
|
-
if (!match || match[2] !== label) continue;
|
|
84
|
-
if (requiredIndent !== null && match[1].length !== requiredIndent) continue;
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
index,
|
|
88
|
-
indent: match[1].length,
|
|
89
|
-
...parseMapping(lines, index + 1, match[1].length),
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return null;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
61
|
const isPlainObject = (value) => (
|
|
97
62
|
value !== null &&
|
|
98
63
|
typeof value === 'object' &&
|
|
@@ -129,29 +94,13 @@ const setPath = (value, path, entry) => {
|
|
|
129
94
|
const annotateResolvedValues = (resolved, sources) => {
|
|
130
95
|
const annotated = {};
|
|
131
96
|
|
|
132
|
-
for (const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
value: getPath(resolved.values, path),
|
|
140
|
-
source: source.source,
|
|
141
|
-
...(source.inherited ? { inherited: true } : {}),
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const path = [role, field];
|
|
148
|
-
const source = getPath(sources, path);
|
|
149
|
-
setPath(annotated, path, {
|
|
150
|
-
value: getPath(resolved.values, path),
|
|
151
|
-
source: source.source,
|
|
152
|
-
...(source.inherited ? { inherited: true } : {}),
|
|
153
|
-
});
|
|
154
|
-
}
|
|
97
|
+
for (const path of typographyValuePaths) {
|
|
98
|
+
const source = getPath(sources, path);
|
|
99
|
+
setPath(annotated, path, {
|
|
100
|
+
value: getPath(resolved.values, path),
|
|
101
|
+
source: source.source,
|
|
102
|
+
...(source.inherited ? { inherited: true } : {}),
|
|
103
|
+
});
|
|
155
104
|
}
|
|
156
105
|
|
|
157
106
|
return annotated;
|
|
@@ -160,23 +109,11 @@ const annotateResolvedValues = (resolved, sources) => {
|
|
|
160
109
|
const presetSources = (presetName) => {
|
|
161
110
|
const sources = {};
|
|
162
111
|
|
|
163
|
-
for (const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
source: `preset:${presetName}`,
|
|
169
|
-
inherited: false,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
setPath(sources, [role, field], {
|
|
176
|
-
source: `preset:${presetName}`,
|
|
177
|
-
inherited: false,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
112
|
+
for (const path of typographyValuePaths) {
|
|
113
|
+
setPath(sources, path, {
|
|
114
|
+
source: `preset:${presetName}`,
|
|
115
|
+
inherited: false,
|
|
116
|
+
});
|
|
180
117
|
}
|
|
181
118
|
|
|
182
119
|
return sources;
|
|
@@ -186,28 +123,12 @@ const applyOverrideSources = (sources, typographyConfig, sourceLabel) => {
|
|
|
186
123
|
const overrides = typographyConfig?.overrides;
|
|
187
124
|
if (!overrides) return sources;
|
|
188
125
|
|
|
189
|
-
for (const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
setPath(sources, path, {
|
|
196
|
-
source: `${sourceLabel} override`,
|
|
197
|
-
inherited: false,
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const path = [role, field];
|
|
205
|
-
if (hasPath(overrides, path)) {
|
|
206
|
-
setPath(sources, path, {
|
|
207
|
-
source: `${sourceLabel} override`,
|
|
208
|
-
inherited: false,
|
|
209
|
-
});
|
|
210
|
-
}
|
|
126
|
+
for (const path of typographyValuePaths) {
|
|
127
|
+
if (hasPath(overrides, path)) {
|
|
128
|
+
setPath(sources, path, {
|
|
129
|
+
source: `${sourceLabel} override`,
|
|
130
|
+
inherited: false,
|
|
131
|
+
});
|
|
211
132
|
}
|
|
212
133
|
}
|
|
213
134
|
|
|
@@ -217,25 +138,11 @@ const applyOverrideSources = (sources, typographyConfig, sourceLabel) => {
|
|
|
217
138
|
const inheritedSources = (sources) => {
|
|
218
139
|
const inherited = structuredClone(sources);
|
|
219
140
|
|
|
220
|
-
for (const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
setPath(inherited, path, {
|
|
226
|
-
...getPath(sources, path),
|
|
227
|
-
inherited: true,
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const path = [role, field];
|
|
234
|
-
setPath(inherited, path, {
|
|
235
|
-
...getPath(sources, path),
|
|
236
|
-
inherited: true,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
141
|
+
for (const path of typographyValuePaths) {
|
|
142
|
+
setPath(inherited, path, {
|
|
143
|
+
...getPath(sources, path),
|
|
144
|
+
inherited: true,
|
|
145
|
+
});
|
|
239
146
|
}
|
|
240
147
|
|
|
241
148
|
return inherited;
|
|
@@ -355,10 +262,7 @@ const readThemeTypography = async () => {
|
|
|
355
262
|
}
|
|
356
263
|
|
|
357
264
|
const themeLines = themeFrontmatterBody.split(/\r?\n/);
|
|
358
|
-
const
|
|
359
|
-
const themeTypographyConfig = themePresentation
|
|
360
|
-
? findMap(themeLines, 'typography', themePresentation.index + 1, themePresentation.nextIndex)?.value
|
|
361
|
-
: null;
|
|
265
|
+
const themeTypographyConfig = findMap(themeLines, 'typography', 0, themeLines.length, 0)?.value;
|
|
362
266
|
return resolveAnnotatedTypographyConfig(themeTypographyConfig ?? defaultTypography, siteThemeLabel);
|
|
363
267
|
};
|
|
364
268
|
|
|
@@ -429,5 +333,5 @@ if (mode === 'presets') {
|
|
|
429
333
|
|
|
430
334
|
console.log(toYamlLines(output).join('\n'));
|
|
431
335
|
} else {
|
|
432
|
-
throw new Error('Usage: norna typography
|
|
336
|
+
throw new Error('Usage: norna typography presets|show');
|
|
433
337
|
}
|
|
@@ -59,7 +59,7 @@ const promptForWrite = async () => {
|
|
|
59
59
|
if (!process.stdin.isTTY) return false;
|
|
60
60
|
|
|
61
61
|
const rl = createInterface({ input, output });
|
|
62
|
-
const answer = await rl.question(`This will rewrite Markdown sections in ${siteContentLabel} and move
|
|
62
|
+
const answer = await rl.question(`This will rewrite Markdown sections in ${siteContentLabel} and move image files if needed. Continue? [y/N] `);
|
|
63
63
|
rl.close();
|
|
64
64
|
|
|
65
65
|
return answer.trim().toLowerCase() === 'y';
|
|
@@ -269,7 +269,7 @@ const validateRouteContentFiles = async () => {
|
|
|
269
269
|
if (referencedImages.has(imageName)) {
|
|
270
270
|
const previousSectionId = referencedImages.get(imageName);
|
|
271
271
|
const message = `Image "${imageName}" is referenced more than once, in "${previousSectionId}" and "${contentFile.contentLabel}:${section.id}".`;
|
|
272
|
-
const fix = 'Each image filename can be referenced by only one
|
|
272
|
+
const fix = 'Each image filename can be referenced by only one image row.';
|
|
273
273
|
|
|
274
274
|
addIssue({ severity: 'error', sectionId: previousSectionId, message, fix });
|
|
275
275
|
addIssue({
|
|
@@ -291,7 +291,7 @@ const validateRouteContentFiles = async () => {
|
|
|
291
291
|
sectionId: `${contentFile.contentLabel}:${section.id}`,
|
|
292
292
|
sectionLabel: `${contentFile.contentLabel} [${section.id}]`,
|
|
293
293
|
message: `Image "${imageName}" does not exist anywhere under ${contentFile.imagesLabel}/.`,
|
|
294
|
-
fix: `Add the source image to ${contentFile.imagesLabel}/${section.id}/ or remove the
|
|
294
|
+
fix: `Add the source image to ${contentFile.imagesLabel}/${section.id}/ or remove the image row.`,
|
|
295
295
|
});
|
|
296
296
|
continue;
|
|
297
297
|
}
|
|
@@ -380,7 +380,7 @@ const getReportLines = (title) => {
|
|
|
380
380
|
leftKey.localeCompare(rightKey, 'sv')
|
|
381
381
|
));
|
|
382
382
|
|
|
383
|
-
lines.push('', 'Section
|
|
383
|
+
lines.push('', 'Section And Image Issues');
|
|
384
384
|
|
|
385
385
|
for (const [, group] of orderedSectionGroups) {
|
|
386
386
|
lines.push('', `[${group.label}]`);
|
|
@@ -506,7 +506,7 @@ for (const section of frontmatterSections) {
|
|
|
506
506
|
const message = previousSectionId === section.id
|
|
507
507
|
? `Image "${imageName}" is referenced more than once in this section.`
|
|
508
508
|
: `Image "${imageName}" is referenced more than once, in sections "${previousSectionId}" and "${section.id}".`;
|
|
509
|
-
const fix = 'Each image filename can be referenced by only one
|
|
509
|
+
const fix = 'Each image filename can be referenced by only one image row.';
|
|
510
510
|
|
|
511
511
|
addSectionIssue(previousSectionId, { severity: 'error', message, fix });
|
|
512
512
|
if (previousSectionId !== section.id) {
|
|
@@ -522,7 +522,7 @@ for (const section of frontmatterSections) {
|
|
|
522
522
|
addSectionIssue(section.id, {
|
|
523
523
|
severity: 'error',
|
|
524
524
|
message: `Image "${imageName}" does not exist anywhere under ${siteImagesLabel}/.`,
|
|
525
|
-
fix: `Add the source image to ${siteImagesLabel}/${section.id}/ or remove the
|
|
525
|
+
fix: `Add the source image to ${siteImagesLabel}/${section.id}/ or remove the image row.`,
|
|
526
526
|
});
|
|
527
527
|
continue;
|
|
528
528
|
}
|
|
@@ -43,9 +43,8 @@ const makePngHeader = ({ width, height }) => {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
const defaultTheme = `---
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
preset: quiet-gallery
|
|
46
|
+
typography:
|
|
47
|
+
preset: quiet-gallery
|
|
49
48
|
frame:
|
|
50
49
|
colors: presentation
|
|
51
50
|
---
|
|
@@ -114,7 +113,7 @@ test('content:check groups section issues, global issues, and unreferenced image
|
|
|
114
113
|
|
|
115
114
|
assert.equal(result.status, 1, output);
|
|
116
115
|
assert.match(output, /^Content check failed\./m);
|
|
117
|
-
assert.match(output, /Section
|
|
116
|
+
assert.match(output, /Section And Image Issues\n\n\[min-konst\]\n Errors:/);
|
|
118
117
|
assert.match(output, /Image "vav\.jpeg" is used here but is located in site\/images\/mitt-hem\/\./);
|
|
119
118
|
assert.match(output, /Image "missing\.jpeg" does not exist anywhere under site\/images\/\./);
|
|
120
119
|
assert.match(output, /Image "duplicate\.jpg" is referenced more than once in this section\./);
|
|
@@ -47,12 +47,12 @@ try {
|
|
|
47
47
|
assert.equal(initializedPackageJson.scripts['engine:update'], undefined);
|
|
48
48
|
assert.equal(initializedPackageJson.scripts['engine:version'], undefined);
|
|
49
49
|
|
|
50
|
-
const presetsResult = runCli(['typography
|
|
50
|
+
const presetsResult = runCli(['typography', 'presets']);
|
|
51
51
|
assert.equal(presetsResult.status, 0, presetsResult.stderr || presetsResult.stdout);
|
|
52
52
|
assert.match(presetsResult.stdout, /quiet-gallery:/);
|
|
53
53
|
assert.match(presetsResult.stdout, /text-forward:/);
|
|
54
54
|
|
|
55
|
-
const showResult = runCli(['--site-dir', path.join(initializedSiteRoot, 'site'), 'typography
|
|
55
|
+
const showResult = runCli(['--site-dir', path.join(initializedSiteRoot, 'site'), 'typography', 'show']);
|
|
56
56
|
assert.equal(showResult.status, 0, showResult.stderr || showResult.stdout);
|
|
57
57
|
assert.match(showResult.stdout, /theme:/);
|
|
58
58
|
assert.match(showResult.stdout, /pages:/);
|
|
@@ -181,18 +181,18 @@ try {
|
|
|
181
181
|
await writeFile(
|
|
182
182
|
packageCheckConfigPath,
|
|
183
183
|
packageCheckConfig
|
|
184
|
-
.replace("url: 'https://example.com/'", "url: 'https://example.com/
|
|
185
|
-
.replace("basePath: '/'", "basePath: '/
|
|
184
|
+
.replace("url: 'https://example.com/'", "url: 'https://example.com/site/'")
|
|
185
|
+
.replace("basePath: '/'", "basePath: '/site/'"),
|
|
186
186
|
);
|
|
187
187
|
const packageCheckThemePath = path.join(siteProjectRoot, 'site', 'theme.md');
|
|
188
188
|
const packageCheckTheme = await readFile(packageCheckThemePath, 'utf8');
|
|
189
189
|
await writeFile(
|
|
190
190
|
packageCheckThemePath,
|
|
191
|
-
packageCheckTheme.replace('brand: Example
|
|
191
|
+
packageCheckTheme.replace('brand: Example Site', 'brand: Package Check Brand'),
|
|
192
192
|
);
|
|
193
193
|
await mkdir(path.join(siteProjectRoot, 'site', 'routes', 'about'), { recursive: true });
|
|
194
194
|
await writeFile(path.join(siteProjectRoot, 'site', 'routes', 'about', 'route-content.md'), `---
|
|
195
|
-
title: About the
|
|
195
|
+
title: About the site
|
|
196
196
|
description: Route used by package checks.
|
|
197
197
|
navigation:
|
|
198
198
|
label: About
|
|
@@ -235,7 +235,7 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
235
235
|
);
|
|
236
236
|
await assertFileIncludes(
|
|
237
237
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
238
|
-
'--section-heading-font-size-desktop: clamp(1.
|
|
238
|
+
'--section-heading-font-size-desktop: clamp(1.6rem, 1.22rem + 1.45vw, 2.75rem)',
|
|
239
239
|
);
|
|
240
240
|
await assertFileIncludes(
|
|
241
241
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -247,15 +247,15 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
247
247
|
);
|
|
248
248
|
await assertFileIncludes(
|
|
249
249
|
path.join(siteProjectRoot, 'dist', 'about', 'index.html'),
|
|
250
|
-
'<link rel="canonical" href="https://example.com/
|
|
250
|
+
'<link rel="canonical" href="https://example.com/site/about/">',
|
|
251
251
|
);
|
|
252
252
|
await assertFileIncludes(
|
|
253
253
|
path.join(siteProjectRoot, 'dist', 'about', 'index.html'),
|
|
254
|
-
'href="/
|
|
254
|
+
'href="/site/about/" aria-current="page"',
|
|
255
255
|
);
|
|
256
256
|
await assertFileIncludes(
|
|
257
257
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
258
|
-
'<a class="site-brand" href="/
|
|
258
|
+
'<a class="site-brand" href="/site/">Package Check Brand</a>',
|
|
259
259
|
);
|
|
260
260
|
await assertFileIncludes(
|
|
261
261
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -306,7 +306,7 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
306
306
|
await assertFileExists(path.join(siteProjectRoot, 'dist', 'favicon.ico'));
|
|
307
307
|
await assertFileIncludes(
|
|
308
308
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
309
|
-
'<link rel="icon" sizes="any" href="/
|
|
309
|
+
'<link rel="icon" sizes="any" href="/site/favicon.ico">',
|
|
310
310
|
);
|
|
311
311
|
await assertFileExcludes(
|
|
312
312
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -316,12 +316,12 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
316
316
|
const siteContent = await readFile(siteContentPath, 'utf8');
|
|
317
317
|
const siteThemePath = path.join(siteProjectRoot, 'site', 'theme.md');
|
|
318
318
|
const siteTheme = await readFile(siteThemePath, 'utf8');
|
|
319
|
-
await writeFile(siteThemePath, siteTheme.replace('\n
|
|
319
|
+
await writeFile(siteThemePath, siteTheme.replace('\n preset: quiet-gallery', '\n preset: noisy-gallery'));
|
|
320
320
|
await runExpectFailure(
|
|
321
321
|
npxBin,
|
|
322
322
|
['norna', 'build'],
|
|
323
323
|
{ cwd: siteProjectRoot, env: npmEnv },
|
|
324
|
-
'
|
|
324
|
+
'typography.preset',
|
|
325
325
|
);
|
|
326
326
|
await writeFile(
|
|
327
327
|
siteThemePath,
|
|
@@ -390,11 +390,9 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
390
390
|
{ cwd: siteProjectRoot, env: npmEnv },
|
|
391
391
|
'sections.0.presentation.typography.preset',
|
|
392
392
|
);
|
|
393
|
-
const siteConfigPath = path.join(siteProjectRoot, 'site', 'config.mjs');
|
|
394
|
-
const siteConfig = await readFile(siteConfigPath, 'utf8');
|
|
395
393
|
await writeFile(
|
|
396
|
-
|
|
397
|
-
|
|
394
|
+
siteThemePath,
|
|
395
|
+
siteTheme.replace(
|
|
398
396
|
'fontFamily: "Arial, \'Helvetica Neue\', Helvetica, sans-serif"',
|
|
399
397
|
'fontFamily: "Arial; color: red"',
|
|
400
398
|
),
|
|
@@ -405,9 +403,12 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
405
403
|
{ cwd: siteProjectRoot, env: npmEnv },
|
|
406
404
|
'typography.fontFamily',
|
|
407
405
|
);
|
|
406
|
+
await writeFile(siteThemePath, siteTheme);
|
|
407
|
+
const siteConfigPath = path.join(siteProjectRoot, 'site', 'config.mjs');
|
|
408
|
+
const siteConfig = await readFile(siteConfigPath, 'utf8');
|
|
408
409
|
await writeFile(
|
|
409
410
|
siteConfigPath,
|
|
410
|
-
siteConfig.replace("basePath: '/
|
|
411
|
+
siteConfig.replace("basePath: '/site/'", "basePath: 'site'"),
|
|
411
412
|
);
|
|
412
413
|
await runExpectFailure(
|
|
413
414
|
npxBin,
|
|
@@ -27,10 +27,9 @@ const navigationPages = getNavigationPages(sitePages);
|
|
|
27
27
|
const homePage = sitePages.find((page) => page.isHome) ?? currentPage;
|
|
28
28
|
const themeData = theme?.data ?? {};
|
|
29
29
|
const brandLabel = themeData.navigation?.brand ?? homePage.title;
|
|
30
|
-
const pagePresentation = resolvePagePresentation(themeData
|
|
30
|
+
const pagePresentation = resolvePagePresentation(themeData, entry.data.presentation);
|
|
31
31
|
const frameColors = resolveFrameColors({
|
|
32
|
-
|
|
33
|
-
themeFrame: themeData.frame,
|
|
32
|
+
theme: themeData,
|
|
34
33
|
pagePresentation,
|
|
35
34
|
pageFrame: entry.data.frame,
|
|
36
35
|
});
|