@janga/norna 0.7.16 → 0.7.18

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 (342) hide show
  1. package/README.md +18 -9
  2. package/astro.config.mjs +35 -3
  3. package/bin/norna-cli.mjs +1 -1
  4. package/docs/README.md +16 -14
  5. package/docs/commands.md +2 -2
  6. package/docs/configuration.md +25 -2
  7. package/docs/content.md +92 -103
  8. package/docs/design/navigation-and-theme-plan.md +186 -0
  9. package/docs/design/norna-diagram-design.md +9 -9
  10. package/docs/design/site-examples-structure.md +15 -11
  11. package/docs/engine-development.md +19 -22
  12. package/docs/getting-started.md +21 -16
  13. package/docs/images-and-metadata.md +12 -9
  14. package/docs/pages.md +190 -0
  15. package/docs/public-files.md +49 -36
  16. package/docs/publishing.md +19 -3
  17. package/docs/site-files.md +46 -38
  18. package/docs/sitewide-content.md +20 -36
  19. package/docs/theme.md +109 -143
  20. package/docs/typography.md +19 -31
  21. package/examples/README.md +10 -4
  22. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/site.schema.json +17 -41
  23. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/sitewide.schema.json +26 -67
  24. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/theme.schema.json +185 -88
  25. package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +1 -1
  26. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev-local.json +4 -4
  27. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.json +5 -5
  28. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +33 -23
  29. package/examples/complete-sites/dog-shelter-multi-page/README.md +1 -1
  30. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/_metadata.json +8 -8
  31. package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +20 -20
  32. package/examples/complete-sites/dog-shelter-multi-page/site/{content.md → pages/000-home/content.md} +3 -4
  33. package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/010-dogs/content.md +3 -4
  34. package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/020-adopt/content.md +3 -4
  35. package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.yaml +2 -4
  36. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/site.schema.json +17 -41
  37. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/sitewide.schema.json +26 -67
  38. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/theme.schema.json +185 -88
  39. package/examples/complete-sites/dog-shelter-single-page/.astro/data-store.json +1 -1
  40. package/examples/complete-sites/dog-shelter-single-page/.astro/dev-local.json +8 -0
  41. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.json +5 -5
  42. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.log +16 -12
  43. package/examples/complete-sites/dog-shelter-single-page/README.md +1 -1
  44. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/_metadata.json +8 -8
  45. package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +12 -12
  46. package/examples/complete-sites/dog-shelter-single-page/site/{content.md → pages/000-home/content.md} +5 -2
  47. package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.yaml +2 -4
  48. package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +17 -41
  49. package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +26 -67
  50. package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +180 -91
  51. package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +1 -1
  52. package/examples/feature-demos/media-and-surfaces/.astro/dev.log +4 -14
  53. package/examples/feature-demos/media-and-surfaces/README.md +2 -2
  54. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +9 -9
  55. package/examples/feature-demos/media-and-surfaces/site/.norna/generated-images.json +16 -16
  56. package/examples/feature-demos/media-and-surfaces/site/{content.md → pages/000-home/content.md} +4 -7
  57. package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/010-media/content.md +6 -5
  58. package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/020-surfaces/content.md +9 -7
  59. package/examples/feature-demos/media-and-surfaces/site/pages/020-surfaces/theme.yaml +2 -0
  60. package/examples/feature-demos/media-and-surfaces/site/sitewide-content.yaml +0 -2
  61. package/examples/feature-demos/sitewide-content/README.md +3 -3
  62. package/examples/feature-demos/sitewide-content/site/pages/000-home/content.md +17 -0
  63. package/examples/feature-demos/sitewide-content/site/pages/010-logo-and-navigation/content.md +17 -0
  64. package/examples/feature-demos/sitewide-content/site/{routes → pages}/020-notices/content.md +7 -6
  65. package/examples/feature-demos/sitewide-content/site/{routes → pages}/030-footer/content.md +6 -5
  66. package/examples/feature-demos/sitewide-content/site/sitewide-content.yaml +4 -13
  67. package/examples/feature-demos/theme-preset-documentation/README.md +16 -0
  68. package/examples/feature-demos/theme-preset-documentation/site/.norna/generated-images.json +74 -0
  69. package/examples/feature-demos/{theme-presets/site/routes/020-documentation → theme-preset-documentation/site/pages/000-home}/content.md +4 -7
  70. package/examples/feature-demos/theme-preset-documentation/site/sitewide-content.yaml +3 -0
  71. package/examples/feature-demos/theme-preset-portfolio/README.md +16 -0
  72. package/examples/feature-demos/theme-preset-portfolio/site/.norna/generated-images.json +74 -0
  73. package/examples/feature-demos/theme-preset-portfolio/site/config.yaml +1 -0
  74. package/examples/feature-demos/{theme-presets/site/routes/010-portfolio → theme-preset-portfolio/site/pages/000-home}/content.md +4 -7
  75. package/examples/feature-demos/theme-preset-portfolio/site/public/robots.txt +2 -0
  76. package/examples/feature-demos/theme-preset-portfolio/site/sitewide-content.yaml +3 -0
  77. package/examples/feature-demos/theme-preset-project/README.md +16 -0
  78. package/examples/feature-demos/theme-preset-project/site/.norna/generated-images.json +74 -0
  79. package/examples/feature-demos/theme-preset-project/site/config.yaml +1 -0
  80. package/examples/feature-demos/{theme-presets/site/routes/030-project → theme-preset-project/site/pages/000-home}/content.md +4 -7
  81. package/examples/feature-demos/theme-preset-project/site/public/robots.txt +2 -0
  82. package/examples/feature-demos/theme-preset-project/site/sitewide-content.yaml +3 -0
  83. package/examples/feature-demos/theme-preset-statement/README.md +16 -0
  84. package/examples/feature-demos/theme-preset-statement/site/.norna/generated-images.json +74 -0
  85. package/examples/feature-demos/theme-preset-statement/site/config.yaml +1 -0
  86. package/examples/feature-demos/{theme-presets/site/routes/040-statement → theme-preset-statement/site/pages/000-home}/content.md +4 -7
  87. package/examples/feature-demos/theme-preset-statement/site/public/robots.txt +2 -0
  88. package/examples/feature-demos/theme-preset-statement/site/sitewide-content.yaml +3 -0
  89. package/fixtures/basic/site/{content.md → pages/000-home/content.md} +5 -6
  90. package/fixtures/basic/site/sitewide-content.yaml +1 -8
  91. package/fixtures/basic/site/theme.yaml +1 -8
  92. package/fixtures/content-model-v2/site/{content.md → pages/000-home/content.md} +11 -13
  93. package/fixtures/content-model-v2/site/pages/010-guide/content.md +18 -0
  94. package/fixtures/nested-pages/.astro/collections/site.schema.json +35 -0
  95. package/fixtures/nested-pages/.astro/collections/sitewide.schema.json +97 -0
  96. package/fixtures/nested-pages/.astro/collections/theme.schema.json +844 -0
  97. package/fixtures/nested-pages/.astro/content-assets.mjs +4 -0
  98. package/fixtures/nested-pages/.astro/content-modules.mjs +1 -0
  99. package/fixtures/nested-pages/.astro/content.d.ts +183 -0
  100. package/fixtures/nested-pages/.astro/data-store.json +1 -0
  101. package/fixtures/nested-pages/.astro/dev-local.json +8 -0
  102. package/fixtures/nested-pages/.astro/dev.log +1128 -0
  103. package/fixtures/nested-pages/.astro/settings.json +5 -0
  104. package/fixtures/nested-pages/.astro/types.d.ts +2 -0
  105. package/fixtures/nested-pages/node_modules/.vite/deps/_metadata.json +74 -0
  106. package/fixtures/nested-pages/node_modules/.vite/deps/astro-D_GIpJIE.js +434 -0
  107. package/fixtures/nested-pages/node_modules/.vite/deps/astro-D_GIpJIE.js.map +1 -0
  108. package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
  109. package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
  110. package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
  111. package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
  112. package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
  113. package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
  114. package/fixtures/nested-pages/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
  115. package/fixtures/nested-pages/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
  116. package/fixtures/nested-pages/node_modules/.vite/deps/audit-DM9Hkl5B.js +1534 -0
  117. package/fixtures/nested-pages/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +1 -0
  118. package/fixtures/nested-pages/node_modules/.vite/deps/highlight-DnZ1ULOL.js +48 -0
  119. package/fixtures/nested-pages/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +1 -0
  120. package/fixtures/nested-pages/node_modules/.vite/deps/icons-RyebKi45.js +42 -0
  121. package/fixtures/nested-pages/node_modules/.vite/deps/icons-RyebKi45.js.map +1 -0
  122. package/fixtures/nested-pages/node_modules/.vite/deps/package.json +3 -0
  123. package/fixtures/nested-pages/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
  124. package/fixtures/nested-pages/node_modules/.vite/deps/settings-DaU-gNnK.js +190 -0
  125. package/fixtures/nested-pages/node_modules/.vite/deps/settings-DaU-gNnK.js.map +1 -0
  126. package/fixtures/nested-pages/node_modules/.vite/deps/toolbar-63PA619H.js +458 -0
  127. package/fixtures/nested-pages/node_modules/.vite/deps/toolbar-63PA619H.js.map +1 -0
  128. package/fixtures/nested-pages/node_modules/.vite/deps/ui-library--bkcNSYz.js +1016 -0
  129. package/fixtures/nested-pages/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +1 -0
  130. package/fixtures/nested-pages/node_modules/.vite/deps/window-jPkpKVcy.js +32 -0
  131. package/fixtures/nested-pages/node_modules/.vite/deps/window-jPkpKVcy.js.map +1 -0
  132. package/fixtures/nested-pages/node_modules/.vite/deps/xray-BXCHpEJP.js +111 -0
  133. package/fixtures/nested-pages/node_modules/.vite/deps/xray-BXCHpEJP.js.map +1 -0
  134. package/fixtures/nested-pages/site/.norna/generated-images.json +10 -0
  135. package/fixtures/nested-pages/site/config.yaml +3 -0
  136. package/fixtures/nested-pages/site/pages/000-home/content.md +15 -0
  137. package/fixtures/nested-pages/site/pages/010-guides/content.md +15 -0
  138. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/content.md +21 -0
  139. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/images/diagram.svg +21 -0
  140. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/pages/010-macos/content.md +18 -0
  141. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/theme.yaml +2 -0
  142. package/fixtures/nested-pages/site/pages/010-guides/pages/020-workflows/content.md +11 -0
  143. package/fixtures/nested-pages/site/pages/010-guides/pages/030-release-notes/content.md +9 -0
  144. package/fixtures/nested-pages/site/pages/010-guides/pages/040-configuration/content.md +3 -0
  145. package/fixtures/nested-pages/site/pages/010-guides/pages/050-content/content.md +3 -0
  146. package/fixtures/nested-pages/site/pages/010-guides/pages/060-themes/content.md +3 -0
  147. package/fixtures/nested-pages/site/pages/010-guides/pages/070-images/content.md +3 -0
  148. package/fixtures/nested-pages/site/pages/010-guides/pages/080-cards/content.md +3 -0
  149. package/fixtures/nested-pages/site/pages/010-guides/pages/090-notes/content.md +3 -0
  150. package/fixtures/nested-pages/site/pages/010-guides/pages/100-validation/content.md +3 -0
  151. package/fixtures/nested-pages/site/pages/010-guides/pages/110-synchronization/content.md +3 -0
  152. package/fixtures/nested-pages/site/pages/010-guides/pages/120-building/content.md +3 -0
  153. package/fixtures/nested-pages/site/pages/010-guides/pages/130-publishing/content.md +3 -0
  154. package/fixtures/nested-pages/site/pages/010-guides/pages/140-troubleshooting/content.md +3 -0
  155. package/fixtures/nested-pages/site/pages/010-guides/pages/150-migration/content.md +3 -0
  156. package/fixtures/nested-pages/site/pages/010-guides/pages/160-accessibility/content.md +3 -0
  157. package/fixtures/nested-pages/site/pages/010-guides/pages/170-performance/content.md +3 -0
  158. package/fixtures/nested-pages/site/pages/010-guides/pages/180-security/content.md +3 -0
  159. package/fixtures/nested-pages/site/pages/010-guides/pages/190-localization/content.md +3 -0
  160. package/fixtures/nested-pages/site/pages/010-guides/pages/200-upgrading/content.md +3 -0
  161. package/fixtures/nested-pages/site/pages/010-guides/pages/210-faq/content.md +3 -0
  162. package/fixtures/nested-pages/site/pages/010-guides/theme.yaml +7 -0
  163. package/fixtures/nested-pages/site/pages/020-reference/content.md +10 -0
  164. package/fixtures/nested-pages/site/pages/020-reference/pages/010-installation/content.md +11 -0
  165. package/fixtures/nested-pages/site/theme.yaml +1 -0
  166. package/package.json +8 -4
  167. package/schemas/config.schema.json +46 -5
  168. package/schemas/content-frontmatter.schema.json +28 -63
  169. package/schemas/manifest.json +4 -2
  170. package/schemas/page-theme.schema.json +192 -0
  171. package/schemas/sitewide-content.schema.json +58 -132
  172. package/schemas/theme.schema.json +434 -152
  173. package/scripts/check-config.mjs +8 -6
  174. package/scripts/deploy-site.mjs +6 -8
  175. package/scripts/doctor.mjs +2 -2
  176. package/scripts/generate-images.mjs +15 -29
  177. package/scripts/generate-schemas.mjs +7 -218
  178. package/scripts/lib/base-path-redirect.mjs +9 -0
  179. package/scripts/lib/editor-language-service.mjs +125 -79
  180. package/scripts/lib/example-sites.mjs +15 -3
  181. package/scripts/lib/heading-ids.mjs +161 -0
  182. package/scripts/lib/navigation-model.mjs +51 -0
  183. package/scripts/lib/norna-markdown-blocks.mjs +3 -4
  184. package/scripts/lib/page-model.mjs +102 -0
  185. package/scripts/lib/presentation.mjs +25 -17
  186. package/scripts/lib/project-config.mjs +46 -8
  187. package/scripts/lib/schema-definitions.mjs +78 -55
  188. package/scripts/lib/schema-editor-metadata.mjs +519 -0
  189. package/scripts/lib/schema-value-definitions.mjs +20 -6
  190. package/scripts/lib/site-content.mjs +159 -97
  191. package/scripts/lib/site-conventions.mjs +1 -0
  192. package/scripts/lib/site-paths.mjs +11 -5
  193. package/scripts/lib/theme-config.mjs +12 -18
  194. package/scripts/lib/theme-presets.mjs +55 -14
  195. package/scripts/release.mjs +1 -1
  196. package/scripts/show-typography.mjs +4 -30
  197. package/scripts/sync-content-sections.mjs +107 -68
  198. package/scripts/{test-temporary-visibility.mjs → test-banner-visibility.mjs} +8 -25
  199. package/scripts/test-client-javascript.mjs +50 -46
  200. package/scripts/test-content-check.mjs +153 -69
  201. package/scripts/test-content-model-v2.mjs +566 -285
  202. package/scripts/test-documentation.mjs +10 -3
  203. package/scripts/test-editor-language-service.mjs +172 -25
  204. package/scripts/test-engine-commands.mjs +6 -5
  205. package/scripts/test-examples.mjs +30 -1
  206. package/scripts/test-heading-ids.mjs +68 -0
  207. package/scripts/test-navigation-model.mjs +63 -0
  208. package/scripts/test-navigation.mjs +11 -2
  209. package/scripts/test-nested-pages.mjs +125 -0
  210. package/scripts/test-package-check.mjs +55 -95
  211. package/scripts/test-page-model.mjs +108 -0
  212. package/scripts/test-project-config.mjs +22 -3
  213. package/scripts/test-schemas.mjs +82 -15
  214. package/scripts/test-theme-presets.mjs +57 -42
  215. package/src/components/NavigationPageTree.astro +157 -0
  216. package/src/components/PageContentsLinks.astro +40 -0
  217. package/src/components/SectionNavigationScript.astro +117 -5
  218. package/src/components/SiteBreadcrumbs.astro +32 -0
  219. package/src/components/SiteNavigation.astro +97 -68
  220. package/src/components/SitePage.astro +93 -55
  221. package/src/components/SiteSection.astro +29 -27
  222. package/src/components/SiteTreeNavigation.astro +35 -0
  223. package/src/components/TreeNavigationScript.astro +83 -0
  224. package/src/content.config.ts +8 -10
  225. package/src/layouts/BaseLayout.astro +21 -20
  226. package/src/lib/pageThemes.ts +44 -0
  227. package/src/lib/sectionContent.ts +106 -107
  228. package/src/lib/siteNavigation.ts +49 -0
  229. package/src/lib/sitePages.ts +96 -38
  230. package/src/pages/{[slug].astro → [...slug].astro} +2 -2
  231. package/src/pages/index.astro +2 -1
  232. package/src/styles/global.css +743 -57
  233. package/starters/basic/README.md +9 -11
  234. package/starters/basic/site/{content.md → pages/000-home/content.md} +7 -4
  235. package/starters/basic/site/sitewide-content.yaml +1 -10
  236. package/starters/basic/site/theme.yaml +1 -105
  237. package/starters/project/README.md +14 -14
  238. package/starters/project/site/{content.md → pages/000-home/content.md} +5 -4
  239. package/starters/project/site/{routes → pages}/010-guide/content.md +5 -4
  240. package/starters/project/site/sitewide-content.yaml +1 -10
  241. package/starters/project/site/theme.yaml +1 -31
  242. package/docs/routes.md +0 -121
  243. package/examples/feature-demos/media-and-surfaces/site/routes/020-surfaces/theme.yaml +0 -3
  244. package/examples/feature-demos/sitewide-content/site/content.md +0 -16
  245. package/examples/feature-demos/sitewide-content/site/routes/010-identity/content.md +0 -20
  246. package/examples/feature-demos/theme-presets/README.md +0 -18
  247. package/examples/feature-demos/theme-presets/site/.norna/generated-images.json +0 -290
  248. package/examples/feature-demos/theme-presets/site/content.md +0 -17
  249. package/examples/feature-demos/theme-presets/site/sitewide-content.yaml +0 -12
  250. package/examples/feature-demos/theme-presets/site/theme.yaml +0 -1
  251. package/fixtures/content-model-v2/site/routes/010-guide/content.md +0 -17
  252. package/scripts/lib/route-model.mjs +0 -17
  253. package/scripts/test-route-model.mjs +0 -32
  254. package/src/lib/routeThemes.ts +0 -41
  255. /package/examples/complete-sites/dog-shelter-multi-page/site/{images/intro → pages/000-home/images}/shelter-dog.jpg +0 -0
  256. /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rex.jpg +0 -0
  257. /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rover.jpg +0 -0
  258. /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/020-adopt/images/adopt → pages/020-adopt/images}/adoption-dog.jpg +0 -0
  259. /package/examples/complete-sites/dog-shelter-single-page/site/{images/you-can-help → pages/000-home/images}/foster-dog.jpg +0 -0
  260. /package/examples/complete-sites/dog-shelter-single-page/site/{images/what-we-do → pages/000-home/images}/rescue-dog.jpg +0 -0
  261. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-carousel.svg +0 -0
  262. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-stack.svg +0 -0
  263. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-surfaces.svg +0 -0
  264. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-one.svg +0 -0
  265. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-three.svg +0 -0
  266. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-two.svg +0 -0
  267. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-one.svg +0 -0
  268. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-two.svg +0 -0
  269. /package/examples/feature-demos/{theme-presets → theme-preset-documentation}/site/config.yaml +0 -0
  270. /package/examples/feature-demos/{theme-presets/site/routes/020-documentation/images/documentation → theme-preset-documentation/site/pages/000-home/images}/black-schnauzer.jpg +0 -0
  271. /package/examples/feature-demos/{theme-presets/site/routes/020-documentation/images/documentation → theme-preset-documentation/site/pages/000-home/images}/retriever-portrait.jpg +0 -0
  272. /package/examples/feature-demos/{theme-presets/site/routes/020-documentation/images/documentation → theme-preset-documentation/site/pages/000-home/images}/schnauzer-portrait.jpg +0 -0
  273. /package/examples/feature-demos/{theme-presets → theme-preset-documentation}/site/public/robots.txt +0 -0
  274. /package/examples/feature-demos/{theme-presets/site/routes/020-documentation → theme-preset-documentation/site}/theme.yaml +0 -0
  275. /package/examples/feature-demos/{theme-presets/site/routes/010-portfolio/images/portfolio → theme-preset-portfolio/site/pages/000-home/images}/puppy-portrait.jpg +0 -0
  276. /package/examples/feature-demos/{theme-presets/site/routes/010-portfolio/images/portfolio → theme-preset-portfolio/site/pages/000-home/images}/shepherd-portrait.jpg +0 -0
  277. /package/examples/feature-demos/{theme-presets/site/routes/010-portfolio/images/portfolio → theme-preset-portfolio/site/pages/000-home/images}/white-puppy.jpg +0 -0
  278. /package/examples/feature-demos/{theme-presets/site/routes/010-portfolio → theme-preset-portfolio/site}/theme.yaml +0 -0
  279. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/collections/routeTheme.schema.json +0 -0
  280. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/collections/site.schema.json +0 -0
  281. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/collections/sitewide.schema.json +0 -0
  282. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/collections/theme.schema.json +0 -0
  283. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/content-assets.mjs +0 -0
  284. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/content-modules.mjs +0 -0
  285. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/content.d.ts +0 -0
  286. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/data-store.json +0 -0
  287. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/dev-local.json +0 -0
  288. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/dev.json +0 -0
  289. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/dev.log +0 -0
  290. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/settings.json +0 -0
  291. /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/types.d.ts +0 -0
  292. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/_metadata.json +0 -0
  293. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -0
  294. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -0
  295. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_aria-query.js +0 -0
  296. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -0
  297. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_axobject-query.js +0 -0
  298. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -0
  299. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_html-escaper.js +0 -0
  300. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -0
  301. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -0
  302. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -0
  303. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -0
  304. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -0
  305. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/embla-carousel.js +0 -0
  306. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/embla-carousel.js.map +0 -0
  307. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -0
  308. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -0
  309. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/icons-RyebKi45.js +0 -0
  310. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -0
  311. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/package.json +0 -0
  312. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -0
  313. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -0
  314. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -0
  315. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/toolbar-63PA619H.js +0 -0
  316. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -0
  317. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -0
  318. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -0
  319. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/window-jPkpKVcy.js +0 -0
  320. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -0
  321. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -0
  322. /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -0
  323. /package/examples/feature-demos/{theme-presets/site/routes/030-project/images/project → theme-preset-project/site/pages/000-home/images}/boxer-portrait.jpg +0 -0
  324. /package/examples/feature-demos/{theme-presets/site/routes/030-project/images/project → theme-preset-project/site/pages/000-home/images}/grass-puppy.jpg +0 -0
  325. /package/examples/feature-demos/{theme-presets/site/routes/030-project/images/project → theme-preset-project/site/pages/000-home/images}/grey-street-dog.jpg +0 -0
  326. /package/examples/feature-demos/{theme-presets/site/routes/030-project → theme-preset-project/site}/theme.yaml +0 -0
  327. /package/examples/feature-demos/{theme-presets/site/routes/040-statement/images/statement → theme-preset-statement/site/pages/000-home/images}/black-pedigree.jpg +0 -0
  328. /package/examples/feature-demos/{theme-presets/site/routes/040-statement/images/statement → theme-preset-statement/site/pages/000-home/images}/sheepdog-grass.jpg +0 -0
  329. /package/examples/feature-demos/{theme-presets/site/routes/040-statement/images/statement → theme-preset-statement/site/pages/000-home/images}/sheepdog-wide.jpg +0 -0
  330. /package/examples/feature-demos/{theme-presets/site/routes/040-statement → theme-preset-statement/site}/theme.yaml +0 -0
  331. /package/fixtures/basic/site/{images/work → pages/000-home/images}/.gitkeep +0 -0
  332. /package/fixtures/content-model-v2/site/{images/card-section → pages/000-home/images}/adopt.svg +0 -0
  333. /package/fixtures/content-model-v2/site/{images/intro → pages/000-home/images}/detail.jpg +0 -0
  334. /package/fixtures/content-model-v2/site/{images/intro → pages/000-home/images}/duplicate.jpg +0 -0
  335. /package/fixtures/content-model-v2/site/{images/card-section → pages/000-home/images}/foster.svg +0 -0
  336. /package/fixtures/content-model-v2/site/{images/intro → pages/000-home/images}/hero.jpg +0 -0
  337. /package/fixtures/content-model-v2/site/{images/plain → pages/000-home/images}/image.jpg +0 -0
  338. /package/fixtures/content-model-v2/site/{images/timed → pages/000-home/images}/slide-one.jpg +0 -0
  339. /package/fixtures/content-model-v2/site/{images/timed → pages/000-home/images}/slide-three.jpg +0 -0
  340. /package/fixtures/content-model-v2/site/{images/timed → pages/000-home/images}/slide-two.jpg +0 -0
  341. /package/fixtures/content-model-v2/site/{routes/010-guide/images/intro → pages/010-guide/images}/duplicate.jpg +0 -0
  342. /package/starters/basic/site/{images/work → pages/000-home/images}/.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/).
@@ -52,17 +52,23 @@ site/
52
52
  |-- config.yaml
53
53
  |-- theme.yaml
54
54
  |-- sitewide-content.yaml
55
- |-- content.md
56
- |-- images/
57
- |-- routes/
55
+ |-- pages/
56
+ | |-- 000-home/
57
+ | | |-- content.md
58
+ | | `-- images/
59
+ | `-- 010-guide/
60
+ | |-- content.md
61
+ | `-- pages/
62
+ | `-- 010-installation/
58
63
  `-- public/
59
64
  ```
60
65
 
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.
66
+ - `pages/000-home/content.md` is the required homepage at `/`.
67
+ - Other top-level directories under `pages/` are global navigation roots.
68
+ - A page may contain local images, limited presentation settings, and nested
69
+ child pages under its own `pages/` directory.
64
70
  - `theme.yaml` normally selects one complete visual preset.
65
- - `sitewide-content.yaml` holds shared identity, banners, and footer content.
71
+ - `sitewide-content.yaml` holds shared logo display settings, banners, and footer content.
66
72
  - `config.yaml` holds the public URL and optional language and scroll behavior.
67
73
  - `public/` holds static files copied without processing.
68
74
 
@@ -89,7 +95,10 @@ documentation.
89
95
  | --- | --- | --- |
90
96
  | Dog shelter, single page | [Open demo](https://janga.github.io/norna/examples/complete-sites/dog-shelter-single-page/) | [View files](examples/complete-sites/dog-shelter-single-page/) |
91
97
  | Dog shelter, multi-page | [Open demo](https://janga.github.io/norna/examples/complete-sites/dog-shelter-multi-page/) | [View files](examples/complete-sites/dog-shelter-multi-page/) |
92
- | Theme presets | [Open demo](https://janga.github.io/norna/examples/feature-demos/theme-presets/) | [View files](examples/feature-demos/theme-presets/) |
98
+ | Portfolio preset | [Open demo](https://janga.github.io/norna/examples/feature-demos/theme-preset-portfolio/) | [View files](examples/feature-demos/theme-preset-portfolio/) |
99
+ | Documentation preset | [Open demo](https://janga.github.io/norna/examples/feature-demos/theme-preset-documentation/) | [View files](examples/feature-demos/theme-preset-documentation/) |
100
+ | Project preset | [Open demo](https://janga.github.io/norna/examples/feature-demos/theme-preset-project/) | [View files](examples/feature-demos/theme-preset-project/) |
101
+ | Statement preset | [Open demo](https://janga.github.io/norna/examples/feature-demos/theme-preset-statement/) | [View files](examples/feature-demos/theme-preset-statement/) |
93
102
  | Media and surfaces | [Open demo](https://janga.github.io/norna/examples/feature-demos/media-and-surfaces/) | [View files](examples/feature-demos/media-and-surfaces/) |
94
103
  | Sitewide content | [Open demo](https://janga.github.io/norna/examples/feature-demos/sitewide-content/) | [View files](examples/feature-demos/sitewide-content/) |
95
104
 
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/bin/norna-cli.mjs CHANGED
@@ -16,7 +16,7 @@ Commands:
16
16
  dev:stop Stop local dev server
17
17
  check Validate configuration and content
18
18
  config:check Validate site/config.yaml
19
- content:check Validate site/content.md and image references
19
+ content:check Validate page content and managed image references
20
20
  content:sync Move misplaced Norna-managed images and refresh generated images
21
21
  theme:presets List available theme presets and their intended uses
22
22
  theme:export Export a commented theme preset reference
package/docs/README.md CHANGED
@@ -27,9 +27,12 @@ site/
27
27
  |-- config.yaml
28
28
  |-- theme.yaml
29
29
  |-- sitewide-content.yaml
30
- |-- content.md
31
- |-- images/
32
- |-- routes/
30
+ |-- pages/
31
+ | |-- 000-home/
32
+ | | |-- content.md
33
+ | | `-- images/
34
+ | `-- 010-guide/
35
+ | `-- content.md
33
36
  `-- public/
34
37
  ```
35
38
 
@@ -37,14 +40,13 @@ site/
37
40
  scroll behavior.
38
41
  - [`theme.yaml`](theme.md): complete visual presets and focused presentation
39
42
  overrides.
40
- - [`sitewide-content.yaml`](sitewide-content.md): shared navigation identity,
43
+ - [`sitewide-content.yaml`](sitewide-content.md): shared logo display settings,
41
44
  banners, and footer.
42
- - [`content.md`](content.md): page metadata, sections, prose, notes, and Norna
43
- blocks.
44
- - [`images/`](images-and-metadata.md): managed source formats, variants, sync,
45
- and generated image state.
46
- - [`routes/`](routes.md): additional pages, ordering, URLs, route themes, and
47
- route-local images.
45
+ - [`pages/`](pages.md): Home, top-level areas, nested pages, ordering, and URLs.
46
+ - [`content.md`](content.md): the content file inside every page directory,
47
+ containing its title, optional metadata, sections, prose, notes, and blocks.
48
+ - [`images/`](images-and-metadata.md): managed images kept inside the page that
49
+ references them, plus variants, sync, and generated image state.
48
50
  - [`public/`](public-files.md): navigation logos, favicons, and other static
49
51
  files copied without managed-image processing.
50
52
  - [Generated files](site-files.md#generated-files): `site/.norna/public/`,
@@ -67,7 +69,7 @@ required, optional, convention-discovered, versioned, or generated.
67
69
  - [Write page sections](content.md#sections)
68
70
  - [Use image stacks, carousels, and cards](content.md#norna-blocks)
69
71
  - [Add notes to prose](content.md#markdown-text)
70
- - [Add another page](routes.md)
72
+ - [Add another page](pages.md)
71
73
  - [Add shared banners or footer content](sitewide-content.md)
72
74
 
73
75
  ### Work With Images And Public Assets
@@ -75,14 +77,14 @@ required, optional, convention-discovered, versioned, or generated.
75
77
  - [Add managed source images](images-and-metadata.md#managed-source-images)
76
78
  - [Check and sync moved image references](content.md#validation-and-sync)
77
79
  - [Add a navigation logo](public-files.md#navigation-logo)
78
- - [Add favicons](public-files.md#logos-and-favicons)
80
+ - [Add browser icons](public-files.md#browser-icons)
79
81
  - [Add other static files](public-files.md#other-static-files)
80
82
 
81
83
  ### Change Presentation
82
84
 
83
85
  - [Choose a complete theme preset](theme.md#theme-presets)
84
86
  - [Inspect and override a preset](theme.md#overrides)
85
- - [Give a route a different theme](theme.md#route-themes)
87
+ - [Adjust limited presentation for a page subtree](theme.md#page-themes)
86
88
  - [Adjust typography](typography.md)
87
89
 
88
90
  ### Check, Build, And Publish
@@ -95,7 +97,7 @@ required, optional, convention-discovered, versioned, or generated.
95
97
  ## Concepts And Explanation
96
98
 
97
99
  - [Norna's site model](https://janga.github.io/norna/concepts/) explains how
98
- files, sections, images, and routes become a website.
100
+ files, sections, images, and pages become a website.
99
101
  - [Images and Metadata](images-and-metadata.md) explains managed variants and
100
102
  published URLs.
101
103
  - [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.
@@ -13,7 +13,7 @@ url: https://example.com/
13
13
  Norna deliberately keeps this file small. Visual choices belong in
14
14
  [`theme.yaml`](theme.md), shared editorial content belongs in
15
15
  [`sitewide-content.yaml`](sitewide-content.md), and page content belongs in
16
- [`content.md`](content.md).
16
+ [`pages/*/content.md`](content.md).
17
17
 
18
18
  ## `url`
19
19
 
@@ -58,6 +58,26 @@ would be misleading.
58
58
  Interface labels are part of the engine and are not configured individually.
59
59
  Editorial text remains in page content and `sitewide-content.yaml`.
60
60
 
61
+ ## `navigation`
62
+
63
+ `navigation.mode` selects the site-wide navigation model:
64
+
65
+ - `automatic`: choose from the discovered page and heading structure. This is
66
+ the default.
67
+ - `sections`: navigate headings on a single page.
68
+ - `top`: use the sticky top navigation for a shallow multi-page site.
69
+ - `tree`: combine global top-level navigation with a local page hierarchy.
70
+
71
+ ```yaml
72
+ url: https://example.com/
73
+ navigation:
74
+ mode: automatic
75
+ ```
76
+
77
+ Navigation behavior is technical and site-wide. It cannot be configured in
78
+ `theme.yaml` or in an individual page. See [Pages](pages.md#navigation) for the
79
+ relationship between Home, top-level pages, child pages, and headings.
80
+
61
81
  ## `scrollBehavior`
62
82
 
63
83
  - Purpose: select native same-page anchor movement.
@@ -80,6 +100,8 @@ requests reduced motion always get immediate anchor movement.
80
100
  ```yaml
81
101
  url: https://example.com/
82
102
  language: en-GB
103
+ navigation:
104
+ mode: automatic
83
105
  scrollBehavior: instant
84
106
  ```
85
107
 
@@ -110,7 +132,8 @@ norna --site-dir presentation build
110
132
 
111
133
  If `NORNA_SITE_DIR` is set to an empty value, commands fail. Relative site
112
134
  directories are resolved by walking upward from the invocation directory until
113
- the selected directory contains `config.yaml` and `content.md`.
135
+ the selected directory contains `config.yaml` and
136
+ `pages/000-home/content.md`.
114
137
 
115
138
  Without an explicit selection, the current directory itself can be the site
116
139
  directory when it contains those two files. Otherwise Norna walks upward for a
package/docs/content.md CHANGED
@@ -1,36 +1,63 @@
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/pages/000-home/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 and nested pages use the same page model in a page directory under
7
+ `site/pages/`. See [Pages](pages.md) for the directory and nesting rules.
9
8
 
10
9
  Site-wide visual defaults belong in [Theme](theme.md). Typography profiles and
11
10
  overrides are described in [Typography](typography.md). Technical site settings
12
11
  belong in [Configuration](configuration.md).
13
12
 
14
- ## Page Frontmatter
13
+ ## Page Title And Frontmatter
15
14
 
16
- The Astro content schema validates these top-level fields in page files:
15
+ Every page must contain exactly one Markdown H1. It must be the first heading,
16
+ must not have a section id, and supplies the visible page title, HTML document
17
+ title, and page label in site navigation:
17
18
 
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.
19
+ ```md
20
+ # My Site
21
+ ```
22
+
23
+ Content between the H1 and the first H2 is the page introduction. It may
24
+ contain prose and Norna blocks.
25
+
26
+ Frontmatter is optional. When present, the content schema validates these
27
+ top-level fields:
28
+
29
+ - `page`: optional page metadata.
30
+ - `navigation`: optional page-listing metadata. See [Pages](pages.md).
31
+
32
+ `page` contains:
33
+
34
+ - `description`: optional string. Used only as the page's HTML meta description
35
+ for search engines, link previews, and other metadata consumers. It is not
36
+ rendered as visible page content.
37
+
38
+ Minimal homepage without metadata:
39
+
40
+ ```md
41
+ # My Site
42
+
43
+ Introductory text.
44
+
45
+ ## Work {#work}
46
+
47
+ Text...
48
+ ```
22
49
 
23
- Minimal homepage:
50
+ Homepage with a meta description:
24
51
 
25
52
  ```md
26
53
  ---
27
- title: My Site
28
- description: A small Norna site.
54
+ page:
55
+ description: A small Norna site.
29
56
  ---
30
57
 
31
- ## Intro {#intro}
58
+ # My Site
32
59
 
33
- Text...
60
+ Introductory text.
34
61
  ```
35
62
 
36
63
  ## Sections
@@ -51,44 +78,29 @@ Markdown level 2 headings define the page sections and their order:
51
78
  ...
52
79
  ```
53
80
 
54
- Every section heading must have an explicit id:
81
+ Norna derives a stable lowercase id from the heading text when no explicit id
82
+ is present:
55
83
 
56
84
  ```md
57
- ## Work {#work}
58
- ```
59
-
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.
63
-
64
- Markdown section content starts at the level 2 heading and continues until the
65
- next level 2 heading. `###` and `####` headings are body subheadings within the
66
- current section, not new sections.
67
-
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"
85
+ ## Work
79
86
  ```
80
87
 
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:
88
+ Add an explicit id when a public anchor must remain stable even if the heading
89
+ text changes:
85
90
 
86
91
  ```md
87
92
  ## Work {#work}
88
93
  ```
89
94
 
90
- Do not list sections in frontmatter just to define order. Section order comes
91
- from the Markdown heading order.
95
+ Explicit ids must match `^[a-z0-9-]+$`. Derived and explicit ids are used for
96
+ anchors and section navigation; the visible label still comes from the heading
97
+ text. H3 headings use the same derivation for deeper local navigation. If two
98
+ headings on one page resolve to the same id, `content:check` reports the page
99
+ and both headings instead of guessing.
100
+
101
+ Markdown section content starts at the level 2 heading and continues until the
102
+ next level 2 heading. `###` and `####` headings are body subheadings within the
103
+ current section, not new sections.
92
104
 
93
105
  ## Norna Blocks
94
106
 
@@ -97,6 +109,8 @@ the point where they should appear in the section. Markdown determines
97
109
  placement: move the fenced block in the page file to move the rendered image,
98
110
  carousel, or card list.
99
111
 
112
+ ### Image Stack
113
+
100
114
  Use `norna-image-stack` for one or more stacked images:
101
115
 
102
116
  ````md
@@ -107,6 +121,8 @@ Use `norna-image-stack` for one or more stacked images:
107
121
  ```
108
122
  ````
109
123
 
124
+ ### Image Carousel
125
+
110
126
  Use `norna-image-carousel` for a carousel:
111
127
 
112
128
  ````md
@@ -120,6 +136,8 @@ Use `norna-image-carousel` for a carousel:
120
136
  ```
121
137
  ````
122
138
 
139
+ ### Card List
140
+
123
141
  Use `norna-card-list` for a list of compact cards. Cards can include text,
124
142
  managed images, links, and optional badge text:
125
143
 
@@ -198,13 +216,13 @@ sizing is less predictable.
198
216
  Homepage images live under:
199
217
 
200
218
  ```text
201
- site/images/<section-id>/
219
+ site/pages/000-home/images/
202
220
  ```
203
221
 
204
- Route images live under:
222
+ Images for any page live directly under that page directory. For example:
205
223
 
206
224
  ```text
207
- site/routes/<NNN-route-id>/images/<section-id>/
225
+ site/pages/010-guide/pages/020-installation/images/
208
226
  ```
209
227
 
210
228
  Image references in Norna managed image blocks use only the filename:
@@ -215,13 +233,15 @@ Image references in Norna managed image blocks use only the filename:
215
233
  ```
216
234
  ````
217
235
 
218
- If `portrait.jpg` is referenced from `## Team {#team}`, the expected homepage
219
- location is `site/images/team/portrait.jpg`.
236
+ If `portrait.jpg` is referenced anywhere on the homepage, its expected
237
+ location is `site/pages/000-home/images/portrait.jpg`. The same file may be referenced from
238
+ more than one section on that page.
220
239
 
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.
240
+ Filenames must be unique within one page's image directory, but do not have to
241
+ be globally unique across the site. Automatic sync only moves files between
242
+ page image roots when the filename identifies exactly one source candidate
243
+ across the site. If more than one candidate exists, Norna reports the
244
+ ambiguity instead of guessing.
225
245
 
226
246
  ## Markdown Images
227
247
 
@@ -237,36 +257,6 @@ managed by Norna. Use `norna-image-stack`, `norna-image-carousel`, or
237
257
  `norna-card-list` for local site images that should be validated, processed and
238
258
  synced.
239
259
 
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
260
  ## Markdown Text
271
261
 
272
262
  Use ordinary Markdown for emphasis and structure:
@@ -277,7 +267,7 @@ This sentence contains **important text** and *emphasised text*.
277
267
 
278
268
  Norna intentionally does not support arbitrary inline color or style classes.
279
269
  Deprecated syntax such as `[highlighted text]{.yellow}` is rejected by
280
- `content:check`. Keep the route visually coherent through its `theme.yaml`
270
+ `content:check`. Keep the page visually coherent through its `theme.yaml`
281
271
  instead of styling individual phrases.
282
272
 
283
273
  ### Side Notes
@@ -315,7 +305,7 @@ Run:
315
305
  npm run norna:content:check
316
306
  ```
317
307
 
318
- This checks section heading ids, section metadata, duplicate image names,
308
+ This checks section heading ids, duplicate image names,
319
309
  missing image files, misplaced referenced images, duplicate image references,
320
310
  invalid Norna blocks, unreferenced images, removed inline style syntax,
321
311
  Markdown image references to unmanaged local files, and common frontmatter
@@ -327,15 +317,12 @@ invalid, when a key is indented under a line that already has a value, or when a
327
317
  known nested key appears at the top level:
328
318
 
329
319
  ```yaml
330
- sections:
331
- intro:
332
- visible:
333
- from: "2026-08-01"
320
+ navigation:
321
+ listed: false
334
322
  ```
335
323
 
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`.
324
+ Top-level page frontmatter may contain only `page` and `navigation`. Visual
325
+ settings belong in the root or page-local `theme.yaml`.
339
326
 
340
327
  Run:
341
328
 
@@ -343,20 +330,22 @@ Run:
343
330
  npm run norna:sync
344
331
  ```
345
332
 
346
- This moves referenced image files into the section directory shown by the
347
- Markdown placement. It prompts before writing unless `--yes` is passed.
333
+ This moves referenced image files into the image directory for the page that
334
+ references them. Moving a block between sections on the same page does not
335
+ move the file because all sections share the page image directory. The command
336
+ prompts before writing unless `--yes` is passed.
348
337
 
349
338
  `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.
339
+ filename identifies exactly one matching source candidate across all page
340
+ image roots, and when the move will not break another reference.
352
341
  If the intended move is ambiguous, rename or move the file manually and run
353
342
  `content:check` again.
354
343
 
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.
344
+ The same filename may exist in different page image directories. Automatic
345
+ relocation only requires site-wide filename uniqueness for the file being
346
+ moved.
358
347
 
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
348
+ When `content:sync` needs to move an image between the homepage and a page, or
349
+ between two pages, the Git working tree must be clean before the write. This
350
+ keeps cross-page sync easy to roll back. `content:check` only reports issues
362
351
  and does not require a clean working tree.