@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,146 @@
1
+ import assert from 'node:assert/strict';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { parseYamlMapping } from './lib/frontmatter-yaml.mjs';
7
+ import { splitSiteFile } from './lib/site-content.mjs';
8
+ import {
9
+ resolveThemeConfig,
10
+ themePresetNames,
11
+ themePresets,
12
+ } from './lib/theme-presets.mjs';
13
+
14
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
15
+ const cliPath = path.join(repoRoot, 'bin', 'norna.mjs');
16
+ const tempParent = path.join(repoRoot, 'node_modules', '.cache');
17
+ await mkdir(tempParent, { recursive: true });
18
+ const tempRoot = await mkdtemp(path.join(tempParent, 'norna theme presets-'));
19
+ const siteDir = path.join(tempRoot, 'site');
20
+
21
+ const runCli = (args) => spawnSync(process.execPath, [cliPath, '--site-dir', siteDir, ...args], {
22
+ cwd: repoRoot,
23
+ encoding: 'utf8',
24
+ });
25
+
26
+ try {
27
+ assert.deepEqual(Object.keys(themePresets), themePresetNames);
28
+ for (const presetName of themePresetNames) {
29
+ const resolved = resolveThemeConfig({ preset: presetName }, 'test theme');
30
+ assert.equal(resolved.preset, presetName);
31
+ assert.ok(resolved.layout?.density);
32
+ assert.ok(resolved.gallery?.width);
33
+ assert.ok(resolved.typography?.fontFamily);
34
+ assert.ok(resolved.typography?.preset);
35
+ assert.ok(resolved.presentation?.palette);
36
+ }
37
+
38
+ const overridden = resolveThemeConfig({
39
+ preset: 'documentation',
40
+ layout: { pageWidth: '1300px' },
41
+ presentation: { palette: 'dark' },
42
+ }, 'test theme');
43
+ assert.equal(overridden.layout.density, 'compact');
44
+ assert.equal(overridden.layout.pageWidth, '1300px');
45
+ assert.equal(overridden.gallery.width, '920px');
46
+ assert.equal(overridden.presentation.palette, 'dark');
47
+ assert.deepEqual(overridden.presentation.sectionSurfaces.sequence, ['base', 'soft']);
48
+ assert.throws(
49
+ () => resolveThemeConfig({ preset: 'unknown' }, 'test/theme.md'),
50
+ /Unknown theme preset "unknown" in test\/theme\.md.*portfolio, documentation, project, statement/,
51
+ );
52
+
53
+ await mkdir(path.join(siteDir, 'routes', '010-guide'), { recursive: true });
54
+ await writeFile(path.join(siteDir, 'config.md'), `---
55
+ url: https://example.com/
56
+ ---
57
+ `);
58
+ await writeFile(path.join(siteDir, 'content.md'), `---
59
+ title: Theme preset test
60
+ description: Root page
61
+ ---
62
+
63
+ ## Home {#home}
64
+
65
+ Root content.
66
+ `);
67
+ await writeFile(path.join(siteDir, 'theme.md'), `---
68
+ preset: documentation
69
+ layout:
70
+ pageWidth: 1300px
71
+ presentation:
72
+ palette: dark
73
+ ---
74
+ `);
75
+ await writeFile(path.join(siteDir, 'routes', '010-guide', 'route-content.md'), `---
76
+ title: Guide
77
+ description: Route page
78
+ navigation:
79
+ label: Guide
80
+ ---
81
+
82
+ ## Guide {#guide}
83
+
84
+ Route content.
85
+ `);
86
+ await writeFile(path.join(siteDir, 'routes', '010-guide', 'theme.md'), `---
87
+ preset: portfolio
88
+ layout:
89
+ pageWidth: 1010px
90
+ presentation:
91
+ palette: light
92
+ ---
93
+ `);
94
+
95
+ const buildResult = runCli(['build']);
96
+ assert.equal(buildResult.status, 0, buildResult.stderr || buildResult.stdout);
97
+ const rootHtml = await readFile(path.join(tempRoot, 'dist', 'index.html'), 'utf8');
98
+ const routeHtml = await readFile(path.join(tempRoot, 'dist', 'guide', 'index.html'), 'utf8');
99
+ assert.match(rootHtml, /--page-width: 1300px/);
100
+ assert.match(rootHtml, /--font-sans: Georgia, 'Times New Roman', serif/);
101
+ assert.match(rootHtml, /--color-page: #000000/);
102
+ assert.match(routeHtml, /--page-width: 1010px/);
103
+ assert.match(routeHtml, /--font-sans: 'Helvetica Neue', Arial, sans-serif/);
104
+ assert.match(routeHtml, /--color-page: #ffffff/);
105
+
106
+ const typographyResult = runCli(['typography', 'show']);
107
+ assert.equal(typographyResult.status, 0, typographyResult.stderr || typographyResult.stdout);
108
+ assert.match(typographyResult.stdout, /value: text-forward/);
109
+ assert.match(typographyResult.stdout, /value: quiet-gallery/);
110
+
111
+ const routeThemePath = path.join(siteDir, 'routes', '010-guide', 'theme.md');
112
+ const routeThemeSource = await readFile(routeThemePath, 'utf8');
113
+ await writeFile(routeThemePath, `---\npreset: unknown\n---\n`);
114
+ const invalidRoutePresetResult = runCli(['config:check']);
115
+ assert.notEqual(invalidRoutePresetResult.status, 0);
116
+ assert.match(invalidRoutePresetResult.stderr, /Unknown theme preset "unknown" in .*routes\/010-guide\/theme\.md/);
117
+ await writeFile(routeThemePath, routeThemeSource);
118
+
119
+ const exportResult = runCli(['theme:export', 'documentation']);
120
+ assert.equal(exportResult.status, 0, exportResult.stderr || exportResult.stdout);
121
+ assert.match(exportResult.stdout, /orig-documentation-theme\.md/);
122
+ const exportedPath = path.join(siteDir, 'orig-documentation-theme.md');
123
+ const exportedSource = await readFile(exportedPath, 'utf8');
124
+ assert.match(exportedSource, /This is a reference file\. Norna only loads theme\.md\./);
125
+ assert.match(exportedSource, /Available theme presets: portfolio, documentation, project, statement\./);
126
+ assert.match(exportedSource, /# Alternatives: dark, light, paper\./);
127
+ const { frontmatterBody } = splitSiteFile(exportedSource, 'exported theme reference');
128
+ const exportedConfig = parseYamlMapping(frontmatterBody);
129
+ assert.equal(exportedConfig.preset, 'documentation');
130
+ assert.equal(exportedConfig.layout.pageWidth, themePresets.documentation.layout.pageWidth);
131
+ assert.equal(exportedConfig.typography.fontFamily, themePresets.documentation.typography.fontFamily);
132
+ assert.deepEqual(exportedConfig.presentation.sectionSurfaces.sequence, ['base', 'soft']);
133
+
134
+ const exportAgainResult = runCli(['theme:export', 'documentation']);
135
+ assert.notEqual(exportAgainResult.status, 0);
136
+ assert.match(exportAgainResult.stderr, /already exists\. Norna will not overwrite it\./);
137
+ assert.equal(await readFile(exportedPath, 'utf8'), exportedSource);
138
+
139
+ const unknownExportResult = runCli(['theme:export', 'unknown']);
140
+ assert.notEqual(unknownExportResult.status, 0);
141
+ assert.match(unknownExportResult.stderr, /Unknown theme preset "unknown"/);
142
+
143
+ console.log('ok - complete theme presets resolve for root and route themes and export as protected references');
144
+ } finally {
145
+ await rm(tempRoot, { force: true, recursive: true });
146
+ }
@@ -1,18 +1,17 @@
1
1
  import { execFile } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
+ import { getGitHubRepositoryContext, githubPagesWorkflow } from './lib/github-repository.mjs';
3
4
  import { projectConfig } from './lib/project-config.mjs';
4
5
  import { siteProjectRoot } from './lib/site-paths.mjs';
5
6
 
6
7
  const execFileAsync = promisify(execFile);
7
8
 
8
9
  const root = siteProjectRoot;
9
- const defaultRepo = projectConfig.github.repo;
10
- const defaultWorkflow = projectConfig.github.pagesWorkflow;
11
- const defaultBranch = projectConfig.github.branch;
10
+ const defaultWorkflow = githubPagesWorkflow;
12
11
  const defaultSiteUrl = projectConfig.site.url;
13
- const defaultPollIntervalMs = projectConfig.deploy.watch.intervalMs;
14
- const defaultTimeoutMs = projectConfig.deploy.watch.timeoutMs;
15
- const defaultRunLimit = projectConfig.deploy.watch.runLimit;
12
+ const defaultPollIntervalMs = 10_000;
13
+ const defaultTimeoutMs = 15 * 60_000;
14
+ const defaultRunLimit = 10;
16
15
  const runListFields = [
17
16
  'conclusion',
18
17
  'createdAt',
@@ -49,9 +48,9 @@ const usage = `
49
48
  Usage: norna deploy:watch [options]
50
49
 
51
50
  Options:
52
- --repo <owner/name> GitHub repository. Default: ${defaultRepo}
53
- --workflow <name> Workflow name. Default: ${defaultWorkflow}
54
- --branch <name> Branch to monitor. Default: ${defaultBranch}
51
+ --repo <owner/name> GitHub repository. Default: current repository
52
+ --workflow <name> Workflow name or file. Default: ${defaultWorkflow}
53
+ --branch <name> Branch to monitor. Default: repository default branch
55
54
  --sha <sha> Commit SHA to monitor. Default: current HEAD
56
55
  --site-url <url> Public site URL to print. Default: ${defaultSiteUrl}
57
56
  --interval <duration> Poll interval, for example 5s or 0.5m. Default: 10s
@@ -99,10 +98,10 @@ const readOptionValue = (args, index, optionName) => {
99
98
 
100
99
  const parseArgs = (args) => {
101
100
  const options = {
102
- branch: defaultBranch,
101
+ branch: null,
103
102
  intervalMs: defaultPollIntervalMs,
104
103
  limit: defaultRunLimit,
105
- repo: defaultRepo,
104
+ repo: null,
106
105
  sha: null,
107
106
  siteUrl: defaultSiteUrl,
108
107
  timeoutMs: defaultTimeoutMs,
@@ -367,6 +366,11 @@ const printFailureDetails = async (run, options, elapsedMs) => {
367
366
 
368
367
  const monitor = async () => {
369
368
  const options = parseArgs(process.argv.slice(2));
369
+ if (!options.repo || !options.branch) {
370
+ const repository = await getGitHubRepositoryContext({ cwd: root, repo: options.repo });
371
+ options.repo ??= repository.repo;
372
+ options.branch ??= repository.branch;
373
+ }
370
374
  options.sha ??= await getCurrentSha();
371
375
 
372
376
  const startedAt = Date.now();
@@ -1,22 +1,17 @@
1
1
  ---
2
2
  import projectConfig from '../../scripts/lib/project-config.mjs';
3
- import { getGeneratedImage, getImageAttributes } from '../lib/generatedImages';
4
-
5
- type GalleryImage = {
6
- image: string;
7
- src?: string;
8
- alt?: string;
9
- caption?: string;
10
- };
11
- type GalleryItem = GalleryImage | { carousel: GalleryImage[] };
12
- type GeneratedImageWithDimensions = NonNullable<ReturnType<typeof getGeneratedImage>> & {
13
- width: number;
14
- height: number;
15
- };
3
+ import { getImageAttributes } from '../lib/generatedImages';
4
+ import {
5
+ getCaptionId,
6
+ getGalleryImageSizes,
7
+ getImageClass,
8
+ getImageLoadingProps,
9
+ type GalleryImage,
10
+ } from '../lib/galleryImages';
16
11
 
17
12
  interface Props {
18
13
  title: string;
19
- items: GalleryItem[];
14
+ images: GalleryImage[];
20
15
  maxAvailableWidthPercent: {
21
16
  desktop: number;
22
17
  mobile: number;
@@ -24,229 +19,34 @@ interface Props {
24
19
  priorityFirstImage?: boolean;
25
20
  }
26
21
 
27
- const { title, items, maxAvailableWidthPercent, priorityFirstImage = false } = Astro.props;
28
- const getCaptionId = (image: GalleryImage, itemIndex: number, imageIndex = 0) => {
29
- const source = (image.src ?? image.image)
30
- .toLowerCase()
31
- .replace(/[^a-z0-9]+/g, '-')
32
- .replace(/^-|-$/g, '');
33
-
34
- return `gallery-caption-${source}-${itemIndex}-${imageIndex}`;
35
- };
36
- const galleryImageSizes = [
37
- `(max-width: 700px) ${maxAvailableWidthPercent.mobile}vw`,
38
- `${maxAvailableWidthPercent.desktop}vw`,
39
- ].join(', ');
40
- const hasDimensions = (image: ReturnType<typeof getGeneratedImage>): image is GeneratedImageWithDimensions => (
41
- Boolean(image) && Number.isFinite(image.width) && Number.isFinite(image.height)
42
- );
43
- const getImageClass = (image: GalleryImage) => {
44
- const generatedImage = getGeneratedImage(image.src ?? image.image);
45
- return hasDimensions(generatedImage) && generatedImage.width > generatedImage.height
46
- ? 'gallery-image-landscape'
47
- : undefined;
48
- };
49
- const getImageLoadingProps = (isPriority: boolean) => ({
50
- decoding: 'async' as const,
51
- fetchpriority: isPriority ? 'high' as const : 'low' as const,
52
- loading: isPriority ? 'eager' as const : 'lazy' as const,
53
- });
54
- const getCarouselAspectRatio = (images: GalleryImage[]) => {
55
- const ratios = images
56
- .map((image) => getGeneratedImage(image.src ?? image.image))
57
- .filter(hasDimensions)
58
- .map((image) => image.width / image.height);
59
-
60
- return ratios.length > 0 ? Math.min(...ratios) : null;
61
- };
22
+ const { title, images, maxAvailableWidthPercent, priorityFirstImage = false } = Astro.props;
23
+ const galleryImageSizes = getGalleryImageSizes(maxAvailableWidthPercent);
62
24
  ---
63
25
 
64
26
  <div class="gallery" aria-label={`${projectConfig.locale.labels.gallery}: ${title}`}>
65
- {items.map((item, itemIndex) => {
27
+ {images.map((image, itemIndex) => {
66
28
  const isPriorityItem = priorityFirstImage && itemIndex === 0;
67
-
68
- if ('image' in item) {
69
- const captionId = item.caption ? getCaptionId(item, itemIndex) : undefined;
70
-
71
- return (
72
- <figure class="gallery-item">
73
- <div class="gallery-image-frame">
74
- <img
75
- {...getImageAttributes(item.src ?? item.image, galleryImageSizes)}
76
- class:list={['gallery-image', getImageClass(item)]}
77
- alt={item.alt ?? ''}
78
- aria-describedby={captionId}
79
- {...getImageLoadingProps(isPriorityItem)}
80
- />
81
- </div>
82
- {item.caption && (
83
- <figcaption class="gallery-meta" id={captionId}>
84
- <div class="gallery-details">
85
- <span>{item.caption}</span>
86
- </div>
87
- </figcaption>
88
- )}
89
- </figure>
90
- );
91
- }
92
-
93
- const carouselAspectRatio = getCarouselAspectRatio(item.carousel);
94
- const carouselStyle = carouselAspectRatio
95
- ? `--gallery-carousel-aspect-ratio: ${carouselAspectRatio}`
96
- : undefined;
29
+ const captionId = image.caption ? getCaptionId(image, itemIndex) : undefined;
97
30
 
98
31
  return (
99
- <section
100
- class="gallery-item gallery-carousel"
101
- data-carousel
102
- tabindex="0"
103
- role="group"
104
- aria-roledescription="carousel"
105
- aria-label={`${title}, bildkarusell`}
106
- style={carouselStyle}
107
- >
108
- <div class="gallery-carousel-stage">
109
- <div class="gallery-carousel-viewport" data-carousel-viewport>
110
- <div class="gallery-carousel-slides">
111
- {item.carousel.map((image, imageIndex) => {
112
- const captionId = image.caption ? getCaptionId(image, itemIndex, imageIndex) : undefined;
113
-
114
- return (
115
- <figure class="gallery-carousel-slide" data-carousel-slide>
116
- <div class="gallery-carousel-image-frame">
117
- <img
118
- {...getImageAttributes(image.src ?? image.image, galleryImageSizes)}
119
- class:list={['gallery-image', getImageClass(image)]}
120
- alt={image.alt ?? ''}
121
- aria-describedby={captionId}
122
- {...getImageLoadingProps(isPriorityItem && imageIndex === 0)}
123
- />
124
- </div>
125
- </figure>
126
- );
127
- })}
128
- </div>
129
- </div>
130
- <button
131
- class="gallery-carousel-button gallery-carousel-button-previous"
132
- type="button"
133
- data-carousel-previous
134
- aria-label="Föregående bild"
135
- title="Föregående bild"
136
- >
137
- <span aria-hidden="true">‹</span>
138
- </button>
139
- <button
140
- class="gallery-carousel-button gallery-carousel-button-next"
141
- type="button"
142
- data-carousel-next
143
- aria-label="Nästa bild"
144
- title="Nästa bild"
145
- >
146
- <span aria-hidden="true">›</span>
147
- </button>
148
- <output class="gallery-carousel-position" data-carousel-position aria-live="polite">
149
- 1 / {item.carousel.length}
150
- </output>
32
+ <figure class="gallery-item">
33
+ <div class="gallery-image-frame">
34
+ <img
35
+ {...getImageAttributes(image.src ?? image.image, galleryImageSizes)}
36
+ class:list={['gallery-image', getImageClass(image)]}
37
+ alt={image.alt ?? ''}
38
+ aria-describedby={captionId}
39
+ {...getImageLoadingProps(isPriorityItem)}
40
+ />
151
41
  </div>
152
- <div class="gallery-carousel-captions" data-carousel-captions>
153
- {item.carousel.map((image, imageIndex) => (
154
- image.caption && (
155
- <p
156
- class="gallery-meta gallery-carousel-caption"
157
- id={getCaptionId(image, itemIndex, imageIndex)}
158
- data-carousel-caption
159
- data-carousel-caption-index={imageIndex}
160
- >
161
- <span class="gallery-details">
162
- <span>{image.caption}</span>
163
- </span>
164
- </p>
165
- )
166
- ))}
167
- </div>
168
- </section>
42
+ {image.caption && (
43
+ <figcaption class="gallery-meta" id={captionId}>
44
+ <div class="gallery-details">
45
+ <span>{image.caption}</span>
46
+ </div>
47
+ </figcaption>
48
+ )}
49
+ </figure>
169
50
  );
170
51
  })}
171
52
  </div>
172
-
173
- <script>
174
- import EmblaCarousel from 'embla-carousel';
175
-
176
- const carouselSelector = '[data-carousel]';
177
-
178
- const initializeCarousel = (carousel: HTMLElement) => {
179
- const viewport = carousel.querySelector<HTMLElement>('[data-carousel-viewport]');
180
- const previous = carousel.querySelector<HTMLButtonElement>('[data-carousel-previous]');
181
- const next = carousel.querySelector<HTMLButtonElement>('[data-carousel-next]');
182
- const position = carousel.querySelector<HTMLOutputElement>('[data-carousel-position]');
183
- const captions = Array.from(carousel.querySelectorAll<HTMLElement>('[data-carousel-caption]'));
184
- const slides = Array.from(carousel.querySelectorAll<HTMLElement>('[data-carousel-slide]'));
185
- if (!viewport || !previous || !next || !position || slides.length < 2) return;
186
-
187
- let controlsTimeout: number | undefined;
188
- const showControls = () => {
189
- carousel.classList.add('is-interacting');
190
- window.clearTimeout(controlsTimeout);
191
- controlsTimeout = window.setTimeout(() => {
192
- carousel.classList.remove('is-interacting');
193
- }, 1600);
194
- };
195
-
196
- carousel.dataset.carouselReady = 'true';
197
-
198
- const embla = EmblaCarousel(viewport, {
199
- align: 'start',
200
- containScroll: false,
201
- loop: true,
202
- });
203
-
204
- const update = () => {
205
- const activeIndex = embla.selectedScrollSnap();
206
- slides.forEach((slide, index) => {
207
- const isSelected = index === activeIndex;
208
- slide.classList.toggle('is-active', isSelected);
209
- slide.setAttribute('aria-hidden', String(!isSelected));
210
- });
211
- captions.forEach((caption) => {
212
- const isSelected = Number(caption.dataset.carouselCaptionIndex) === activeIndex;
213
- caption.classList.toggle('is-active', isSelected);
214
- caption.setAttribute('aria-hidden', String(!isSelected));
215
- });
216
- previous.disabled = false;
217
- next.disabled = false;
218
- position.textContent = `${activeIndex + 1} / ${slides.length}`;
219
- };
220
-
221
- previous.addEventListener('click', () => {
222
- showControls();
223
- embla.scrollPrev();
224
- });
225
- next.addEventListener('click', () => {
226
- showControls();
227
- embla.scrollNext();
228
- });
229
- carousel.addEventListener('focusin', showControls);
230
- carousel.addEventListener('pointerdown', showControls);
231
- carousel.addEventListener('keydown', (event) => {
232
- if (event.key === 'ArrowLeft') {
233
- event.preventDefault();
234
- showControls();
235
- embla.scrollPrev();
236
- }
237
- if (event.key === 'ArrowRight') {
238
- event.preventDefault();
239
- showControls();
240
- embla.scrollNext();
241
- }
242
- });
243
- embla.on('select', () => {
244
- showControls();
245
- update();
246
- });
247
- embla.on('reInit', update);
248
- update();
249
- };
250
-
251
- document.querySelectorAll<HTMLElement>(carouselSelector).forEach(initializeCarousel);
252
- </script>
@@ -0,0 +1,184 @@
1
+ ---
2
+ import projectConfig from '../../scripts/lib/project-config.mjs';
3
+ import { getImageAttributes } from '../lib/generatedImages';
4
+ import {
5
+ getCaptionId,
6
+ getCarouselAspectRatio,
7
+ getGalleryImageSizes,
8
+ getImageClass,
9
+ getImageLoadingProps,
10
+ type GalleryImage,
11
+ } from '../lib/galleryImages';
12
+
13
+ interface Props {
14
+ title: string;
15
+ images: GalleryImage[];
16
+ maxAvailableWidthPercent: {
17
+ desktop: number;
18
+ mobile: number;
19
+ };
20
+ priorityFirstImage?: boolean;
21
+ }
22
+
23
+ const { title, images, maxAvailableWidthPercent, priorityFirstImage = false } = Astro.props;
24
+ const galleryImageSizes = getGalleryImageSizes(maxAvailableWidthPercent);
25
+ const carouselAspectRatio = getCarouselAspectRatio(images);
26
+ const carouselStyle = carouselAspectRatio
27
+ ? `--gallery-carousel-aspect-ratio: ${carouselAspectRatio}`
28
+ : undefined;
29
+ ---
30
+
31
+ <div class="gallery" aria-label={`${projectConfig.locale.labels.gallery}: ${title}`}>
32
+ <section
33
+ class="gallery-item gallery-carousel"
34
+ data-carousel
35
+ tabindex="0"
36
+ role="group"
37
+ aria-roledescription="carousel"
38
+ aria-label={`${title}, bildkarusell`}
39
+ style={carouselStyle}
40
+ >
41
+ <div class="gallery-carousel-stage">
42
+ <div class="gallery-carousel-viewport" data-carousel-viewport>
43
+ <div class="gallery-carousel-slides">
44
+ {images.map((image, imageIndex) => {
45
+ const captionId = image.caption ? getCaptionId(image, 0, imageIndex) : undefined;
46
+
47
+ return (
48
+ <figure class="gallery-carousel-slide" data-carousel-slide>
49
+ <div class="gallery-carousel-image-frame">
50
+ <img
51
+ {...getImageAttributes(image.src ?? image.image, galleryImageSizes)}
52
+ class:list={['gallery-image', getImageClass(image)]}
53
+ alt={image.alt ?? ''}
54
+ aria-describedby={captionId}
55
+ {...getImageLoadingProps(priorityFirstImage && imageIndex === 0)}
56
+ />
57
+ </div>
58
+ </figure>
59
+ );
60
+ })}
61
+ </div>
62
+ </div>
63
+ <button
64
+ class="gallery-carousel-button gallery-carousel-button-previous"
65
+ type="button"
66
+ data-carousel-previous
67
+ aria-label="Föregående bild"
68
+ title="Föregående bild"
69
+ >
70
+ <span aria-hidden="true">‹</span>
71
+ </button>
72
+ <button
73
+ class="gallery-carousel-button gallery-carousel-button-next"
74
+ type="button"
75
+ data-carousel-next
76
+ aria-label="Nästa bild"
77
+ title="Nästa bild"
78
+ >
79
+ <span aria-hidden="true">›</span>
80
+ </button>
81
+ <output class="gallery-carousel-position" data-carousel-position aria-live="polite">
82
+ 1 / {images.length}
83
+ </output>
84
+ </div>
85
+ <div class="gallery-carousel-captions" data-carousel-captions>
86
+ {images.map((image, imageIndex) => (
87
+ image.caption && (
88
+ <p
89
+ class="gallery-meta gallery-carousel-caption"
90
+ id={getCaptionId(image, 0, imageIndex)}
91
+ data-carousel-caption
92
+ data-carousel-caption-index={imageIndex}
93
+ >
94
+ <span class="gallery-details">
95
+ <span>{image.caption}</span>
96
+ </span>
97
+ </p>
98
+ )
99
+ ))}
100
+ </div>
101
+ </section>
102
+ </div>
103
+
104
+ <script>
105
+ import EmblaCarousel from 'embla-carousel';
106
+
107
+ const initializeCarousel = (carousel: HTMLElement) => {
108
+ if (carousel.dataset.carouselInitialized === 'true') return;
109
+
110
+ const viewport = carousel.querySelector<HTMLElement>('[data-carousel-viewport]');
111
+ const previous = carousel.querySelector<HTMLButtonElement>('[data-carousel-previous]');
112
+ const next = carousel.querySelector<HTMLButtonElement>('[data-carousel-next]');
113
+ const position = carousel.querySelector<HTMLOutputElement>('[data-carousel-position]');
114
+ const captions = Array.from(carousel.querySelectorAll<HTMLElement>('[data-carousel-caption]'));
115
+ const slides = Array.from(carousel.querySelectorAll<HTMLElement>('[data-carousel-slide]'));
116
+ if (!viewport || !previous || !next || !position || slides.length < 2) return;
117
+
118
+ let controlsTimeout: number | undefined;
119
+ const showControls = () => {
120
+ carousel.classList.add('is-interacting');
121
+ window.clearTimeout(controlsTimeout);
122
+ controlsTimeout = window.setTimeout(() => {
123
+ carousel.classList.remove('is-interacting');
124
+ }, 1600);
125
+ };
126
+
127
+ carousel.dataset.carouselInitialized = 'true';
128
+ carousel.dataset.carouselReady = 'true';
129
+
130
+ const embla = EmblaCarousel(viewport, {
131
+ align: 'start',
132
+ containScroll: false,
133
+ loop: true,
134
+ });
135
+
136
+ const update = () => {
137
+ const activeIndex = embla.selectedScrollSnap();
138
+ slides.forEach((slide, index) => {
139
+ const isSelected = index === activeIndex;
140
+ slide.classList.toggle('is-active', isSelected);
141
+ slide.setAttribute('aria-hidden', String(!isSelected));
142
+ });
143
+ captions.forEach((caption) => {
144
+ const isSelected = Number(caption.dataset.carouselCaptionIndex) === activeIndex;
145
+ caption.classList.toggle('is-active', isSelected);
146
+ caption.setAttribute('aria-hidden', String(!isSelected));
147
+ });
148
+ previous.disabled = false;
149
+ next.disabled = false;
150
+ position.textContent = `${activeIndex + 1} / ${slides.length}`;
151
+ };
152
+
153
+ previous.addEventListener('click', () => {
154
+ showControls();
155
+ embla.scrollPrev();
156
+ });
157
+ next.addEventListener('click', () => {
158
+ showControls();
159
+ embla.scrollNext();
160
+ });
161
+ carousel.addEventListener('focusin', showControls);
162
+ carousel.addEventListener('pointerdown', showControls);
163
+ carousel.addEventListener('keydown', (event) => {
164
+ if (event.key === 'ArrowLeft') {
165
+ event.preventDefault();
166
+ showControls();
167
+ embla.scrollPrev();
168
+ }
169
+ if (event.key === 'ArrowRight') {
170
+ event.preventDefault();
171
+ showControls();
172
+ embla.scrollNext();
173
+ }
174
+ });
175
+ embla.on('select', () => {
176
+ showControls();
177
+ update();
178
+ });
179
+ embla.on('reInit', update);
180
+ update();
181
+ };
182
+
183
+ document.querySelectorAll<HTMLElement>('[data-carousel]').forEach(initializeCarousel);
184
+ </script>
@@ -0,0 +1,14 @@
1
+ <script>
2
+ const mobileMenu = document.querySelector<HTMLDetailsElement>('.mobile-nav-menu');
3
+ const sectionLinks = Array.from(document.querySelectorAll<HTMLAnchorElement>('.mobile-page-nav a'));
4
+
5
+ sectionLinks.forEach((link) => {
6
+ link.addEventListener('click', (event) => {
7
+ const linkUrl = new URL(link.href, window.location.href);
8
+ if (linkUrl.pathname !== window.location.pathname) return;
9
+
10
+ if (mobileMenu) mobileMenu.open = false;
11
+ if (event.detail > 0) link.blur();
12
+ });
13
+ });
14
+ </script>