@janga/norna 0.7.9 → 0.7.11

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 (287) hide show
  1. package/README.md +4 -2
  2. package/bin/norna-cli.mjs +3 -0
  3. package/docs/README.md +16 -12
  4. package/docs/commands.md +6 -0
  5. package/docs/configuration.md +10 -54
  6. package/docs/content.md +20 -21
  7. package/docs/design/norna-diagram-design.md +2 -0
  8. package/docs/design/site-examples-structure.md +35 -24
  9. package/docs/engine-development.md +13 -7
  10. package/docs/getting-started.md +56 -19
  11. package/docs/routes.md +8 -6
  12. package/docs/site-structure.md +11 -6
  13. package/docs/sitewide-content.md +74 -0
  14. package/docs/theme.md +125 -140
  15. package/docs/typography.md +72 -45
  16. package/examples/README.md +41 -0
  17. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/site.schema.json +59 -0
  18. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/sitewide.schema.json +138 -0
  19. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/theme.schema.json +755 -0
  20. package/examples/complete-sites/dog-shelter-multi-page/.astro/content-modules.mjs +1 -0
  21. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/content.d.ts +8 -0
  22. package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +1 -0
  23. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/dev-local.json +2 -2
  24. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/dev.json +2 -2
  25. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +53 -0
  26. package/examples/complete-sites/dog-shelter-multi-page/.astro/settings.json +5 -0
  27. package/examples/complete-sites/dog-shelter-multi-page/README.md +9 -0
  28. package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/_metadata.json +13 -7
  29. package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +18 -0
  30. package/examples/complete-sites/dog-shelter-multi-page/site/config.mjs +30 -0
  31. package/examples/complete-sites/dog-shelter-multi-page/site/content.md +12 -0
  32. package/examples/complete-sites/dog-shelter-multi-page/site/public/favicon.svg +10 -0
  33. package/examples/complete-sites/dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rex.svg +19 -0
  34. package/examples/complete-sites/dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rover.svg +19 -0
  35. package/examples/complete-sites/dog-shelter-multi-page/site/routes/010-dogs/route-content.md +30 -0
  36. package/examples/complete-sites/dog-shelter-multi-page/site/routes/020-adopt/route-content.md +12 -0
  37. package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.md +6 -0
  38. package/examples/complete-sites/dog-shelter-multi-page/site/theme.md +25 -0
  39. package/examples/complete-sites/dog-shelter-single-page/README.md +9 -0
  40. package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +18 -0
  41. package/examples/complete-sites/dog-shelter-single-page/site/config.mjs +30 -0
  42. package/examples/complete-sites/dog-shelter-single-page/site/content.md +38 -0
  43. package/examples/complete-sites/dog-shelter-single-page/site/images/what-we-do/dog-house.svg +25 -0
  44. package/examples/complete-sites/dog-shelter-single-page/site/images/you-can-help/heart.svg +13 -0
  45. package/examples/complete-sites/dog-shelter-single-page/site/public/favicon.svg +10 -0
  46. package/examples/complete-sites/dog-shelter-single-page/site/public/robots.txt +2 -0
  47. package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.md +6 -0
  48. package/examples/complete-sites/dog-shelter-single-page/site/theme.md +25 -0
  49. package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +59 -0
  50. package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +138 -0
  51. package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +755 -0
  52. package/examples/feature-demos/media-and-surfaces/.astro/content-modules.mjs +1 -0
  53. package/examples/feature-demos/media-and-surfaces/.astro/content.d.ts +183 -0
  54. package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +1 -0
  55. package/examples/feature-demos/media-and-surfaces/.astro/dev.log +11 -0
  56. package/examples/feature-demos/media-and-surfaces/.astro/settings.json +5 -0
  57. package/examples/feature-demos/media-and-surfaces/.astro/types.d.ts +2 -0
  58. package/examples/feature-demos/media-and-surfaces/README.md +15 -0
  59. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +74 -0
  60. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js +434 -0
  61. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js.map +1 -0
  62. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
  63. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
  64. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
  65. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
  66. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
  67. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
  68. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
  69. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
  70. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js +1534 -0
  71. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js.map +1 -0
  72. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js +48 -0
  73. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +1 -0
  74. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js +42 -0
  75. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js.map +1 -0
  76. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js +190 -0
  77. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js.map +1 -0
  78. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js +458 -0
  79. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +1 -0
  80. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js +1016 -0
  81. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +1 -0
  82. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js +32 -0
  83. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js.map +1 -0
  84. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js +111 -0
  85. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js.map +1 -0
  86. package/examples/feature-demos/media-and-surfaces/site/.norna/generated-images.json +66 -0
  87. package/examples/feature-demos/media-and-surfaces/site/config.mjs +30 -0
  88. package/examples/feature-demos/media-and-surfaces/site/content.md +64 -0
  89. package/examples/feature-demos/media-and-surfaces/site/public/robots.txt +2 -0
  90. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/images/cards/card-carousel.svg +11 -0
  91. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/images/cards/card-stack.svg +9 -0
  92. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/images/cards/card-surfaces.svg +8 -0
  93. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/images/carousel/carousel-one.svg +8 -0
  94. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/images/carousel/carousel-three.svg +13 -0
  95. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/images/carousel/carousel-two.svg +8 -0
  96. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/images/stack/stack-one.svg +8 -0
  97. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/images/stack/stack-two.svg +9 -0
  98. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/route-content.md +85 -0
  99. package/examples/feature-demos/media-and-surfaces/site/routes/010-media/theme.md +3 -0
  100. package/examples/feature-demos/media-and-surfaces/site/routes/020-surfaces/route-content.md +44 -0
  101. package/examples/feature-demos/media-and-surfaces/site/routes/020-surfaces/theme.md +8 -0
  102. package/examples/feature-demos/media-and-surfaces/site/sitewide-content.md +6 -0
  103. package/examples/feature-demos/media-and-surfaces/site/theme.md +3 -0
  104. package/examples/{typography-presets/.astro/collections/theme.schema.json → feature-demos/theme-presets/.astro/collections/routeTheme.schema.json} +143 -65
  105. package/examples/feature-demos/theme-presets/.astro/collections/site.schema.json +59 -0
  106. package/examples/feature-demos/theme-presets/.astro/collections/sitewide.schema.json +138 -0
  107. package/examples/feature-demos/theme-presets/.astro/collections/theme.schema.json +755 -0
  108. package/examples/feature-demos/theme-presets/.astro/content-assets.mjs +4 -0
  109. package/examples/feature-demos/theme-presets/.astro/content-modules.mjs +1 -0
  110. package/examples/feature-demos/theme-presets/.astro/content.d.ts +183 -0
  111. package/examples/feature-demos/theme-presets/.astro/data-store.json +1 -0
  112. package/examples/feature-demos/theme-presets/.astro/dev-local.json +8 -0
  113. package/examples/feature-demos/theme-presets/.astro/dev.json +15 -0
  114. package/examples/feature-demos/theme-presets/.astro/dev.log +127 -0
  115. package/examples/feature-demos/theme-presets/.astro/types.d.ts +2 -0
  116. package/examples/feature-demos/theme-presets/README.md +14 -0
  117. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/embla-carousel.js +1389 -0
  118. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/embla-carousel.js.map +1 -0
  119. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/package.json +3 -0
  120. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
  121. package/examples/feature-demos/theme-presets/site/.norna/generated-images.json +290 -0
  122. package/examples/{typography-presets → feature-demos/theme-presets}/site/config.mjs +4 -16
  123. package/examples/feature-demos/theme-presets/site/content.md +17 -0
  124. package/examples/feature-demos/theme-presets/site/routes/010-portfolio/route-content.md +34 -0
  125. package/examples/feature-demos/theme-presets/site/routes/010-portfolio/theme.md +3 -0
  126. package/examples/feature-demos/theme-presets/site/routes/020-documentation/route-content.md +33 -0
  127. package/examples/feature-demos/theme-presets/site/routes/020-documentation/theme.md +3 -0
  128. package/examples/feature-demos/theme-presets/site/routes/030-project/route-content.md +34 -0
  129. package/examples/feature-demos/theme-presets/site/routes/030-project/theme.md +3 -0
  130. package/examples/feature-demos/theme-presets/site/routes/040-statement/route-content.md +34 -0
  131. package/examples/feature-demos/theme-presets/site/routes/040-statement/theme.md +3 -0
  132. package/examples/feature-demos/theme-presets/site/sitewide-content.md +14 -0
  133. package/examples/feature-demos/theme-presets/site/theme.md +3 -0
  134. package/fixtures/basic/site/config.mjs +0 -13
  135. package/fixtures/basic/site/sitewide-content.md +12 -0
  136. package/fixtures/basic/site/theme.md +2 -2
  137. package/fixtures/content-model-v2/site/content.md +2 -5
  138. package/fixtures/content-model-v2/site/theme.md +1 -3
  139. package/package.json +9 -4
  140. package/scripts/build-pages.mjs +71 -0
  141. package/scripts/check-config.mjs +23 -1
  142. package/scripts/export-theme-preset.mjs +31 -0
  143. package/scripts/init-site.mjs +1 -0
  144. package/scripts/lib/example-sites.mjs +34 -0
  145. package/scripts/lib/frontmatter-yaml.mjs +28 -0
  146. package/scripts/lib/logo-assets.mjs +35 -0
  147. package/scripts/lib/norna-markdown-blocks.mjs +166 -0
  148. package/scripts/lib/presentation.mjs +106 -47
  149. package/scripts/lib/project-config.mjs +68 -105
  150. package/scripts/lib/site-content.mjs +26 -118
  151. package/scripts/lib/site-paths.mjs +2 -0
  152. package/scripts/lib/sitewide-config.mjs +34 -0
  153. package/scripts/lib/theme-config.mjs +75 -8
  154. package/scripts/lib/theme-presets.mjs +209 -0
  155. package/scripts/lib/typography.mjs +20 -26
  156. package/scripts/show-typography.mjs +43 -149
  157. package/scripts/sync-content-sections.mjs +19 -17
  158. package/scripts/test-content-check.mjs +59 -27
  159. package/scripts/test-content-model-v2.mjs +154 -0
  160. package/scripts/test-engine-commands.mjs +4 -1
  161. package/scripts/test-examples.mjs +15 -0
  162. package/scripts/test-navigation.mjs +73 -45
  163. package/scripts/test-package-check.mjs +66 -24
  164. package/scripts/test-temporary-visibility.mjs +19 -2
  165. package/scripts/test-theme-presets.mjs +151 -0
  166. package/src/components/CardList.astro +5 -2
  167. package/src/components/GalleryGrid.astro +37 -16
  168. package/src/components/SiteBanners.astro +100 -0
  169. package/src/components/SiteNavigation.astro +48 -31
  170. package/src/components/SitePage.astro +55 -13
  171. package/src/components/SiteSection.astro +193 -35
  172. package/src/content.config.ts +80 -48
  173. package/src/layouts/BaseLayout.astro +64 -14
  174. package/src/lib/routeThemes.ts +61 -0
  175. package/src/lib/sectionContent.ts +235 -51
  176. package/src/lib/sitePublicAssets.ts +1 -0
  177. package/src/styles/global.css +284 -93
  178. package/starters/basic/.github/workflows/deploy.yml +1 -1
  179. package/starters/basic/README.md +7 -6
  180. package/starters/basic/package.json +1 -0
  181. package/starters/basic/site/config.mjs +0 -13
  182. package/starters/basic/site/content.md +1 -1
  183. package/starters/basic/site/sitewide-content.md +14 -0
  184. package/starters/basic/site/theme.md +13 -24
  185. package/starters/project/.github/workflows/deploy.yml +1 -1
  186. package/starters/project/README.md +10 -8
  187. package/starters/project/package.json +1 -0
  188. package/starters/project/site/config.mjs +0 -13
  189. package/starters/project/site/sitewide-content.md +14 -0
  190. package/starters/project/site/theme.md +3 -11
  191. package/examples/dog-gallery/site/.norna/generated-images.json +0 -226
  192. package/examples/dog-gallery/site/config.mjs +0 -67
  193. package/examples/dog-gallery/site/content.md +0 -128
  194. package/examples/dog-gallery/site/images/black-dogs/black-puppy-meadow.png +0 -0
  195. package/examples/dog-gallery/site/images/black-dogs/photo-of-a-black-dog.jpg +0 -0
  196. package/examples/dog-gallery/site/images/brown-dogs/brown-dog.jpg +0 -0
  197. package/examples/dog-gallery/site/images/brown-dogs/dog-accompanies-master.jpg +0 -0
  198. package/examples/dog-gallery/site/images/golden-dogs/golden-retriever.jpg +0 -0
  199. package/examples/dog-gallery/site/images/golden-dogs/toller-puppy.jpg +0 -0
  200. package/examples/dog-gallery/site/images/white-dogs/white-cute-dog.jpg +0 -0
  201. package/examples/dog-gallery/site/images/white-dogs/white-puppy-garden.png +0 -0
  202. package/examples/dog-gallery/site/public/favicon.svg +0 -7
  203. package/examples/dog-gallery/site/routes/010-dog-care/route-content.md +0 -38
  204. package/examples/dog-gallery/site/theme.md +0 -112
  205. package/examples/typography-presets/.astro/collections/site.schema.json +0 -776
  206. package/examples/typography-presets/.astro/data-store.json +0 -1
  207. package/examples/typography-presets/.astro/dev.log +0 -24
  208. package/examples/typography-presets/site/.norna/generated-images.json +0 -290
  209. package/examples/typography-presets/site/content.md +0 -134
  210. package/examples/typography-presets/site/theme.md +0 -43
  211. /package/examples/{typography-presets/.astro/content-modules.mjs → complete-sites/dog-shelter-multi-page/.astro/content-assets.mjs} +0 -0
  212. /package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/types.d.ts +0 -0
  213. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -0
  214. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -0
  215. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_aria-query.js +0 -0
  216. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -0
  217. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_axobject-query.js +0 -0
  218. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -0
  219. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_html-escaper.js +0 -0
  220. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -0
  221. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -0
  222. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -0
  223. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -0
  224. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -0
  225. /package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/embla-carousel.js +0 -0
  226. /package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/embla-carousel.js.map +0 -0
  227. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -0
  228. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -0
  229. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/icons-RyebKi45.js +0 -0
  230. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -0
  231. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/package.json +0 -0
  232. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -0
  233. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -0
  234. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -0
  235. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/toolbar-63PA619H.js +0 -0
  236. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -0
  237. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -0
  238. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -0
  239. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/window-jPkpKVcy.js +0 -0
  240. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -0
  241. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -0
  242. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -0
  243. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/site/public/robots.txt +0 -0
  244. /package/examples/{typography-presets → feature-demos/media-and-surfaces}/.astro/content-assets.mjs +0 -0
  245. /package/examples/{typography-presets → feature-demos/media-and-surfaces}/node_modules/.vite/deps/package.json +0 -0
  246. /package/examples/{typography-presets → feature-demos/media-and-surfaces}/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -0
  247. /package/examples/{typography-presets → feature-demos/theme-presets}/.astro/settings.json +0 -0
  248. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/_metadata.json +0 -0
  249. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -0
  250. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -0
  251. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_aria-query.js +0 -0
  252. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -0
  253. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_axobject-query.js +0 -0
  254. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -0
  255. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_html-escaper.js +0 -0
  256. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -0
  257. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -0
  258. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -0
  259. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -0
  260. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -0
  261. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -0
  262. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -0
  263. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/icons-RyebKi45.js +0 -0
  264. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -0
  265. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -0
  266. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -0
  267. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/toolbar-63PA619H.js +0 -0
  268. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -0
  269. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -0
  270. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -0
  271. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/window-jPkpKVcy.js +0 -0
  272. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -0
  273. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -0
  274. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -0
  275. /package/examples/{typography-presets → feature-demos/theme-presets}/site/public/robots.txt +0 -0
  276. /package/examples/{typography-presets/site/images/quiet-gallery → feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio}/puppy-portrait.jpg +0 -0
  277. /package/examples/{typography-presets/site/images/quiet-gallery → feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio}/shepherd-portrait.jpg +0 -0
  278. /package/examples/{typography-presets/site/images/quiet-gallery → feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio}/white-puppy.jpg +0 -0
  279. /package/examples/{typography-presets/site/images/compact-gallery → feature-demos/theme-presets/site/routes/020-documentation/images/documentation}/black-schnauzer.jpg +0 -0
  280. /package/examples/{typography-presets/site/images/compact-gallery → feature-demos/theme-presets/site/routes/020-documentation/images/documentation}/retriever-portrait.jpg +0 -0
  281. /package/examples/{typography-presets/site/images/compact-gallery → feature-demos/theme-presets/site/routes/020-documentation/images/documentation}/schnauzer-portrait.jpg +0 -0
  282. /package/examples/{typography-presets/site/images/text-forward → feature-demos/theme-presets/site/routes/030-project/images/project}/boxer-portrait.jpg +0 -0
  283. /package/examples/{typography-presets/site/images/text-forward → feature-demos/theme-presets/site/routes/030-project/images/project}/grass-puppy.jpg +0 -0
  284. /package/examples/{typography-presets/site/images/text-forward → feature-demos/theme-presets/site/routes/030-project/images/project}/grey-street-dog.jpg +0 -0
  285. /package/examples/{typography-presets/site → feature-demos/theme-presets/site/routes/040-statement}/images/statement/black-pedigree.jpg +0 -0
  286. /package/examples/{typography-presets/site → feature-demos/theme-presets/site/routes/040-statement}/images/statement/sheepdog-grass.jpg +0 -0
  287. /package/examples/{typography-presets/site → feature-demos/theme-presets/site/routes/040-statement}/images/statement/sheepdog-wide.jpg +0 -0
@@ -1,8 +1,8 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { findMap } from './lib/frontmatter-yaml.mjs';
2
+ import path from 'node:path';
3
+ import { parseYamlMapping } from './lib/frontmatter-yaml.mjs';
3
4
  import {
4
5
  defaultTypography,
5
- resolveTypographyOverride,
6
6
  resolveTypographyConfig,
7
7
  toYamlLines,
8
8
  typographyPresets,
@@ -15,14 +15,17 @@ import {
15
15
  splitSiteFile,
16
16
  validateContentFrontmatterStructure,
17
17
  validateFrontmatterIndentation,
18
+ validateRouteThemeFrontmatterStructure,
18
19
  validateThemeFrontmatterStructure,
19
20
  } from './lib/site-content.mjs';
20
21
  import {
21
22
  siteContentLabel,
22
23
  siteContentPath,
24
+ siteRoutesDir,
23
25
  siteThemeLabel,
24
26
  siteThemePath,
25
27
  } from './lib/site-paths.mjs';
28
+ import { resolveThemeConfig } from './lib/theme-presets.mjs';
26
29
 
27
30
  const mode = process.argv[2] ?? 'show';
28
31
 
@@ -30,30 +33,35 @@ const typographyValuePaths = [
30
33
  ['headings', 'h1', 'align', 'desktop'],
31
34
  ['headings', 'h1', 'align', 'mobile'],
32
35
  ['headings', 'h1', 'size'],
36
+ ['headings', 'h1', 'weight'],
33
37
  ['headings', 'h1', 'lineHeight'],
34
38
  ['headings', 'h1', 'spacingBefore'],
35
39
  ['headings', 'h1', 'spacingAfter'],
36
40
  ['headings', 'h2', 'align', 'desktop'],
37
41
  ['headings', 'h2', 'align', 'mobile'],
38
42
  ['headings', 'h2', 'size'],
43
+ ['headings', 'h2', 'weight'],
39
44
  ['headings', 'h2', 'lineHeight'],
40
45
  ['headings', 'h2', 'spacingBefore'],
41
46
  ['headings', 'h2', 'spacingAfter'],
42
47
  ['headings', 'h3', 'align', 'desktop'],
43
48
  ['headings', 'h3', 'align', 'mobile'],
44
49
  ['headings', 'h3', 'size'],
50
+ ['headings', 'h3', 'weight'],
45
51
  ['headings', 'h3', 'lineHeight'],
46
52
  ['headings', 'h3', 'spacingBefore'],
47
53
  ['headings', 'h3', 'spacingAfter'],
48
54
  ['headings', 'h4', 'align', 'desktop'],
49
55
  ['headings', 'h4', 'align', 'mobile'],
50
56
  ['headings', 'h4', 'size'],
57
+ ['headings', 'h4', 'weight'],
51
58
  ['headings', 'h4', 'lineHeight'],
52
59
  ['headings', 'h4', 'spacingBefore'],
53
60
  ['headings', 'h4', 'spacingAfter'],
54
61
  ['body', 'align', 'desktop'],
55
62
  ['body', 'align', 'mobile'],
56
63
  ['body', 'size'],
64
+ ['body', 'width'],
57
65
  ['body', 'lineHeight'],
58
66
  ['body', 'paragraphSpacing'],
59
67
  ['caption', 'align', 'desktop'],
@@ -74,8 +82,6 @@ const rhythmValuePaths = new Set([
74
82
  'body.paragraphSpacing',
75
83
  'caption.spacingBefore',
76
84
  ]);
77
- const countIndent = (line) => line.match(/^\s*/)?.[0].length ?? 0;
78
-
79
85
  const isPlainObject = (value) => (
80
86
  value !== null &&
81
87
  typeof value === 'object' &&
@@ -156,19 +162,6 @@ const applyOverrideSources = (sources, typographyConfig, sourceLabel) => {
156
162
  return sources;
157
163
  };
158
164
 
159
- const inheritedSources = (sources) => {
160
- const inherited = structuredClone(sources);
161
-
162
- for (const path of typographyValuePaths) {
163
- setPath(inherited, path, {
164
- ...getPath(sources, path),
165
- inherited: true,
166
- });
167
- }
168
-
169
- return inherited;
170
- };
171
-
172
165
  const resolveAnnotatedTypographyConfig = (typographyConfig, sourceLabel) => {
173
166
  const resolved = resolveTypographyConfig(typographyConfig ?? defaultTypography);
174
167
  const sources = applyOverrideSources(
@@ -193,144 +186,59 @@ const resolveAnnotatedTypographyConfig = (typographyConfig, sourceLabel) => {
193
186
  };
194
187
  };
195
188
 
196
- const resolveAnnotatedTypographyOverride = (baseAnnotated, typographyConfig, sourceLabel) => {
197
- if (typographyConfig?.preset || typographyConfig?.rhythm) {
198
- const resolvedConfig = {
199
- preset: typographyConfig.preset ?? baseAnnotated.resolved.preset,
200
- rhythm: typographyConfig.rhythm ?? baseAnnotated.resolved.rhythm,
201
- overrides: typographyConfig.overrides,
202
- };
203
- const resolved = resolveTypographyConfig(resolvedConfig);
204
- const sources = applyOverrideSources(
205
- defaultSources(resolved.preset, resolved.rhythm),
206
- typographyConfig,
207
- sourceLabel,
208
- );
209
-
210
- return {
211
- preset: {
212
- value: resolved.preset,
213
- source: typographyConfig.preset ? sourceLabel : baseAnnotated.preset.source,
214
- ...(typographyConfig.preset ? {} : { inherited: true }),
215
- },
216
- rhythm: {
217
- value: resolved.rhythm,
218
- source: typographyConfig.rhythm ? sourceLabel : baseAnnotated.rhythm.source,
219
- ...(typographyConfig.rhythm ? {} : { inherited: true }),
220
- },
221
- resolved,
222
- sources,
223
- };
224
- }
225
-
226
- if (typographyConfig?.overrides) {
227
- const resolved = resolveTypographyOverride(baseAnnotated.resolved, typographyConfig);
228
- const sources = applyOverrideSources(
229
- inheritedSources(baseAnnotated.sources),
230
- typographyConfig,
231
- sourceLabel,
232
- );
233
-
234
- return {
235
- preset: {
236
- value: resolved.preset,
237
- source: baseAnnotated.preset.source,
238
- inherited: true,
239
- },
240
- rhythm: {
241
- value: resolved.rhythm,
242
- source: baseAnnotated.rhythm.source,
243
- inherited: true,
244
- },
245
- resolved,
246
- sources,
247
- };
248
- }
249
-
250
- return {
251
- preset: {
252
- value: baseAnnotated.resolved.preset,
253
- source: baseAnnotated.preset.source,
254
- inherited: true,
255
- },
256
- rhythm: {
257
- value: baseAnnotated.resolved.rhythm,
258
- source: baseAnnotated.rhythm.source,
259
- inherited: true,
260
- },
261
- resolved: baseAnnotated.resolved,
262
- sources: inheritedSources(baseAnnotated.sources),
263
- };
264
- };
265
-
266
189
  const formatAnnotatedTypography = (annotated) => ({
267
190
  preset: annotated.preset,
268
191
  rhythm: annotated.rhythm,
269
192
  resolved: annotateResolvedValues(annotated.resolved, annotated.sources),
270
193
  });
271
194
 
272
- const getSectionMetadataBlocks = (lines) => {
273
- const sectionsMap = findMap(lines, 'sections');
274
- if (!sectionsMap) return new Map();
275
-
276
- const sections = new Map();
277
- let current = null;
278
-
279
- for (let index = sectionsMap.index + 1; index < lines.length; index += 1) {
280
- const line = lines[index];
281
- if (!line.trim()) continue;
282
-
283
- const indent = countIndent(line);
284
- if (indent <= sectionsMap.indent) break;
285
-
286
- const sectionMatch = line.match(/^\s{2}([a-z0-9-]+):(?:\s+.*)?\s*$/);
287
- if (sectionMatch) {
288
- if (current) current.end = index;
289
- current = { id: sectionMatch[1], start: index, end: lines.length };
290
- sections.set(current.id, current);
291
- }
292
- }
293
-
294
- const sectionList = Array.from(sections.values());
295
- const finalSection = sectionList.at(-1);
296
- if (finalSection) {
297
- const afterSections = lines.findIndex((line, index) => (
298
- index > finalSection.start &&
299
- line.trim() &&
300
- countIndent(line) <= sectionsMap.indent
301
- ));
302
- finalSection.end = afterSections === -1 ? lines.length : afterSections;
195
+ const readThemeTypography = async () => {
196
+ const themeFile = await readFile(siteThemePath, 'utf8');
197
+ const { frontmatter: themeFrontmatter, frontmatterBody: themeFrontmatterBody } = splitSiteFile(themeFile, siteThemeLabel);
198
+ const indentationIssues = [];
199
+ validateFrontmatterIndentation(themeFrontmatter, (issue) => indentationIssues.push(issue));
200
+ validateThemeFrontmatterStructure(themeFrontmatter, (issue) => indentationIssues.push(issue));
201
+ if (indentationIssues.length > 0) {
202
+ throw new Error([
203
+ `Cannot inspect typography because ${siteThemeLabel} has invalid frontmatter.`,
204
+ ...indentationIssues.map((issue) => `- ${issue.message}`),
205
+ ].join('\n'));
303
206
  }
304
207
 
305
- return sections;
208
+ const themeConfig = resolveThemeConfig(parseYamlMapping(themeFrontmatterBody), siteThemeLabel);
209
+ const themeTypographyConfig = themeConfig.typography;
210
+ return resolveAnnotatedTypographyConfig(themeTypographyConfig ?? defaultTypography, siteThemeLabel);
306
211
  };
307
212
 
308
- const readThemeTypography = async () => {
309
- const themeFile = await readFile(siteThemePath, 'utf8').catch((error) => {
310
- if (error?.code === 'ENOENT') {
311
- return '---\n---\n';
312
- }
213
+ const readRouteThemeTypography = async (contentFile, themeTypography) => {
214
+ if (contentFile.isHome) return themeTypography;
313
215
 
216
+ const routeThemePath = path.join(siteRoutesDir, contentFile.routeDirectory, 'theme.md');
217
+ const routeThemeLabel = `${contentFile.contentLabel.replace(/\/route-content\.md$/, '')}/theme.md`;
218
+ const routeThemeFile = await readFile(routeThemePath, 'utf8').catch((error) => {
219
+ if (error?.code === 'ENOENT') return null;
314
220
  throw error;
315
221
  });
316
- const { frontmatter: themeFrontmatter, frontmatterBody: themeFrontmatterBody } = splitSiteFile(themeFile, siteThemeLabel);
222
+ if (!routeThemeFile) return themeTypography;
223
+
224
+ const { frontmatter, frontmatterBody } = splitSiteFile(routeThemeFile, routeThemeLabel);
317
225
  const indentationIssues = [];
318
- validateFrontmatterIndentation(themeFrontmatter, (issue) => indentationIssues.push(issue));
319
- validateThemeFrontmatterStructure(themeFrontmatter, (issue) => indentationIssues.push(issue));
226
+ validateFrontmatterIndentation(frontmatter, (issue) => indentationIssues.push(issue));
227
+ validateRouteThemeFrontmatterStructure(frontmatter, (issue) => indentationIssues.push(issue));
320
228
  if (indentationIssues.length > 0) {
321
229
  throw new Error([
322
- `Cannot inspect typography because ${siteThemeLabel} has invalid frontmatter.`,
230
+ `Cannot inspect typography because ${routeThemeLabel} has invalid frontmatter.`,
323
231
  ...indentationIssues.map((issue) => `- ${issue.message}`),
324
232
  ].join('\n'));
325
233
  }
326
234
 
327
- const themeLines = themeFrontmatterBody.split(/\r?\n/);
328
- const themeTypographyConfig = findMap(themeLines, 'typography', 0, themeLines.length, 0)?.value;
329
- return resolveAnnotatedTypographyConfig(themeTypographyConfig ?? defaultTypography, siteThemeLabel);
235
+ const routeThemeConfig = resolveThemeConfig(parseYamlMapping(frontmatterBody), routeThemeLabel);
236
+ const typographyConfig = routeThemeConfig.typography;
237
+ return resolveAnnotatedTypographyConfig(typographyConfig ?? defaultTypography, routeThemeLabel);
330
238
  };
331
239
 
332
- const readPageTypography = async (contentFile, themeTypography) => {
333
- const { frontmatter, frontmatterBody, body } = await readSiteFile(contentFile.contentPath, contentFile.contentLabel);
240
+ const readPageTypography = async (contentFile, siteThemeTypography) => {
241
+ const { frontmatter, body } = await readSiteFile(contentFile.contentPath, contentFile.contentLabel);
334
242
  const indentationIssues = [];
335
243
  validateFrontmatterIndentation(frontmatter, (issue) => indentationIssues.push(issue));
336
244
  validateContentFrontmatterStructure(frontmatter, (issue) => indentationIssues.push(issue));
@@ -341,27 +249,13 @@ const readPageTypography = async (contentFile, themeTypography) => {
341
249
  ].join('\n'));
342
250
  }
343
251
 
344
- const lines = frontmatterBody.split(/\r?\n/);
345
- const pagePresentation = findMap(lines, 'presentation', 0, lines.length, 0);
346
- const pageTypographyConfig = pagePresentation
347
- ? findMap(lines, 'typography', pagePresentation.index + 1, pagePresentation.nextIndex)?.value
348
- : null;
349
- const pageTypography = resolveAnnotatedTypographyOverride(themeTypography, pageTypographyConfig ?? undefined, contentFile.contentLabel);
350
- const sectionMetadataBlocks = getSectionMetadataBlocks(lines);
252
+ const pageTypography = await readRouteThemeTypography(contentFile, siteThemeTypography);
351
253
  const sections = getBodySections(body).sections
352
254
  .filter((section) => section.id)
353
255
  .map((section) => {
354
- const metadata = sectionMetadataBlocks.get(section.id);
355
- const presentation = metadata
356
- ? findMap(lines, 'presentation', metadata.start + 1, metadata.end)
357
- : null;
358
- const typography = presentation
359
- ? findMap(lines, 'typography', presentation.index + 1, presentation.nextIndex)?.value
360
- : null;
361
-
362
256
  return {
363
257
  id: section.id,
364
- typography: resolveAnnotatedTypographyOverride(pageTypography, typography ?? undefined, `${contentFile.contentLabel} sections.${section.id}`),
258
+ typography: pageTypography,
365
259
  };
366
260
  });
367
261
 
@@ -5,6 +5,7 @@ import { stdin as input, stdout as output } from 'node:process';
5
5
  import path from 'node:path';
6
6
  import { promisify } from 'node:util';
7
7
  import {
8
+ extractInlineNoteDiagnostics,
8
9
  extractMarkdownImageReferences,
9
10
  extractNornaMarkdownBlockDiagnostics,
10
11
  getNornaBlockImageReferences,
@@ -12,15 +13,13 @@ import {
12
13
  import {
13
14
  getBodySections,
14
15
  getContentFiles,
15
- getFrontmatterInlineStyleNames,
16
16
  getFrontmatterSections,
17
17
  getImageCandidatesByName,
18
- getInlineStyleReferences,
18
+ getDeprecatedInlineStyleReferences,
19
19
  readSiteFile,
20
20
  readThemeFile,
21
21
  toPosixPath,
22
22
  validateContentFrontmatterStructure,
23
- validateFrontmatterColorValues,
24
23
  validateFrontmatterIndentation,
25
24
  validateThemeFrontmatterStructure,
26
25
  } from './lib/site-content.mjs';
@@ -395,17 +394,12 @@ try {
395
394
  themeFrontmatter = (await readThemeFile(siteThemePath)).frontmatter;
396
395
  validateFrontmatterIndentation(themeFrontmatter, addIssue);
397
396
  validateThemeFrontmatterStructure(themeFrontmatter, addIssue);
398
- validateFrontmatterColorValues(themeFrontmatter, addIssue, siteThemeLabel);
399
397
  } catch (error) {
400
398
  if (error?.code !== 'ENOENT') {
401
399
  throw error;
402
400
  }
403
401
  }
404
402
 
405
- const themeInlineStyleNames = themeFrontmatter
406
- ? getFrontmatterInlineStyleNames(themeFrontmatter)
407
- : new Set();
408
-
409
403
  const contentFiles = await getContentFiles();
410
404
  const allImageFiles = [];
411
405
  const contentFileContexts = [];
@@ -417,7 +411,6 @@ for (const contentFile of contentFiles) {
417
411
  const bodyLineOffset = frontmatter.split(/\r?\n/).length - 1;
418
412
  validateFrontmatterIndentation(frontmatter, addIssue);
419
413
  validateContentFrontmatterStructure(frontmatter, addIssue);
420
- validateFrontmatterColorValues(frontmatter, addIssue, contentFile.contentLabel);
421
414
 
422
415
  const frontmatterSections = getFrontmatterSections(frontmatter);
423
416
  const frontmatterIds = new Set(frontmatterSections.map((section) => section.id));
@@ -465,6 +458,17 @@ for (const contentFile of contentFiles) {
465
458
  });
466
459
  blockResultsBySectionId.set(section.id, blockResults);
467
460
 
461
+ const inlineNoteResults = extractInlineNoteDiagnostics(section.text, {
462
+ label: contentFile.contentLabel,
463
+ lineOffset: bodyLineOffset + section.line - 1,
464
+ });
465
+ for (const error of inlineNoteResults.errors) {
466
+ addSectionIssue(contentFile, section, {
467
+ severity: 'error',
468
+ message: error.message,
469
+ });
470
+ }
471
+
468
472
  for (const reference of getNornaBlockImageReferences(blockResults.blocks)) {
469
473
  const expectedPath = getExpectedImagePath(contentFile, section.id, reference.image);
470
474
  addExpectedReference(globalExpectedReferencesByPath, expectedPath, { contentFile, section, reference });
@@ -501,14 +505,12 @@ for (const context of contentFileContexts) {
501
505
  }
502
506
  }
503
507
 
504
- for (const styleName of new Set(getInlineStyleReferences(body))) {
505
- if (!themeInlineStyleNames.has(styleName)) {
506
- addContentIssue(contentFile, {
507
- severity: 'error',
508
- message: `Inline style ".${styleName}" is used in ${contentFile.contentLabel} but is not defined in ${siteThemeLabel} presentation.inlineStyles.`,
509
- fix: `Add presentation.inlineStyles.${styleName} to ${siteThemeLabel} or remove "{.${styleName}}" from Markdown.`,
510
- });
511
- }
508
+ for (const styleName of new Set(getDeprecatedInlineStyleReferences(body))) {
509
+ addContentIssue(contentFile, {
510
+ severity: 'error',
511
+ message: `Inline color style ".${styleName}" is no longer supported in ${contentFile.contentLabel}.`,
512
+ fix: 'Use standard Markdown emphasis, a blockquote, or a semantic Norna block instead of color syntax.',
513
+ });
512
514
  }
513
515
 
514
516
  for (const section of sections) {
@@ -45,8 +45,8 @@ const makePngHeader = ({ width, height }) => {
45
45
  const defaultTheme = `---
46
46
  typography:
47
47
  preset: quiet-gallery
48
- frame:
49
- colors: presentation
48
+ presentation:
49
+ palette: dark
50
50
  ---
51
51
  `;
52
52
 
@@ -173,14 +173,6 @@ test('content:check warns when carousel images use different aspect ratios', asy
173
173
  });
174
174
  });
175
175
 
176
- const inlineStyleTheme = `---
177
- presentation:
178
- inlineStyles:
179
- highlight:
180
- color: "#ffd84d"
181
- ---
182
- `;
183
-
184
176
  const inlineStyleSite = `---
185
177
  title: Inline Style
186
178
  ---
@@ -188,10 +180,9 @@ title: Inline Style
188
180
  This has [known text]{.highlight} and [unknown text]{.missing}.
189
181
  `;
190
182
 
191
- test('content:check fails when Markdown uses undefined inline styles', async () => {
183
+ test('content:check fails when Markdown uses removed inline color styles', async () => {
192
184
  await withTempProject({
193
185
  site: inlineStyleSite,
194
- theme: inlineStyleTheme,
195
186
  files: [],
196
187
  }, async (root) => {
197
188
  const result = runContentScript(root, ['--check']);
@@ -199,20 +190,12 @@ test('content:check fails when Markdown uses undefined inline styles', async ()
199
190
 
200
191
  assert.equal(result.status, 1, output);
201
192
  assert.match(output, /^Content check failed\./m);
202
- assert.match(output, /Inline style "\.missing" is used in site\/content\.md but is not defined in site\/theme\.md presentation\.inlineStyles\./);
203
- assert.doesNotMatch(output, /"\.highlight" is used in Markdown/);
193
+ assert.match(output, /Inline color style "\.highlight" is no longer supported in site\/content\.md\./);
194
+ assert.match(output, /Inline color style "\.missing" is no longer supported in site\/content\.md\./);
204
195
  });
205
196
  });
206
197
 
207
- const invalidInlineStyleColorTheme = `---
208
- presentation:
209
- inlineStyles:
210
- yellow:
211
- color: "#ffd844d"
212
- ---
213
- `;
214
-
215
- test('content:check explains invalid inline style colors', async () => {
198
+ test('content:check suggests semantic Markdown instead of inline color styles', async () => {
216
199
  await withTempProject({
217
200
  site: `---
218
201
  title: Invalid Inline Color
@@ -220,7 +203,6 @@ title: Invalid Inline Color
220
203
  ## Intro {#intro}
221
204
  This has [yellow text]{.yellow}.
222
205
  `,
223
- theme: invalidInlineStyleColorTheme,
224
206
  files: [],
225
207
  }, async (root) => {
226
208
  const result = runContentScript(root, ['--check']);
@@ -228,9 +210,59 @@ This has [yellow text]{.yellow}.
228
210
 
229
211
  assert.equal(result.status, 1, output);
230
212
  assert.match(output, /^Content check failed\./m);
231
- assert.match(output, /site\/theme\.md line 5 defines presentation\.inlineStyles\.yellow\.color with invalid color value "#ffd844d"\./);
232
- assert.match(output, /Use a quoted hex color in #rgb, #rrggbb, or #rrggbbaa form, for example color: "#ffd84d"\./);
233
- assert.doesNotMatch(output, /Inline style "\.yellow" is used in site\/content\.md but is not defined/);
213
+ assert.match(output, /Use standard Markdown emphasis, a blockquote, or a semantic Norna block instead of color syntax\./);
214
+ });
215
+ });
216
+
217
+ const inlineNoteSite = `---
218
+ title: Inline notes
219
+ description: Fixture
220
+ ---
221
+ ## Intro {#intro}
222
+ This paragraph has a note reference.{note-ref}
223
+
224
+ {note: Additional context.}
225
+
226
+ \`\`\`text
227
+ {note-ref}
228
+ {note: This is code, not a note.
229
+ \`\`\`
230
+ `;
231
+
232
+ test('content:check accepts valid inline notes and ignores note syntax in code fences', async () => {
233
+ await withTempProject({ site: inlineNoteSite, files: [] }, async (root) => {
234
+ const result = runContentScript(root, ['--check']);
235
+ const output = getOutput(result);
236
+
237
+ assert.equal(result.status, 0, output);
238
+ assert.match(output, /Content check passed\./);
239
+ });
240
+ });
241
+
242
+ test('content:check rejects unpaired and repeated inline notes', async () => {
243
+ await withTempProject({
244
+ site: `---
245
+ title: Invalid inline notes
246
+ description: Fixture
247
+ ---
248
+ ## Orphan {#orphan}
249
+ {note: This note has no reference.}
250
+
251
+ ## Missing {#missing}
252
+ This reference has no note.{note-ref}
253
+
254
+ ## Repeated {#repeated}
255
+ This paragraph has {note-ref} two references {note-ref}.
256
+ `,
257
+ files: [],
258
+ }, async (root) => {
259
+ const result = runContentScript(root, ['--check']);
260
+ const output = getOutput(result);
261
+
262
+ assert.equal(result.status, 1, output);
263
+ assert.match(output, /A "\{note: \.\.\.\}" requires a preceding paragraph containing "\{note-ref\}"\./);
264
+ assert.match(output, /contains "\{note-ref\}" but has no following "\{note: \.\.\.\}"/);
265
+ assert.match(output, /A paragraph may contain only one "\{note-ref\}"\./);
234
266
  });
235
267
  });
236
268