@janga/norna 0.7.15 → 0.7.17

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 (200) hide show
  1. package/README.md +6 -6
  2. package/astro.config.mjs +35 -3
  3. package/docs/README.md +10 -10
  4. package/docs/commands.md +2 -2
  5. package/docs/content.md +82 -102
  6. package/docs/design/navigation-and-theme-plan.md +115 -0
  7. package/docs/design/norna-diagram-design.md +9 -9
  8. package/docs/design/site-examples-structure.md +9 -9
  9. package/docs/engine-development.md +9 -9
  10. package/docs/getting-started.md +20 -15
  11. package/docs/images-and-metadata.md +10 -9
  12. package/docs/pages.md +134 -0
  13. package/docs/public-files.md +49 -36
  14. package/docs/publishing.md +19 -3
  15. package/docs/site-files.md +29 -28
  16. package/docs/sitewide-content.md +20 -36
  17. package/docs/theme.md +20 -20
  18. package/docs/typography.md +10 -10
  19. package/examples/README.md +2 -2
  20. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/site.schema.json +17 -41
  21. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/sitewide.schema.json +26 -67
  22. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/theme.schema.json +185 -88
  23. package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +1 -1
  24. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev-local.json +4 -4
  25. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.json +5 -5
  26. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +33 -23
  27. package/examples/complete-sites/dog-shelter-multi-page/README.md +1 -1
  28. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/_metadata.json +8 -8
  29. package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +20 -20
  30. package/examples/complete-sites/dog-shelter-multi-page/site/content.md +3 -4
  31. package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/010-dogs/content.md +3 -4
  32. package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/020-adopt/content.md +3 -4
  33. package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.yaml +2 -4
  34. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/site.schema.json +17 -41
  35. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/sitewide.schema.json +26 -67
  36. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/theme.schema.json +185 -88
  37. package/examples/complete-sites/dog-shelter-single-page/.astro/data-store.json +1 -1
  38. package/examples/complete-sites/dog-shelter-single-page/.astro/dev-local.json +8 -0
  39. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.json +5 -5
  40. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.log +16 -12
  41. package/examples/complete-sites/dog-shelter-single-page/README.md +1 -1
  42. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/_metadata.json +8 -8
  43. package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +12 -12
  44. package/examples/complete-sites/dog-shelter-single-page/site/content.md +5 -2
  45. package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.yaml +2 -4
  46. package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +17 -41
  47. package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +26 -67
  48. package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +185 -88
  49. package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +1 -1
  50. package/examples/feature-demos/media-and-surfaces/.astro/dev.log +4 -14
  51. package/examples/feature-demos/media-and-surfaces/README.md +2 -2
  52. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +9 -9
  53. package/examples/feature-demos/media-and-surfaces/site/.norna/generated-images.json +16 -16
  54. package/examples/feature-demos/media-and-surfaces/site/content.md +4 -7
  55. package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/010-media/content.md +6 -5
  56. package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/020-surfaces/content.md +7 -6
  57. package/examples/feature-demos/media-and-surfaces/site/sitewide-content.yaml +0 -2
  58. package/examples/feature-demos/sitewide-content/README.md +3 -3
  59. package/examples/feature-demos/sitewide-content/site/content.md +8 -7
  60. package/examples/feature-demos/sitewide-content/site/pages/010-logo-and-navigation/content.md +17 -0
  61. package/examples/feature-demos/sitewide-content/site/{routes → pages}/020-notices/content.md +7 -6
  62. package/examples/feature-demos/sitewide-content/site/{routes → pages}/030-footer/content.md +6 -5
  63. package/examples/feature-demos/sitewide-content/site/sitewide-content.yaml +4 -13
  64. package/examples/feature-demos/theme-presets/README.md +1 -1
  65. package/examples/feature-demos/theme-presets/site/.norna/generated-images.json +60 -60
  66. package/examples/feature-demos/theme-presets/site/content.md +4 -7
  67. package/examples/feature-demos/theme-presets/site/{routes → pages}/010-portfolio/content.md +4 -7
  68. package/examples/feature-demos/theme-presets/site/{routes → pages}/020-documentation/content.md +4 -7
  69. package/examples/feature-demos/theme-presets/site/{routes → pages}/030-project/content.md +4 -7
  70. package/examples/feature-demos/theme-presets/site/{routes → pages}/040-statement/content.md +4 -7
  71. package/examples/feature-demos/theme-presets/site/sitewide-content.yaml +1 -10
  72. package/fixtures/basic/site/content.md +5 -6
  73. package/fixtures/basic/site/sitewide-content.yaml +1 -8
  74. package/fixtures/content-model-v2/site/content.md +11 -13
  75. package/fixtures/content-model-v2/site/pages/010-guide/content.md +18 -0
  76. package/fixtures/nested-pages/site/.norna/generated-images.json +10 -0
  77. package/fixtures/nested-pages/site/config.yaml +1 -0
  78. package/fixtures/nested-pages/site/content.md +15 -0
  79. package/fixtures/nested-pages/site/pages/010-guides/content.md +15 -0
  80. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/content.md +21 -0
  81. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/images/diagram.svg +21 -0
  82. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/pages/010-macos/content.md +14 -0
  83. package/fixtures/nested-pages/site/pages/010-guides/pages/020-workflows/content.md +11 -0
  84. package/fixtures/nested-pages/site/pages/010-guides/theme.yaml +3 -0
  85. package/fixtures/nested-pages/site/pages/020-reference/content.md +10 -0
  86. package/fixtures/nested-pages/site/pages/020-reference/pages/010-installation/content.md +11 -0
  87. package/fixtures/nested-pages/site/theme.yaml +3 -0
  88. package/package.json +7 -4
  89. package/schemas/config.schema.json +5 -5
  90. package/schemas/content-frontmatter.schema.json +28 -63
  91. package/schemas/manifest.json +1 -0
  92. package/schemas/sitewide-content.schema.json +58 -132
  93. package/schemas/theme.schema.json +396 -86
  94. package/scripts/check-config.mjs +6 -5
  95. package/scripts/deploy-site.mjs +6 -8
  96. package/scripts/doctor.mjs +2 -2
  97. package/scripts/generate-images.mjs +11 -18
  98. package/scripts/generate-schemas.mjs +3 -217
  99. package/scripts/lib/base-path-redirect.mjs +9 -0
  100. package/scripts/lib/editor-language-service.mjs +126 -66
  101. package/scripts/lib/heading-ids.mjs +161 -0
  102. package/scripts/lib/navigation-model.mjs +51 -0
  103. package/scripts/lib/norna-markdown-blocks.mjs +3 -4
  104. package/scripts/lib/page-model.mjs +83 -0
  105. package/scripts/lib/project-config.mjs +28 -0
  106. package/scripts/lib/schema-definitions.mjs +41 -46
  107. package/scripts/lib/schema-editor-metadata.mjs +475 -0
  108. package/scripts/lib/schema-value-definitions.mjs +6 -6
  109. package/scripts/lib/site-content.mjs +124 -87
  110. package/scripts/lib/site-paths.mjs +2 -2
  111. package/scripts/lib/theme-config.mjs +9 -16
  112. package/scripts/lib/theme-presets.mjs +9 -1
  113. package/scripts/release.mjs +1 -1
  114. package/scripts/show-typography.mjs +26 -20
  115. package/scripts/sync-content-sections.mjs +106 -65
  116. package/scripts/{test-temporary-visibility.mjs → test-banner-visibility.mjs} +7 -24
  117. package/scripts/test-client-javascript.mjs +39 -42
  118. package/scripts/test-content-check.mjs +138 -54
  119. package/scripts/test-content-model-v2.mjs +445 -228
  120. package/scripts/test-documentation.mjs +6 -1
  121. package/scripts/test-editor-language-service.mjs +168 -24
  122. package/scripts/test-engine-commands.mjs +2 -1
  123. package/scripts/test-heading-ids.mjs +68 -0
  124. package/scripts/test-navigation-model.mjs +63 -0
  125. package/scripts/test-nested-pages.mjs +110 -0
  126. package/scripts/test-package-check.mjs +31 -40
  127. package/scripts/test-page-model.mjs +80 -0
  128. package/scripts/test-project-config.mjs +25 -1
  129. package/scripts/test-schemas.mjs +66 -14
  130. package/scripts/test-theme-presets.mjs +33 -24
  131. package/src/components/NavigationPageTree.astro +68 -0
  132. package/src/components/SectionNavigationScript.astro +110 -5
  133. package/src/components/SiteBreadcrumbs.astro +29 -0
  134. package/src/components/SiteNavigation.astro +65 -69
  135. package/src/components/SitePage.astro +70 -46
  136. package/src/components/SiteSection.astro +27 -20
  137. package/src/content.config.ts +9 -5
  138. package/src/layouts/BaseLayout.astro +11 -20
  139. package/src/lib/pageThemes.ts +42 -0
  140. package/src/lib/sectionContent.ts +109 -106
  141. package/src/lib/siteNavigation.ts +48 -0
  142. package/src/lib/sitePages.ts +85 -38
  143. package/src/pages/{[slug].astro → [...slug].astro} +2 -2
  144. package/src/styles/global.css +373 -55
  145. package/starters/basic/README.md +5 -7
  146. package/starters/basic/site/content.md +7 -4
  147. package/starters/basic/site/sitewide-content.yaml +1 -10
  148. package/starters/project/README.md +8 -8
  149. package/starters/project/site/content.md +5 -4
  150. package/starters/project/site/{routes → pages}/010-guide/content.md +5 -4
  151. package/starters/project/site/sitewide-content.yaml +1 -10
  152. package/docs/routes.md +0 -121
  153. package/examples/feature-demos/sitewide-content/site/routes/010-identity/content.md +0 -20
  154. package/fixtures/content-model-v2/site/routes/010-guide/content.md +0 -17
  155. package/scripts/lib/route-model.mjs +0 -17
  156. package/scripts/test-route-model.mjs +0 -32
  157. package/src/lib/routeThemes.ts +0 -41
  158. /package/examples/complete-sites/dog-shelter-multi-page/site/images/{intro/shelter-dog.jpg → shelter-dog.jpg} +0 -0
  159. /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rex.jpg +0 -0
  160. /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rover.jpg +0 -0
  161. /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/020-adopt/images/adopt → pages/020-adopt/images}/adoption-dog.jpg +0 -0
  162. /package/examples/complete-sites/dog-shelter-single-page/site/images/{you-can-help/foster-dog.jpg → foster-dog.jpg} +0 -0
  163. /package/examples/complete-sites/dog-shelter-single-page/site/images/{what-we-do/rescue-dog.jpg → rescue-dog.jpg} +0 -0
  164. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-carousel.svg +0 -0
  165. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-stack.svg +0 -0
  166. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-surfaces.svg +0 -0
  167. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-one.svg +0 -0
  168. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-three.svg +0 -0
  169. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-two.svg +0 -0
  170. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-one.svg +0 -0
  171. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-two.svg +0 -0
  172. /package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/020-surfaces/theme.yaml +0 -0
  173. /package/examples/feature-demos/theme-presets/site/{routes/010-portfolio/images/portfolio → pages/010-portfolio/images}/puppy-portrait.jpg +0 -0
  174. /package/examples/feature-demos/theme-presets/site/{routes/010-portfolio/images/portfolio → pages/010-portfolio/images}/shepherd-portrait.jpg +0 -0
  175. /package/examples/feature-demos/theme-presets/site/{routes/010-portfolio/images/portfolio → pages/010-portfolio/images}/white-puppy.jpg +0 -0
  176. /package/examples/feature-demos/theme-presets/site/{routes → pages}/010-portfolio/theme.yaml +0 -0
  177. /package/examples/feature-demos/theme-presets/site/{routes/020-documentation/images/documentation → pages/020-documentation/images}/black-schnauzer.jpg +0 -0
  178. /package/examples/feature-demos/theme-presets/site/{routes/020-documentation/images/documentation → pages/020-documentation/images}/retriever-portrait.jpg +0 -0
  179. /package/examples/feature-demos/theme-presets/site/{routes/020-documentation/images/documentation → pages/020-documentation/images}/schnauzer-portrait.jpg +0 -0
  180. /package/examples/feature-demos/theme-presets/site/{routes → pages}/020-documentation/theme.yaml +0 -0
  181. /package/examples/feature-demos/theme-presets/site/{routes/030-project/images/project → pages/030-project/images}/boxer-portrait.jpg +0 -0
  182. /package/examples/feature-demos/theme-presets/site/{routes/030-project/images/project → pages/030-project/images}/grass-puppy.jpg +0 -0
  183. /package/examples/feature-demos/theme-presets/site/{routes/030-project/images/project → pages/030-project/images}/grey-street-dog.jpg +0 -0
  184. /package/examples/feature-demos/theme-presets/site/{routes → pages}/030-project/theme.yaml +0 -0
  185. /package/examples/feature-demos/theme-presets/site/{routes/040-statement/images/statement → pages/040-statement/images}/black-pedigree.jpg +0 -0
  186. /package/examples/feature-demos/theme-presets/site/{routes/040-statement/images/statement → pages/040-statement/images}/sheepdog-grass.jpg +0 -0
  187. /package/examples/feature-demos/theme-presets/site/{routes/040-statement/images/statement → pages/040-statement/images}/sheepdog-wide.jpg +0 -0
  188. /package/examples/feature-demos/theme-presets/site/{routes → pages}/040-statement/theme.yaml +0 -0
  189. /package/fixtures/basic/site/images/{work/.gitkeep → .gitkeep} +0 -0
  190. /package/fixtures/content-model-v2/site/images/{card-section/adopt.svg → adopt.svg} +0 -0
  191. /package/fixtures/content-model-v2/site/images/{intro/detail.jpg → detail.jpg} +0 -0
  192. /package/fixtures/content-model-v2/site/images/{intro/duplicate.jpg → duplicate.jpg} +0 -0
  193. /package/fixtures/content-model-v2/site/images/{card-section/foster.svg → foster.svg} +0 -0
  194. /package/fixtures/content-model-v2/site/images/{intro/hero.jpg → hero.jpg} +0 -0
  195. /package/fixtures/content-model-v2/site/images/{plain/image.jpg → image.jpg} +0 -0
  196. /package/fixtures/content-model-v2/site/images/{timed/slide-one.jpg → slide-one.jpg} +0 -0
  197. /package/fixtures/content-model-v2/site/images/{timed/slide-three.jpg → slide-three.jpg} +0 -0
  198. /package/fixtures/content-model-v2/site/images/{timed/slide-two.jpg → slide-two.jpg} +0 -0
  199. /package/fixtures/content-model-v2/site/{routes/010-guide/images/intro → pages/010-guide/images}/duplicate.jpg +0 -0
  200. /package/starters/basic/site/images/{work/.gitkeep → .gitkeep} +0 -0
package/README.md CHANGED
@@ -17,7 +17,7 @@ implementing a new presentation layer for every project.
17
17
  [Live examples](https://janga.github.io/norna/examples/) |
18
18
  [npm package](https://www.npmjs.com/package/@janga/norna)
19
19
 
20
- [![A multi-page dog shelter site with a logo, route navigation, text, a card, and a managed image.](docs/assets/norna-dog-shelter.jpg)](https://janga.github.io/norna/examples/complete-sites/dog-shelter-multi-page/)
20
+ [![A multi-page dog shelter site with a logo, navigation between pages, text, a card, and a managed image.](docs/assets/norna-dog-shelter.jpg)](https://janga.github.io/norna/examples/complete-sites/dog-shelter-multi-page/)
21
21
 
22
22
  The screenshot shows the built
23
23
  [multi-page example source](examples/complete-sites/dog-shelter-multi-page/).
@@ -54,15 +54,15 @@ site/
54
54
  |-- sitewide-content.yaml
55
55
  |-- content.md
56
56
  |-- images/
57
- |-- routes/
57
+ |-- pages/
58
58
  `-- public/
59
59
  ```
60
60
 
61
- - `content.md` holds the homepage and its sections.
62
- - `images/` holds managed source images beside the content they belong to.
63
- - `routes/` adds pages, each with content and optional local images and theme.
61
+ - `content.md` holds the homepage title, introduction, and sections.
62
+ - `images/` holds the homepage's managed source images.
63
+ - `pages/` adds pages, each with content and optional local images and theme.
64
64
  - `theme.yaml` normally selects one complete visual preset.
65
- - `sitewide-content.yaml` holds shared identity, banners, and footer content.
65
+ - `sitewide-content.yaml` holds shared logo display settings, banners, and footer content.
66
66
  - `config.yaml` holds the public URL and optional language and scroll behavior.
67
67
  - `public/` holds static files copied without processing.
68
68
 
package/astro.config.mjs CHANGED
@@ -3,6 +3,7 @@ import { execFile } from 'node:child_process';
3
3
  import path from 'node:path';
4
4
  import { promisify } from 'node:util';
5
5
  import { defineConfig } from 'astro/config';
6
+ import { getBasePathRedirectLocation } from './scripts/lib/base-path-redirect.mjs';
6
7
  import {
7
8
  astroCacheDir,
8
9
  astroDistDir,
@@ -12,7 +13,7 @@ import {
12
13
  siteContentPath,
13
14
  siteImagesDir,
14
15
  siteProjectRoot,
15
- siteRoutesDir,
16
+ sitePagesDir,
16
17
  } from './scripts/lib/site-paths.mjs';
17
18
  import projectConfig from './scripts/lib/project-config.mjs';
18
19
 
@@ -28,6 +29,37 @@ const runGenerateImages = () => execFileAsync(process.execPath, [path.join(engin
28
29
  maxBuffer: 1024 * 1024 * 10,
29
30
  });
30
31
 
32
+ const nornaBasePathRedirect = () => {
33
+ const middleware = (request, response, next) => {
34
+ if (!request.url) {
35
+ next();
36
+ return;
37
+ }
38
+
39
+ const redirectLocation = getBasePathRedirectLocation(projectConfig.site.basePath, request.url);
40
+ if (!redirectLocation) {
41
+ next();
42
+ return;
43
+ }
44
+
45
+ response.statusCode = 308;
46
+ response.setHeader('Location', redirectLocation);
47
+ response.end();
48
+ };
49
+
50
+ return {
51
+ name: 'norna-base-path-redirect',
52
+ configureServer(server) {
53
+ return () => {
54
+ server.middlewares.stack.unshift({ route: '', handle: middleware });
55
+ };
56
+ },
57
+ configurePreviewServer(server) {
58
+ server.middlewares.use(middleware);
59
+ },
60
+ };
61
+ };
62
+
31
63
  const nornaGeneratedImagesWatcher = () => ({
32
64
  name: 'norna-generated-images-watcher',
33
65
  configureServer(server) {
@@ -35,7 +67,7 @@ const nornaGeneratedImagesWatcher = () => ({
35
67
  const watchedSourcePaths = [
36
68
  siteContentPath,
37
69
  siteImagesDir,
38
- siteRoutesDir,
70
+ sitePagesDir,
39
71
  ].map((watchedPath) => path.resolve(watchedPath));
40
72
  let refreshTimer;
41
73
  let refreshPromise = Promise.resolve();
@@ -90,6 +122,6 @@ export default defineConfig({
90
122
  publicDir: astroPublicDir,
91
123
  srcDir: path.join(engineRoot, 'src'),
92
124
  vite: {
93
- plugins: [nornaGeneratedImagesWatcher()],
125
+ plugins: [nornaBasePathRedirect(), nornaGeneratedImagesWatcher()],
94
126
  },
95
127
  });
package/docs/README.md CHANGED
@@ -29,7 +29,7 @@ site/
29
29
  |-- sitewide-content.yaml
30
30
  |-- content.md
31
31
  |-- images/
32
- |-- routes/
32
+ |-- pages/
33
33
  `-- public/
34
34
  ```
35
35
 
@@ -37,14 +37,14 @@ site/
37
37
  scroll behavior.
38
38
  - [`theme.yaml`](theme.md): complete visual presets and focused presentation
39
39
  overrides.
40
- - [`sitewide-content.yaml`](sitewide-content.md): shared navigation identity,
40
+ - [`sitewide-content.yaml`](sitewide-content.md): shared logo display settings,
41
41
  banners, and footer.
42
- - [`content.md`](content.md): page metadata, sections, prose, notes, and Norna
43
- blocks.
42
+ - [`content.md`](content.md): Markdown page title, optional metadata, sections,
43
+ prose, notes, and Norna blocks.
44
44
  - [`images/`](images-and-metadata.md): managed source formats, variants, sync,
45
45
  and generated image state.
46
- - [`routes/`](routes.md): additional pages, ordering, URLs, route themes, and
47
- route-local images.
46
+ - [`pages/`](pages.md): additional pages, ordering, URLs, page themes, and
47
+ page-local images.
48
48
  - [`public/`](public-files.md): navigation logos, favicons, and other static
49
49
  files copied without managed-image processing.
50
50
  - [Generated files](site-files.md#generated-files): `site/.norna/public/`,
@@ -67,7 +67,7 @@ required, optional, convention-discovered, versioned, or generated.
67
67
  - [Write page sections](content.md#sections)
68
68
  - [Use image stacks, carousels, and cards](content.md#norna-blocks)
69
69
  - [Add notes to prose](content.md#markdown-text)
70
- - [Add another page](routes.md)
70
+ - [Add another page](pages.md)
71
71
  - [Add shared banners or footer content](sitewide-content.md)
72
72
 
73
73
  ### Work With Images And Public Assets
@@ -75,14 +75,14 @@ required, optional, convention-discovered, versioned, or generated.
75
75
  - [Add managed source images](images-and-metadata.md#managed-source-images)
76
76
  - [Check and sync moved image references](content.md#validation-and-sync)
77
77
  - [Add a navigation logo](public-files.md#navigation-logo)
78
- - [Add favicons](public-files.md#logos-and-favicons)
78
+ - [Add browser icons](public-files.md#browser-icons)
79
79
  - [Add other static files](public-files.md#other-static-files)
80
80
 
81
81
  ### Change Presentation
82
82
 
83
83
  - [Choose a complete theme preset](theme.md#theme-presets)
84
84
  - [Inspect and override a preset](theme.md#overrides)
85
- - [Give a route a different theme](theme.md#route-themes)
85
+ - [Give a page a different theme](theme.md#page-themes)
86
86
  - [Adjust typography](typography.md)
87
87
 
88
88
  ### Check, Build, And Publish
@@ -95,7 +95,7 @@ required, optional, convention-discovered, versioned, or generated.
95
95
  ## Concepts And Explanation
96
96
 
97
97
  - [Norna's site model](https://janga.github.io/norna/concepts/) explains how
98
- files, sections, images, and routes become a website.
98
+ files, sections, images, and pages become a website.
99
99
  - [Images and Metadata](images-and-metadata.md) explains managed variants and
100
100
  published URLs.
101
101
  - [Command Organization](design/command-organization.md) explains standalone,
package/docs/commands.md CHANGED
@@ -119,7 +119,7 @@ should normally mean the repository's complete publishable artifact, while
119
119
  inline styles, and common content mistakes.
120
120
  - `content:sync` / `norna:sync`: moves misplaced referenced image files after
121
121
  confirmation when the intended move is unambiguous. Moving files between the
122
- homepage and routes, or between routes, requires a clean Git working tree.
122
+ homepage and an additional page, or between additional pages, requires a clean Git working tree.
123
123
  - `theme:presets`: lists the available complete theme presets and explains the
124
124
  intended use of each one.
125
125
  - `theme:export <preset>`: writes a protected, commented
@@ -129,7 +129,7 @@ should normally mean the repository's complete publishable artifact, while
129
129
  - `typography profiles`: prints the exact built-in values for typography
130
130
  profiles and rhythms.
131
131
  - `typography show`: prints the selected site's resolved typography for the
132
- theme, every page route, and every section. Each value includes its source,
132
+ theme, every page, and every section. Each value includes its source,
133
133
  and inherited page or section values are marked with `inherited: true`.
134
134
  - `site:public`: copies `site/public/` into `site/.norna/public/` and
135
135
  removes stale copied static files.
package/docs/content.md CHANGED
@@ -1,36 +1,64 @@
1
1
  # Content
2
2
 
3
- `site/content.md` is the homepage page file for a Norna site. It contains page
4
- metadata in frontmatter and the homepage content in Markdown.
3
+ `site/content.md` is the homepage file for a Norna site. Its Markdown H1 is
4
+ the page title. Optional page metadata can be added in YAML frontmatter.
5
5
 
6
- Route pages use the same page model in
7
- `site/routes/<NNN-route-id>/content.md`. See [Routes](routes.md) for the
8
- route-specific rules.
6
+ Additional pages use the same page model in
7
+ `site/pages/<NNN-page-id>/content.md`. See [Pages](pages.md) for the
8
+ page-specific rules.
9
9
 
10
10
  Site-wide visual defaults belong in [Theme](theme.md). Typography profiles and
11
11
  overrides are described in [Typography](typography.md). Technical site settings
12
12
  belong in [Configuration](configuration.md).
13
13
 
14
- ## Page Frontmatter
14
+ ## Page Title And Frontmatter
15
15
 
16
- The Astro content schema validates these top-level fields in page files:
16
+ Every page must contain exactly one Markdown H1. It must be the first heading,
17
+ must not have a section id, and supplies the visible page title, HTML document
18
+ title, and page label in site navigation:
17
19
 
18
- - `title`: required string. Rendered as the document title.
19
- - `description`: required string. Rendered as the meta description.
20
- - `navigation`: optional page navigation metadata. See [Routes](routes.md).
21
- - `sections`: optional section metadata keyed by section id.
20
+ ```md
21
+ # My Site
22
+ ```
23
+
24
+ Content between the H1 and the first H2 is the page introduction. It may
25
+ contain prose and Norna blocks.
26
+
27
+ Frontmatter is optional. When present, the content schema validates these
28
+ top-level fields:
29
+
30
+ - `page`: optional page metadata.
31
+ - `navigation`: optional page-listing metadata. See [Pages](pages.md).
32
+
33
+ `page` contains:
34
+
35
+ - `description`: optional string. Used only as the page's HTML meta description
36
+ for search engines, link previews, and other metadata consumers. It is not
37
+ rendered as visible page content.
38
+
39
+ Minimal homepage without metadata:
40
+
41
+ ```md
42
+ # My Site
43
+
44
+ Introductory text.
22
45
 
23
- Minimal homepage:
46
+ ## Work {#work}
47
+
48
+ Text...
49
+ ```
50
+
51
+ Homepage with a meta description:
24
52
 
25
53
  ```md
26
54
  ---
27
- title: My Site
28
- description: A small Norna site.
55
+ page:
56
+ description: A small Norna site.
29
57
  ---
30
58
 
31
- ## Intro {#intro}
59
+ # My Site
32
60
 
33
- Text...
61
+ Introductory text.
34
62
  ```
35
63
 
36
64
  ## Sections
@@ -57,39 +85,14 @@ Every section heading must have an explicit id:
57
85
  ## Work {#work}
58
86
  ```
59
87
 
60
- The id must match `^[a-z0-9-]+$`. It is used for anchors, navigation, image
61
- directories, and optional section metadata. The visible section navigation
62
- label comes from the Markdown heading text.
88
+ The id must match `^[a-z0-9-]+$`. It is used for anchors and section
89
+ navigation. The visible section navigation label comes from the Markdown
90
+ heading text.
63
91
 
64
92
  Markdown section content starts at the level 2 heading and continues until the
65
93
  next level 2 heading. `###` and `####` headings are body subheadings within the
66
94
  current section, not new sections.
67
95
 
68
- ## Section Metadata
69
-
70
- Use `sections` only when a section needs structured metadata that is not
71
- naturally expressed by Markdown. Currently this is date-based visibility.
72
-
73
- ```yaml
74
- sections:
75
- work:
76
- visible:
77
- from: "2026-08-01"
78
- until: "2026-09-16"
79
- ```
80
-
81
- See [Temporary Sections](#temporary-sections) for visibility semantics.
82
-
83
- Each `sections.<section-id>` key must match a Markdown heading id in the same
84
- page file:
85
-
86
- ```md
87
- ## Work {#work}
88
- ```
89
-
90
- Do not list sections in frontmatter just to define order. Section order comes
91
- from the Markdown heading order.
92
-
93
96
  ## Norna Blocks
94
97
 
95
98
  Norna-managed local images and cards are written in Markdown fenced blocks at
@@ -97,6 +100,8 @@ the point where they should appear in the section. Markdown determines
97
100
  placement: move the fenced block in the page file to move the rendered image,
98
101
  carousel, or card list.
99
102
 
103
+ ### Image Stack
104
+
100
105
  Use `norna-image-stack` for one or more stacked images:
101
106
 
102
107
  ````md
@@ -107,6 +112,8 @@ Use `norna-image-stack` for one or more stacked images:
107
112
  ```
108
113
  ````
109
114
 
115
+ ### Image Carousel
116
+
110
117
  Use `norna-image-carousel` for a carousel:
111
118
 
112
119
  ````md
@@ -120,6 +127,8 @@ Use `norna-image-carousel` for a carousel:
120
127
  ```
121
128
  ````
122
129
 
130
+ ### Card List
131
+
123
132
  Use `norna-card-list` for a list of compact cards. Cards can include text,
124
133
  managed images, links, and optional badge text:
125
134
 
@@ -198,13 +207,13 @@ sizing is less predictable.
198
207
  Homepage images live under:
199
208
 
200
209
  ```text
201
- site/images/<section-id>/
210
+ site/images/
202
211
  ```
203
212
 
204
- Route images live under:
213
+ Page images live under:
205
214
 
206
215
  ```text
207
- site/routes/<NNN-route-id>/images/<section-id>/
216
+ site/pages/<NNN-page-id>/images/
208
217
  ```
209
218
 
210
219
  Image references in Norna managed image blocks use only the filename:
@@ -215,13 +224,15 @@ Image references in Norna managed image blocks use only the filename:
215
224
  ```
216
225
  ````
217
226
 
218
- If `portrait.jpg` is referenced from `## Team {#team}`, the expected homepage
219
- location is `site/images/team/portrait.jpg`.
227
+ If `portrait.jpg` is referenced anywhere on the homepage, its expected
228
+ location is `site/images/portrait.jpg`. The same file may be referenced from
229
+ more than one section on that page.
220
230
 
221
- Filenames do not have to be globally unique for the site to be valid. Automatic
222
- sync only moves files when the filename identifies exactly one source candidate
223
- across the site's page and route image roots. If more than one candidate
224
- exists, Norna reports the ambiguity instead of guessing.
231
+ Filenames must be unique within one page's image directory, but do not have to
232
+ be globally unique across the site. Automatic sync only moves files between
233
+ page image roots when the filename identifies exactly one source candidate
234
+ across the site. If more than one candidate exists, Norna reports the
235
+ ambiguity instead of guessing.
225
236
 
226
237
  ## Markdown Images
227
238
 
@@ -237,36 +248,6 @@ managed by Norna. Use `norna-image-stack`, `norna-image-carousel`, or
237
248
  `norna-card-list` for local site images that should be validated, processed and
238
249
  synced.
239
250
 
240
- ## Temporary Sections
241
-
242
- Use `sections.<section-id>.visible` for sections that should be rendered only
243
- during a date window:
244
-
245
- ```yaml
246
- sections:
247
- exhibition:
248
- visible:
249
- from: "2026-08-01"
250
- until: "2026-09-16"
251
- ```
252
-
253
- `from` is inclusive. `until` is exclusive. With the example above, the section
254
- is visible from 2026-08-01 through 2026-09-15 and hidden again on 2026-09-16.
255
-
256
- Both `from` and `until` use `YYYY-MM-DD`. Either value may be omitted, but a
257
- `visible` object must contain at least one of them.
258
-
259
- Hidden sections are omitted from the rendered HTML and sticky navigation. They
260
- remain in the page file, and `content:check` still validates their matching
261
- Markdown headings and image references.
262
-
263
- The current date is evaluated at dev/build time. Set `NORNA_TODAY` to preview
264
- or test a specific date:
265
-
266
- ```sh
267
- NORNA_TODAY=2026-08-15 npm run norna:build
268
- ```
269
-
270
251
  ## Markdown Text
271
252
 
272
253
  Use ordinary Markdown for emphasis and structure:
@@ -277,7 +258,7 @@ This sentence contains **important text** and *emphasised text*.
277
258
 
278
259
  Norna intentionally does not support arbitrary inline color or style classes.
279
260
  Deprecated syntax such as `[highlighted text]{.yellow}` is rejected by
280
- `content:check`. Keep the route visually coherent through its `theme.yaml`
261
+ `content:check`. Keep the page visually coherent through its `theme.yaml`
281
262
  instead of styling individual phrases.
282
263
 
283
264
  ### Side Notes
@@ -315,7 +296,7 @@ Run:
315
296
  npm run norna:content:check
316
297
  ```
317
298
 
318
- This checks section heading ids, section metadata, duplicate image names,
299
+ This checks section heading ids, duplicate image names,
319
300
  missing image files, misplaced referenced images, duplicate image references,
320
301
  invalid Norna blocks, unreferenced images, removed inline style syntax,
321
302
  Markdown image references to unmanaged local files, and common frontmatter
@@ -327,15 +308,12 @@ invalid, when a key is indented under a line that already has a value, or when a
327
308
  known nested key appears at the top level:
328
309
 
329
310
  ```yaml
330
- sections:
331
- intro:
332
- visible:
333
- from: "2026-08-01"
311
+ navigation:
312
+ listed: false
334
313
  ```
335
314
 
336
- Top-level page frontmatter may contain only `title`, `description`,
337
- `navigation`, and `sections`. Visual settings belong in the root or route-local
338
- `theme.yaml`.
315
+ Top-level page frontmatter may contain only `page` and `navigation`. Visual
316
+ settings belong in the root or page-local `theme.yaml`.
339
317
 
340
318
  Run:
341
319
 
@@ -343,20 +321,22 @@ Run:
343
321
  npm run norna:sync
344
322
  ```
345
323
 
346
- This moves referenced image files into the section directory shown by the
347
- Markdown placement. It prompts before writing unless `--yes` is passed.
324
+ This moves referenced image files into the image directory for the page that
325
+ references them. Moving a block between sections on the same page does not
326
+ move the file because all sections share the page image directory. The command
327
+ prompts before writing unless `--yes` is passed.
348
328
 
349
329
  `content:sync` is intentionally conservative. It only moves a file when the
350
- filename identifies exactly one matching source candidate across the site's
351
- page and route image roots, and when the move will not break another reference.
330
+ filename identifies exactly one matching source candidate across all page
331
+ image roots, and when the move will not break another reference.
352
332
  If the intended move is ambiguous, rename or move the file manually and run
353
333
  `content:check` again.
354
334
 
355
- Duplicate filenames are allowed when files already live where their Markdown
356
- references expect them. Automatic relocation only requires site-wide filename
357
- uniqueness for the file being moved.
335
+ The same filename may exist in different page image directories. Automatic
336
+ relocation only requires site-wide filename uniqueness for the file being
337
+ moved.
358
338
 
359
- When `content:sync` needs to move an image between the homepage and a route, or
360
- between two routes, the Git working tree must be clean before the write. This
361
- keeps cross-route sync easy to roll back. `content:check` only reports issues
339
+ When `content:sync` needs to move an image between the homepage and a page, or
340
+ between two pages, the Git working tree must be clean before the write. This
341
+ keeps cross-page sync easy to roll back. `content:check` only reports issues
362
342
  and does not require a clean working tree.
@@ -0,0 +1,115 @@
1
+ # Navigation And Theme Plan
2
+
3
+ This document records the intended order of work for page hierarchy,
4
+ navigation, and theme presets. It is an implementation plan, not a description
5
+ of released behavior.
6
+
7
+ ## Goal
8
+
9
+ Norna should support sites with limited global navigation and a larger local
10
+ page hierarchy without making mobile navigation harder to understand. Theme
11
+ presets should provide a coherent visual system without changing the site's
12
+ information architecture.
13
+
14
+ ## Working Principles
15
+
16
+ - The file structure defines the page hierarchy and presentation order.
17
+ - Navigation behavior and navigation styling are separate concerns.
18
+ - Global site navigation, local page navigation, and headings on the current
19
+ page have distinct roles.
20
+ - Changing a theme preset must not change which pages are available or how the
21
+ page hierarchy is interpreted.
22
+ - Site-wide visual identity should remain coherent while individual pages may
23
+ vary where that does not disrupt navigation or orientation.
24
+ - Documentation and broad example migration should follow implementation and
25
+ manual evaluation, not precede them.
26
+
27
+ ## Order Of Work
28
+
29
+ ### 1. Stabilize The Page Tree
30
+
31
+ Finish and test nested page discovery independently of final navigation
32
+ presentation. Establish deterministic rules for:
33
+
34
+ - directory parsing, page ids, URL paths, and presentation order;
35
+ - parent and ancestor relationships;
36
+ - collisions and invalid nesting;
37
+ - page-local content, images, and themes;
38
+ - breadcrumbs and current-branch discovery.
39
+
40
+ Commit this foundation separately before broad theme or preset changes.
41
+
42
+ ### 2. Define The Navigation Contract
43
+
44
+ The intended information architecture is:
45
+
46
+ - a small global navigation for the site's top-level areas;
47
+ - a larger local page tree for the selected area;
48
+ - a separate `On this page` list for headings on the current page;
49
+ - breadcrumbs for location and ancestry;
50
+ - one unified mobile navigation containing the whole page hierarchy, with the
51
+ current branch expanded and current page marked.
52
+
53
+ The exact contract is potentially difficult to evaluate at an abstract level.
54
+ The maintainer therefore expects this phase to use executable test sites,
55
+ focused automated tests, or clear illustrative examples. These artifacts
56
+ should demonstrate short single-page sites, ordinary two-level sites, and
57
+ deeper documentation-style hierarchies on both desktop and mobile before the
58
+ contract is considered stable.
59
+
60
+ The contract should also define the fallback and override behavior for the
61
+ supported navigation modes. Structural behavior belongs to site-level engine
62
+ configuration or deterministic automatic selection, not to presentation
63
+ presets.
64
+
65
+ ### 3. Implement Navigation In Layers
66
+
67
+ Implement and verify the navigation model in this order:
68
+
69
+ 1. page-tree data and validation;
70
+ 2. desktop global navigation, local tree, breadcrumbs, and `On this page`;
71
+ 3. unified mobile navigation;
72
+ 4. keyboard, focus, current-page, and progressive-enhancement behavior;
73
+ 5. visual evaluation at representative viewport sizes.
74
+
75
+ Keep real links as the foundation. Client-side JavaScript should only enhance
76
+ interaction that cannot be expressed adequately with HTML and CSS.
77
+
78
+ ### 4. Refine Theme And Preset Responsibilities
79
+
80
+ Presets should control visual presentation, including:
81
+
82
+ - color system;
83
+ - typography;
84
+ - spacing and density;
85
+ - page and content widths;
86
+ - the visual treatment of global navigation, local navigation, breadcrumbs,
87
+ and `On this page`.
88
+
89
+ Presets must not determine page hierarchy, link membership, or semantic
90
+ navigation structure. Those must remain stable when a preset changes.
91
+
92
+ Site-wide color, typography, and navigation treatment should normally remain
93
+ consistent. Page-local theme variation should be limited to properties such as
94
+ content width, density, and media presentation when variation does not weaken
95
+ site identity or navigation clarity.
96
+
97
+ ### 5. Migrate After Evaluation
98
+
99
+ After the page tree, navigation contract, and preset boundaries have been
100
+ manually evaluated:
101
+
102
+ - migrate fixtures and examples;
103
+ - update schemas and editor assistance;
104
+ - update Markdown reference documentation;
105
+ - update the rendered documentation site;
106
+ - remove obsolete navigation and preset behavior rather than retaining
107
+ compatibility layers.
108
+
109
+ Keep foundation, navigation, preset, migration, and documentation changes in
110
+ separate commits where practical.
111
+
112
+ ## Immediate Checkpoint
113
+
114
+ The current nested-page implementation should be reviewed, tested, and secured
115
+ before work continues on the final navigation contract or preset model.
@@ -54,9 +54,9 @@ the image, or in `docs/design/` when it is useful for future maintenance.
54
54
  - Keep arrows few and directional.
55
55
  - Avoid diagrams where every object connects to every other object.
56
56
  - Prefer multiple simple diagrams over one dense diagram.
57
- - Make route order, URL slugs, section ids, image folders, source files, and
57
+ - Make page order, URL slugs, section ids, image folders, source files, and
58
58
  generated output visually distinct when those ideas matter.
59
- - Do not show templates, components, custom rendering logic, route-level
59
+ - Do not show templates, components, custom rendering logic, page-level
60
60
  technical configuration, or hosting integrations that Norna does not support.
61
61
  - Do not show page layouts that Norna cannot actually render unless the diagram
62
62
  is clearly abstract and not a product capability example.
@@ -67,12 +67,12 @@ Diagrams must match the current Norna model:
67
67
 
68
68
  - A Norna site is described with site files, not arbitrary project structure.
69
69
  - `content.md` is the homepage content file.
70
- - `sitewide-content.yaml` contains shared site identity, banners, and footer
70
+ - `sitewide-content.yaml` contains shared logo settings, banners, and footer
71
71
  content.
72
- - Additional pages are route directories with `content.md`.
73
- - Route folder prefixes control route presentation order.
74
- - Route ids become default URL slugs.
75
- - Images belong under the image root for the page or route, usually grouped by
72
+ - Additional pages are page directories with `content.md`.
73
+ - Page folder prefixes control navigation order.
74
+ - Page ids become URL segments.
75
+ - Images belong under the image root for their page, usually grouped by
76
76
  section id.
77
77
  - Markdown remains the primary writing format.
78
78
  - Norna blocks cover fixed site patterns such as image stacks,
@@ -108,7 +108,7 @@ over relying on horizontal scrolling.
108
108
  Store diagram SVG files as normal Norna managed image assets:
109
109
 
110
110
  ```text
111
- site/routes/<NNN-route-id>/images/<section-id>/<diagram-name>.svg
111
+ site/pages/<NNN-page-id>/images/<diagram-name>.svg
112
112
  ```
113
113
 
114
114
  Reference them with a Norna image block:
@@ -132,7 +132,7 @@ Before accepting a diagram:
132
132
 
133
133
  - The main message is obvious without reading the surrounding section.
134
134
  - The diagram does not imply unsupported Norna functionality.
135
- - URL, route, section, image, theme, config, and output terminology is
135
+ - URL, page, section, image, theme, config, and output terminology is
136
136
  consistent with documentation.
137
137
  - Text fits inside boxes at desktop and mobile widths.
138
138
  - Arrows clarify the relationship instead of adding noise.