@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,141 @@
1
+ const preferenceDefinitions = Object.freeze({
2
+ appearance: Object.freeze({
3
+ allowed: Object.freeze(['system', 'light', 'dark']),
4
+ cookieName: 'norna-color-mode',
5
+ }),
6
+ readingWidth: Object.freeze({
7
+ allowed: Object.freeze(['narrow', 'standard', 'wide']),
8
+ cookieName: 'norna-reading-width',
9
+ }),
10
+ focusReading: Object.freeze({
11
+ allowed: Object.freeze(['off', 'on']),
12
+ cookieName: 'norna-focus-reading',
13
+ }),
14
+ });
15
+
16
+ export const getReaderPreferencesScript = ({ controls, defaults, cookiePath }) => `(() => {
17
+ const root = document.documentElement;
18
+ const controls = ${JSON.stringify(controls)};
19
+ const defaults = ${JSON.stringify(defaults)};
20
+ const cookiePath = ${JSON.stringify(cookiePath)};
21
+ const definitions = ${JSON.stringify(preferenceDefinitions)};
22
+ const values = { ...defaults };
23
+ const readCookie = (name) => {
24
+ const prefix = encodeURIComponent(name) + '=';
25
+ const cookie = document.cookie.split('; ').find((part) => part.startsWith(prefix));
26
+ return cookie ? decodeURIComponent(cookie.slice(prefix.length)) : null;
27
+ };
28
+ const writeCookie = (name, value, maxAge = 31536000) => {
29
+ try {
30
+ const secure = location.protocol === 'https:' ? '; Secure' : '';
31
+ document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value)
32
+ + '; Path=' + cookiePath + '; Max-Age=' + maxAge + '; SameSite=Lax' + secure;
33
+ } catch {}
34
+ };
35
+ const isAllowed = (name, value) => definitions[name].allowed.includes(value);
36
+ const captureReadingPosition = () => {
37
+ if (window.scrollY <= 1) return null;
38
+ const contentTop = document.querySelector('.site-top')?.getBoundingClientRect().bottom ?? 0;
39
+ const candidates = document.querySelectorAll([
40
+ '#main-content .section-header',
41
+ '#main-content .section-markdown > *',
42
+ '#main-content .image-stack',
43
+ '#main-content .image-carousel',
44
+ '#main-content .card-list',
45
+ ].join(', '));
46
+ const element = Array.from(candidates).find((candidate) => {
47
+ const rectangle = candidate.getBoundingClientRect();
48
+ return rectangle.height > 0 && rectangle.bottom > contentTop + 1;
49
+ });
50
+ return element ? { element, top: element.getBoundingClientRect().top } : null;
51
+ };
52
+ const restoreReadingPosition = (position) => {
53
+ if (!position) return;
54
+ requestAnimationFrame(() => {
55
+ const delta = position.element.getBoundingClientRect().top - position.top;
56
+ if (Math.abs(delta) < 0.5) return;
57
+ const scrollBehavior = root.style.scrollBehavior;
58
+ root.style.scrollBehavior = 'auto';
59
+ window.scrollBy(0, delta);
60
+ root.style.scrollBehavior = scrollBehavior;
61
+ });
62
+ };
63
+ const preserveReadingPosition = (change) => {
64
+ const position = captureReadingPosition();
65
+ change();
66
+ restoreReadingPosition(position);
67
+ };
68
+ const updateThemeColor = () => requestAnimationFrame(() => {
69
+ const themeColor = getComputedStyle(root).getPropertyValue('--color-page').trim();
70
+ if (themeColor) document.querySelectorAll('meta[name="theme-color"]').forEach((meta) => meta.content = themeColor);
71
+ });
72
+ const apply = (name, value, persist = false) => {
73
+ const nextValue = isAllowed(name, value) ? value : defaults[name];
74
+ values[name] = nextValue;
75
+ if (name === 'appearance') root.dataset.colorMode = nextValue;
76
+ if (name === 'readingWidth') root.dataset.readingWidth = nextValue;
77
+ if (name === 'focusReading') root.dataset.focusReading = nextValue;
78
+ if (persist) writeCookie(definitions[name].cookieName, nextValue);
79
+ if (name === 'appearance') updateThemeColor();
80
+ };
81
+ for (const name of Object.keys(definitions)) {
82
+ const saved = controls[name] ? readCookie(definitions[name].cookieName) : null;
83
+ apply(name, saved && isAllowed(name, saved) ? saved : defaults[name]);
84
+ }
85
+ root.dataset.readerPreferencesReady = 'true';
86
+ const syncControls = () => {
87
+ document.querySelectorAll('[data-reader-appearance]').forEach((input) => {
88
+ input.checked = input.value === values.appearance;
89
+ });
90
+ document.querySelectorAll('[data-reader-width]').forEach((input) => {
91
+ input.checked = input.value === values.readingWidth;
92
+ });
93
+ document.querySelectorAll('[data-reader-focus]').forEach((input) => {
94
+ input.checked = values.focusReading === 'on';
95
+ });
96
+ };
97
+ document.addEventListener('DOMContentLoaded', () => {
98
+ syncControls();
99
+ document.querySelectorAll('[data-reader-appearance]').forEach((input) => {
100
+ input.addEventListener('change', () => {
101
+ if (input.checked) apply('appearance', input.value, true);
102
+ });
103
+ });
104
+ document.querySelectorAll('[data-reader-width]').forEach((input) => {
105
+ input.addEventListener('change', () => {
106
+ if (input.checked) preserveReadingPosition(() => apply('readingWidth', input.value, true));
107
+ });
108
+ });
109
+ document.querySelectorAll('[data-reader-focus]').forEach((input) => {
110
+ input.addEventListener('change', () => preserveReadingPosition(() => {
111
+ apply('focusReading', input.checked ? 'on' : 'off', true);
112
+ }));
113
+ });
114
+ document.querySelectorAll('[data-reader-reset]').forEach((button) => {
115
+ button.addEventListener('click', () => {
116
+ preserveReadingPosition(() => {
117
+ for (const name of Object.keys(definitions)) {
118
+ writeCookie(definitions[name].cookieName, '', 0);
119
+ apply(name, defaults[name]);
120
+ }
121
+ syncControls();
122
+ });
123
+ });
124
+ });
125
+ document.querySelectorAll('[data-display-settings]').forEach((settings) => {
126
+ settings.addEventListener('keydown', (event) => {
127
+ if (event.key !== 'Escape') return;
128
+ settings.removeAttribute('open');
129
+ settings.querySelector('summary')?.focus();
130
+ });
131
+ });
132
+ });
133
+ document.addEventListener('click', (event) => {
134
+ document.querySelectorAll('[data-display-settings][open]').forEach((settings) => {
135
+ if (!settings.contains(event.target)) settings.removeAttribute('open');
136
+ });
137
+ });
138
+ matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
139
+ if (values.appearance === 'system') updateThemeColor();
140
+ });
141
+ })();`;
@@ -2,15 +2,7 @@ import { markdownToHtml } from 'satteri';
2
2
  import projectConfig from '../../scripts/lib/project-config.mjs';
3
3
  import {
4
4
  formatHeadingIdentifierIssue,
5
- getHeadingIdentifierIssues,
6
5
  } from '../../scripts/lib/heading-ids.mjs';
7
- import { getBodySections } from '../../scripts/lib/site-content.mjs';
8
- import {
9
- extractInlineNoteDiagnostics,
10
- extractNornaMarkdownBlocks,
11
- splitNornaMarkdownBlockMarkers,
12
- splitNornaRenderedCodeBlocks,
13
- } from '../../scripts/lib/norna-markdown-blocks.mjs';
14
6
  import { applyBasePathToHtml } from './basePath';
15
7
  import type { SitePage } from './sitePages';
16
8
 
@@ -32,18 +24,31 @@ type CardListLayout = 'image-top' | 'image-left' | 'image-right';
32
24
  type CardListFlow = 'grid' | 'stack';
33
25
  type CardListSize = 's' | 'm' | 'l' | 'xl';
34
26
  type CardListWidth = 'text' | 'narrow' | 'normal' | 'wide';
27
+ type ParsedImageBlock = {
28
+ type: 'image-stack' | 'image-carousel';
29
+ images: Array<{ image: string; alt?: string; caption?: string }>;
30
+ };
31
+ type ParsedCardListBlock = {
32
+ type: 'card-list';
33
+ layout: CardListLayout;
34
+ flow: CardListFlow;
35
+ size: CardListSize;
36
+ width?: CardListWidth;
37
+ cards: CardListItem[];
38
+ };
39
+ type ParsedNornaBlock = ParsedImageBlock | ParsedCardListBlock;
35
40
  type InlineNote = {
36
41
  markdown: string;
37
42
  number: number;
38
43
  id: string;
39
44
  referenceId: string;
45
+ html?: string;
40
46
  };
41
47
  type SectionContentBlock =
42
48
  | { type: 'html'; html: string }
43
49
  | { type: 'image-stack'; images: ManagedImage[] }
44
50
  | { type: 'image-carousel'; images: ManagedImage[] }
45
- | { type: 'card-list'; layout: CardListLayout; flow: CardListFlow; size: CardListSize; width: CardListWidth; cards: CardListItem[] }
46
- | { type: 'note'; html: string; number?: number; id?: string; referenceId?: string };
51
+ | { type: 'card-list'; layout: CardListLayout; flow: CardListFlow; size: CardListSize; width?: CardListWidth; cards: CardListItem[] };
47
52
  export type ResolvedSection = {
48
53
  id: string | null;
49
54
  title: string;
@@ -62,57 +67,9 @@ export type HeadingNavigation = SectionNavigation & {
62
67
  parentId: string | null;
63
68
  };
64
69
 
65
- const contentHeadingRegex = /<h([12])\b([^>]*)>([\s\S]*?)<\/h\1>/gi;
66
70
  const explicitHeadingIdRegex = /\s*\{#([a-z0-9-]+)\}\s*$/;
67
71
  const imageProvenanceCommentRegex = /<!--\s*norna-image-provenance:[\s\S]*?-->/gi;
68
72
 
69
- const stripTags = (html: string) => html.replace(/<[^>]*>/g, '');
70
-
71
- const decodeHtmlEntities = (value: string) =>
72
- value
73
- .replace(/&amp;/g, '&')
74
- .replace(/&lt;/g, '<')
75
- .replace(/&gt;/g, '>')
76
- .replace(/&quot;/g, '"')
77
- .replace(/&#39;/g, "'");
78
-
79
- const getHeadingTitle = (headingHtml: string) =>
80
- decodeHtmlEntities(stripTags(headingHtml)).replace(explicitHeadingIdRegex, '').trim();
81
-
82
- const getHeadingTitleHtml = (headingHtml: string) =>
83
- prepareContentHtml(headingHtml.replace(explicitHeadingIdRegex, '').trim());
84
-
85
- export const getHeadingNavigation = async (
86
- markdown: string,
87
- sourceLabel = 'Markdown',
88
- ): Promise<HeadingNavigation[]> => {
89
- const bodyStructure = await getBodySections(markdown);
90
- const issues = getHeadingIdentifierIssues(bodyStructure.headings);
91
- if (issues.length > 0) throw new Error(formatHeadingIdentifierIssue(issues[0], sourceLabel));
92
-
93
- let parentId: string | null = null;
94
- return bodyStructure.headings.flatMap((heading) => {
95
- if (heading.depth === 1 || !heading.id) return [];
96
- if (heading.depth === 2) parentId = heading.id;
97
-
98
- return [{
99
- depth: heading.depth,
100
- id: heading.id,
101
- parentId: heading.depth === 3 ? parentId : null,
102
- title: heading.title,
103
- }];
104
- });
105
- };
106
-
107
- export const getSectionNavigation = async (
108
- markdown: string,
109
- sourceLabel = 'Markdown',
110
- ): Promise<SectionNavigation[]> => (
111
- (await getHeadingNavigation(markdown, sourceLabel))
112
- .filter((heading) => heading.depth === 2)
113
- .map(({ id, title }) => ({ id, title }))
114
- );
115
-
116
73
  const stripImageProvenanceComments = (html: string) => html.replace(imageProvenanceCommentRegex, '');
117
74
 
118
75
  const prepareContentHtml = (html: string) =>
@@ -121,62 +78,6 @@ const prepareContentHtml = (html: string) =>
121
78
  stripImageProvenanceComments(html),
122
79
  );
123
80
 
124
- const htmlVoidElements = new Set([
125
- 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link',
126
- 'meta', 'param', 'source', 'track', 'wbr',
127
- ]);
128
-
129
- // Keep notes aligned with the Markdown block immediately before them instead of
130
- // aligning them with a whole run of paragraphs rendered as one HTML fragment.
131
- const splitHtmlIntoBlocks = (html: string) => {
132
- const tagRegex = /<!--[\s\S]*?-->|<\/?([a-z][\w:-]*)(?:\s[^<>]*?)?\/?>/gi;
133
- const blocks: string[] = [];
134
- let blockStart = -1;
135
- let depth = 0;
136
- let cursor = 0;
137
-
138
- for (const match of html.matchAll(tagRegex)) {
139
- const start = match.index ?? 0;
140
- const token = match[0] ?? '';
141
- const tagName = match[1]?.toLowerCase();
142
- if (!tagName) continue;
143
-
144
- const isClosing = /^<\//.test(token);
145
- const isSelfClosing = /\/\s*>$/.test(token) || htmlVoidElements.has(tagName);
146
-
147
- if (isClosing) {
148
- if (depth > 0) depth -= 1;
149
- if (depth === 0 && blockStart >= 0) {
150
- blocks.push(html.slice(blockStart, start + token.length));
151
- cursor = start + token.length;
152
- blockStart = -1;
153
- }
154
- continue;
155
- }
156
-
157
- if (depth === 0) {
158
- if (blockStart < 0) blockStart = start;
159
- if (isSelfClosing) {
160
- blocks.push(html.slice(blockStart, start + token.length));
161
- cursor = start + token.length;
162
- blockStart = -1;
163
- }
164
- }
165
-
166
- if (!isSelfClosing) depth += 1;
167
- }
168
-
169
- if (blockStart >= 0) {
170
- blocks.push(html.slice(blockStart).trim());
171
- cursor = html.length;
172
- }
173
-
174
- const prefix = html.slice(0, blocks.length > 0 ? html.indexOf(blocks[0]!) : html.length).trim();
175
- const suffix = html.slice(cursor).trim();
176
- return [prefix, ...blocks, suffix].filter(Boolean);
177
- };
178
-
179
- const inlineNoteMarkerRegex = /^\s*<norna-inline-note\s+data-note-index="(\d+)"\s*><\/norna-inline-note>\s*$/i;
180
81
  const noteDeclarationParagraphRegex = /<p>\s*\{note:\s*[\s\S]*?\}\s*<\/p>/gi;
181
82
  const htmlCodeRegionRegex = /<pre\b[\s\S]*?<\/pre>|<code\b[\s\S]*?<\/code>/gi;
182
83
 
@@ -201,32 +102,22 @@ const applyInlineNoteMarkup = (html: string, notes: InlineNote[]) => {
201
102
  if (!note) return '{note-ref}';
202
103
 
203
104
  referenceIndex += 1;
204
- return `\u2060<sup class="section-note-ref"><a id="${note.referenceId}" href="#${note.id}" aria-label="Note ${note.number}" aria-describedby="${note.id}" data-note-id="${note.id}">${note.number}</a></sup>`;
105
+ return [
106
+ '\u2060',
107
+ `<sup class="section-note-ref"><a id="${note.referenceId}" href="#${note.id}" aria-label="Note ${note.number}" aria-describedby="${note.id}">${note.number}</a></sup>`,
108
+ `<span class="section-note section-note-margin" id="${note.id}" aria-label="Note ${note.number}" role="note">`,
109
+ `<a class="section-note-number" href="#${note.referenceId}" aria-label="Note ${note.number}">${note.number}</a>`,
110
+ `<span class="section-note-content">${note.html ?? ''}</span>`,
111
+ '</span>',
112
+ ].join('');
205
113
  }));
206
114
 
207
- let noteIndex = 0;
208
- return withReferences.replace(noteDeclarationParagraphRegex, () => {
209
- const marker = `<norna-inline-note data-note-index="${noteIndex}"></norna-inline-note>`;
210
- noteIndex += 1;
211
- return marker;
212
- });
213
- };
214
-
215
- const getRawMarkdownSections = (bodySections: Awaited<ReturnType<typeof getBodySections>>['sections']) => {
216
- const sections = new Map<string, string>();
217
-
218
- for (const section of bodySections) {
219
- const id = section.isPageTitle ? '__page-title' : section.id;
220
- if (!id) continue;
221
- sections.set(id, section.text);
222
- }
223
-
224
- return sections;
115
+ return withReferences.replace(noteDeclarationParagraphRegex, '');
225
116
  };
226
117
 
227
118
  const applyH3HeadingIds = (
228
119
  html: string,
229
- headings: Awaited<ReturnType<typeof getBodySections>>['headings'],
120
+ headings: Array<{ id: string | null }>,
230
121
  ) => {
231
122
  let headingIndex = 0;
232
123
  const result = html.replace(/<h3\b([^>]*)>([\s\S]*?)<\/h3>/gi, (_match, attributes, headingHtml) => {
@@ -246,11 +137,7 @@ const applyH3HeadingIds = (
246
137
  return result;
247
138
  };
248
139
 
249
- const getImageSourceKey = (page: SitePage, image: string) => (
250
- page.pageDirectory
251
- ? `pages/${page.pageDirectory}/images/${image}`
252
- : `images/${image}`
253
- );
140
+ const getImageSourceKey = (page: SitePage, image: string) => `pages/${page.pageDirectory}/images/${image}`;
254
141
 
255
142
  const renderInlineNoteMarkdown = async (markdown: string) => {
256
143
  const result = await markdownToHtml(markdown, {
@@ -264,47 +151,89 @@ const renderInlineNoteMarkdown = async (markdown: string) => {
264
151
  throw new Error('Inline notes cannot contain images. Use a Norna image block with a caption instead.');
265
152
  }
266
153
 
267
- return prepareContentHtml(result.html);
154
+ const inlineHtml = result.html.trim();
155
+ const paragraph = inlineHtml.match(/^<p>([\s\S]*)<\/p>$/i);
156
+ if (!paragraph) {
157
+ throw new Error('Inline notes support inline Markdown only. Move headings, lists, and separate paragraphs into the page content.');
158
+ }
159
+
160
+ return paragraph[1] ?? '';
161
+ };
162
+
163
+ const renderHeadingTitleHtml = async (headingSource: string) => {
164
+ const headingMarkdown = headingSource
165
+ .replace(/^#{1,6}[ \t]+/, '')
166
+ .replace(explicitHeadingIdRegex, '')
167
+ .trim();
168
+ const result = await markdownToHtml(headingMarkdown, {
169
+ features: {
170
+ gfm: true,
171
+ smartPunctuation: true,
172
+ },
173
+ });
174
+ const paragraph = result.html.trim().match(/^<p>([\s\S]*)<\/p>$/i);
175
+ if (!paragraph) throw new Error('Markdown heading could not be rendered as inline content.');
176
+ return prepareContentHtml(paragraph[1] ?? '');
177
+ };
178
+
179
+ const splitRenderedRegions = (html: string, regionCount: number) => {
180
+ const markerRegex = /<norna-region\s+data-index="(\d+)"\s*><\/norna-region>/g;
181
+ const markers = Array.from(html.matchAll(markerRegex));
182
+ if (markers.length !== regionCount) {
183
+ throw new Error(`Rendered Markdown contains ${markers.length} page region markers, but ${regionCount} regions were parsed.`);
184
+ }
185
+
186
+ return markers.map((marker, position) => {
187
+ const index = Number.parseInt(marker[1] ?? '', 10);
188
+ if (index !== position) throw new Error(`Rendered page region ${position + 1} has unexpected index ${index}.`);
189
+ const start = (marker.index ?? 0) + marker[0].length;
190
+ const end = markers[position + 1]?.index ?? html.length;
191
+ return html.slice(start, end).trim();
192
+ });
193
+ };
194
+
195
+ const splitNornaBlockMarkers = (html: string, blocks: ParsedNornaBlock[]) => {
196
+ const result: Array<{ type: 'html'; html: string } | ParsedNornaBlock> = [];
197
+ const markerRegex = /<norna-block\s+data-index="(\d+)"\s*><\/norna-block>/g;
198
+ const seen = new Set<number>();
199
+ let cursor = 0;
200
+
201
+ for (const match of html.matchAll(markerRegex)) {
202
+ const start = match.index ?? 0;
203
+ if (start > cursor) result.push({ type: 'html', html: html.slice(cursor, start) });
204
+
205
+ const index = Number.parseInt(match[1] ?? '', 10);
206
+ const block = blocks[index];
207
+ if (!block) throw new Error(`Rendered Norna block ${index + 1} has no matching parsed block.`);
208
+ seen.add(index);
209
+ result.push(block);
210
+ cursor = start + match[0].length;
211
+ }
212
+
213
+ if (cursor < html.length) result.push({ type: 'html', html: html.slice(cursor) });
214
+ if (seen.size !== blocks.length) {
215
+ throw new Error(`Rendered Markdown contains ${seen.size} Norna block markers, but ${blocks.length} blocks were parsed.`);
216
+ }
217
+
218
+ return result.filter((block) => block.type !== 'html' || block.html.trim());
268
219
  };
269
220
 
270
221
  const resolveContentBlocks = async (
271
222
  html: string,
272
- rawMarkdown: string,
223
+ blocks: ParsedNornaBlock[],
273
224
  page: SitePage,
274
225
  inlineNotes: InlineNote[] = [],
275
226
  ) => {
276
- const rawBlocks = extractNornaMarkdownBlocks(rawMarkdown);
277
- const renderedHtml = applyInlineNoteMarkup(html, inlineNotes);
278
- const splitBlocks = rawBlocks.length > 0
279
- ? splitNornaRenderedCodeBlocks(renderedHtml, rawBlocks)
280
- : splitNornaMarkdownBlockMarkers(renderedHtml);
281
- const hasNotes = inlineNotes.length > 0;
282
- const contentBlocks = hasNotes
283
- ? splitBlocks.flatMap((block) => block.type === 'html'
284
- ? splitHtmlIntoBlocks(block.html).map((htmlBlock) => ({ type: 'html' as const, html: htmlBlock }))
285
- : [block])
286
- : splitBlocks;
227
+ const renderedNotes = await Promise.all(inlineNotes.map(async (note) => ({
228
+ ...note,
229
+ html: await renderInlineNoteMarkdown(note.markdown),
230
+ })));
231
+ const renderedHtml = applyInlineNoteMarkup(html, renderedNotes);
232
+ const splitBlocks = splitNornaBlockMarkers(renderedHtml, blocks);
287
233
  const resolvedBlocks: SectionContentBlock[] = [];
288
234
 
289
- for (const block of contentBlocks) {
235
+ for (const block of splitBlocks) {
290
236
  if (block.type === 'html') {
291
- const inlineNoteMarker = block.html.match(inlineNoteMarkerRegex);
292
- if (inlineNoteMarker) {
293
- const note = inlineNotes[Number(inlineNoteMarker[1])];
294
- if (!note) {
295
- throw new Error('Norna inline note markup could not be matched to its note text.');
296
- }
297
-
298
- resolvedBlocks.push({
299
- type: 'note',
300
- html: await renderInlineNoteMarkdown(note.markdown),
301
- number: note.number,
302
- id: note.id,
303
- referenceId: note.referenceId,
304
- });
305
- continue;
306
- }
307
-
308
237
  resolvedBlocks.push({ type: 'html', html: prepareContentHtml(block.html) });
309
238
  continue;
310
239
  }
@@ -338,46 +267,32 @@ const resolveContentBlocks = async (
338
267
 
339
268
  export const getSectionsContent = async (
340
269
  html: string,
341
- rawMarkdown: string,
342
270
  page: SitePage,
343
- sourceLabel = 'Markdown',
344
271
  ) => {
345
- const matches = Array.from(html.matchAll(contentHeadingRegex));
346
- const bodyStructure = await getBodySections(rawMarkdown);
347
- const headingIdentifierIssues = getHeadingIdentifierIssues(bodyStructure.headings);
272
+ const pageDocument = page.markdownDocument;
273
+ const sourceLabel = page.contentLabel;
274
+ const headingIdentifierIssues = pageDocument.headingIssues;
348
275
  if (headingIdentifierIssues.length > 0) {
349
276
  throw new Error(formatHeadingIdentifierIssue(headingIdentifierIssues[0], sourceLabel));
350
277
  }
351
- const rawSections = getRawMarkdownSections(bodyStructure.sections);
352
278
  const sections: ResolvedSection[] = [];
353
279
  const sectionIds = new Set<string>();
354
280
  let nextNoteNumber = 1;
355
- const pageHeadingCount = matches.filter((match) => match[1] === '1').length;
281
+ const pageHeadingCount = pageDocument.pageHeadings.length;
356
282
 
357
- if (pageHeadingCount !== 1 || matches[0]?.[1] !== '1') {
283
+ if (pageHeadingCount !== 1 || pageDocument.regions[0]?.kind !== 'page-intro') {
358
284
  throw new Error('Each Norna page must start with exactly one Markdown H1 page title, for example "# About".');
359
285
  }
286
+ const renderedRegions = splitRenderedRegions(html, pageDocument.regions.length);
360
287
 
361
- for (let index = 0; index < matches.length; index += 1) {
362
- const match = matches[index];
363
- const bodySection = bodyStructure.sections[index];
364
- const headingLevel = Number.parseInt(match[1] ?? '', 10) as 1 | 2;
365
- const headingHtml = match[3] ?? '';
366
- if (!bodySection || bodySection.level !== headingLevel) {
367
- throw new Error('Markdown H1/H2 headings could not be matched to the rendered page content.');
368
- }
288
+ for (let index = 0; index < renderedRegions.length; index += 1) {
289
+ const bodySection = pageDocument.regions[index];
290
+ if (!bodySection) throw new Error(`Parsed page region ${index + 1} is missing.`);
291
+ const headingLevel = bodySection.heading.depth as 1 | 2;
369
292
  const id = bodySection.id;
370
- const contentStart = (match.index ?? 0) + match[0].length;
371
- const nextMatch = matches[index + 1];
372
- const contentEnd = nextMatch?.index ?? html.length;
373
- const nextBodySection = bodyStructure.sections[index + 1];
374
- const h3Headings = bodyStructure.headings.filter((heading) => (
375
- heading.depth === 3
376
- && heading.index > bodySection.index
377
- && heading.index < (nextBodySection?.index ?? Number.POSITIVE_INFINITY)
378
- ));
379
- const content = applyH3HeadingIds(html.slice(contentStart, contentEnd).trim(), h3Headings);
380
- const title = getHeadingTitle(headingHtml);
293
+ const h3Headings = bodySection.headings.filter((heading) => heading.depth === 3);
294
+ const content = applyH3HeadingIds(renderedRegions[index] ?? '', h3Headings);
295
+ const title = bodySection.title;
381
296
 
382
297
  if (headingLevel === 2 && !id) throw new Error(`Section heading "${title}" cannot produce an automatic ASCII id.`);
383
298
 
@@ -386,15 +301,14 @@ export const getSectionsContent = async (
386
301
  }
387
302
 
388
303
  if (id) sectionIds.add(id);
389
- const rawSection = rawSections.get(id ?? '__page-title') ?? '';
390
- const inlineNoteDiagnostics = extractInlineNoteDiagnostics(rawSection, {
391
- label: 'Markdown section',
392
- });
393
- if (inlineNoteDiagnostics.errors.length > 0) {
394
- throw new Error(inlineNoteDiagnostics.errors[0].message);
304
+ if (bodySection.blockErrors.length > 0) {
305
+ throw new Error(bodySection.blockErrors[0].message);
306
+ }
307
+ if (bodySection.noteErrors.length > 0) {
308
+ throw new Error(bodySection.noteErrors[0].message);
395
309
  }
396
310
 
397
- const inlineNotes = inlineNoteDiagnostics.notes.map((note) => {
311
+ const inlineNotes = bodySection.notes.map((note) => {
398
312
  const number = nextNoteNumber;
399
313
  nextNoteNumber += 1;
400
314
  const pageKey = page.pageId || 'home';
@@ -410,9 +324,9 @@ export const getSectionsContent = async (
410
324
  sections.push({
411
325
  id,
412
326
  title,
413
- titleHtml: getHeadingTitleHtml(headingHtml),
327
+ titleHtml: await renderHeadingTitleHtml(bodySection.heading.source),
414
328
  headingLevel,
415
- contentBlocks: await resolveContentBlocks(content, rawSection, page, inlineNotes),
329
+ contentBlocks: await resolveContentBlocks(content, bodySection.blocks, page, inlineNotes),
416
330
  });
417
331
  }
418
332
 
@@ -1,35 +1,36 @@
1
- import type { SectionNavigation } from './sectionContent';
2
- import type { SitePage } from './sitePages';
1
+ import type { HeadingNavigation, SectionNavigation } from './sectionContent';
2
+ import type { SiteNode, SitePage } from './sitePages';
3
3
 
4
- export type PageNavigationEntry = {
5
- page: SitePage;
4
+ export type SiteNavigationEntry = {
5
+ node: SiteNode;
6
+ headings: HeadingNavigation[];
6
7
  sections: SectionNavigation[];
7
8
  };
8
9
 
9
- export type PageNavigationNode = PageNavigationEntry & {
10
- children: PageNavigationNode[];
10
+ export type SiteNavigationNode = SiteNavigationEntry & {
11
+ children: SiteNavigationNode[];
11
12
  };
12
13
 
13
- export const getPageNavigationTree = (entries: PageNavigationEntry[]) => {
14
- const nodes = new Map<string, PageNavigationNode>();
15
- const roots: PageNavigationNode[] = [];
14
+ export const getSiteNavigationTree = (entries: SiteNavigationEntry[]) => {
15
+ const nodes = new Map<string, SiteNavigationNode>();
16
+ const roots: SiteNavigationNode[] = [];
16
17
 
17
18
  for (const entry of entries) {
18
- nodes.set(entry.page.pagePath, { ...entry, children: [] });
19
+ nodes.set(entry.node.pagePath, { ...entry, children: [] });
19
20
  }
20
21
 
21
22
  for (const entry of entries) {
22
- const node = nodes.get(entry.page.pagePath);
23
+ const node = nodes.get(entry.node.pagePath);
23
24
  if (!node) continue;
24
25
 
25
- if (entry.page.isHome || entry.page.parentPagePath === null) {
26
+ if (entry.node.isHome || entry.node.parentPagePath === null) {
26
27
  roots.push(node);
27
28
  continue;
28
29
  }
29
30
 
30
- const parent = nodes.get(entry.page.parentPagePath);
31
+ const parent = nodes.get(entry.node.parentPagePath);
31
32
  if (!parent) {
32
- throw new Error(`Page "${entry.page.pathname}" has no parent page "${entry.page.parentPagePath}".`);
33
+ throw new Error(`Site node "${entry.node.pagePath}" has no parent node "${entry.node.parentPagePath}".`);
33
34
  }
34
35
 
35
36
  parent.children.push(node);
@@ -38,11 +39,29 @@ export const getPageNavigationTree = (entries: PageNavigationEntry[]) => {
38
39
  return roots;
39
40
  };
40
41
 
41
- export const getListedPageNavigationTree = (entries: PageNavigationEntry[]) => {
42
- const filterListed = (nodes: PageNavigationNode[]): PageNavigationNode[] => nodes.flatMap((node) => {
43
- if (!node.page.isHome && !node.page.navigation.listed) return [];
44
- return [{ ...node, children: filterListed(node.children) }];
42
+ export const getListedSiteNavigationTree = (entries: SiteNavigationEntry[]) => {
43
+ const filterListed = (nodes: SiteNavigationNode[]): SiteNavigationNode[] => nodes.flatMap((node) => {
44
+ if (!node.node.isHome && !node.node.navigation.listed) return [];
45
+ const children = filterListed(node.children);
46
+ if (node.node.kind === 'category' && children.length === 0) return [];
47
+ return [{ ...node, children }];
45
48
  });
46
49
 
47
- return filterListed(getPageNavigationTree(entries));
50
+ return filterListed(getSiteNavigationTree(entries));
48
51
  };
52
+
53
+ export const getFirstPageInNavigationNode = (node: SiteNavigationNode): SitePage | null => {
54
+ if (node.node.kind === 'page') return node.node;
55
+
56
+ for (const child of node.children) {
57
+ const page = getFirstPageInNavigationNode(child);
58
+ if (page) return page;
59
+ }
60
+
61
+ return null;
62
+ };
63
+
64
+ export const flattenSiteNavigationTree = (nodes: SiteNavigationNode[]): SiteNavigationNode[] => nodes.flatMap((node) => [
65
+ node,
66
+ ...flattenSiteNavigationTree(node.children),
67
+ ]);