@janga/norna 0.7.17 → 0.7.22

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 (533) hide show
  1. package/README.md +32 -13
  2. package/astro.config.mjs +22 -0
  3. package/bin/norna-cli.mjs +7 -1
  4. package/package.json +46 -12
  5. package/schemas/category.schema.json +20 -0
  6. package/schemas/config.schema.json +55 -4
  7. package/schemas/content-frontmatter.schema.json +5 -5
  8. package/schemas/manifest.json +4 -2
  9. package/schemas/page-theme.schema.json +192 -0
  10. package/schemas/sitewide-content.schema.json +18 -18
  11. package/schemas/theme.schema.json +364 -226
  12. package/scripts/add-site-node.mjs +251 -0
  13. package/scripts/check-config.mjs +12 -3
  14. package/scripts/deploy-site.mjs +6 -9
  15. package/scripts/generate-images.mjs +18 -29
  16. package/scripts/generate-schemas.mjs +7 -1
  17. package/scripts/init-site.mjs +35 -0
  18. package/scripts/lib/astro-command.mjs +14 -9
  19. package/scripts/lib/editor-language-service.mjs +28 -191
  20. package/scripts/lib/heading-ids.mjs +3 -1
  21. package/scripts/lib/navigation-model.mjs +23 -17
  22. package/scripts/lib/norna-markdown-blocks.mjs +64 -145
  23. package/scripts/lib/norna-markdown-render-plugin.mjs +37 -0
  24. package/scripts/lib/object.mjs +28 -0
  25. package/scripts/lib/page-markdown.mjs +282 -0
  26. package/scripts/lib/page-model.mjs +26 -7
  27. package/scripts/lib/presentation-contract.mjs +266 -0
  28. package/scripts/lib/presentation-palette-metadata.mjs +51 -0
  29. package/scripts/lib/presentation.mjs +548 -93
  30. package/scripts/lib/project-config.mjs +73 -16
  31. package/scripts/lib/schema-definitions.mjs +89 -21
  32. package/scripts/lib/schema-editor-metadata.mjs +166 -33
  33. package/scripts/lib/schema-value-definitions.mjs +32 -4
  34. package/scripts/lib/site-content.mjs +33 -223
  35. package/scripts/lib/site-conventions.mjs +1 -0
  36. package/scripts/lib/site-paths.mjs +11 -6
  37. package/scripts/lib/site-structure.mjs +189 -0
  38. package/scripts/lib/theme-config.mjs +3 -2
  39. package/scripts/lib/theme-presets.mjs +105 -101
  40. package/scripts/lib/theme-profiles.mjs +221 -0
  41. package/scripts/lib/typography.mjs +220 -35
  42. package/scripts/lib/yaml-config.mjs +46 -6
  43. package/scripts/lib/yaml-indentation.mjs +86 -0
  44. package/scripts/show-typography.mjs +3 -36
  45. package/scripts/sync-content-sections.mjs +88 -79
  46. package/src/components/DisplaySettings.astro +107 -0
  47. package/src/components/ImageCarousel.astro +34 -13
  48. package/src/components/NavigationPageTree.astro +154 -34
  49. package/src/components/PageContentsLinks.astro +40 -0
  50. package/src/components/SectionNavigationScript.astro +68 -7
  51. package/src/components/SiteBreadcrumbs.astro +24 -18
  52. package/src/components/SiteNavigation.astro +130 -46
  53. package/src/components/SitePage.astro +65 -55
  54. package/src/components/SiteSection.astro +37 -198
  55. package/src/components/SiteTreeNavigation.astro +36 -0
  56. package/src/components/TreeNavigationScript.astro +83 -0
  57. package/src/content.config.ts +2 -8
  58. package/src/layouts/BaseLayout.astro +52 -2
  59. package/src/lib/generatedImages.ts +0 -7
  60. package/src/lib/pageThemes.ts +11 -9
  61. package/src/lib/readerPreferencesScript.mjs +141 -0
  62. package/src/lib/sectionContent.ts +120 -206
  63. package/src/lib/siteNavigation.ts +38 -19
  64. package/src/lib/sitePages.ts +115 -33
  65. package/src/pages/[...slug].astro +2 -2
  66. package/src/pages/index.astro +2 -1
  67. package/src/styles/global.css +1110 -279
  68. package/starters/basic/README.md +8 -8
  69. package/starters/basic/site/theme.yaml +1 -105
  70. package/docs/README.md +0 -135
  71. package/docs/assets/norna-dog-shelter.jpg +0 -0
  72. package/docs/commands.md +0 -189
  73. package/docs/configuration.md +0 -119
  74. package/docs/content.md +0 -342
  75. package/docs/design/command-organization.md +0 -414
  76. package/docs/design/navigation-and-theme-plan.md +0 -115
  77. package/docs/design/norna-diagram-design.md +0 -159
  78. package/docs/design/site-examples-structure.md +0 -115
  79. package/docs/engine-development.md +0 -218
  80. package/docs/getting-started.md +0 -206
  81. package/docs/how-to/embedded-site.md +0 -35
  82. package/docs/images-and-metadata.md +0 -186
  83. package/docs/local-development.md +0 -82
  84. package/docs/pages.md +0 -134
  85. package/docs/public-files.md +0 -118
  86. package/docs/publishing.md +0 -117
  87. package/docs/requirements.md +0 -54
  88. package/docs/site-files.md +0 -145
  89. package/docs/sitewide-content.md +0 -73
  90. package/docs/theme.md +0 -271
  91. package/docs/typography.md +0 -180
  92. package/examples/README.md +0 -43
  93. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/site.schema.json +0 -35
  94. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/sitewide.schema.json +0 -97
  95. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/theme.schema.json +0 -852
  96. package/examples/complete-sites/dog-shelter-multi-page/.astro/content-assets.mjs +0 -4
  97. package/examples/complete-sites/dog-shelter-multi-page/.astro/content-modules.mjs +0 -1
  98. package/examples/complete-sites/dog-shelter-multi-page/.astro/content.d.ts +0 -183
  99. package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +0 -1
  100. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev-local.json +0 -8
  101. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.json +0 -13
  102. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +0 -36
  103. package/examples/complete-sites/dog-shelter-multi-page/.astro/settings.json +0 -5
  104. package/examples/complete-sites/dog-shelter-multi-page/.astro/types.d.ts +0 -2
  105. package/examples/complete-sites/dog-shelter-multi-page/README.md +0 -24
  106. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/_metadata.json +0 -74
  107. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro-B3JHJyiv.js +0 -434
  108. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro-B3JHJyiv.js.map +0 -1
  109. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  110. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  111. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  112. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  113. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  114. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  115. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  116. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  117. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/audit-C3SVr7dT.js +0 -1534
  118. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/audit-C3SVr7dT.js.map +0 -1
  119. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/highlight-BLtvqtzO.js +0 -48
  120. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +0 -1
  121. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/icons-C92i61-2.js +0 -42
  122. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/icons-C92i61-2.js.map +0 -1
  123. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/package.json +0 -3
  124. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  125. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/settings-v5GgKks_.js +0 -190
  126. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/settings-v5GgKks_.js.map +0 -1
  127. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/toolbar-BFvJVp26.js +0 -458
  128. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +0 -1
  129. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js +0 -1016
  130. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +0 -1
  131. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/window-vo3A6TMn.js +0 -32
  132. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/window-vo3A6TMn.js.map +0 -1
  133. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/xray-DwhzGckb.js +0 -111
  134. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/xray-DwhzGckb.js.map +0 -1
  135. package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +0 -98
  136. package/examples/complete-sites/dog-shelter-multi-page/site/config.yaml +0 -1
  137. package/examples/complete-sites/dog-shelter-multi-page/site/content.md +0 -23
  138. package/examples/complete-sites/dog-shelter-multi-page/site/images/shelter-dog.jpg +0 -0
  139. package/examples/complete-sites/dog-shelter-multi-page/site/pages/010-dogs/content.md +0 -21
  140. package/examples/complete-sites/dog-shelter-multi-page/site/pages/010-dogs/images/rex.jpg +0 -0
  141. package/examples/complete-sites/dog-shelter-multi-page/site/pages/010-dogs/images/rover.jpg +0 -0
  142. package/examples/complete-sites/dog-shelter-multi-page/site/pages/020-adopt/content.md +0 -22
  143. package/examples/complete-sites/dog-shelter-multi-page/site/pages/020-adopt/images/adoption-dog.jpg +0 -0
  144. package/examples/complete-sites/dog-shelter-multi-page/site/public/favicon.svg +0 -10
  145. package/examples/complete-sites/dog-shelter-multi-page/site/public/logo.svg +0 -9
  146. package/examples/complete-sites/dog-shelter-multi-page/site/public/robots.txt +0 -2
  147. package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.yaml +0 -4
  148. package/examples/complete-sites/dog-shelter-multi-page/site/theme.yaml +0 -1
  149. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/site.schema.json +0 -35
  150. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/sitewide.schema.json +0 -97
  151. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/theme.schema.json +0 -852
  152. package/examples/complete-sites/dog-shelter-single-page/.astro/content-assets.mjs +0 -4
  153. package/examples/complete-sites/dog-shelter-single-page/.astro/content-modules.mjs +0 -1
  154. package/examples/complete-sites/dog-shelter-single-page/.astro/content.d.ts +0 -183
  155. package/examples/complete-sites/dog-shelter-single-page/.astro/data-store.json +0 -1
  156. package/examples/complete-sites/dog-shelter-single-page/.astro/dev-local.json +0 -8
  157. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.json +0 -13
  158. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.log +0 -18
  159. package/examples/complete-sites/dog-shelter-single-page/.astro/settings.json +0 -5
  160. package/examples/complete-sites/dog-shelter-single-page/.astro/types.d.ts +0 -2
  161. package/examples/complete-sites/dog-shelter-single-page/README.md +0 -24
  162. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/_metadata.json +0 -74
  163. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro-B3JHJyiv.js +0 -434
  164. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro-B3JHJyiv.js.map +0 -1
  165. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  166. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  167. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  168. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  169. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  170. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  171. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  172. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  173. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/audit-C3SVr7dT.js +0 -1534
  174. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/audit-C3SVr7dT.js.map +0 -1
  175. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/highlight-BLtvqtzO.js +0 -48
  176. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +0 -1
  177. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/icons-C92i61-2.js +0 -42
  178. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/icons-C92i61-2.js.map +0 -1
  179. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/package.json +0 -3
  180. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  181. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/settings-v5GgKks_.js +0 -190
  182. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/settings-v5GgKks_.js.map +0 -1
  183. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/toolbar-BFvJVp26.js +0 -458
  184. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +0 -1
  185. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js +0 -1016
  186. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +0 -1
  187. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/window-vo3A6TMn.js +0 -32
  188. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/window-vo3A6TMn.js.map +0 -1
  189. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/xray-DwhzGckb.js +0 -111
  190. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/xray-DwhzGckb.js.map +0 -1
  191. package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +0 -50
  192. package/examples/complete-sites/dog-shelter-single-page/site/config.yaml +0 -1
  193. package/examples/complete-sites/dog-shelter-single-page/site/content.md +0 -37
  194. package/examples/complete-sites/dog-shelter-single-page/site/images/foster-dog.jpg +0 -0
  195. package/examples/complete-sites/dog-shelter-single-page/site/images/rescue-dog.jpg +0 -0
  196. package/examples/complete-sites/dog-shelter-single-page/site/public/favicon.svg +0 -10
  197. package/examples/complete-sites/dog-shelter-single-page/site/public/logo.svg +0 -9
  198. package/examples/complete-sites/dog-shelter-single-page/site/public/robots.txt +0 -2
  199. package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.yaml +0 -4
  200. package/examples/complete-sites/dog-shelter-single-page/site/theme.yaml +0 -1
  201. package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +0 -35
  202. package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +0 -97
  203. package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +0 -852
  204. package/examples/feature-demos/media-and-surfaces/.astro/content-assets.mjs +0 -4
  205. package/examples/feature-demos/media-and-surfaces/.astro/content-modules.mjs +0 -1
  206. package/examples/feature-demos/media-and-surfaces/.astro/content.d.ts +0 -183
  207. package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +0 -1
  208. package/examples/feature-demos/media-and-surfaces/.astro/dev.log +0 -14
  209. package/examples/feature-demos/media-and-surfaces/.astro/settings.json +0 -5
  210. package/examples/feature-demos/media-and-surfaces/.astro/types.d.ts +0 -2
  211. package/examples/feature-demos/media-and-surfaces/README.md +0 -21
  212. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +0 -80
  213. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js +0 -434
  214. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js.map +0 -1
  215. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  216. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  217. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  218. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  219. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  220. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  221. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  222. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  223. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js +0 -1534
  224. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js.map +0 -1
  225. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/embla-carousel.js +0 -1389
  226. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/embla-carousel.js.map +0 -1
  227. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js +0 -48
  228. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +0 -1
  229. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js +0 -42
  230. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js.map +0 -1
  231. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/package.json +0 -3
  232. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  233. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js +0 -190
  234. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js.map +0 -1
  235. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js +0 -458
  236. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +0 -1
  237. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js +0 -1016
  238. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +0 -1
  239. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js +0 -32
  240. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js.map +0 -1
  241. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js +0 -111
  242. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js.map +0 -1
  243. package/examples/feature-demos/media-and-surfaces/site/.norna/generated-images.json +0 -66
  244. package/examples/feature-demos/media-and-surfaces/site/config.yaml +0 -1
  245. package/examples/feature-demos/media-and-surfaces/site/content.md +0 -15
  246. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/content.md +0 -71
  247. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/card-carousel.svg +0 -11
  248. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/card-stack.svg +0 -9
  249. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/card-surfaces.svg +0 -8
  250. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/carousel-one.svg +0 -8
  251. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/carousel-three.svg +0 -13
  252. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/carousel-two.svg +0 -8
  253. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/stack-one.svg +0 -8
  254. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/stack-two.svg +0 -9
  255. package/examples/feature-demos/media-and-surfaces/site/pages/020-surfaces/content.md +0 -41
  256. package/examples/feature-demos/media-and-surfaces/site/pages/020-surfaces/theme.yaml +0 -3
  257. package/examples/feature-demos/media-and-surfaces/site/public/robots.txt +0 -2
  258. package/examples/feature-demos/media-and-surfaces/site/sitewide-content.yaml +0 -2
  259. package/examples/feature-demos/media-and-surfaces/site/theme.yaml +0 -1
  260. package/examples/feature-demos/sitewide-content/.astro/collections/site.schema.json +0 -59
  261. package/examples/feature-demos/sitewide-content/.astro/collections/sitewide.schema.json +0 -138
  262. package/examples/feature-demos/sitewide-content/.astro/collections/theme.schema.json +0 -755
  263. package/examples/feature-demos/sitewide-content/.astro/content-assets.mjs +0 -1
  264. package/examples/feature-demos/sitewide-content/.astro/content-modules.mjs +0 -1
  265. package/examples/feature-demos/sitewide-content/.astro/content.d.ts +0 -183
  266. package/examples/feature-demos/sitewide-content/.astro/data-store.json +0 -1
  267. package/examples/feature-demos/sitewide-content/.astro/dev.json +0 -13
  268. package/examples/feature-demos/sitewide-content/.astro/dev.log +0 -18
  269. package/examples/feature-demos/sitewide-content/.astro/settings.json +0 -5
  270. package/examples/feature-demos/sitewide-content/.astro/types.d.ts +0 -2
  271. package/examples/feature-demos/sitewide-content/README.md +0 -26
  272. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/_metadata.json +0 -74
  273. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro-B3JHJyiv.js +0 -434
  274. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro-B3JHJyiv.js.map +0 -1
  275. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  276. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  277. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  278. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  279. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  280. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  281. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  282. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  283. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/audit-C3SVr7dT.js +0 -1534
  284. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/audit-C3SVr7dT.js.map +0 -1
  285. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/highlight-BLtvqtzO.js +0 -48
  286. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +0 -1
  287. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/icons-C92i61-2.js +0 -42
  288. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/icons-C92i61-2.js.map +0 -1
  289. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/package.json +0 -3
  290. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  291. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/settings-v5GgKks_.js +0 -190
  292. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/settings-v5GgKks_.js.map +0 -1
  293. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/toolbar-BFvJVp26.js +0 -458
  294. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +0 -1
  295. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/ui-library-Cd35oAvo.js +0 -1016
  296. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +0 -1
  297. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/window-vo3A6TMn.js +0 -32
  298. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/window-vo3A6TMn.js.map +0 -1
  299. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/xray-DwhzGckb.js +0 -111
  300. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/xray-DwhzGckb.js.map +0 -1
  301. package/examples/feature-demos/sitewide-content/site/.norna/generated-images.json +0 -1
  302. package/examples/feature-demos/sitewide-content/site/config.yaml +0 -1
  303. package/examples/feature-demos/sitewide-content/site/content.md +0 -17
  304. package/examples/feature-demos/sitewide-content/site/pages/010-logo-and-navigation/content.md +0 -17
  305. package/examples/feature-demos/sitewide-content/site/pages/020-notices/content.md +0 -23
  306. package/examples/feature-demos/sitewide-content/site/pages/030-footer/content.md +0 -18
  307. package/examples/feature-demos/sitewide-content/site/public/logo.svg +0 -6
  308. package/examples/feature-demos/sitewide-content/site/public/robots.txt +0 -2
  309. package/examples/feature-demos/sitewide-content/site/sitewide-content.yaml +0 -14
  310. package/examples/feature-demos/sitewide-content/site/theme.yaml +0 -1
  311. package/examples/feature-demos/theme-presets/.astro/collections/routeTheme.schema.json +0 -746
  312. package/examples/feature-demos/theme-presets/.astro/collections/site.schema.json +0 -59
  313. package/examples/feature-demos/theme-presets/.astro/collections/sitewide.schema.json +0 -138
  314. package/examples/feature-demos/theme-presets/.astro/collections/theme.schema.json +0 -755
  315. package/examples/feature-demos/theme-presets/.astro/content-assets.mjs +0 -4
  316. package/examples/feature-demos/theme-presets/.astro/content-modules.mjs +0 -1
  317. package/examples/feature-demos/theme-presets/.astro/content.d.ts +0 -183
  318. package/examples/feature-demos/theme-presets/.astro/data-store.json +0 -1
  319. package/examples/feature-demos/theme-presets/.astro/dev-local.json +0 -8
  320. package/examples/feature-demos/theme-presets/.astro/dev.json +0 -15
  321. package/examples/feature-demos/theme-presets/.astro/dev.log +0 -164
  322. package/examples/feature-demos/theme-presets/.astro/settings.json +0 -5
  323. package/examples/feature-demos/theme-presets/.astro/types.d.ts +0 -2
  324. package/examples/feature-demos/theme-presets/README.md +0 -18
  325. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/_metadata.json +0 -80
  326. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -434
  327. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -1
  328. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  329. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  330. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  331. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  332. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  333. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  334. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  335. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  336. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -1534
  337. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -1
  338. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/embla-carousel.js +0 -1389
  339. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/embla-carousel.js.map +0 -1
  340. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -48
  341. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -1
  342. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/icons-RyebKi45.js +0 -42
  343. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -1
  344. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/package.json +0 -3
  345. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  346. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -190
  347. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -1
  348. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/toolbar-63PA619H.js +0 -458
  349. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -1
  350. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -1016
  351. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -1
  352. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/window-jPkpKVcy.js +0 -32
  353. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -1
  354. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -111
  355. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -1
  356. package/examples/feature-demos/theme-presets/site/.norna/generated-images.json +0 -290
  357. package/examples/feature-demos/theme-presets/site/config.yaml +0 -1
  358. package/examples/feature-demos/theme-presets/site/content.md +0 -14
  359. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/content.md +0 -31
  360. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/images/puppy-portrait.jpg +0 -0
  361. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/images/shepherd-portrait.jpg +0 -0
  362. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/images/white-puppy.jpg +0 -0
  363. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/theme.yaml +0 -1
  364. package/examples/feature-demos/theme-presets/site/pages/020-documentation/content.md +0 -30
  365. package/examples/feature-demos/theme-presets/site/pages/020-documentation/images/black-schnauzer.jpg +0 -0
  366. package/examples/feature-demos/theme-presets/site/pages/020-documentation/images/retriever-portrait.jpg +0 -0
  367. package/examples/feature-demos/theme-presets/site/pages/020-documentation/images/schnauzer-portrait.jpg +0 -0
  368. package/examples/feature-demos/theme-presets/site/pages/020-documentation/theme.yaml +0 -1
  369. package/examples/feature-demos/theme-presets/site/pages/030-project/content.md +0 -31
  370. package/examples/feature-demos/theme-presets/site/pages/030-project/images/boxer-portrait.jpg +0 -0
  371. package/examples/feature-demos/theme-presets/site/pages/030-project/images/grass-puppy.jpg +0 -0
  372. package/examples/feature-demos/theme-presets/site/pages/030-project/images/grey-street-dog.jpg +0 -0
  373. package/examples/feature-demos/theme-presets/site/pages/030-project/theme.yaml +0 -1
  374. package/examples/feature-demos/theme-presets/site/pages/040-statement/content.md +0 -31
  375. package/examples/feature-demos/theme-presets/site/pages/040-statement/images/black-pedigree.jpg +0 -0
  376. package/examples/feature-demos/theme-presets/site/pages/040-statement/images/sheepdog-grass.jpg +0 -0
  377. package/examples/feature-demos/theme-presets/site/pages/040-statement/images/sheepdog-wide.jpg +0 -0
  378. package/examples/feature-demos/theme-presets/site/pages/040-statement/theme.yaml +0 -1
  379. package/examples/feature-demos/theme-presets/site/public/robots.txt +0 -2
  380. package/examples/feature-demos/theme-presets/site/sitewide-content.yaml +0 -3
  381. package/examples/feature-demos/theme-presets/site/theme.yaml +0 -1
  382. package/fixtures/basic/site/.norna/generated-images.json +0 -1
  383. package/fixtures/basic/site/config.yaml +0 -1
  384. package/fixtures/basic/site/content.md +0 -14
  385. package/fixtures/basic/site/public/robots.txt +0 -2
  386. package/fixtures/basic/site/sitewide-content.yaml +0 -3
  387. package/fixtures/basic/site/theme.yaml +0 -8
  388. package/fixtures/content-model-v2/.astro/collections/site.schema.json +0 -776
  389. package/fixtures/content-model-v2/.astro/collections/theme.schema.json +0 -668
  390. package/fixtures/content-model-v2/.astro/content-assets.mjs +0 -4
  391. package/fixtures/content-model-v2/.astro/content-modules.mjs +0 -1
  392. package/fixtures/content-model-v2/.astro/content.d.ts +0 -175
  393. package/fixtures/content-model-v2/.astro/data-store.json +0 -1
  394. package/fixtures/content-model-v2/.astro/dev-local.json +0 -8
  395. package/fixtures/content-model-v2/.astro/dev.json +0 -13
  396. package/fixtures/content-model-v2/.astro/dev.log +0 -231
  397. package/fixtures/content-model-v2/.astro/settings.json +0 -5
  398. package/fixtures/content-model-v2/.astro/types.d.ts +0 -2
  399. package/fixtures/content-model-v2/dist/_astro/GalleryGrid.astro_astro_type_script_index_0_lang.B0kxDyGz.js +0 -1
  400. package/fixtures/content-model-v2/dist/_astro/SitePage.BbfZub4g.css +0 -1
  401. package/fixtures/content-model-v2/dist/guide/index.html +0 -3
  402. package/fixtures/content-model-v2/dist/images/generated/intro/detail-27930b14-480.webp +0 -0
  403. package/fixtures/content-model-v2/dist/images/generated/intro/detail-27930b14-768.webp +0 -0
  404. package/fixtures/content-model-v2/dist/images/generated/intro/detail-27930b14-971.webp +0 -0
  405. package/fixtures/content-model-v2/dist/images/generated/intro/duplicate-49c98f6c-480.webp +0 -0
  406. package/fixtures/content-model-v2/dist/images/generated/intro/duplicate-49c98f6c-768.webp +0 -0
  407. package/fixtures/content-model-v2/dist/images/generated/intro/duplicate-49c98f6c-971.webp +0 -0
  408. package/fixtures/content-model-v2/dist/images/generated/intro/hero-6d588a83-480.webp +0 -0
  409. package/fixtures/content-model-v2/dist/images/generated/intro/hero-6d588a83-768.webp +0 -0
  410. package/fixtures/content-model-v2/dist/images/generated/intro/hero-6d588a83-971.webp +0 -0
  411. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-1080.webp +0 -0
  412. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-1440.webp +0 -0
  413. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-1600.webp +0 -0
  414. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-480.webp +0 -0
  415. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-768.webp +0 -0
  416. package/fixtures/content-model-v2/dist/images/generated/routes/010-guide/images/intro/duplicate-5cf614d2-480.webp +0 -0
  417. package/fixtures/content-model-v2/dist/images/generated/routes/010-guide/images/intro/duplicate-5cf614d2-768.webp +0 -0
  418. package/fixtures/content-model-v2/dist/images/generated/routes/010-guide/images/intro/duplicate-5cf614d2-960.webp +0 -0
  419. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-1080.webp +0 -0
  420. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-1440.webp +0 -0
  421. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-1600.webp +0 -0
  422. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-480.webp +0 -0
  423. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-768.webp +0 -0
  424. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-1080.webp +0 -0
  425. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-1440.webp +0 -0
  426. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-1600.webp +0 -0
  427. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-480.webp +0 -0
  428. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-768.webp +0 -0
  429. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-1080.webp +0 -0
  430. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-1440.webp +0 -0
  431. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-1600.webp +0 -0
  432. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-480.webp +0 -0
  433. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-768.webp +0 -0
  434. package/fixtures/content-model-v2/dist/index.html +0 -8
  435. package/fixtures/content-model-v2/node_modules/.vite/deps/_metadata.json +0 -80
  436. package/fixtures/content-model-v2/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -434
  437. package/fixtures/content-model-v2/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -1
  438. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  439. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  440. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  441. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  442. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  443. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  444. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  445. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  446. package/fixtures/content-model-v2/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -1534
  447. package/fixtures/content-model-v2/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -1
  448. package/fixtures/content-model-v2/node_modules/.vite/deps/embla-carousel.js +0 -1389
  449. package/fixtures/content-model-v2/node_modules/.vite/deps/embla-carousel.js.map +0 -1
  450. package/fixtures/content-model-v2/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -48
  451. package/fixtures/content-model-v2/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -1
  452. package/fixtures/content-model-v2/node_modules/.vite/deps/icons-RyebKi45.js +0 -42
  453. package/fixtures/content-model-v2/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -1
  454. package/fixtures/content-model-v2/node_modules/.vite/deps/package.json +0 -3
  455. package/fixtures/content-model-v2/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  456. package/fixtures/content-model-v2/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -190
  457. package/fixtures/content-model-v2/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -1
  458. package/fixtures/content-model-v2/node_modules/.vite/deps/toolbar-63PA619H.js +0 -458
  459. package/fixtures/content-model-v2/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -1
  460. package/fixtures/content-model-v2/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -1016
  461. package/fixtures/content-model-v2/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -1
  462. package/fixtures/content-model-v2/node_modules/.vite/deps/window-jPkpKVcy.js +0 -32
  463. package/fixtures/content-model-v2/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -1
  464. package/fixtures/content-model-v2/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -111
  465. package/fixtures/content-model-v2/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -1
  466. package/fixtures/content-model-v2/site/.norna/generated-images.json +0 -210
  467. package/fixtures/content-model-v2/site/config.yaml +0 -1
  468. package/fixtures/content-model-v2/site/content.md +0 -79
  469. package/fixtures/content-model-v2/site/images/adopt.svg +0 -9
  470. package/fixtures/content-model-v2/site/images/detail.jpg +0 -0
  471. package/fixtures/content-model-v2/site/images/duplicate.jpg +0 -0
  472. package/fixtures/content-model-v2/site/images/foster.svg +0 -12
  473. package/fixtures/content-model-v2/site/images/hero.jpg +0 -0
  474. package/fixtures/content-model-v2/site/images/image.jpg +0 -0
  475. package/fixtures/content-model-v2/site/images/slide-one.jpg +0 -0
  476. package/fixtures/content-model-v2/site/images/slide-three.jpg +0 -0
  477. package/fixtures/content-model-v2/site/images/slide-two.jpg +0 -0
  478. package/fixtures/content-model-v2/site/pages/010-guide/content.md +0 -18
  479. package/fixtures/content-model-v2/site/pages/010-guide/images/duplicate.jpg +0 -0
  480. package/fixtures/content-model-v2/site/theme.yaml +0 -4
  481. package/fixtures/nested-pages/site/.norna/generated-images.json +0 -10
  482. package/fixtures/nested-pages/site/config.yaml +0 -1
  483. package/fixtures/nested-pages/site/content.md +0 -15
  484. package/fixtures/nested-pages/site/pages/010-guides/content.md +0 -15
  485. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/content.md +0 -21
  486. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/images/diagram.svg +0 -21
  487. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/pages/010-macos/content.md +0 -14
  488. package/fixtures/nested-pages/site/pages/010-guides/pages/020-workflows/content.md +0 -11
  489. package/fixtures/nested-pages/site/pages/010-guides/theme.yaml +0 -3
  490. package/fixtures/nested-pages/site/pages/020-reference/content.md +0 -10
  491. package/fixtures/nested-pages/site/pages/020-reference/pages/010-installation/content.md +0 -11
  492. package/fixtures/nested-pages/site/theme.yaml +0 -3
  493. package/scripts/build-pages.mjs +0 -69
  494. package/scripts/lib/example-sites.mjs +0 -37
  495. package/scripts/lib/frontmatter-yaml.mjs +0 -113
  496. package/scripts/lib/git-status.mjs +0 -7
  497. package/scripts/release.mjs +0 -153
  498. package/scripts/test-banner-visibility.mjs +0 -80
  499. package/scripts/test-ci-lockfile.mjs +0 -65
  500. package/scripts/test-cli-discovery.mjs +0 -124
  501. package/scripts/test-client-javascript.mjs +0 -218
  502. package/scripts/test-content-check.mjs +0 -621
  503. package/scripts/test-content-model-v2.mjs +0 -1629
  504. package/scripts/test-documentation.mjs +0 -187
  505. package/scripts/test-editor-language-service.mjs +0 -302
  506. package/scripts/test-engine-commands.mjs +0 -204
  507. package/scripts/test-examples.mjs +0 -24
  508. package/scripts/test-heading-ids.mjs +0 -68
  509. package/scripts/test-navigation-model.mjs +0 -63
  510. package/scripts/test-navigation-preview.mjs +0 -108
  511. package/scripts/test-navigation.mjs +0 -148
  512. package/scripts/test-nested-pages.mjs +0 -110
  513. package/scripts/test-package-check.mjs +0 -531
  514. package/scripts/test-page-model.mjs +0 -80
  515. package/scripts/test-project-config.mjs +0 -144
  516. package/scripts/test-schemas.mjs +0 -154
  517. package/scripts/test-site-public.mjs +0 -85
  518. package/scripts/test-theme-presets.mjs +0 -182
  519. package/src/components/SiteNotesScript.astro +0 -43
  520. package/starters/basic/site/images/.gitkeep +0 -1
  521. package/starters/project/.github/workflows/deploy.yml +0 -64
  522. package/starters/project/README.md +0 -84
  523. package/starters/project/package-lock.json +0 -4296
  524. package/starters/project/package.json +0 -37
  525. package/starters/project/site/config.yaml +0 -1
  526. package/starters/project/site/content.md +0 -119
  527. package/starters/project/site/pages/010-guide/content.md +0 -80
  528. package/starters/project/site/public/robots.txt +0 -2
  529. package/starters/project/site/sitewide-content.yaml +0 -3
  530. package/starters/project/site/theme.yaml +0 -31
  531. package/tsconfig.json +0 -5
  532. /package/starters/basic/site/{content.md → pages/000-home/content.md} +0 -0
  533. /package/{fixtures/basic/site → starters/basic/site/pages/000-home}/images/.gitkeep +0 -0
@@ -0,0 +1,251 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdir, realpath, rename, rm, rmdir, stat, writeFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { dump as dumpYaml } from 'js-yaml';
5
+ import { slugifyAsciiIdentifier } from './lib/heading-ids.mjs';
6
+ import { pageDirectoryPattern } from './lib/page-model.mjs';
7
+ import {
8
+ invocationRoot,
9
+ siteDir,
10
+ sitePagesDir,
11
+ siteProjectRoot,
12
+ } from './lib/site-paths.mjs';
13
+ import { getSiteStructure } from './lib/site-structure.mjs';
14
+
15
+ const usage = `
16
+ Usage:
17
+ norna page:add <title> [--parent <path>] [--slug <slug>] [--order <NNN>] [--dry-run]
18
+ norna category:add <label> [--parent <path>] [--slug <slug>] [--order <NNN>] [--dry-run]
19
+
20
+ Parent selection:
21
+ --parent / Add a top-level node
22
+ --parent /guides/ Add a child below the guides node
23
+ no --parent Use the current node directory, or site/pages/
24
+ `.trim();
25
+
26
+ const parseValueOption = (rawArgs, index, name) => {
27
+ const arg = rawArgs[index];
28
+ if (arg === name) {
29
+ const value = rawArgs[index + 1];
30
+ if (!value || value.startsWith('-')) throw new Error(`${name} requires a value.\n${usage}`);
31
+ return { consumed: 2, value };
32
+ }
33
+ if (arg.startsWith(`${name}=`)) {
34
+ const value = arg.slice(name.length + 1);
35
+ if (!value) throw new Error(`${name} requires a value.\n${usage}`);
36
+ return { consumed: 1, value };
37
+ }
38
+ return null;
39
+ };
40
+
41
+ const parseArgs = (rawArgs) => {
42
+ const options = {
43
+ dryRun: false,
44
+ help: false,
45
+ order: null,
46
+ parent: null,
47
+ slug: null,
48
+ titleParts: [],
49
+ };
50
+ const seen = new Set();
51
+
52
+ for (let index = 0; index < rawArgs.length;) {
53
+ const arg = rawArgs[index];
54
+ if (arg === '-h' || arg === '--help') {
55
+ options.help = true;
56
+ index += 1;
57
+ continue;
58
+ }
59
+ if (arg === '--dry-run') {
60
+ if (seen.has('dryRun')) throw new Error(`--dry-run may be specified only once.\n${usage}`);
61
+ seen.add('dryRun');
62
+ options.dryRun = true;
63
+ index += 1;
64
+ continue;
65
+ }
66
+
67
+ let matched = false;
68
+ for (const [name, key] of [['--order', 'order'], ['--parent', 'parent'], ['--slug', 'slug']]) {
69
+ const parsed = parseValueOption(rawArgs, index, name);
70
+ if (!parsed) continue;
71
+ if (seen.has(key)) throw new Error(`${name} may be specified only once.\n${usage}`);
72
+ seen.add(key);
73
+ options[key] = parsed.value;
74
+ index += parsed.consumed;
75
+ matched = true;
76
+ break;
77
+ }
78
+ if (matched) continue;
79
+
80
+ if (arg.startsWith('-')) throw new Error(`Unknown option: ${arg}\n${usage}`);
81
+ options.titleParts.push(arg);
82
+ index += 1;
83
+ }
84
+
85
+ return options;
86
+ };
87
+
88
+ const parseOrder = (value) => {
89
+ if (!/^\d{1,3}$/.test(value)) {
90
+ throw new Error(`Invalid --order "${value}". Use an integer from 1 to 999.`);
91
+ }
92
+ const order = Number.parseInt(value, 10);
93
+ if (order < 1 || order > 999) {
94
+ throw new Error(`Invalid --order "${value}". Use an integer from 1 to 999.`);
95
+ }
96
+ return order;
97
+ };
98
+
99
+ const normalizeParentPath = (value) => {
100
+ if (value === '/') return '';
101
+ if (value.includes('\\') || value.includes('?') || value.includes('#')) {
102
+ throw new Error(`Invalid --parent "${value}". Use a logical path such as /guides/installation/.`);
103
+ }
104
+ const normalized = value.replace(/^\/+|\/+$/g, '');
105
+ if (!normalized || normalized.split('/').some((segment) => !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(segment))) {
106
+ throw new Error(`Invalid --parent "${value}". Use / for the top level or a logical path such as /guides/installation/.`);
107
+ }
108
+ return normalized;
109
+ };
110
+
111
+ const getNextOrder = (siblings) => {
112
+ const highestOrder = siblings.reduce((highest, node) => Math.max(highest, node.pageOrder), 0);
113
+ const nextOrder = Math.floor(highestOrder / 10) * 10 + 10;
114
+ if (nextOrder > 999) {
115
+ throw new Error('No automatic page order remains below 1000. Reorder the sibling nodes before adding another one.');
116
+ }
117
+ return nextOrder;
118
+ };
119
+
120
+ const toDisplayPath = (filePath) => {
121
+ const relativePath = path.relative(siteProjectRoot, filePath);
122
+ return (relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath)
123
+ ? relativePath
124
+ : filePath).split(path.sep).join('/');
125
+ };
126
+
127
+ const escapeMarkdownHeading = (value) => value.replace(/([\\`*_[\]{}<>#])/g, '\\$1');
128
+
129
+ const canonicalDirectory = async (directory) => realpath(directory).catch((error) => {
130
+ if (error?.code === 'ENOENT') return path.resolve(directory);
131
+ throw error;
132
+ });
133
+
134
+ const resolveParent = async ({ nodes, parent }) => {
135
+ if (parent !== null) {
136
+ const parentPath = normalizeParentPath(parent);
137
+ if (!parentPath) {
138
+ return { collectionDir: sitePagesDir, node: null, pagePath: '' };
139
+ }
140
+ const node = nodes.find((candidate) => candidate.pagePath === parentPath);
141
+ if (!node) {
142
+ throw new Error(`Cannot find parent "${parent}". Use an existing logical page/category path, or / for the top level.`);
143
+ }
144
+ if (node.isHome) throw new Error('The homepage cannot contain child pages or categories.');
145
+ return { collectionDir: path.join(node.nodeDir, 'pages'), node, pagePath: node.pagePath };
146
+ }
147
+
148
+ const currentDirectory = await canonicalDirectory(invocationRoot);
149
+ if (currentDirectory === await canonicalDirectory(sitePagesDir)) {
150
+ return { collectionDir: sitePagesDir, node: null, pagePath: '' };
151
+ }
152
+ let node = null;
153
+ for (const candidate of nodes) {
154
+ if (await canonicalDirectory(candidate.nodeDir) === currentDirectory) {
155
+ node = candidate;
156
+ break;
157
+ }
158
+ }
159
+ if (!node) {
160
+ throw new Error([
161
+ 'Cannot infer where to add the node from the current directory.',
162
+ `Run the command from ${toDisplayPath(sitePagesDir)} for a top-level node, from an existing page/category directory for a child, or pass --parent.`,
163
+ ].join('\n'));
164
+ }
165
+ if (node.isHome) throw new Error('The homepage cannot contain child pages or categories.');
166
+ return { collectionDir: path.join(node.nodeDir, 'pages'), node, pagePath: node.pagePath };
167
+ };
168
+
169
+ const assertCollectionDirectory = async (collectionDir) => {
170
+ try {
171
+ const info = await stat(collectionDir);
172
+ if (!info.isDirectory()) throw new Error(`${toDisplayPath(collectionDir)} exists but is not a directory.`);
173
+ return false;
174
+ } catch (error) {
175
+ if (error?.code !== 'ENOENT') throw error;
176
+ await mkdir(collectionDir);
177
+ return true;
178
+ }
179
+ };
180
+
181
+ const writeNode = async ({ destination, kind, title }) => {
182
+ const stagingRoot = path.join(siteDir, '.norna', 'create');
183
+ await mkdir(stagingRoot, { recursive: true });
184
+ const stagingDirectory = path.join(stagingRoot, `node-${process.pid}-${randomUUID()}`);
185
+ await mkdir(stagingDirectory);
186
+
187
+ try {
188
+ if (kind === 'page') {
189
+ await writeFile(path.join(stagingDirectory, 'content.md'), `# ${escapeMarkdownHeading(title)}\n\n## Introduction\n\nStart writing here.\n`);
190
+ await mkdir(path.join(stagingDirectory, 'images'));
191
+ } else {
192
+ await writeFile(path.join(stagingDirectory, 'category.yaml'), dumpYaml({ label: title }, {
193
+ lineWidth: -1,
194
+ noRefs: true,
195
+ }));
196
+ await mkdir(path.join(stagingDirectory, 'pages'));
197
+ }
198
+ await rename(stagingDirectory, destination);
199
+ } finally {
200
+ await rm(stagingDirectory, { force: true, recursive: true });
201
+ }
202
+ };
203
+
204
+ const [kind, ...rawArgs] = process.argv.slice(2);
205
+ if (!['category', 'page'].includes(kind)) throw new Error(usage);
206
+ const options = parseArgs(rawArgs);
207
+ if (options.help) {
208
+ console.log(usage);
209
+ process.exit(0);
210
+ }
211
+
212
+ const title = options.titleParts.join(' ').trim();
213
+ if (!title || /[\r\n]/.test(title)) throw new Error(`A one-line ${kind === 'page' ? 'page title' : 'category label'} is required.\n${usage}`);
214
+ const slug = options.slug ?? slugifyAsciiIdentifier(title);
215
+ if (!slug || !pageDirectoryPattern.test(`010-${slug}`)) {
216
+ throw new Error(`Invalid ${options.slug === null ? 'generated ' : ''}slug "${slug}". Use lowercase ASCII letters, numbers, and single hyphens; pass --slug when automatic transliteration is unsuitable.`);
217
+ }
218
+
219
+ const structure = await getSiteStructure();
220
+ const parent = await resolveParent({ nodes: structure.nodes, parent: options.parent });
221
+ const siblings = structure.nodes.filter((node) => node.parentPagePath === (parent.pagePath || null) && !node.isHome);
222
+ if (siblings.some((node) => node.pageId === slug)) {
223
+ throw new Error(`Cannot create "${slug}" below ${parent.pagePath ? `/${parent.pagePath}/` : '/'}. A sibling with that slug already exists.`);
224
+ }
225
+ const order = options.order === null ? getNextOrder(siblings) : parseOrder(options.order);
226
+ if (siblings.some((node) => node.pageOrder === order)) {
227
+ throw new Error(`Cannot use order ${String(order).padStart(3, '0')} below ${parent.pagePath ? `/${parent.pagePath}/` : '/'}. A sibling already uses it.`);
228
+ }
229
+
230
+ const directoryName = `${String(order).padStart(3, '0')}-${slug}`;
231
+ const destination = path.join(parent.collectionDir, directoryName);
232
+ const pagePath = [parent.pagePath, slug].filter(Boolean).join('/');
233
+ const action = options.dryRun ? 'Would create' : 'Created';
234
+
235
+ if (!options.dryRun) {
236
+ const createdCollection = await assertCollectionDirectory(parent.collectionDir);
237
+ try {
238
+ await writeNode({ destination, kind, title });
239
+ } catch (error) {
240
+ if (createdCollection) await rmdir(parent.collectionDir).catch(() => {});
241
+ throw error;
242
+ }
243
+ }
244
+
245
+ console.log(`${action} ${kind} "${title}" at ${toDisplayPath(destination)}.`);
246
+ if (kind === 'page') {
247
+ console.log(`URL: /${pagePath}/`);
248
+ } else {
249
+ console.log('This navigation category has no page or URL of its own.');
250
+ console.log(`Child URL prefix: /${pagePath}/`);
251
+ }
@@ -1,7 +1,8 @@
1
- import { siteConfigLabel, sitePublicLabel } from './lib/site-paths.mjs';
1
+ import { siteConfigLabel, sitePublicLabel, siteThemeLabel } from './lib/site-paths.mjs';
2
2
  import { getLogoAssets, getPublicAssetInspection } from './lib/logo-assets.mjs';
3
3
  import { logoAssetFilenames } from './lib/public-asset-conventions.mjs';
4
4
  import { readSitewideContent } from './lib/sitewide-content.mjs';
5
+ import { assertSectionBackgroundPatternCompatibility } from './lib/presentation.mjs';
5
6
  import { readThemeConfig, validatePageThemeFiles } from './lib/theme-config.mjs';
6
7
 
7
8
  const formatErrorMessage = (error) => {
@@ -16,7 +17,13 @@ try {
16
17
  const { projectConfig } = await import('./lib/project-config.mjs');
17
18
  const themeConfig = await readThemeConfig();
18
19
  const sitewideContent = await readSitewideContent();
19
- await validatePageThemeFiles();
20
+ const pageThemeFiles = await validatePageThemeFiles();
21
+ if (projectConfig.navigation.mode === 'tree') {
22
+ assertSectionBackgroundPatternCompatibility(themeConfig, siteThemeLabel, 'tree');
23
+ for (const pageThemeFile of pageThemeFiles) {
24
+ assertSectionBackgroundPatternCompatibility(pageThemeFile.config, pageThemeFile.label, 'tree');
25
+ }
26
+ }
20
27
  const logoAssets = getLogoAssets();
21
28
  const publicAssetInspection = getPublicAssetInspection();
22
29
  const logoAssetPaths = logoAssetFilenames.map((filename) => `${sitePublicLabel}/${filename}`);
@@ -45,13 +52,15 @@ try {
45
52
  console.log(`Theme preset: ${themeConfig.preset ?? '(none)'}`);
46
53
  console.log(`Page width: ${projectConfig.layout.pageWidth}`);
47
54
  console.log(`Gutter: desktop ${projectConfig.layout.gutter.desktop}, mobile ${projectConfig.layout.gutter.mobile}`);
48
- console.log(`Layout density: ${projectConfig.layout.density}`);
55
+ console.log(`Content spacing: ${projectConfig.layout.contentSpacing}`);
56
+ console.log(`Text width: ${projectConfig.layout.textWidth}`);
49
57
  console.log(`Image area width: ${projectConfig.images.width}`);
50
58
  console.log(`Image max available width: desktop ${projectConfig.images.maxAvailableWidthPercent.desktop}%, mobile ${projectConfig.images.maxAvailableWidthPercent.mobile}%`);
51
59
  console.log(`Image max available height: desktop ${projectConfig.images.maxAvailableHeightPercent.desktop}%, mobile ${projectConfig.images.maxAvailableHeightPercent.mobile}%`);
52
60
  console.log(`Font family: ${projectConfig.typography.fontFamily}`);
53
61
  console.log(`Language: ${projectConfig.locale.lang}`);
54
62
  console.log(`Navigation mode: ${projectConfig.navigation.mode}`);
63
+ console.log(`Section tracking: ${projectConfig.navigation.sectionTracking ? 'enabled' : 'disabled'}`);
55
64
  console.log(`Scroll behavior: ${projectConfig.navigation.scrollBehavior}`);
56
65
  } catch (error) {
57
66
  console.error('Config check failed.');
@@ -2,16 +2,12 @@ import { execFile, spawn } from 'node:child_process';
2
2
  import path from 'node:path';
3
3
  import { promisify } from 'node:util';
4
4
  import {
5
- getBodySections,
6
5
  getContentFiles,
7
6
  readSiteFile,
8
7
  supportedImageExtensions,
9
8
  toPosixPath,
10
9
  } from './lib/site-content.mjs';
11
- import {
12
- extractNornaMarkdownBlocks,
13
- getNornaBlockImageReferences,
14
- } from './lib/norna-markdown-blocks.mjs';
10
+ import { parsePageMarkdown } from './lib/page-markdown.mjs';
15
11
  import { getGitHubRepositoryContext, githubPagesWorkflow } from './lib/github-repository.mjs';
16
12
  import {
17
13
  engineRoot,
@@ -149,10 +145,11 @@ const getExpectedImagePaths = async () => {
149
145
 
150
146
  for (const contentFile of contentFiles) {
151
147
  const { body } = await readSiteFile(contentFile.contentPath, contentFile.contentLabel);
148
+ const page = await parsePageMarkdown(body, { label: contentFile.contentLabel });
152
149
 
153
- for (const section of (await getBodySections(body)).sections) {
154
- const blocks = extractNornaMarkdownBlocks(section.text, { label: contentFile.contentLabel });
155
- for (const { image } of getNornaBlockImageReferences(blocks)) {
150
+ for (const region of page.regions) {
151
+ if (region.blockErrors.length > 0) throw new Error(region.blockErrors[0].message);
152
+ for (const { image } of region.managedImages) {
156
153
  if (image.includes('/') || image.includes('\\')) continue;
157
154
  if (!supportedImageExtensions.has(path.extname(image).toLowerCase())) continue;
158
155
 
@@ -211,7 +208,7 @@ const assertDeployableStatus = async (entries, expectedImagePaths) => {
211
208
  if (unexpectedUntracked.length > 0) {
212
209
  fail([
213
210
  'Refusing to deploy: unexpected untracked files are present.',
214
- `Only new referenced images directly under ${siteImagesLabel}/ or ${sitePagesLabel}/<NNN-page-id>/images/ are staged automatically.`,
211
+ `Only new referenced images directly under a page's images/ directory in ${sitePagesLabel}/ are staged automatically.`,
215
212
  ...unexpectedUntracked.map((entry) => `- ${formatEntry(entry)}`),
216
213
  ].join('\n'));
217
214
  }
@@ -4,7 +4,6 @@ import { copyFile, mkdir, readdir, readFile, rm, stat, writeFile } from 'node:fs
4
4
  import path from 'node:path';
5
5
  import { promisify } from 'node:util';
6
6
  import {
7
- getBodySections,
8
7
  getContentFiles,
9
8
  readSiteFile,
10
9
  rasterImageExtensions,
@@ -13,17 +12,13 @@ import {
13
12
  toPosixPath,
14
13
  } from './lib/site-content.mjs';
15
14
  import { readImageDimensions } from './lib/image-dimensions.mjs';
16
- import {
17
- extractNornaMarkdownBlocks,
18
- getNornaBlockImageReferences,
19
- } from './lib/norna-markdown-blocks.mjs';
15
+ import { parsePageMarkdown } from './lib/page-markdown.mjs';
20
16
  import {
21
17
  astroPublicDir,
22
18
  generatedImagesDir,
23
19
  generatedImagesManifestPath,
24
20
  originalImagesDir,
25
21
  siteDir,
26
- siteImagesDir,
27
22
  } from './lib/site-paths.mjs';
28
23
 
29
24
  const execFileAsync = promisify(execFile);
@@ -88,10 +83,8 @@ const getFilePathFromPublicPath = (publicPath) => path.join(astroPublicDir, publ
88
83
 
89
84
  const getSourceHashSlug = (sourceHash) => sourceHash.slice(0, sourceHashSlugLength);
90
85
 
91
- const getGeneratedPath = (sourcePath, sourceHash, width) => {
92
- const parsed = path.parse(path.relative(siteImagesDir, sourcePath).startsWith('..')
93
- ? path.relative(path.dirname(siteImagesDir), sourcePath)
94
- : path.relative(siteImagesDir, sourcePath));
86
+ const getGeneratedPath = (sourceKey, sourceHash, width) => {
87
+ const parsed = path.parse(sourceKey);
95
88
  return path.join(generatedImagesDir, parsed.dir, `${parsed.name}-${getSourceHashSlug(sourceHash)}-${width}.webp`);
96
89
  };
97
90
 
@@ -104,26 +97,22 @@ const fail = (message) => {
104
97
  throw new Error(message);
105
98
  };
106
99
 
107
- const getImageSourceKey = (contentFile, image) => (
108
- contentFile.isHome
109
- ? `images/${image}`
110
- : `pages/${contentFile.pageDirectory}/images/${image}`
111
- );
100
+ const getImageSourceKey = (contentFile, image) => `pages/${contentFile.pageDirectory}/images/${image}`;
112
101
 
113
102
  const getReferencedImages = async (contentFile) => {
114
103
  const { body } = await readSiteFile(contentFile.contentPath, contentFile.contentLabel);
115
- const { sections } = await getBodySections(body);
104
+ const page = await parsePageMarkdown(body, { label: contentFile.contentLabel });
116
105
  const references = [];
117
106
 
118
- for (const section of sections) {
119
- const blocks = extractNornaMarkdownBlocks(section.text, { label: contentFile.contentLabel });
120
- for (const { image, line, blockDisplayType } of getNornaBlockImageReferences(blocks)) {
107
+ for (const region of page.regions) {
108
+ if (region.blockErrors.length > 0) throw new Error(region.blockErrors[0].message);
109
+ for (const { image, line, blockDisplayType } of region.managedImages) {
121
110
  references.push({
122
111
  contentFile,
123
112
  image,
124
113
  line,
125
114
  blockDisplayType,
126
- sectionLabel: section.id ?? 'page title',
115
+ sectionLabel: region.id ?? 'page title',
127
116
  sourceKey: getImageSourceKey(contentFile, image),
128
117
  });
129
118
  }
@@ -189,11 +178,11 @@ const validateCarouselOrientations = async (manifest) => {
189
178
 
190
179
  for (const contentFile of contentFiles) {
191
180
  const { body } = await readSiteFile(contentFile.contentPath, contentFile.contentLabel);
192
- const { sections } = await getBodySections(body);
181
+ const page = await parsePageMarkdown(body, { label: contentFile.contentLabel });
193
182
 
194
- for (const section of sections) {
195
- const blocks = extractNornaMarkdownBlocks(section.text, { label: contentFile.contentLabel });
196
- for (const block of blocks.filter((candidate) => candidate.type === 'image-carousel')) {
183
+ for (const region of page.regions) {
184
+ if (region.blockErrors.length > 0) throw new Error(region.blockErrors[0].message);
185
+ for (const block of region.blocks.filter((candidate) => candidate.type === 'image-carousel')) {
197
186
  const orientations = new Set(
198
187
  block.images
199
188
  .map((image) => manifest[getImageSourceKey(contentFile, image.image)])
@@ -205,7 +194,7 @@ const validateCarouselOrientations = async (manifest) => {
205
194
  orientations.delete('square');
206
195
  if (orientations.size > 1) {
207
196
  throw new Error(
208
- `Carousel in ${section.id ? `section "${section.id}"` : 'the page introduction'} on line ${block.line} mixes landscape and portrait images. Use landscape images with optional square images, or portrait images with optional square images.`,
197
+ `Carousel in ${region.id ? `section "${region.id}"` : 'the page introduction'} on line ${block.line} mixes landscape and portrait images. Use landscape images with optional square images, or portrait images with optional square images.`,
209
198
  );
210
199
  }
211
200
  }
@@ -241,8 +230,8 @@ const getVariantWidths = ({ width }) => {
241
230
  return variantWidths;
242
231
  };
243
232
 
244
- const getVariants = (sourcePath, sourceHash, variantWidths) => variantWidths.map((width) => ({
245
- src: getPublicPath(getGeneratedPath(sourcePath, sourceHash, width)),
233
+ const getVariants = (sourceKey, sourceHash, variantWidths) => variantWidths.map((width) => ({
234
+ src: getPublicPath(getGeneratedPath(sourceKey, sourceHash, width)),
246
235
  width,
247
236
  }));
248
237
 
@@ -417,9 +406,9 @@ for (const { sourcePath, sourceKey } of sources) {
417
406
 
418
407
  const dimensions = await identify(sourcePath);
419
408
  const variantWidths = getVariantWidths(dimensions);
420
- const variants = getVariants(sourcePath, sourceHash, variantWidths);
409
+ const variants = getVariants(sourceKey, sourceHash, variantWidths);
421
410
  for (const width of variantWidths) {
422
- const outputPath = getGeneratedPath(sourcePath, sourceHash, width);
411
+ const outputPath = getGeneratedPath(sourceKey, sourceHash, width);
423
412
  await convert(sourcePath, outputPath, width);
424
413
  }
425
414
 
@@ -3,7 +3,9 @@ import path from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { z } from 'astro/zod';
5
5
  import {
6
+ categorySchema,
6
7
  configSchema,
8
+ pageThemeSchema,
7
9
  siteSchema,
8
10
  sitewideSchema,
9
11
  themeVisualSchema,
@@ -13,8 +15,10 @@ import { applySchemaEditorMetadata } from './lib/schema-editor-metadata.mjs';
13
15
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
14
16
  const schemaDirectory = path.join(root, 'schemas');
15
17
  const definitions = [
18
+ ['category.schema.json', 'Norna page category', categorySchema],
16
19
  ['config.schema.json', 'Norna site configuration', configSchema],
17
20
  ['theme.schema.json', 'Norna visual theme', themeVisualSchema],
21
+ ['page-theme.schema.json', 'Norna page theme', pageThemeSchema],
18
22
  ['sitewide-content.schema.json', 'Norna site-wide content', sitewideSchema],
19
23
  ['content-frontmatter.schema.json', 'Norna page frontmatter', siteSchema],
20
24
  ];
@@ -30,12 +34,14 @@ for (const [filename, title, schema] of definitions) {
30
34
 
31
35
  schemaFiles.set('manifest.json', `${JSON.stringify({
32
36
  editorApiVersion: 1,
33
- schemaVersion: 1,
37
+ schemaVersion: 3,
34
38
  files: {
39
+ category: 'category.schema.json',
35
40
  config: 'config.schema.json',
36
41
  contentFrontmatter: 'content-frontmatter.schema.json',
37
42
  sitewideContent: 'sitewide-content.schema.json',
38
43
  theme: 'theme.schema.json',
44
+ pageTheme: 'page-theme.schema.json',
39
45
  },
40
46
  }, null, 2)}\n`);
41
47
 
@@ -9,6 +9,38 @@ import {
9
9
 
10
10
  const packageName = '@janga/norna';
11
11
  const cliExecutableName = 'norna';
12
+ const standaloneGitignore = `# build output
13
+ dist/
14
+
15
+ # legacy generated public output
16
+ /public/
17
+
18
+ # generated site state
19
+ **/.norna/public/
20
+ **/.norna/.astro/
21
+
22
+ # legacy Astro cache location
23
+ .astro/
24
+
25
+ # dependencies
26
+ node_modules/
27
+
28
+ # logs
29
+ npm-debug.log*
30
+ yarn-debug.log*
31
+ yarn-error.log*
32
+ pnpm-debug.log*
33
+
34
+ # environment variables
35
+ .env
36
+ .env.production
37
+
38
+ # macOS-specific files
39
+ .DS_Store
40
+ `;
41
+ const siteGitignore = `.norna/public/
42
+ .norna/.astro/
43
+ `;
12
44
 
13
45
  const usage = `
14
46
  Usage: norna init <target-dir> [--type standalone|embedded] [--site-dir <path>]
@@ -203,6 +235,8 @@ if (type === 'standalone') {
203
235
  if (siteDirectory !== 'site') targetPackageJson.scripts = {};
204
236
  addNornaScripts(targetPackageJson, nornaScripts, { includeStandaloneAliases: true });
205
237
  await writeFile(targetPackageJsonPath, `${JSON.stringify(targetPackageJson, null, 2)}\n`);
238
+ await writeFile(path.join(targetRoot, '.gitignore'), standaloneGitignore);
239
+ await writeFile(path.join(targetSiteDir, '.gitignore'), siteGitignore);
206
240
  } else {
207
241
  if (!existingEntries) {
208
242
  throw new Error(`Target directory must exist for --type embedded: ${targetRoot}`);
@@ -228,6 +262,7 @@ if (type === 'standalone') {
228
262
  filter: (source) => path.basename(source) !== '.DS_Store',
229
263
  recursive: true,
230
264
  });
265
+ await writeFile(path.join(targetSiteDir, '.gitignore'), siteGitignore);
231
266
  await writeFile(targetPackageJsonPath, `${JSON.stringify(targetPackageJson, null, 2)}\n`);
232
267
  }
233
268
 
@@ -1,6 +1,8 @@
1
1
  import path from 'node:path';
2
2
  import { createRequire } from 'node:module';
3
+ import { mkdirSync } from 'node:fs';
3
4
  import {
5
+ astroRootDir,
4
6
  engineRoot,
5
7
  siteProjectRoot,
6
8
  } from './site-paths.mjs';
@@ -11,18 +13,21 @@ const astroPackagePath = require.resolve('astro/package.json');
11
13
  const astroPackage = require(astroPackagePath);
12
14
 
13
15
  export const astroBinPath = path.join(path.dirname(astroPackagePath), astroPackage.bin.astro);
14
- export const astroConfigPath = path.relative(siteProjectRoot, path.join(engineRoot, 'astro.config.mjs'))
16
+ export const astroConfigPath = path.relative(astroRootDir, path.join(engineRoot, 'astro.config.mjs'))
15
17
  .split(path.sep)
16
18
  .join('/');
17
19
 
18
- export const getAstroArgs = (args) => [
19
- astroBinPath,
20
- '--root',
21
- siteProjectRoot,
22
- '--config',
23
- astroConfigPath,
24
- ...args,
25
- ];
20
+ export const getAstroArgs = (args) => {
21
+ mkdirSync(astroRootDir, { recursive: true });
22
+ return [
23
+ astroBinPath,
24
+ '--root',
25
+ astroRootDir,
26
+ '--config',
27
+ astroConfigPath,
28
+ ...args,
29
+ ];
30
+ };
26
31
 
27
32
  export const runAstroInherit = (args, options = {}) => runInherit(
28
33
  process.execPath,