@janga/norna 0.7.10 → 0.7.12

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 (476) hide show
  1. package/README.md +120 -106
  2. package/bin/norna-cli.mjs +4 -1
  3. package/docs/README.md +107 -74
  4. package/docs/assets/norna-dog-shelter.jpg +0 -0
  5. package/docs/commands.md +13 -4
  6. package/docs/configuration.md +86 -184
  7. package/docs/content.md +14 -14
  8. package/docs/design/command-organization.md +1 -1
  9. package/docs/design/norna-diagram-design.md +2 -1
  10. package/docs/design/site-examples-structure.md +38 -24
  11. package/docs/engine-development.md +28 -15
  12. package/docs/getting-started.md +141 -124
  13. package/docs/how-to/embedded-site.md +35 -0
  14. package/docs/publishing.md +47 -46
  15. package/docs/requirements.md +54 -0
  16. package/docs/routes.md +3 -2
  17. package/docs/site-structure.md +12 -9
  18. package/docs/sitewide-content.md +2 -1
  19. package/docs/theme.md +104 -34
  20. package/docs/typography.md +32 -17
  21. package/examples/README.md +43 -0
  22. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/collections/sitewide.schema.json +24 -0
  23. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/collections/theme.schema.json +9 -24
  24. package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/.astro/content.d.ts +9 -1
  25. package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +1 -0
  26. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/dev-local.json +2 -2
  27. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.json +13 -0
  28. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +26 -0
  29. package/examples/complete-sites/dog-shelter-multi-page/.astro/settings.json +5 -0
  30. package/examples/complete-sites/dog-shelter-multi-page/README.md +16 -0
  31. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/_metadata.json +74 -0
  32. package/examples/{typography-presets/node_modules/.vite/deps/astro-D_GIpJIE.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro-B3JHJyiv.js} +4 -4
  33. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro-B3JHJyiv.js.map +1 -0
  34. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_aria-query.js +151 -151
  35. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
  36. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_axobject-query.js +131 -131
  37. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
  38. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_html-escaper.js +1 -1
  39. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
  40. package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +10 -10
  41. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
  42. package/examples/{typography-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/audit-C3SVr7dT.js} +10 -10
  43. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/audit-C3SVr7dT.js.map +1 -0
  44. package/examples/{typography-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/highlight-BLtvqtzO.js} +1 -1
  45. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +1 -0
  46. package/examples/{typography-presets/node_modules/.vite/deps/icons-RyebKi45.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/icons-C92i61-2.js} +1 -1
  47. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/icons-C92i61-2.js.map +1 -0
  48. package/examples/{typography-presets/node_modules/.vite/deps/settings-DaU-gNnK.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/settings-v5GgKks_.js} +2 -2
  49. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/settings-v5GgKks_.js.map +1 -0
  50. package/examples/{typography-presets/node_modules/.vite/deps/toolbar-63PA619H.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/toolbar-BFvJVp26.js} +2 -2
  51. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +1 -0
  52. package/examples/{typography-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js} +10 -10
  53. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +1 -0
  54. package/examples/{typography-presets/node_modules/.vite/deps/window-jPkpKVcy.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/window-vo3A6TMn.js} +1 -1
  55. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/window-vo3A6TMn.js.map +1 -0
  56. package/examples/{typography-presets/node_modules/.vite/deps/xray-BXCHpEJP.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/xray-DwhzGckb.js} +3 -3
  57. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/xray-DwhzGckb.js.map +1 -0
  58. package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +98 -0
  59. package/examples/complete-sites/dog-shelter-multi-page/site/config.md +3 -0
  60. package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/content.md +12 -0
  61. package/examples/complete-sites/dog-shelter-multi-page/site/public/logo.svg +9 -0
  62. package/examples/complete-sites/dog-shelter-multi-page/site/routes/010-dogs/route-content.md +22 -0
  63. package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/routes/020-adopt/route-content.md +11 -0
  64. package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.md +16 -0
  65. package/examples/complete-sites/dog-shelter-multi-page/site/theme.md +3 -0
  66. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/site.schema.json +59 -0
  67. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/sitewide.schema.json +138 -0
  68. package/examples/{dog-gallery → complete-sites/dog-shelter-single-page}/.astro/collections/theme.schema.json +151 -68
  69. package/examples/complete-sites/dog-shelter-single-page/.astro/content.d.ts +183 -0
  70. package/examples/complete-sites/dog-shelter-single-page/.astro/data-store.json +1 -0
  71. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.json +13 -0
  72. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.log +14 -0
  73. package/examples/complete-sites/dog-shelter-single-page/.astro/settings.json +5 -0
  74. package/examples/complete-sites/dog-shelter-single-page/README.md +16 -0
  75. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/_metadata.json +74 -0
  76. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro-B3JHJyiv.js +434 -0
  77. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro-B3JHJyiv.js.map +1 -0
  78. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
  79. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
  80. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
  81. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
  82. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
  83. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
  84. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
  85. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
  86. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/audit-C3SVr7dT.js +1534 -0
  87. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/audit-C3SVr7dT.js.map +1 -0
  88. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/highlight-BLtvqtzO.js +48 -0
  89. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +1 -0
  90. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/icons-C92i61-2.js +42 -0
  91. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/icons-C92i61-2.js.map +1 -0
  92. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/settings-v5GgKks_.js +190 -0
  93. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/settings-v5GgKks_.js.map +1 -0
  94. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/toolbar-BFvJVp26.js +458 -0
  95. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +1 -0
  96. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js +1016 -0
  97. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +1 -0
  98. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/window-vo3A6TMn.js +32 -0
  99. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/window-vo3A6TMn.js.map +1 -0
  100. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/xray-DwhzGckb.js +111 -0
  101. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/xray-DwhzGckb.js.map +1 -0
  102. package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +50 -0
  103. package/examples/complete-sites/dog-shelter-single-page/site/config.md +3 -0
  104. package/examples/complete-sites/dog-shelter-single-page/site/content.md +34 -0
  105. package/examples/complete-sites/dog-shelter-single-page/site/public/logo.svg +9 -0
  106. package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.md +16 -0
  107. package/examples/complete-sites/dog-shelter-single-page/site/theme.md +3 -0
  108. package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +59 -0
  109. package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +138 -0
  110. package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +755 -0
  111. package/examples/feature-demos/media-and-surfaces/.astro/content-assets.mjs +4 -0
  112. package/examples/feature-demos/media-and-surfaces/.astro/content-modules.mjs +1 -0
  113. package/examples/feature-demos/media-and-surfaces/.astro/content.d.ts +183 -0
  114. package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +1 -0
  115. package/examples/feature-demos/media-and-surfaces/.astro/dev.log +24 -0
  116. package/examples/feature-demos/media-and-surfaces/.astro/settings.json +5 -0
  117. package/examples/feature-demos/media-and-surfaces/.astro/types.d.ts +2 -0
  118. package/examples/feature-demos/media-and-surfaces/README.md +21 -0
  119. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +80 -0
  120. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js +434 -0
  121. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js.map +1 -0
  122. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
  123. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
  124. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
  125. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
  126. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
  127. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
  128. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
  129. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
  130. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js +1534 -0
  131. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js.map +1 -0
  132. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/embla-carousel.js +1389 -0
  133. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/embla-carousel.js.map +1 -0
  134. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js +48 -0
  135. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +1 -0
  136. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js +42 -0
  137. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js.map +1 -0
  138. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/package.json +3 -0
  139. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
  140. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js +190 -0
  141. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js.map +1 -0
  142. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js +458 -0
  143. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +1 -0
  144. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js +1016 -0
  145. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +1 -0
  146. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js +32 -0
  147. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js.map +1 -0
  148. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js +111 -0
  149. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js.map +1 -0
  150. package/examples/{presentation → feature-demos/media-and-surfaces}/site/.norna/generated-images.json +16 -16
  151. package/examples/feature-demos/media-and-surfaces/site/config.md +4 -0
  152. package/examples/feature-demos/media-and-surfaces/site/content.md +18 -0
  153. package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/route-content.md +17 -24
  154. package/examples/{presentation/site/routes/030-surfaces → feature-demos/media-and-surfaces/site/routes/020-surfaces}/route-content.md +1 -1
  155. package/examples/{presentation/site/routes/030-surfaces → feature-demos/media-and-surfaces/site/routes/020-surfaces}/theme.md +1 -0
  156. package/examples/feature-demos/media-and-surfaces/site/sitewide-content.md +6 -0
  157. package/examples/feature-demos/media-and-surfaces/site/theme.md +3 -0
  158. package/examples/feature-demos/sitewide-content/.astro/collections/site.schema.json +59 -0
  159. package/examples/feature-demos/sitewide-content/.astro/collections/sitewide.schema.json +138 -0
  160. package/examples/feature-demos/sitewide-content/.astro/collections/theme.schema.json +755 -0
  161. package/examples/feature-demos/sitewide-content/.astro/content-assets.mjs +1 -0
  162. package/examples/feature-demos/sitewide-content/.astro/content-modules.mjs +1 -0
  163. package/examples/feature-demos/sitewide-content/.astro/content.d.ts +183 -0
  164. package/examples/feature-demos/sitewide-content/.astro/data-store.json +1 -0
  165. package/examples/feature-demos/sitewide-content/.astro/dev.json +13 -0
  166. package/examples/feature-demos/sitewide-content/.astro/dev.log +18 -0
  167. package/examples/feature-demos/sitewide-content/.astro/settings.json +5 -0
  168. package/examples/feature-demos/sitewide-content/.astro/types.d.ts +2 -0
  169. package/examples/feature-demos/sitewide-content/README.md +18 -0
  170. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/_metadata.json +74 -0
  171. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro-B3JHJyiv.js +434 -0
  172. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro-B3JHJyiv.js.map +1 -0
  173. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
  174. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
  175. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
  176. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
  177. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
  178. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
  179. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
  180. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
  181. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/audit-C3SVr7dT.js +1534 -0
  182. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/audit-C3SVr7dT.js.map +1 -0
  183. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/highlight-BLtvqtzO.js +48 -0
  184. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +1 -0
  185. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/icons-C92i61-2.js +42 -0
  186. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/icons-C92i61-2.js.map +1 -0
  187. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/package.json +3 -0
  188. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
  189. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/settings-v5GgKks_.js +190 -0
  190. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/settings-v5GgKks_.js.map +1 -0
  191. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/toolbar-BFvJVp26.js +458 -0
  192. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +1 -0
  193. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/ui-library-Cd35oAvo.js +1016 -0
  194. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +1 -0
  195. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/window-vo3A6TMn.js +32 -0
  196. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/window-vo3A6TMn.js.map +1 -0
  197. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/xray-DwhzGckb.js +111 -0
  198. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/xray-DwhzGckb.js.map +1 -0
  199. package/examples/feature-demos/sitewide-content/site/.norna/generated-images.json +1 -0
  200. package/examples/feature-demos/sitewide-content/site/config.md +3 -0
  201. package/examples/feature-demos/sitewide-content/site/content.md +16 -0
  202. package/examples/feature-demos/sitewide-content/site/public/logo.svg +6 -0
  203. package/examples/feature-demos/sitewide-content/site/routes/010-identity/route-content.md +20 -0
  204. package/examples/feature-demos/sitewide-content/site/routes/020-notices/route-content.md +22 -0
  205. package/examples/feature-demos/sitewide-content/site/routes/030-footer/route-content.md +17 -0
  206. package/examples/feature-demos/sitewide-content/site/sitewide-content.md +33 -0
  207. package/examples/feature-demos/sitewide-content/site/theme.md +3 -0
  208. package/examples/feature-demos/theme-presets/.astro/collections/site.schema.json +59 -0
  209. package/examples/feature-demos/theme-presets/.astro/collections/sitewide.schema.json +138 -0
  210. package/examples/feature-demos/theme-presets/.astro/collections/theme.schema.json +755 -0
  211. package/examples/feature-demos/theme-presets/.astro/content-assets.mjs +4 -0
  212. package/examples/feature-demos/theme-presets/.astro/content-modules.mjs +1 -0
  213. package/examples/{typography-presets → feature-demos/theme-presets}/.astro/data-store.json +1 -1
  214. package/examples/feature-demos/theme-presets/.astro/dev-local.json +8 -0
  215. package/examples/{typography-presets → feature-demos/theme-presets}/.astro/dev.json +2 -2
  216. package/examples/feature-demos/theme-presets/.astro/dev.log +164 -0
  217. package/examples/feature-demos/theme-presets/.astro/types.d.ts +2 -0
  218. package/examples/feature-demos/theme-presets/README.md +18 -0
  219. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/package.json +3 -0
  220. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
  221. package/examples/{typography-presets → feature-demos/theme-presets}/site/.norna/generated-images.json +45 -45
  222. package/examples/feature-demos/theme-presets/site/config.md +3 -0
  223. package/examples/feature-demos/theme-presets/site/content.md +17 -0
  224. package/examples/feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio/shepherd-portrait.jpg +0 -0
  225. package/examples/feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio/white-puppy.jpg +0 -0
  226. package/examples/{typography-presets/site/routes/010-quiet-gallery → feature-demos/theme-presets/site/routes/010-portfolio}/route-content.md +8 -8
  227. package/examples/feature-demos/theme-presets/site/routes/010-portfolio/theme.md +3 -0
  228. package/examples/feature-demos/theme-presets/site/routes/020-documentation/images/documentation/retriever-portrait.jpg +0 -0
  229. package/examples/{typography-presets/site/routes/020-compact-gallery → feature-demos/theme-presets/site/routes/020-documentation}/route-content.md +8 -8
  230. package/examples/feature-demos/theme-presets/site/routes/020-documentation/theme.md +3 -0
  231. package/examples/feature-demos/theme-presets/site/routes/030-project/images/project/boxer-portrait.jpg +0 -0
  232. package/examples/feature-demos/theme-presets/site/routes/030-project/images/project/grass-puppy.jpg +0 -0
  233. package/examples/{typography-presets/site/routes/030-text-forward → feature-demos/theme-presets/site/routes/030-project}/route-content.md +8 -8
  234. package/examples/feature-demos/theme-presets/site/routes/030-project/theme.md +3 -0
  235. package/examples/feature-demos/theme-presets/site/routes/040-statement/images/statement/sheepdog-grass.jpg +0 -0
  236. package/examples/{typography-presets → feature-demos/theme-presets}/site/routes/040-statement/route-content.md +3 -3
  237. package/examples/feature-demos/theme-presets/site/routes/040-statement/theme.md +3 -0
  238. package/examples/{typography-presets → feature-demos/theme-presets}/site/sitewide-content.md +1 -1
  239. package/examples/feature-demos/theme-presets/site/theme.md +3 -0
  240. package/fixtures/basic/site/config.md +3 -0
  241. package/fixtures/content-model-v2/site/config.md +3 -0
  242. package/package.json +17 -8
  243. package/scripts/build-pages.mjs +69 -0
  244. package/scripts/check-config.mjs +3 -11
  245. package/scripts/deploy-site.mjs +12 -8
  246. package/scripts/export-theme-preset.mjs +31 -0
  247. package/scripts/init-site.mjs +1 -0
  248. package/scripts/lib/example-sites.mjs +37 -0
  249. package/scripts/lib/github-repository.mjs +44 -0
  250. package/scripts/lib/norna-markdown-blocks.mjs +97 -10
  251. package/scripts/lib/presentation.mjs +6 -5
  252. package/scripts/lib/project-config.mjs +114 -124
  253. package/scripts/lib/site-content.mjs +9 -2
  254. package/scripts/lib/site-paths.mjs +6 -2
  255. package/scripts/lib/theme-config.mjs +3 -0
  256. package/scripts/lib/theme-presets.mjs +209 -0
  257. package/scripts/show-typography.mjs +6 -5
  258. package/scripts/test-client-javascript.mjs +236 -0
  259. package/scripts/test-content-check.mjs +103 -0
  260. package/scripts/test-content-model-v2.mjs +9 -13
  261. package/scripts/test-documentation.mjs +116 -0
  262. package/scripts/test-engine-commands.mjs +13 -3
  263. package/scripts/test-examples.mjs +24 -0
  264. package/scripts/test-navigation.mjs +73 -45
  265. package/scripts/test-package-check.mjs +17 -9
  266. package/scripts/test-project-config.mjs +130 -0
  267. package/scripts/test-temporary-visibility.mjs +3 -10
  268. package/scripts/test-theme-presets.mjs +146 -0
  269. package/scripts/watch-pages-deploy.mjs +15 -11
  270. package/src/components/GalleryGrid.astro +30 -230
  271. package/src/components/ImageCarousel.astro +184 -0
  272. package/src/components/MobileSectionNavigationScript.astro +14 -0
  273. package/src/components/NornaSmoothScrollScript.astro +250 -0
  274. package/src/components/SiteNavigation.astro +58 -341
  275. package/src/components/SiteNotesScript.astro +43 -0
  276. package/src/components/SitePage.astro +6 -3
  277. package/src/components/SiteSection.astro +4 -47
  278. package/src/content.config.ts +2 -0
  279. package/src/layouts/BaseLayout.astro +1 -1
  280. package/src/lib/galleryImages.ts +53 -0
  281. package/src/styles/global.css +83 -1
  282. package/starters/basic/.github/workflows/deploy.yml +1 -2
  283. package/starters/basic/README.md +10 -8
  284. package/starters/basic/package.json +1 -0
  285. package/starters/basic/site/config.md +3 -0
  286. package/starters/project/.github/workflows/deploy.yml +1 -2
  287. package/starters/project/README.md +3 -4
  288. package/starters/project/package.json +1 -0
  289. package/starters/project/site/config.md +3 -0
  290. package/examples/001-dog-shelter-single-page/README.md +0 -9
  291. package/examples/001-dog-shelter-single-page/site/config.mjs +0 -27
  292. package/examples/001-dog-shelter-single-page/site/content.md +0 -38
  293. package/examples/001-dog-shelter-single-page/site/images/what-we-do/dog-house.svg +0 -25
  294. package/examples/001-dog-shelter-single-page/site/images/you-can-help/heart.svg +0 -13
  295. package/examples/001-dog-shelter-single-page/site/sitewide-content.md +0 -6
  296. package/examples/001-dog-shelter-single-page/site/theme.md +0 -25
  297. package/examples/002-dog-shelter-multi-page/README.md +0 -9
  298. package/examples/002-dog-shelter-multi-page/site/config.mjs +0 -27
  299. package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rex.svg +0 -19
  300. package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rover.svg +0 -19
  301. package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/route-content.md +0 -30
  302. package/examples/002-dog-shelter-multi-page/site/sitewide-content.md +0 -6
  303. package/examples/002-dog-shelter-multi-page/site/theme.md +0 -25
  304. package/examples/dog-gallery/.astro/collections/site.schema.json +0 -776
  305. package/examples/dog-gallery/.astro/data-store.json +0 -1
  306. package/examples/dog-gallery/.astro/dev-local.json +0 -8
  307. package/examples/dog-gallery/.astro/dev.json +0 -13
  308. package/examples/dog-gallery/.astro/dev.log +0 -95
  309. package/examples/dog-gallery/.astro/settings.json +0 -5
  310. package/examples/dog-gallery/dist/_astro/GalleryGrid.astro_astro_type_script_index_0_lang.B0kxDyGz.js +0 -1
  311. package/examples/dog-gallery/dist/_astro/SitePage.DicGh_5N.css +0 -1
  312. package/examples/dog-gallery/dist/dog-care/index.html +0 -15
  313. package/examples/dog-gallery/dist/dog-shelter-logo.svg +0 -14
  314. package/examples/dog-gallery/dist/favicon.svg +0 -7
  315. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1080.webp +0 -0
  316. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1440.webp +0 -0
  317. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1536.webp +0 -0
  318. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-480.webp +0 -0
  319. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-768.webp +0 -0
  320. package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-480.webp +0 -0
  321. package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-768.webp +0 -0
  322. package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-960.webp +0 -0
  323. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1080.webp +0 -0
  324. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1440.webp +0 -0
  325. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1920.webp +0 -0
  326. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-3939.webp +0 -0
  327. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-480.webp +0 -0
  328. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-768.webp +0 -0
  329. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1080.webp +0 -0
  330. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1440.webp +0 -0
  331. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1920.webp +0 -0
  332. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-2400.webp +0 -0
  333. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-480.webp +0 -0
  334. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-768.webp +0 -0
  335. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1080.webp +0 -0
  336. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1440.webp +0 -0
  337. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1600.webp +0 -0
  338. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-480.webp +0 -0
  339. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-768.webp +0 -0
  340. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1080.webp +0 -0
  341. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1440.webp +0 -0
  342. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1920.webp +0 -0
  343. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-2576.webp +0 -0
  344. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-480.webp +0 -0
  345. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-768.webp +0 -0
  346. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1080.webp +0 -0
  347. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1277.webp +0 -0
  348. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-480.webp +0 -0
  349. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-768.webp +0 -0
  350. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1080.webp +0 -0
  351. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1440.webp +0 -0
  352. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1536.webp +0 -0
  353. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-480.webp +0 -0
  354. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-768.webp +0 -0
  355. package/examples/dog-gallery/dist/index.html +0 -45
  356. package/examples/dog-gallery/node_modules/.vite/deps/_metadata.json +0 -74
  357. package/examples/dog-gallery/site/.norna/generated-images.json +0 -226
  358. package/examples/dog-gallery/site/config.mjs +0 -47
  359. package/examples/dog-gallery/site/content.md +0 -127
  360. package/examples/dog-gallery/site/images/black-dogs/black-puppy-meadow.png +0 -0
  361. package/examples/dog-gallery/site/images/black-dogs/photo-of-a-black-dog.jpg +0 -0
  362. package/examples/dog-gallery/site/images/brown-dogs/brown-dog.jpg +0 -0
  363. package/examples/dog-gallery/site/images/brown-dogs/dog-accompanies-master.jpg +0 -0
  364. package/examples/dog-gallery/site/images/golden-dogs/golden-retriever.jpg +0 -0
  365. package/examples/dog-gallery/site/images/golden-dogs/toller-puppy.jpg +0 -0
  366. package/examples/dog-gallery/site/images/white-dogs/white-cute-dog.jpg +0 -0
  367. package/examples/dog-gallery/site/images/white-dogs/white-puppy-garden.png +0 -0
  368. package/examples/dog-gallery/site/public/favicon.svg +0 -7
  369. package/examples/dog-gallery/site/public/logo.svg +0 -14
  370. package/examples/dog-gallery/site/routes/010-dog-care/route-content.md +0 -38
  371. package/examples/dog-gallery/site/sitewide-content.md +0 -16
  372. package/examples/dog-gallery/site/theme.md +0 -101
  373. package/examples/presentation/README.md +0 -15
  374. package/examples/presentation/site/config.mjs +0 -29
  375. package/examples/presentation/site/content.md +0 -67
  376. package/examples/presentation/site/public/robots.txt +0 -2
  377. package/examples/presentation/site/routes/010-presets/route-content.md +0 -63
  378. package/examples/presentation/site/routes/010-presets/theme.md +0 -4
  379. package/examples/presentation/site/routes/020-media/theme.md +0 -4
  380. package/examples/presentation/site/sitewide-content.md +0 -6
  381. package/examples/presentation/site/theme.md +0 -43
  382. package/examples/typography-presets/.astro/dev.log +0 -45
  383. package/examples/typography-presets/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -1
  384. package/examples/typography-presets/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  385. package/examples/typography-presets/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  386. package/examples/typography-presets/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  387. package/examples/typography-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  388. package/examples/typography-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -1
  389. package/examples/typography-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -1
  390. package/examples/typography-presets/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -1
  391. package/examples/typography-presets/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -1
  392. package/examples/typography-presets/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -1
  393. package/examples/typography-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -1
  394. package/examples/typography-presets/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -1
  395. package/examples/typography-presets/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -1
  396. package/examples/typography-presets/site/config.mjs +0 -29
  397. package/examples/typography-presets/site/content.md +0 -16
  398. package/examples/typography-presets/site/routes/010-quiet-gallery/theme.md +0 -4
  399. package/examples/typography-presets/site/routes/020-compact-gallery/theme.md +0 -4
  400. package/examples/typography-presets/site/routes/030-text-forward/theme.md +0 -4
  401. package/examples/typography-presets/site/routes/040-statement/theme.md +0 -4
  402. package/examples/typography-presets/site/theme.md +0 -43
  403. package/fixtures/basic/site/config.mjs +0 -27
  404. package/fixtures/content-model-v2/site/config.mjs +0 -11
  405. package/starters/basic/site/config.mjs +0 -27
  406. package/starters/project/site/config.mjs +0 -30
  407. /package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/collections/site.schema.json +0 -0
  408. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/.astro/content-assets.mjs +0 -0
  409. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/.astro/content-modules.mjs +0 -0
  410. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/.astro/types.d.ts +0 -0
  411. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/package.json +0 -0
  412. /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -0
  413. /package/examples/{typography-presets/site/routes/020-compact-gallery/images/compact-gallery/retriever-portrait.jpg → complete-sites/dog-shelter-multi-page/site/images/intro/shelter-dog.jpg} +0 -0
  414. /package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-multi-page}/site/public/favicon.svg +0 -0
  415. /package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-multi-page}/site/public/robots.txt +0 -0
  416. /package/examples/{typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/white-puppy.jpg → complete-sites/dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rex.jpg} +0 -0
  417. /package/examples/{typography-presets/site/routes/030-text-forward/images/text-forward/boxer-portrait.jpg → complete-sites/dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rover.jpg} +0 -0
  418. /package/examples/{typography-presets/site/routes/040-statement/images/statement/sheepdog-grass.jpg → complete-sites/dog-shelter-multi-page/site/routes/020-adopt/images/adopt/adoption-dog.jpg} +0 -0
  419. /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/.astro/content-assets.mjs +0 -0
  420. /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/.astro/content-modules.mjs +0 -0
  421. /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/.astro/types.d.ts +0 -0
  422. /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/node_modules/.vite/deps/package.json +0 -0
  423. /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -0
  424. /package/examples/{typography-presets/site/routes/030-text-forward/images/text-forward/grass-puppy.jpg → complete-sites/dog-shelter-single-page/site/images/what-we-do/rescue-dog.jpg} +0 -0
  425. /package/examples/{typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/shepherd-portrait.jpg → complete-sites/dog-shelter-single-page/site/images/you-can-help/foster-dog.jpg} +0 -0
  426. /package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-single-page}/site/public/favicon.svg +0 -0
  427. /package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-single-page}/site/public/robots.txt +0 -0
  428. /package/examples/{dog-gallery/dist → feature-demos/media-and-surfaces/site/public}/robots.txt +0 -0
  429. /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/cards/card-carousel.svg +0 -0
  430. /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/cards/card-stack.svg +0 -0
  431. /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/cards/card-surfaces.svg +0 -0
  432. /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/carousel/carousel-one.svg +0 -0
  433. /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/carousel/carousel-three.svg +0 -0
  434. /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/carousel/carousel-two.svg +0 -0
  435. /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/stack/stack-one.svg +0 -0
  436. /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/stack/stack-two.svg +0 -0
  437. /package/examples/{dog-gallery → feature-demos/sitewide-content}/site/public/robots.txt +0 -0
  438. /package/examples/{typography-presets → feature-demos/theme-presets}/.astro/collections/routeTheme.schema.json +0 -0
  439. /package/examples/{typography-presets → feature-demos/theme-presets}/.astro/content.d.ts +0 -0
  440. /package/examples/{typography-presets → feature-demos/theme-presets}/.astro/settings.json +0 -0
  441. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/_metadata.json +0 -0
  442. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -0
  443. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -0
  444. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_aria-query.js +0 -0
  445. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -0
  446. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_axobject-query.js +0 -0
  447. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -0
  448. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_html-escaper.js +0 -0
  449. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -0
  450. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -0
  451. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -0
  452. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -0
  453. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -0
  454. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/embla-carousel.js +0 -0
  455. /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/embla-carousel.js.map +0 -0
  456. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -0
  457. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -0
  458. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/icons-RyebKi45.js +0 -0
  459. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -0
  460. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -0
  461. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -0
  462. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/toolbar-63PA619H.js +0 -0
  463. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -0
  464. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -0
  465. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -0
  466. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/window-jPkpKVcy.js +0 -0
  467. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -0
  468. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -0
  469. /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -0
  470. /package/examples/{typography-presets → feature-demos/theme-presets}/site/public/robots.txt +0 -0
  471. /package/examples/{typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery → feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio}/puppy-portrait.jpg +0 -0
  472. /package/examples/{typography-presets/site/routes/020-compact-gallery/images/compact-gallery → feature-demos/theme-presets/site/routes/020-documentation/images/documentation}/black-schnauzer.jpg +0 -0
  473. /package/examples/{typography-presets/site/routes/020-compact-gallery/images/compact-gallery → feature-demos/theme-presets/site/routes/020-documentation/images/documentation}/schnauzer-portrait.jpg +0 -0
  474. /package/examples/{typography-presets/site/routes/030-text-forward/images/text-forward → feature-demos/theme-presets/site/routes/030-project/images/project}/grey-street-dog.jpg +0 -0
  475. /package/examples/{typography-presets → feature-demos/theme-presets}/site/routes/040-statement/images/statement/black-pedigree.jpg +0 -0
  476. /package/examples/{typography-presets → feature-demos/theme-presets}/site/routes/040-statement/images/statement/sheepdog-wide.jpg +0 -0
@@ -0,0 +1,250 @@
1
+ <script>
2
+ const siteTop = document.querySelector<HTMLElement>('.site-top');
3
+ const sections = Array.from(document.querySelectorAll<HTMLElement>('.site-section'));
4
+ const links = Array.from(document.querySelectorAll<HTMLAnchorElement>('.site-nav-submenu a, .mobile-page-nav a, .page-nav a'));
5
+ const mobileMenu = document.querySelector<HTMLDetailsElement>('.mobile-nav-menu');
6
+ const anchorCorrectionDelays = [120, 320, 700, 1_000, 2_000];
7
+ const reduceMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
8
+ const minimumScrollDuration = 700;
9
+ const maximumScrollDuration = 1_800;
10
+ const scrollDurationPerPixel = 0.18;
11
+ const scrollInterruptEvents = ['wheel', 'touchstart'];
12
+ const scrollInterruptKeys = new Set(['ArrowDown', 'ArrowUp', 'End', 'Home', 'PageDown', 'PageUp', ' ']);
13
+ let activeScrollAnimation: { cancel: () => void } | null = null;
14
+ let anchorCorrectionToken = 0;
15
+
16
+ if ('scrollRestoration' in history) {
17
+ history.scrollRestoration = 'manual';
18
+ }
19
+
20
+ const setAnchorOffset = () => {
21
+ if (!siteTop) return;
22
+
23
+ const offset = Math.ceil(siteTop.getBoundingClientRect().height);
24
+ document.documentElement.style.setProperty('--site-top-anchor-offset', `${offset}px`);
25
+ return offset;
26
+ };
27
+
28
+ const getSectionFromHash = (hash: string) => {
29
+ const id = hash.replace(/^#/, '');
30
+ return sections.find((section) => section.id === id);
31
+ };
32
+
33
+ const getSectionHeading = (section?: HTMLElement) => section?.querySelector<HTMLElement>('h1, h2');
34
+
35
+ const cancelActiveScroll = () => {
36
+ activeScrollAnimation?.cancel();
37
+ activeScrollAnimation = null;
38
+ };
39
+
40
+ const getHashSection = () => getSectionFromHash(window.location.hash);
41
+
42
+ const setHash = (targetHash: string) => {
43
+ if (window.location.hash !== targetHash) {
44
+ history.pushState(null, '', targetHash);
45
+ }
46
+ };
47
+
48
+ const closeMobileMenu = () => {
49
+ if (mobileMenu) mobileMenu.open = false;
50
+ };
51
+
52
+ const getSectionScrollTop = (section?: HTMLElement) => {
53
+ const heading = getSectionHeading(section);
54
+ if (!heading) return;
55
+
56
+ const offset = setAnchorOffset();
57
+ if (offset === undefined) return;
58
+
59
+ return Math.max(0, heading.getBoundingClientRect().top + window.scrollY - offset);
60
+ };
61
+
62
+ const jumpTo = (top: number) => {
63
+ cancelActiveScroll();
64
+
65
+ const root = document.documentElement;
66
+ const previousScrollBehavior = root.style.scrollBehavior;
67
+ root.style.scrollBehavior = 'auto';
68
+ window.scrollTo(0, top);
69
+ root.style.scrollBehavior = previousScrollBehavior;
70
+ };
71
+
72
+ const getScrollDuration = (distance: number) => {
73
+ if (reduceMotionQuery.matches) return 0;
74
+
75
+ return Math.min(
76
+ maximumScrollDuration,
77
+ Math.max(minimumScrollDuration, Math.abs(distance) * scrollDurationPerPixel),
78
+ );
79
+ };
80
+
81
+ const easeInOutCubic = (progress: number) => (
82
+ progress < 0.5
83
+ ? 4 * progress * progress * progress
84
+ : 1 - Math.pow(-2 * progress + 2, 3) / 2
85
+ );
86
+
87
+ const animateScrollTo = (
88
+ target: number | (() => number | undefined),
89
+ { duration, onComplete }: { duration?: number; onComplete?: () => void } = {},
90
+ ) => {
91
+ cancelActiveScroll();
92
+
93
+ const getTop = typeof target === 'function' ? target : () => target;
94
+ let latestTop = getTop();
95
+ if (latestTop === undefined) return 0;
96
+
97
+ const startY = window.scrollY;
98
+ const scrollDuration = duration ?? getScrollDuration(latestTop - startY);
99
+
100
+ if (scrollDuration <= 0) {
101
+ const top = getTop();
102
+ if (top === undefined) return 0;
103
+
104
+ jumpTo(top);
105
+ onComplete?.();
106
+ return 0;
107
+ }
108
+
109
+ const root = document.documentElement;
110
+ const previousScrollBehavior = root.style.scrollBehavior;
111
+ const startedAt = performance.now();
112
+ let frameId = 0;
113
+ const state = { cancel: () => {} };
114
+
115
+ const cleanup = () => {
116
+ scrollInterruptEvents.forEach((eventName) => {
117
+ window.removeEventListener(eventName, interruptScroll);
118
+ });
119
+ window.removeEventListener('keydown', interruptScrollKey);
120
+ root.style.scrollBehavior = previousScrollBehavior;
121
+ delete root.dataset.nornaScrollActive;
122
+
123
+ if (activeScrollAnimation === state) {
124
+ activeScrollAnimation = null;
125
+ }
126
+ };
127
+
128
+ const cancel = () => {
129
+ if (frameId) cancelAnimationFrame(frameId);
130
+ cleanup();
131
+ };
132
+
133
+ const interruptScroll = () => cancel();
134
+ const interruptScrollKey = (event: KeyboardEvent) => {
135
+ if (scrollInterruptKeys.has(event.key)) interruptScroll();
136
+ };
137
+
138
+ const step = (now: number) => {
139
+ const progress = Math.min(1, (now - startedAt) / scrollDuration);
140
+ const top = getTop();
141
+ if (top !== undefined) latestTop = top;
142
+
143
+ window.scrollTo(0, startY + (latestTop - startY) * easeInOutCubic(progress));
144
+
145
+ if (progress >= 1) {
146
+ window.scrollTo(0, latestTop);
147
+ cleanup();
148
+ onComplete?.();
149
+ return;
150
+ }
151
+
152
+ frameId = requestAnimationFrame(step);
153
+ };
154
+
155
+ state.cancel = cancel;
156
+ activeScrollAnimation = state;
157
+ root.style.scrollBehavior = 'auto';
158
+ root.dataset.nornaScrollActive = 'true';
159
+ scrollInterruptEvents.forEach((eventName) => {
160
+ window.addEventListener(eventName, interruptScroll, { passive: true });
161
+ });
162
+ window.addEventListener('keydown', interruptScrollKey);
163
+ frameId = requestAnimationFrame(step);
164
+
165
+ return scrollDuration;
166
+ };
167
+
168
+ const scrollToSection = (
169
+ section: HTMLElement,
170
+ { animate = true, duration, onComplete }: { animate?: boolean; duration?: number; onComplete?: () => void } = {},
171
+ ) => {
172
+ const top = getSectionScrollTop(section);
173
+ if (top === undefined) return 0;
174
+
175
+ return animate
176
+ ? animateScrollTo(() => getSectionScrollTop(section), { duration, onComplete })
177
+ : (jumpTo(top), onComplete?.(), 0);
178
+ };
179
+
180
+ const correctCurrentHashAnchor = () => {
181
+ if (activeScrollAnimation) return;
182
+
183
+ const section = getHashSection();
184
+ if (section) scrollToSection(section, { animate: false });
185
+ };
186
+
187
+ const scheduleHashAnchorCorrection = () => {
188
+ if (!window.location.hash) return;
189
+
190
+ anchorCorrectionToken += 1;
191
+ const token = anchorCorrectionToken;
192
+
193
+ anchorCorrectionDelays.forEach((delay) => {
194
+ window.setTimeout(() => {
195
+ if (token === anchorCorrectionToken) requestAnimationFrame(correctCurrentHashAnchor);
196
+ }, delay);
197
+ });
198
+ };
199
+
200
+ const syncToLocation = ({ scrollHashlessTop = false } = {}) => {
201
+ const section = getHashSection();
202
+
203
+ if (section) {
204
+ scrollToSection(section, { animate: false });
205
+ scheduleHashAnchorCorrection();
206
+ return;
207
+ }
208
+
209
+ if (scrollHashlessTop) jumpTo(0);
210
+ };
211
+
212
+ links.forEach((link) => {
213
+ link.addEventListener('click', (event) => {
214
+ const linkUrl = new URL(link.href, window.location.href);
215
+ if (linkUrl.pathname !== window.location.pathname) return;
216
+
217
+ const section = getSectionFromHash(linkUrl.hash);
218
+ if (!section) return;
219
+
220
+ const top = getSectionScrollTop(section);
221
+ if (top === undefined) return;
222
+
223
+ event.preventDefault();
224
+ const duration = getScrollDuration(top - window.scrollY);
225
+
226
+ setHash(linkUrl.hash);
227
+ closeMobileMenu();
228
+ if (event.detail > 0) link.blur();
229
+
230
+ scrollToSection(section, {
231
+ duration,
232
+ onComplete: scheduleHashAnchorCorrection,
233
+ });
234
+ });
235
+ });
236
+
237
+ setAnchorOffset();
238
+ requestAnimationFrame(() => syncToLocation());
239
+
240
+ if (siteTop && 'ResizeObserver' in window) {
241
+ new ResizeObserver(setAnchorOffset).observe(siteTop);
242
+ }
243
+
244
+ window.addEventListener('resize', setAnchorOffset);
245
+ window.addEventListener('load', scheduleHashAnchorCorrection);
246
+ window.addEventListener('hashchange', () => syncToLocation({ scrollHashlessTop: true }));
247
+ window.addEventListener('popstate', () => syncToLocation({ scrollHashlessTop: true }));
248
+
249
+ window.visualViewport?.addEventListener('resize', setAnchorOffset);
250
+ </script>
@@ -3,6 +3,8 @@ import projectConfig from '../../scripts/lib/project-config.mjs';
3
3
  import { withBasePath } from '../lib/basePath';
4
4
  import type { SectionNavigation } from '../lib/sectionContent';
5
5
  import type { SitePage } from '../lib/sitePages';
6
+ import MobileSectionNavigationScript from './MobileSectionNavigationScript.astro';
7
+ import NornaSmoothScrollScript from './NornaSmoothScrollScript.astro';
6
8
 
7
9
  type FrameColors = {
8
10
  backgroundColor: string;
@@ -25,7 +27,6 @@ interface Props {
25
27
  }
26
28
 
27
29
  const { brandLabel, logo, currentPage, pageNavigation, frameColors } = Astro.props;
28
- const smoothScrollConfig = projectConfig.navigation.smoothScroll;
29
30
  const siteTopBackgroundColor = frameColors.backgroundColor === 'transparent'
30
31
  ? 'var(--color-page)'
31
32
  : frameColors.backgroundColor;
@@ -35,53 +36,62 @@ const navigationStyle = [
35
36
  ...(logo?.height ? [`--site-brand-logo-height: ${logo.height}`] : []),
36
37
  ].join('; ');
37
38
  const showSiteNavigation = pageNavigation.length > 1;
39
+ const showNavigationRow = showSiteNavigation || Boolean(logo);
38
40
  const homePage = pageNavigation.find(({ page }) => page.isHome)?.page ?? currentPage;
39
41
  const currentPageNavigation = pageNavigation.find(({ page }) => page.pathname === currentPage.pathname);
40
42
  const isCurrentPage = (page: SitePage) => page.pathname === currentPage.pathname;
41
43
  const pageHref = (page: SitePage) => withBasePath(projectConfig.site.basePath, page.pathname);
42
44
  const sectionHref = (page: SitePage, section: SectionNavigation) => `${pageHref(page)}#${section.id}`;
43
45
  const hasSectionMenu = (pageSections: SectionNavigation[]) => pageSections.length > 1;
46
+ const showSinglePageSectionNavigation = Boolean(
47
+ !showSiteNavigation && currentPageNavigation && hasSectionMenu(currentPageNavigation.sections),
48
+ );
49
+ const hasCurrentPageSectionMenu = Boolean(
50
+ showSiteNavigation && currentPageNavigation && hasSectionMenu(currentPageNavigation.sections),
51
+ );
52
+ const useNornaSmoothScroll = projectConfig.navigation.scrollBehavior === 'norna-smooth';
44
53
  ---
45
54
 
46
55
  <a class="skip-link" href="#main-content">{projectConfig.locale.labels.skipToContent}</a>
47
56
 
48
57
  <header
49
58
  class:list={['site-top', { 'site-top-has-site-nav': showSiteNavigation }]}
50
- data-smooth-scroll={JSON.stringify(smoothScrollConfig)}
51
59
  style={navigationStyle}
52
60
  >
53
- {showSiteNavigation && (
61
+ {showNavigationRow && (
54
62
  <div class="site-nav-row">
55
63
  <a class="site-brand" href={pageHref(homePage)}>
56
64
  {logo ? <img class="site-brand-logo" src={withBasePath(projectConfig.site.basePath, logo.src)} alt={logo.alt} /> : brandLabel}
57
65
  </a>
58
66
 
59
- <nav class="site-nav" aria-label={projectConfig.locale.labels.siteNavigation}>
60
- <ul>
61
- {pageNavigation.map(({ page, sections: pageSections }) => (
62
- <li class:list={['site-nav-item', { 'site-nav-item-has-sections': hasSectionMenu(pageSections) }]}>
63
- <a href={pageHref(page)} aria-current={isCurrentPage(page) ? 'page' : undefined}>
64
- {page.navigation.label}
65
- </a>
66
- {hasSectionMenu(pageSections) && (
67
- <div class="site-nav-submenu">
68
- <nav aria-label={`${page.navigation.label} ${projectConfig.locale.labels.pageNavigation}`}>
69
- <ul>
70
- {pageSections.map((section) => (
71
- <li>
72
- <a href={sectionHref(page, section)}>{section.title}</a>
73
- </li>
74
- ))}
75
- </ul>
76
- </nav>
77
- </div>
78
- )}
79
- </li>
80
- ))}
81
- </ul>
82
- </nav>
83
-
84
- <details class="mobile-nav-menu">
67
+ {showSiteNavigation && (
68
+ <nav class="site-nav" aria-label={projectConfig.locale.labels.siteNavigation}>
69
+ <ul>
70
+ {pageNavigation.map(({ page, sections: pageSections }) => (
71
+ <li class:list={['site-nav-item', { 'site-nav-item-has-sections': hasSectionMenu(pageSections) }]}>
72
+ <a href={pageHref(page)} aria-current={isCurrentPage(page) ? 'page' : undefined}>
73
+ {page.navigation.label}
74
+ </a>
75
+ {hasSectionMenu(pageSections) && (
76
+ <div class="site-nav-submenu">
77
+ <nav aria-label={`${page.navigation.label} ${projectConfig.locale.labels.pageNavigation}`}>
78
+ <ul>
79
+ {pageSections.map((section) => (
80
+ <li>
81
+ <a href={sectionHref(page, section)}>{section.title}</a>
82
+ </li>
83
+ ))}
84
+ </ul>
85
+ </nav>
86
+ </div>
87
+ )}
88
+ </li>
89
+ ))}
90
+ </ul>
91
+ </nav>
92
+ )}
93
+
94
+ {showSiteNavigation && <details class="mobile-nav-menu">
85
95
  <summary>
86
96
  <span>{currentPage.navigation.label}</span>
87
97
  </summary>
@@ -99,13 +109,13 @@ const hasSectionMenu = (pageSections: SectionNavigation[]) => pageSections.lengt
99
109
  </ul>
100
110
  </nav>
101
111
 
102
- {currentPageNavigation && hasSectionMenu(currentPageNavigation.sections) && (
112
+ {currentPageNavigation && hasCurrentPageSectionMenu && (
103
113
  <nav class="mobile-page-nav" aria-label={projectConfig.locale.labels.pageNavigation}>
104
114
  <h2>{projectConfig.locale.labels.pageNavigation}</h2>
105
115
  <ul>
106
- {currentPageNavigation.sections.map((section, index) => (
116
+ {currentPageNavigation.sections.map((section) => (
107
117
  <li>
108
- <a href={sectionHref(currentPage, section)} aria-current={index === 0 ? 'true' : undefined}>
118
+ <a href={sectionHref(currentPage, section)}>
109
119
  {section.title}
110
120
  </a>
111
121
  </li>
@@ -114,317 +124,24 @@ const hasSectionMenu = (pageSections: SectionNavigation[]) => pageSections.lengt
114
124
  </nav>
115
125
  )}
116
126
  </div>
117
- </details>
127
+ </details>}
118
128
  </div>
119
129
  )}
120
130
 
121
- </header>
122
-
123
- <script>
124
- const siteTop = document.querySelector('.site-top');
125
- const sections = Array.from(document.querySelectorAll('.site-section'));
126
- const links = Array.from(document.querySelectorAll('.site-nav-submenu a, .mobile-page-nav a'));
127
- const mobileMenu = document.querySelector('.mobile-nav-menu');
128
- const smoothScrollConfig = JSON.parse(siteTop?.getAttribute('data-smooth-scroll') ?? '{}');
129
- const anchorPadding = 0;
130
- const anchorCorrectionDelays = [120, 320, 700, 1_000, 2_000];
131
- const reduceMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
132
- const minimumScrollDuration = smoothScrollConfig.minimumDurationMs;
133
- const maximumScrollDuration = smoothScrollConfig.maximumDurationMs;
134
- const scrollDurationPerPixel = smoothScrollConfig.durationPerPixelMs;
135
- const scrollInterruptEvents = ['wheel', 'touchstart'];
136
- const scrollInterruptKeys = new Set(['ArrowDown', 'ArrowUp', 'End', 'Home', 'PageDown', 'PageUp', ' ']);
137
- let activeScrollAnimation = null;
138
- let activeSectionId = null;
139
- let anchorCorrectionToken = 0;
140
-
141
- if ('scrollRestoration' in history) {
142
- history.scrollRestoration = 'manual';
143
- }
144
-
145
- const setAnchorOffset = () => {
146
- if (!(siteTop instanceof HTMLElement)) return;
147
-
148
- const offset = Math.ceil(siteTop.getBoundingClientRect().height + anchorPadding);
149
- document.documentElement.style.setProperty('--site-top-anchor-offset', `${offset}px`);
150
- return offset;
151
- };
152
-
153
- const getSectionFromHash = (hash) => {
154
- const id = hash.replace(/^#/, '');
155
- return sections.find((section) => section.id === id);
156
- };
157
-
158
- const getSectionHeading = (section) => section?.querySelector('h1, h2');
159
-
160
- const cancelActiveScroll = () => {
161
- if (activeScrollAnimation) {
162
- activeScrollAnimation.cancel();
163
- activeScrollAnimation = null;
164
- }
165
- };
166
-
167
- const setActiveSection = (section) => {
168
- if (!section) return;
169
- if (activeSectionId === section.id) return;
170
-
171
- activeSectionId = section.id;
172
-
173
- links.forEach((link) => {
174
- const linkUrl = new URL(link.href, window.location.href);
175
- const isCurrentPageLink = linkUrl.pathname === window.location.pathname;
176
- const isActive = isCurrentPageLink && linkUrl.hash === `#${section.id}`;
177
- if (isActive) {
178
- link.setAttribute('aria-current', 'true');
179
- } else {
180
- link.removeAttribute('aria-current');
181
- }
182
- });
183
- };
184
-
185
- const getHashSection = () => getSectionFromHash(window.location.hash);
186
-
187
- const setHash = (targetHash) => {
188
- if (window.location.hash !== targetHash) {
189
- history.pushState(null, '', targetHash);
190
- }
191
- };
192
-
193
- const closeMobileMenu = () => {
194
- if (mobileMenu instanceof HTMLDetailsElement) {
195
- mobileMenu.open = false;
196
- }
197
- };
198
-
199
- const getSectionScrollTop = (section) => {
200
- if (!(section instanceof HTMLElement)) return;
201
- const heading = getSectionHeading(section);
202
- if (!(heading instanceof HTMLElement)) return;
203
-
204
- const offset = setAnchorOffset();
205
- if (!offset) return;
206
-
207
- return Math.max(0, heading.getBoundingClientRect().top + window.scrollY - offset);
208
- };
209
-
210
- const jumpTo = (top) => {
211
- cancelActiveScroll();
212
-
213
- const root = document.documentElement;
214
- const previousScrollBehavior = root.style.scrollBehavior;
215
- root.style.scrollBehavior = 'auto';
216
- window.scrollTo(0, top);
217
- root.style.scrollBehavior = previousScrollBehavior;
218
- };
219
-
220
- const getScrollDuration = (distance) => {
221
- const distancePx = Math.abs(distance);
222
-
223
- if (!smoothScrollConfig.enabled || reduceMotionQuery.matches || distancePx <= anchorPadding) return 0;
224
-
225
- return Math.min(
226
- maximumScrollDuration,
227
- Math.max(minimumScrollDuration, distancePx * scrollDurationPerPixel),
228
- );
229
- };
230
-
231
- const easeInOutCubic = (progress) => (
232
- progress < 0.5
233
- ? 4 * progress * progress * progress
234
- : 1 - Math.pow(-2 * progress + 2, 3) / 2
235
- );
236
-
237
- const animateScrollTo = (
238
- target,
239
- { duration, onComplete } = {},
240
- ) => {
241
- cancelActiveScroll();
242
-
243
- const getTop = typeof target === 'function' ? target : () => target;
244
- let latestTop = getTop();
245
- if (latestTop === undefined) return 0;
246
-
247
- const startY = window.scrollY;
248
- const distance = latestTop - startY;
249
- const scrollDuration = duration ?? getScrollDuration(distance);
250
-
251
- if (scrollDuration <= 0) {
252
- const top = getTop();
253
- if (top === undefined) return 0;
254
-
255
- jumpTo(top);
256
- onComplete?.();
257
- return 0;
258
- }
259
-
260
- const root = document.documentElement;
261
- const previousScrollBehavior = root.style.scrollBehavior;
262
- const startedAt = performance.now();
263
- let frameId = 0;
264
-
265
- const state = {
266
- cancel: () => {},
267
- };
268
-
269
- const cleanup = () => {
270
- scrollInterruptEvents.forEach((eventName) => {
271
- window.removeEventListener(eventName, interruptScroll);
272
- });
273
- window.removeEventListener('keydown', interruptScrollKey);
274
- root.style.scrollBehavior = previousScrollBehavior;
275
-
276
- if (activeScrollAnimation === state) {
277
- activeScrollAnimation = null;
278
- }
279
- };
280
-
281
- const cancel = () => {
282
- if (frameId) {
283
- cancelAnimationFrame(frameId);
284
- }
285
-
286
- cleanup();
287
- };
288
-
289
- const interruptScroll = () => cancel();
290
- const interruptScrollKey = (event) => {
291
- if (scrollInterruptKeys.has(event.key)) {
292
- interruptScroll();
293
- }
294
- };
295
-
296
- const step = (now) => {
297
- const elapsed = now - startedAt;
298
- const progress = Math.min(1, elapsed / scrollDuration);
299
- const top = getTop();
300
- if (top !== undefined) {
301
- latestTop = top;
302
- }
303
-
304
- const nextY = startY + (latestTop - startY) * easeInOutCubic(progress);
305
-
306
- window.scrollTo(0, nextY);
307
-
308
- if (progress >= 1) {
309
- window.scrollTo(0, latestTop);
310
- cleanup();
311
- onComplete?.();
312
- return;
313
- }
314
-
315
- frameId = requestAnimationFrame(step);
316
- };
317
-
318
- state.cancel = cancel;
319
- activeScrollAnimation = state;
320
- root.style.scrollBehavior = 'auto';
321
- scrollInterruptEvents.forEach((eventName) => {
322
- window.addEventListener(eventName, interruptScroll, { passive: true });
323
- });
324
- window.addEventListener('keydown', interruptScrollKey);
325
- frameId = requestAnimationFrame(step);
326
-
327
- return scrollDuration;
328
- };
329
-
330
- const scrollToSection = (section, { behavior = 'smooth', duration, onComplete } = {}) => {
331
- const top = getSectionScrollTop(section);
332
- if (top === undefined) return 0;
333
-
334
- const scrollDuration = behavior === 'smooth'
335
- ? animateScrollTo(() => getSectionScrollTop(section), { duration, onComplete })
336
- : (jumpTo(top), onComplete?.(), 0);
337
-
338
- setActiveSection(section);
339
-
340
- return scrollDuration;
341
- };
342
-
343
- const updateAnchorOffset = () => {
344
- setAnchorOffset();
345
- };
346
-
347
- const correctCurrentHashAnchor = () => {
348
- if (activeScrollAnimation) return;
349
-
350
- const section = getHashSection();
351
- if (section instanceof HTMLElement) {
352
- scrollToSection(section, { behavior: 'auto' });
353
- }
354
- };
355
-
356
- const scheduleHashAnchorCorrection = () => {
357
- if (!window.location.hash) return;
358
-
359
- anchorCorrectionToken += 1;
360
- const token = anchorCorrectionToken;
361
-
362
- anchorCorrectionDelays.forEach((delay) => {
363
- window.setTimeout(() => {
364
- if (token === anchorCorrectionToken) {
365
- requestAnimationFrame(correctCurrentHashAnchor);
366
- }
367
- }, delay);
368
- });
369
- };
370
-
371
- const syncToLocation = ({ behavior = 'auto', scrollHashlessTop = false } = {}) => {
372
- const section = getHashSection();
373
-
374
- if (section instanceof HTMLElement) {
375
- scrollToSection(section, { behavior });
376
- scheduleHashAnchorCorrection();
377
- return;
378
- }
379
-
380
- if (scrollHashlessTop) {
381
- jumpTo(0);
382
- }
383
-
384
- setActiveSection(sections[0]);
385
- };
386
-
387
- links.forEach((link) => {
388
- link.addEventListener('click', (event) => {
389
- const linkUrl = new URL(link.href, window.location.href);
390
- if (linkUrl.pathname !== window.location.pathname) return;
391
-
392
- const section = getSectionFromHash(linkUrl.hash);
393
- if (!(section instanceof HTMLElement)) return;
394
-
395
- const top = getSectionScrollTop(section);
396
- if (top === undefined) return;
397
-
398
- event.preventDefault();
399
-
400
- const targetHash = linkUrl.hash;
401
- const duration = getScrollDuration(top - window.scrollY);
402
-
403
- setHash(targetHash);
404
- setActiveSection(section);
405
- closeMobileMenu();
406
-
407
- scrollToSection(section, {
408
- behavior: 'smooth',
409
- duration,
410
- onComplete: scheduleHashAnchorCorrection,
411
- });
412
- });
413
- });
414
-
415
- updateAnchorOffset();
416
- requestAnimationFrame(() => syncToLocation({ behavior: 'auto' }));
417
-
418
- if (siteTop instanceof HTMLElement && 'ResizeObserver' in window) {
419
- new ResizeObserver(updateAnchorOffset).observe(siteTop);
420
- }
131
+ {showSinglePageSectionNavigation && currentPageNavigation && (
132
+ <nav class="page-nav" aria-label={projectConfig.locale.labels.pageNavigation}>
133
+ <ul>
134
+ {currentPageNavigation.sections.map((section) => (
135
+ <li>
136
+ <a href={`#${section.id}`}>{section.title}</a>
137
+ </li>
138
+ ))}
139
+ </ul>
140
+ </nav>
141
+ )}
421
142
 
422
- window.addEventListener('resize', updateAnchorOffset);
423
- window.addEventListener('load', scheduleHashAnchorCorrection);
424
- window.addEventListener('hashchange', () => syncToLocation({ behavior: 'auto', scrollHashlessTop: true }));
425
- window.addEventListener('popstate', () => syncToLocation({ behavior: 'auto', scrollHashlessTop: true }));
143
+ </header>
426
144
 
427
- if (window.visualViewport) {
428
- window.visualViewport.addEventListener('resize', updateAnchorOffset);
429
- }
430
- </script>
145
+ {useNornaSmoothScroll
146
+ ? <NornaSmoothScrollScript />
147
+ : hasCurrentPageSectionMenu && <MobileSectionNavigationScript />}