@janga/norna 0.7.1 → 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.
Files changed (168) hide show
  1. package/README.md +32 -18
  2. package/astro.config.mjs +2 -0
  3. package/bin/norna-cli.mjs +175 -0
  4. package/bin/norna.mjs +149 -150
  5. package/docs/README.md +41 -22
  6. package/docs/commands.md +25 -12
  7. package/docs/configuration.md +38 -135
  8. package/docs/content.md +108 -265
  9. package/docs/{command-organization.md → design/command-organization.md} +64 -60
  10. package/docs/{site-examples-structure-note.md → design/site-examples-structure.md} +19 -24
  11. package/docs/engine-development.md +35 -7
  12. package/docs/getting-started.md +55 -26
  13. package/docs/images-and-metadata.md +1 -1
  14. package/docs/local-development.md +14 -1
  15. package/docs/publishing.md +24 -1
  16. package/docs/routes.md +90 -0
  17. package/docs/site-structure.md +18 -10
  18. package/docs/theme.md +292 -0
  19. package/docs/typography.md +144 -0
  20. package/examples/dog-gallery/.astro/collections/site.schema.json +802 -0
  21. package/examples/dog-gallery/.astro/collections/theme.schema.json +714 -0
  22. package/examples/dog-gallery/.astro/content-assets.mjs +4 -0
  23. package/examples/dog-gallery/.astro/content-modules.mjs +1 -0
  24. package/examples/dog-gallery/.astro/content.d.ts +175 -0
  25. package/examples/dog-gallery/.astro/data-store.json +1 -0
  26. package/examples/dog-gallery/.astro/dev-local.json +8 -0
  27. package/examples/dog-gallery/.astro/dev.json +13 -0
  28. package/examples/dog-gallery/.astro/dev.log +49 -0
  29. package/examples/dog-gallery/.astro/settings.json +5 -0
  30. package/examples/dog-gallery/.astro/types.d.ts +2 -0
  31. package/examples/dog-gallery/dist/_astro/GalleryGrid.astro_astro_type_script_index_0_lang.B0kxDyGz.js +1 -0
  32. package/examples/dog-gallery/dist/_astro/SitePage.BFHZm5UG.css +1 -0
  33. package/examples/dog-gallery/dist/dog-care/index.html +15 -0
  34. package/examples/dog-gallery/dist/favicon.svg +7 -0
  35. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1080.webp +0 -0
  36. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1440.webp +0 -0
  37. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1536.webp +0 -0
  38. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-480.webp +0 -0
  39. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-768.webp +0 -0
  40. package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-480.webp +0 -0
  41. package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-768.webp +0 -0
  42. package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-960.webp +0 -0
  43. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1080.webp +0 -0
  44. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1440.webp +0 -0
  45. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1920.webp +0 -0
  46. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-3939.webp +0 -0
  47. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-480.webp +0 -0
  48. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-768.webp +0 -0
  49. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1080.webp +0 -0
  50. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1440.webp +0 -0
  51. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1920.webp +0 -0
  52. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-2400.webp +0 -0
  53. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-480.webp +0 -0
  54. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-768.webp +0 -0
  55. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1080.webp +0 -0
  56. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1440.webp +0 -0
  57. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1600.webp +0 -0
  58. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-480.webp +0 -0
  59. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-768.webp +0 -0
  60. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1080.webp +0 -0
  61. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1440.webp +0 -0
  62. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1920.webp +0 -0
  63. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-2576.webp +0 -0
  64. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-480.webp +0 -0
  65. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-768.webp +0 -0
  66. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1080.webp +0 -0
  67. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1277.webp +0 -0
  68. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-480.webp +0 -0
  69. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-768.webp +0 -0
  70. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1080.webp +0 -0
  71. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1440.webp +0 -0
  72. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1536.webp +0 -0
  73. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-480.webp +0 -0
  74. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-768.webp +0 -0
  75. package/examples/dog-gallery/dist/index.html +43 -0
  76. package/examples/dog-gallery/dist/robots.txt +2 -0
  77. package/examples/dog-gallery/node_modules/.vite/deps/_metadata.json +74 -0
  78. package/examples/dog-gallery/node_modules/.vite/deps/astro-D_GIpJIE.js +434 -0
  79. package/examples/dog-gallery/node_modules/.vite/deps/astro-D_GIpJIE.js.map +1 -0
  80. package/examples/dog-gallery/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
  81. package/examples/dog-gallery/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
  82. package/examples/dog-gallery/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
  83. package/examples/dog-gallery/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
  84. package/examples/dog-gallery/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
  85. package/examples/dog-gallery/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
  86. package/examples/dog-gallery/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
  87. package/examples/dog-gallery/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
  88. package/examples/dog-gallery/node_modules/.vite/deps/audit-DM9Hkl5B.js +1534 -0
  89. package/examples/dog-gallery/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +1 -0
  90. package/examples/dog-gallery/node_modules/.vite/deps/highlight-DnZ1ULOL.js +48 -0
  91. package/examples/dog-gallery/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +1 -0
  92. package/examples/dog-gallery/node_modules/.vite/deps/icons-RyebKi45.js +42 -0
  93. package/examples/dog-gallery/node_modules/.vite/deps/icons-RyebKi45.js.map +1 -0
  94. package/examples/dog-gallery/node_modules/.vite/deps/package.json +3 -0
  95. package/examples/dog-gallery/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
  96. package/examples/dog-gallery/node_modules/.vite/deps/settings-DaU-gNnK.js +190 -0
  97. package/examples/dog-gallery/node_modules/.vite/deps/settings-DaU-gNnK.js.map +1 -0
  98. package/examples/dog-gallery/node_modules/.vite/deps/toolbar-63PA619H.js +458 -0
  99. package/examples/dog-gallery/node_modules/.vite/deps/toolbar-63PA619H.js.map +1 -0
  100. package/examples/dog-gallery/node_modules/.vite/deps/ui-library--bkcNSYz.js +1016 -0
  101. package/examples/dog-gallery/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +1 -0
  102. package/examples/dog-gallery/node_modules/.vite/deps/window-jPkpKVcy.js +32 -0
  103. package/examples/dog-gallery/node_modules/.vite/deps/window-jPkpKVcy.js.map +1 -0
  104. package/examples/dog-gallery/node_modules/.vite/deps/xray-BXCHpEJP.js +111 -0
  105. package/examples/dog-gallery/node_modules/.vite/deps/xray-BXCHpEJP.js.map +1 -0
  106. package/examples/dog-gallery/site/.norna/generated-images.json +226 -0
  107. package/examples/dog-gallery/site/config.mjs +67 -0
  108. package/examples/dog-gallery/site/content.md +168 -0
  109. package/examples/dog-gallery/site/images/black-dogs/black-puppy-meadow.png +0 -0
  110. package/examples/dog-gallery/site/images/black-dogs/photo-of-a-black-dog.jpg +0 -0
  111. package/examples/dog-gallery/site/images/brown-dogs/brown-dog.jpg +0 -0
  112. package/examples/dog-gallery/site/images/brown-dogs/dog-accompanies-master.jpg +0 -0
  113. package/examples/dog-gallery/site/images/golden-dogs/golden-retriever.jpg +0 -0
  114. package/examples/dog-gallery/site/images/golden-dogs/toller-puppy.jpg +0 -0
  115. package/examples/dog-gallery/site/images/white-dogs/white-cute-dog.jpg +0 -0
  116. package/examples/dog-gallery/site/images/white-dogs/white-puppy-garden.png +0 -0
  117. package/examples/dog-gallery/site/public/favicon.svg +7 -0
  118. package/examples/dog-gallery/site/public/robots.txt +2 -0
  119. package/examples/dog-gallery/site/routes/dog-care/route-content.md +49 -0
  120. package/examples/dog-gallery/site/theme.md +114 -0
  121. package/fixtures/basic/site/config.mjs +3 -22
  122. package/fixtures/basic/site/content.md +1 -1
  123. package/fixtures/basic/site/theme.md +7 -3
  124. package/package.json +10 -9
  125. package/scripts/check-config.mjs +4 -3
  126. package/scripts/deploy-site.mjs +3 -3
  127. package/scripts/dev-local.mjs +64 -15
  128. package/scripts/init-site.mjs +11 -9
  129. package/scripts/lib/frontmatter-yaml.mjs +85 -0
  130. package/scripts/lib/presentation.mjs +10 -11
  131. package/scripts/lib/project-config.mjs +113 -45
  132. package/scripts/lib/site-content.mjs +21 -2
  133. package/scripts/lib/site-paths.mjs +18 -3
  134. package/scripts/lib/theme-config.mjs +34 -0
  135. package/scripts/lib/typography.mjs +103 -23
  136. package/scripts/show-typography.mjs +202 -75
  137. package/scripts/sync-content-sections.mjs +6 -6
  138. package/scripts/test-cli-discovery.mjs +124 -0
  139. package/scripts/test-content-check.mjs +3 -4
  140. package/scripts/test-engine-commands.mjs +20 -6
  141. package/scripts/test-navigation.mjs +10 -6
  142. package/scripts/test-package-check.mjs +40 -11
  143. package/scripts/test-temporary-visibility.mjs +2 -3
  144. package/src/components/SiteNavigation.astro +7 -5
  145. package/src/components/SitePage.astro +5 -3
  146. package/src/components/SiteSection.astro +63 -29
  147. package/src/content.config.ts +64 -2
  148. package/src/layouts/BaseLayout.astro +19 -1
  149. package/src/lib/basePath.ts +21 -0
  150. package/src/lib/generatedImages.ts +8 -4
  151. package/src/lib/sectionContent.ts +6 -1
  152. package/src/lib/sitePublicAssets.ts +8 -1
  153. package/src/styles/global.css +59 -55
  154. package/starters/basic/.github/workflows/deploy.yml +3 -3
  155. package/starters/basic/README.md +30 -14
  156. package/starters/basic/package.json +3 -3
  157. package/starters/basic/site/config.mjs +4 -24
  158. package/starters/basic/site/content.md +44 -9
  159. package/starters/basic/site/theme.md +113 -16
  160. package/starters/project/.github/workflows/deploy.yml +65 -0
  161. package/starters/project/README.md +72 -0
  162. package/starters/project/package-lock.json +4296 -0
  163. package/starters/project/package.json +35 -0
  164. package/starters/project/site/config.mjs +43 -0
  165. package/starters/project/site/content.md +88 -0
  166. package/starters/project/site/public/robots.txt +2 -0
  167. package/starters/project/site/routes/guide/route-content.md +58 -0
  168. package/starters/project/site/theme.md +15 -0
package/docs/content.md CHANGED
@@ -1,14 +1,18 @@
1
1
  # Content
2
2
 
3
- `site/content.md` is the editable page file for the homepage of a
4
- `norna` site. Optional route pages use
5
- `site/routes/<route-folder>/route-content.md` with the same page frontmatter and
6
- Markdown section model.
3
+ `site/content.md` is the homepage page file for a `norna` site. It defines the
4
+ page metadata, section order, section ids, image rows, and Markdown text for
5
+ the homepage.
7
6
 
8
- Site-wide visual defaults may live in `site/theme.md`. Technical site
9
- configuration lives in `site/config.mjs`.
7
+ Route pages use the same page and section model in
8
+ `site/routes/<route-folder>/route-content.md`. See [Routes](routes.md) for the
9
+ route-specific rules.
10
10
 
11
- ## Frontmatter Schema
11
+ Site-wide visual defaults belong in [Theme](theme.md). Typography presets and
12
+ overrides are described in [Typography](typography.md). Technical site settings
13
+ belong in [Configuration](configuration.md).
14
+
15
+ ## Page Frontmatter
12
16
 
13
17
  The Astro content schema validates these top-level fields in page files:
14
18
 
@@ -16,54 +20,19 @@ The Astro content schema validates these top-level fields in page files:
16
20
  - `description`: required string. Rendered as the meta description.
17
21
  - `slug`: optional route URL slug. It is ignored on the homepage. If omitted on
18
22
  a route page, the route folder name is used.
19
- - `navigation`: optional page navigation metadata.
20
- - `presentation`: optional page-level presentation overrides.
21
- - `frame`: optional page-level frame color source.
23
+ - `navigation`: optional page navigation metadata. See [Routes](routes.md).
24
+ - `presentation`: optional page-level presentation overrides. See
25
+ [Theme](theme.md) and [Typography](typography.md).
26
+ - `frame`: optional page-level frame color source. See [Theme](theme.md).
22
27
  - `sections`: required non-empty array. Defines section order, ids,
23
- presentation overrides, and gallery rows.
24
-
25
- `navigation` may contain:
26
-
27
- - `include`: optional boolean. Defaults to `true`.
28
- - `label`: optional string. Defaults to `title`.
29
- - `order`: optional integer. Defaults to `0` for the homepage and `100` for
30
- route pages.
31
-
32
- Each `sections[]` item has:
33
-
34
- - `id`: required string matching `^[a-z0-9-]+$`. Used for anchors, navigation,
35
- image directories, and Markdown heading ids.
36
- - `visible`: optional date window that controls whether the section is rendered.
37
- - `presentation`: optional object with `backgroundColor`, `textColor`, and/or
38
- `typography` overrides.
39
- - `gallery`: optional array, defaulting to `[]`.
40
-
41
- Each gallery row has:
42
-
43
- - `image`: required filename matching `^[a-z0-9][a-z0-9.-]*\.(jpe?g|png)$`.
44
- It must be a filename, not a path.
45
- - `alt`: required string.
46
- - `caption`: optional string.
28
+ presentation overrides, and image rows.
47
29
 
48
- ## Routes
49
-
50
- The homepage is always `site/content.md` and builds to `/`.
51
-
52
- Add a first-level route by creating:
53
-
54
- ```text
55
- site/routes/about/route-content.md
56
- ```
57
-
58
- Minimal route page:
30
+ Minimal homepage:
59
31
 
60
32
  ```md
61
33
  ---
62
- title: About
63
- description: About this gallery.
64
- navigation:
65
- label: About
66
- order: 20
34
+ title: My Site
35
+ description: A small Norna site.
67
36
  sections:
68
37
  - id: intro
69
38
  ---
@@ -73,83 +42,89 @@ sections:
73
42
  Text...
74
43
  ```
75
44
 
76
- The example above builds to `/about/`. If `slug` is omitted, the route folder
77
- name is used. If `slug` is set, it must use lowercase letters, numbers, and
78
- hyphens. Keep the route folder and `slug` aligned unless you intentionally need
79
- a different URL.
45
+ ## Sections
46
+
47
+ Each `sections[]` item has:
48
+
49
+ - `id`: required string matching `^[a-z0-9-]+$`. Used for anchors, navigation,
50
+ image directories, and Markdown heading ids.
51
+ - `visible`: optional date window that controls whether the section is rendered.
52
+ - `presentation`: optional section-level visual overrides.
53
+ - `gallery`: optional array, defaulting to `[]`.
80
54
 
81
- Route images live under the route:
55
+ Example:
82
56
 
83
- ```text
84
- site/routes/about/images/intro/image.jpg
57
+ ```yaml
58
+ sections:
59
+ - id: work
60
+ gallery:
61
+ - image: work.jpg
62
+ alt: "A woven artwork on a white wall."
63
+ caption: "Work in progress."
85
64
  ```
86
65
 
87
- Image references in route frontmatter still use only the filename.
66
+ Every frontmatter section must have a matching level 2 Markdown heading with an
67
+ explicit id:
68
+
69
+ ```md
70
+ ## Work {#work}
88
71
 
89
- ### Navigation Scope
72
+ Introductory text.
73
+ ```
90
74
 
91
- Current route navigation is intended for small sites. This guidance may change
92
- as route support matures, but the present model is:
75
+ Keep these values aligned:
93
76
 
94
- - A single-page site should normally use only page navigation between sections.
95
- - A small multi-page site may use site navigation between routes plus page
96
- navigation between sections on the current page.
97
- - If a site needs many routes, deeply nested routes, or several navigation
98
- levels, it has probably outgrown the current sticky-navigation model and may
99
- need a different site structure or navigation system.
77
+ - the frontmatter `sections[].id`
78
+ - the Markdown heading id
79
+ - the source image directory `site/images/<section-id>/`
100
80
 
101
- ## Site Theme
81
+ The visible section navigation label comes from the Markdown heading text, not
82
+ from the frontmatter id.
102
83
 
103
- `site/theme.md` optionally defines site-wide visual defaults. It uses
104
- frontmatter and does not need a Markdown body. If the file is missing, built-in
105
- engine defaults are used.
84
+ ## Image Rows
106
85
 
107
- Starter sites include a marked comment block such as
108
- `norna:start theme-help` / `norna:end theme-help`. The block is
109
- only explorable help text; YAML comments do not affect rendering. The active
110
- configuration is the uncommented YAML below it.
86
+ Each image row can contain a single image:
111
87
 
112
88
  ```yaml
113
- ---
114
- # norna:start theme-help
115
- # Site-wide visual defaults. Remove a value to use the engine default.
116
- # norna:end theme-help
117
-
118
- presentation:
119
- backgroundColor: "#000000"
120
- textColor: "#f7f4ee"
121
- inlineStyles:
122
- highlight:
123
- color: "#ffd84d"
124
- typography:
125
- preset: quiet-gallery
126
- frame:
127
- colors: presentation
128
- ---
89
+ gallery:
90
+ - image: work.jpg
91
+ alt: "A woven artwork on a white wall."
92
+ caption: "Work in progress."
129
93
  ```
130
94
 
131
- `presentation.backgroundColor` and `presentation.textColor` are optional quoted
132
- hex colors in `#rgb`, `#rrggbb`, or `#rrggbbaa` form.
95
+ Image rows support:
133
96
 
134
- `presentation.inlineStyles` defines named inline text styles that can be used
135
- from Markdown. Inline style names must match `^[a-z][a-z0-9-]*$`. Each style
136
- currently supports a required `color` field using the same quoted hex color
137
- format as `textColor`.
97
+ - `image`: required filename matching `^[a-z0-9][a-z0-9.-]*\.(jpe?g|png)$`.
98
+ It must be a filename, not a path.
99
+ - `alt`: required string.
100
+ - `caption`: optional string.
138
101
 
139
- `frame.colors` controls the sticky navigation and footer colors:
102
+ Source image filenames must be unique across the selected page's image tree.
103
+ The homepage reads images from `site/images/<section-id>/`. Route pages read
104
+ images from `site/routes/<route-folder>/images/<section-id>/`.
140
105
 
141
- - `presentation`: use the resolved presentation colors for this level.
142
- - `theme`: use the site theme frame colors. This is useful in page-level
143
- frontmatter.
144
- - explicit colors:
106
+ ## Carousels
107
+
108
+ An image row can contain a carousel instead of a single image:
145
109
 
146
110
  ```yaml
147
- frame:
148
- colors:
149
- backgroundColor: "#111111"
150
- textColor: "#eeeeee"
111
+ gallery:
112
+ - carousel:
113
+ - image: first.jpg
114
+ alt: "First image."
115
+ caption: "First caption."
116
+ - image: second.jpg
117
+ alt: "Second image."
118
+ caption: "Second caption."
151
119
  ```
152
120
 
121
+ Each carousel item has the same `image`, `alt`, and `caption` fields as a
122
+ single image row.
123
+
124
+ `content:check` warns when carousel images have different aspect ratios. Exact
125
+ matching proportions are recommended because mixed proportions can make the
126
+ layout move while the user changes slides.
127
+
153
128
  ## Temporary Sections
154
129
 
155
130
  Use `sections[].visible` for sections that should be rendered only during a
@@ -171,171 +146,37 @@ Both `from` and `until` use `YYYY-MM-DD`. Either value may be omitted, but a
171
146
  `visible` object must contain at least one of them.
172
147
 
173
148
  Hidden sections are omitted from the rendered HTML and sticky navigation. They
174
- remain in `content.md`, and `content:check` still validates their matching
175
- Markdown headings and gallery image references.
149
+ remain in the page file, and `content:check` still validates their matching
150
+ Markdown headings and image references.
176
151
 
177
- The current date is evaluated at dev/build time. Set `NORNA_TODAY` to
178
- preview or test a specific date:
152
+ The current date is evaluated at dev/build time. Set `NORNA_TODAY` to preview
153
+ or test a specific date:
179
154
 
180
155
  ```sh
181
156
  NORNA_TODAY=2026-08-15 npm run norna:build
182
157
  ```
183
158
 
184
- ## Presentation
185
-
186
- Site-wide presentation belongs in `site/theme.md`. Page-level presentation in
187
- `site/content.md` is always an override on top of the theme. Section-specific
188
- presentation belongs under `sections[].presentation`.
189
-
190
- If a page omits `presentation`, it uses the theme presentation unchanged. If a
191
- section omits `presentation`, it uses the resolved page presentation.
192
-
193
- ```yaml
194
- presentation:
195
- typography:
196
- overrides:
197
- body:
198
- paragraphSpacing: 1em
199
- ```
200
-
201
- ### Typography Presets
202
-
203
- Typographic presentation is configured through presets with optional overrides:
204
-
205
- ```yaml
206
- presentation:
207
- typography:
208
- preset: quiet-gallery
209
- overrides:
210
- body:
211
- paragraphSpacing: 0.8em
212
- ```
213
-
214
- Available presets:
215
-
216
- - `quiet-gallery`: the default for image-led art and portfolio sites. Text is
217
- restrained and supports the images without dominating the page.
218
- - `compact-gallery`: tighter typography for many sections, many images, or
219
- short information blocks.
220
- - `text-forward`: more generous body text for pages where longer text carries
221
- more of the experience.
222
- - `statement`: stronger type for introductions, first sections, and short
223
- programmatic statements. Use it sparingly, usually as a section override.
224
-
225
- The normal place to choose a site-wide preset is `site/theme.md`. If theme
226
- typography is omitted, `quiet-gallery` is used. A page-level
227
- `presentation.typography.preset` changes the typographic base for the page. A
228
- section-level `sections[].presentation.typography.preset` changes the
229
- typographic base for that section.
230
-
231
- Use this command to inspect the exact preset values shipped with the installed
232
- engine:
233
-
234
- ```sh
235
- norna typography:presets
236
- ```
237
-
238
- Use this command to inspect the effective values for the selected site after
239
- presets and overrides have been applied:
240
-
241
- ```sh
242
- norna typography:show
243
- ```
244
-
245
- The typographic roles are:
246
-
247
- - `heading`: section headings.
248
- - `body`: Markdown body text inside sections.
249
- - `caption`: gallery captions.
250
-
251
- Allowed alignment values are `left`, `center`, and `right`. Alignment can be
252
- responsive:
253
-
254
- ```yaml
255
- align:
256
- desktop: left
257
- mobile: center
258
- ```
259
-
260
- Allowed size values are `small`, `medium`, `large`, and `xlarge`.
261
- `lineHeight` is a unitless number from `1` through `3`. `spacing` and
262
- `paragraphSpacing` are CSS lengths such as `0`, `0.8em`, `1rem`, or `12px`.
263
-
264
- Supported override fields:
265
-
266
- - `heading.align`, `heading.size`, `heading.lineHeight`, `heading.spacing`
267
- - `body.align`, `body.size`, `body.lineHeight`, `body.paragraphSpacing`
268
- - `caption.align`, `caption.size`, `caption.lineHeight`, `caption.spacing`
269
-
270
- Use `site/theme.md` `presentation.inlineStyles` for named inline text styles
271
- that can be applied inside Markdown:
159
+ ## Markdown Text
272
160
 
273
- ```yaml
274
- presentation:
275
- inlineStyles:
276
- highlight:
277
- color: "#ffd84d"
278
- ```
279
-
280
- Apply an inline style in Markdown with `[text]{.style-name}`:
161
+ Section Markdown starts at the matching level 2 heading and continues until the
162
+ next level 2 heading.
281
163
 
282
164
  ```md
283
- This sentence contains [highlighted text]{.highlight}.
284
- ```
285
-
286
- `content:check` fails if Markdown uses an inline style that is not defined in
287
- `site/theme.md` `presentation.inlineStyles`.
165
+ ## Intro {#intro}
288
166
 
289
- `sections[].presentation` contains only section-specific differences:
167
+ Paragraph text.
290
168
 
291
- ```yaml
292
- sections:
293
- - id: intro
294
- presentation:
295
- backgroundColor: "#161616"
296
- textColor: "#ffffff"
297
- typography:
298
- preset: statement
299
- overrides:
300
- body:
301
- paragraphSpacing: 0.7em
169
+ Another paragraph.
302
170
  ```
303
171
 
304
- If a section sets `typography.preset`, that section starts from that preset. If
305
- a section only sets `typography.overrides`, it keeps the resolved page preset
306
- and changes only the specified values.
307
-
308
- Centered text uses narrower text widths. Left- or right-aligned heading and body
309
- text use the calculated gallery layout width so text edges line up with gallery
310
- images after layout gutters and gallery limits are applied.
311
- Configured section backgrounds render as full-width horizontal bands while the
312
- section content keeps the normal page and gallery widths. The top spacing
313
- before the first heading, the spacing between sections, and the spacing after
314
- the final section are part of the section background. The sticky section
315
- navigation row and footer use the resolved frame colors, not section-specific
316
- presentation.
317
- Configured section text colors apply to section headings, Markdown text,
318
- Markdown subheadings, and gallery captions. Links keep the global accent color.
319
-
320
- ## Markdown Sections
321
-
322
- Every frontmatter section must have a matching level 2 Markdown heading with an
323
- explicit id:
172
+ Inline styles use this Markdown form:
324
173
 
325
174
  ```md
326
- ## Work {#work}
327
-
328
- Introductory text.
175
+ This sentence contains [highlighted text]{.highlight}.
329
176
  ```
330
177
 
331
- Keep these values aligned:
332
-
333
- - the frontmatter `sections[].id`
334
- - the Markdown heading id
335
- - the source image directory `site/images/<section-id>/`
336
-
337
- The visible navigation label comes from the Markdown heading text, not from the
338
- frontmatter id.
178
+ Inline style definitions live in `site/theme.md`. See
179
+ [Theme](theme.md#inline-styles).
339
180
 
340
181
  ## Validation And Sync
341
182
 
@@ -346,26 +187,28 @@ npm run norna:content:check
346
187
  ```
347
188
 
348
189
  This checks section order and heading ids, duplicate image names, missing image
349
- files, misplaced referenced images, duplicate gallery references, invalid image
190
+ files, misplaced referenced images, duplicate image references, invalid image
350
191
  references, unreferenced images, undefined inline styles, and common
351
192
  frontmatter indentation and structure mistakes.
352
193
 
353
194
  Frontmatter uses YAML indentation. Use ordinary spaces, not tabs or
354
195
  non-breaking spaces. `content:check` reports a focused error when indentation is
355
- invalid, when a key is indented under a line that already has a value, or when
356
- a known nested key such as `gallery` appears at the top level:
196
+ invalid, when a key is indented under a line that already has a value, or when a
197
+ known nested key such as `gallery` or section-specific `typography` appears at
198
+ the top level:
357
199
 
358
200
  ```yaml
359
- typography:
360
- preset: quiet-gallery
361
- overrides:
362
- body:
363
- paragraphSpacing: 0.8em
201
+ presentation:
202
+ typography:
203
+ preset: quiet-gallery
204
+ overrides:
205
+ body:
206
+ paragraphSpacing: 0.8em
364
207
  ```
365
208
 
366
- Top-level page frontmatter may contain only `title`, `description`,
367
- `presentation`, `frame`, and `sections`. A `gallery` key belongs under one
368
- `sections[]` item:
209
+ Top-level page frontmatter may contain only `title`, `description`, `slug`,
210
+ `navigation`, `presentation`, `frame`, and `sections`. A `gallery` key belongs
211
+ under one `sections[]` item:
369
212
 
370
213
  ```yaml
371
214
  sections: