@morphemecms/cms 0.1.0 → 0.2.0-next-20261104150211

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 (908) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -21
  3. package/README.md +51 -51
  4. package/astro.mjs +162 -162
  5. package/bin/morpheme.mjs +38 -38
  6. package/client.d.ts +10 -10
  7. package/defaults/blockTexts.ts +33 -33
  8. package/defaults/collections.ts +774 -774
  9. package/defaults/colors.ts +125 -125
  10. package/defaults/company.ts +20 -20
  11. package/defaults/editor.ts +178 -178
  12. package/defaults/internalLinks.ts +30 -30
  13. package/defaults/opens.ts +18 -18
  14. package/defaults/popup.tsx +93 -93
  15. package/defaults/privacy.ts +79 -79
  16. package/defaults/rules.ts +450 -450
  17. package/defaults/schema.ts +16 -16
  18. package/defaults/sitedata.ts +129 -129
  19. package/defaults/standard.ts +106 -106
  20. package/defaults/standardPages.ts +87 -87
  21. package/defaults/texts.ts +481 -481
  22. package/demo/README.md +26 -26
  23. package/demo/src/content/blog/build-a-page-from-blocks.md +19 -19
  24. package/demo/src/content/blog/colors-everyone-can-read.md +19 -19
  25. package/demo/src/content/blog/edit-your-website-from-your-phone.md +21 -21
  26. package/demo/src/content/blog/every-save-is-a-version.md +21 -21
  27. package/demo/src/content/blog/schedule-a-post.md +17 -17
  28. package/demo/src/content/blog/secure-from-day-one.md +17 -17
  29. package/demo/src/content/blog/seo-without-the-guesswork.md +23 -23
  30. package/demo/src/content/blog/switch-themes-without-losing-anything.md +23 -23
  31. package/demo/src/content/blog/the-app-store.md +21 -21
  32. package/demo/src/content/pages/about.md +22 -22
  33. package/demo/src/content/pages/app-store.md +30 -30
  34. package/demo/src/content/pages/blocks.md +98 -98
  35. package/demo/src/content/pages/blog-page.md +11 -11
  36. package/demo/src/content/pages/contact.md +16 -16
  37. package/demo/src/content/pages/get-started.md +20 -20
  38. package/demo/src/content/pages/home.md +26 -26
  39. package/demo/src/content/pages/page-not-found.md +11 -11
  40. package/demo/src/content/pages/privacy-policy.md +24 -24
  41. package/demo/src/data/blocks.json +25 -25
  42. package/demo/src/data/booking.json +6 -6
  43. package/demo/src/data/categories/apps.json +6 -6
  44. package/demo/src/data/categories/design.json +6 -6
  45. package/demo/src/data/categories/editing.json +6 -6
  46. package/demo/src/data/categories/security.json +6 -6
  47. package/demo/src/data/categories/seo.json +6 -6
  48. package/demo/src/data/colors.json +75 -75
  49. package/demo/src/data/contact.json +8 -8
  50. package/demo/src/data/cookies.json +21 -21
  51. package/demo/src/data/footer.json +27 -27
  52. package/demo/src/data/menu.json +35 -35
  53. package/demo/src/data/mobile-menu.json +25 -25
  54. package/demo/src/data/popups/booking-bar.json +13 -13
  55. package/demo/src/data/popups/try-the-editor.json +16 -16
  56. package/demo/src/data/standard-pages.json +8 -8
  57. package/demo/src/data/testimonials/sample-bakery.json +10 -10
  58. package/demo/src/data/testimonials/sample-clinic.json +10 -10
  59. package/demo/src/data/testimonials/sample-studio.json +10 -10
  60. package/demo/src/site/colors.ts +11 -11
  61. package/demo/src/site/config.ts +19 -19
  62. package/icons/lucide/LICENSE +43 -43
  63. package/icons/lucide/address-book.svg +1 -1
  64. package/icons/lucide/app-window.svg +1 -1
  65. package/icons/lucide/arrow-counter-clockwise.svg +1 -1
  66. package/icons/lucide/arrow-down.svg +1 -1
  67. package/icons/lucide/arrow-left.svg +1 -1
  68. package/icons/lucide/arrow-right.svg +1 -1
  69. package/icons/lucide/arrow-square-out.svg +1 -1
  70. package/icons/lucide/arrow-u-up-left.svg +1 -1
  71. package/icons/lucide/arrow-u-up-right.svg +1 -1
  72. package/icons/lucide/arrow-up-right.svg +1 -1
  73. package/icons/lucide/arrow-up.svg +1 -1
  74. package/icons/lucide/arrows-down-up.svg +1 -1
  75. package/icons/lucide/arrows-in-line-horizontal.svg +1 -1
  76. package/icons/lucide/arrows-out-line-horizontal.svg +1 -1
  77. package/icons/lucide/article.svg +1 -1
  78. package/icons/lucide/bank.svg +1 -1
  79. package/icons/lucide/bell.svg +1 -1
  80. package/icons/lucide/bicycle.svg +1 -1
  81. package/icons/lucide/binoculars.svg +1 -1
  82. package/icons/lucide/book-open-text.svg +1 -1
  83. package/icons/lucide/book-open.svg +1 -1
  84. package/icons/lucide/browser.svg +1 -1
  85. package/icons/lucide/buildings.svg +1 -1
  86. package/icons/lucide/bus.svg +1 -1
  87. package/icons/lucide/calendar-blank.svg +1 -1
  88. package/icons/lucide/calendar-check.svg +1 -1
  89. package/icons/lucide/car.svg +1 -1
  90. package/icons/lucide/cards.svg +1 -1
  91. package/icons/lucide/caret-down.svg +1 -1
  92. package/icons/lucide/caret-left.svg +1 -1
  93. package/icons/lucide/caret-right.svg +1 -1
  94. package/icons/lucide/caret-up.svg +1 -1
  95. package/icons/lucide/certificate.svg +1 -1
  96. package/icons/lucide/chart-line-up.svg +1 -1
  97. package/icons/lucide/chats.svg +1 -1
  98. package/icons/lucide/check-circle.svg +1 -1
  99. package/icons/lucide/check.svg +1 -1
  100. package/icons/lucide/circle-half.svg +1 -1
  101. package/icons/lucide/circle.svg +1 -1
  102. package/icons/lucide/clock-counter-clockwise.svg +1 -1
  103. package/icons/lucide/clock.svg +1 -1
  104. package/icons/lucide/code.svg +1 -1
  105. package/icons/lucide/coffee.svg +1 -1
  106. package/icons/lucide/columns.svg +1 -1
  107. package/icons/lucide/cookie.svg +1 -1
  108. package/icons/lucide/copy.svg +1 -1
  109. package/icons/lucide/credit-card.svg +1 -1
  110. package/icons/lucide/currency-circle-dollar.svg +1 -1
  111. package/icons/lucide/cursor-click.svg +1 -1
  112. package/icons/lucide/database.svg +1 -1
  113. package/icons/lucide/desktop.svg +1 -1
  114. package/icons/lucide/device-mobile.svg +1 -1
  115. package/icons/lucide/door-open.svg +1 -1
  116. package/icons/lucide/download-simple.svg +1 -1
  117. package/icons/lucide/envelope-simple.svg +1 -1
  118. package/icons/lucide/eye-slash.svg +1 -1
  119. package/icons/lucide/eye.svg +1 -1
  120. package/icons/lucide/file-pdf.svg +1 -1
  121. package/icons/lucide/file-text.svg +1 -1
  122. package/icons/lucide/file-video.svg +1 -1
  123. package/icons/lucide/file-zip.svg +1 -1
  124. package/icons/lucide/flower-lotus.svg +1 -1
  125. package/icons/lucide/folder-simple.svg +1 -1
  126. package/icons/lucide/funnel.svg +1 -1
  127. package/icons/lucide/gauge.svg +1 -1
  128. package/icons/lucide/gear.svg +1 -1
  129. package/icons/lucide/github-logo.svg +1 -1
  130. package/icons/lucide/globe.svg +1 -1
  131. package/icons/lucide/google-logo.svg +1 -1
  132. package/icons/lucide/graduation-cap.svg +1 -1
  133. package/icons/lucide/hammer.svg +1 -1
  134. package/icons/lucide/hand-heart.svg +1 -1
  135. package/icons/lucide/handshake.svg +1 -1
  136. package/icons/lucide/hard-drives.svg +1 -1
  137. package/icons/lucide/heart.svg +1 -1
  138. package/icons/lucide/house.svg +1 -1
  139. package/icons/lucide/image-square.svg +1 -1
  140. package/icons/lucide/image.svg +1 -1
  141. package/icons/lucide/info.svg +1 -1
  142. package/icons/lucide/keyboard.svg +1 -1
  143. package/icons/lucide/leaf.svg +1 -1
  144. package/icons/lucide/lifebuoy.svg +1 -1
  145. package/icons/lucide/lightbulb.svg +1 -1
  146. package/icons/lucide/link-break.svg +1 -1
  147. package/icons/lucide/link-simple.svg +1 -1
  148. package/icons/lucide/list-bullets.svg +1 -1
  149. package/icons/lucide/list-checks.svg +1 -1
  150. package/icons/lucide/list-numbers.svg +1 -1
  151. package/icons/lucide/list.svg +1 -1
  152. package/icons/lucide/lock-simple-open.svg +1 -1
  153. package/icons/lucide/lock-simple.svg +1 -1
  154. package/icons/lucide/magnifying-glass.svg +1 -1
  155. package/icons/lucide/map-pin.svg +1 -1
  156. package/icons/lucide/map-trifold.svg +1 -1
  157. package/icons/lucide/medal.svg +1 -1
  158. package/icons/lucide/megaphone.svg +1 -1
  159. package/icons/lucide/minus.svg +1 -1
  160. package/icons/lucide/moon.svg +1 -1
  161. package/icons/lucide/newspaper.svg +1 -1
  162. package/icons/lucide/pack.json +23 -23
  163. package/icons/lucide/paint-brush-broad.svg +1 -1
  164. package/icons/lucide/palette.svg +1 -1
  165. package/icons/lucide/paper-plane-tilt.svg +1 -1
  166. package/icons/lucide/pencil-simple.svg +1 -1
  167. package/icons/lucide/phone.svg +1 -1
  168. package/icons/lucide/play-fill.svg +1 -1
  169. package/icons/lucide/plus.svg +1 -1
  170. package/icons/lucide/prohibit.svg +1 -1
  171. package/icons/lucide/puzzle-piece.svg +1 -1
  172. package/icons/lucide/question.svg +1 -1
  173. package/icons/lucide/quotes.svg +1 -1
  174. package/icons/lucide/rows.svg +1 -1
  175. package/icons/lucide/ruler.svg +1 -1
  176. package/icons/lucide/scan.svg +1 -1
  177. package/icons/lucide/shapes.svg +1 -1
  178. package/icons/lucide/share-network.svg +1 -1
  179. package/icons/lucide/shield-check.svg +1 -1
  180. package/icons/lucide/sidebar-simple.svg +1 -1
  181. package/icons/lucide/sign-out.svg +1 -1
  182. package/icons/lucide/signpost.svg +1 -1
  183. package/icons/lucide/sliders-horizontal.svg +1 -1
  184. package/icons/lucide/smiley.svg +1 -1
  185. package/icons/lucide/sparkle.svg +1 -1
  186. package/icons/lucide/square-half-bottom.svg +1 -1
  187. package/icons/lucide/square.svg +1 -1
  188. package/icons/lucide/squares-four.svg +1 -1
  189. package/icons/lucide/sticker.svg +1 -1
  190. package/icons/lucide/storefront.svg +1 -1
  191. package/icons/lucide/sun.svg +1 -1
  192. package/icons/lucide/swatches.svg +1 -1
  193. package/icons/lucide/tag.svg +1 -1
  194. package/icons/lucide/text-aa.svg +1 -1
  195. package/icons/lucide/text-align-left.svg +1 -1
  196. package/icons/lucide/text-b.svg +1 -1
  197. package/icons/lucide/text-h-one.svg +1 -1
  198. package/icons/lucide/text-h-three.svg +1 -1
  199. package/icons/lucide/text-h-two.svg +1 -1
  200. package/icons/lucide/text-italic.svg +1 -1
  201. package/icons/lucide/text-t.svg +1 -1
  202. package/icons/lucide/ticket.svg +1 -1
  203. package/icons/lucide/toggle-right.svg +1 -1
  204. package/icons/lucide/train.svg +1 -1
  205. package/icons/lucide/trash.svg +1 -1
  206. package/icons/lucide/upload-simple.svg +1 -1
  207. package/icons/lucide/user-circle.svg +1 -1
  208. package/icons/lucide/user.svg +1 -1
  209. package/icons/lucide/users-three.svg +1 -1
  210. package/icons/lucide/users.svg +1 -1
  211. package/icons/lucide/video-camera.svg +1 -1
  212. package/icons/lucide/warning-circle.svg +1 -1
  213. package/icons/lucide/warning.svg +1 -1
  214. package/icons/lucide/wave-sine.svg +1 -1
  215. package/icons/lucide/wheelchair.svg +1 -1
  216. package/icons/lucide/wrench.svg +1 -1
  217. package/icons/lucide/x.svg +1 -1
  218. package/icons/material-symbols/LICENSE +201 -201
  219. package/icons/material-symbols/address-book.svg +1 -1
  220. package/icons/material-symbols/app-window.svg +1 -1
  221. package/icons/material-symbols/arrow-counter-clockwise.svg +1 -1
  222. package/icons/material-symbols/arrow-down.svg +1 -1
  223. package/icons/material-symbols/arrow-left.svg +1 -1
  224. package/icons/material-symbols/arrow-right.svg +1 -1
  225. package/icons/material-symbols/arrow-square-out.svg +1 -1
  226. package/icons/material-symbols/arrow-u-up-left.svg +1 -1
  227. package/icons/material-symbols/arrow-u-up-right.svg +1 -1
  228. package/icons/material-symbols/arrow-up-right.svg +1 -1
  229. package/icons/material-symbols/arrow-up.svg +1 -1
  230. package/icons/material-symbols/arrows-down-up.svg +1 -1
  231. package/icons/material-symbols/arrows-in-line-horizontal.svg +1 -1
  232. package/icons/material-symbols/arrows-out-line-horizontal.svg +1 -1
  233. package/icons/material-symbols/article.svg +1 -1
  234. package/icons/material-symbols/bank.svg +1 -1
  235. package/icons/material-symbols/bell.svg +1 -1
  236. package/icons/material-symbols/bicycle.svg +1 -1
  237. package/icons/material-symbols/binoculars.svg +1 -1
  238. package/icons/material-symbols/book-open-text.svg +1 -1
  239. package/icons/material-symbols/book-open.svg +1 -1
  240. package/icons/material-symbols/browser.svg +1 -1
  241. package/icons/material-symbols/buildings.svg +1 -1
  242. package/icons/material-symbols/bus.svg +1 -1
  243. package/icons/material-symbols/calendar-blank.svg +1 -1
  244. package/icons/material-symbols/calendar-check.svg +1 -1
  245. package/icons/material-symbols/car.svg +1 -1
  246. package/icons/material-symbols/cards.svg +1 -1
  247. package/icons/material-symbols/caret-down.svg +1 -1
  248. package/icons/material-symbols/caret-left.svg +1 -1
  249. package/icons/material-symbols/caret-right.svg +1 -1
  250. package/icons/material-symbols/caret-up.svg +1 -1
  251. package/icons/material-symbols/certificate.svg +1 -1
  252. package/icons/material-symbols/chart-line-up.svg +1 -1
  253. package/icons/material-symbols/chats.svg +1 -1
  254. package/icons/material-symbols/check-circle.svg +1 -1
  255. package/icons/material-symbols/check.svg +1 -1
  256. package/icons/material-symbols/circle-half.svg +1 -1
  257. package/icons/material-symbols/circle.svg +1 -1
  258. package/icons/material-symbols/clock-counter-clockwise.svg +1 -1
  259. package/icons/material-symbols/clock.svg +1 -1
  260. package/icons/material-symbols/code.svg +1 -1
  261. package/icons/material-symbols/coffee.svg +1 -1
  262. package/icons/material-symbols/columns.svg +1 -1
  263. package/icons/material-symbols/cookie.svg +1 -1
  264. package/icons/material-symbols/copy.svg +1 -1
  265. package/icons/material-symbols/credit-card.svg +1 -1
  266. package/icons/material-symbols/currency-circle-dollar.svg +1 -1
  267. package/icons/material-symbols/cursor-click.svg +1 -1
  268. package/icons/material-symbols/database.svg +1 -1
  269. package/icons/material-symbols/desktop.svg +1 -1
  270. package/icons/material-symbols/device-mobile.svg +1 -1
  271. package/icons/material-symbols/door-open.svg +1 -1
  272. package/icons/material-symbols/download-simple.svg +1 -1
  273. package/icons/material-symbols/envelope-simple.svg +1 -1
  274. package/icons/material-symbols/eye-slash.svg +1 -1
  275. package/icons/material-symbols/eye.svg +1 -1
  276. package/icons/material-symbols/file-pdf.svg +1 -1
  277. package/icons/material-symbols/file-text.svg +1 -1
  278. package/icons/material-symbols/file-video.svg +1 -1
  279. package/icons/material-symbols/file-zip.svg +1 -1
  280. package/icons/material-symbols/flower-lotus.svg +1 -1
  281. package/icons/material-symbols/folder-simple.svg +1 -1
  282. package/icons/material-symbols/funnel.svg +1 -1
  283. package/icons/material-symbols/gauge.svg +1 -1
  284. package/icons/material-symbols/gear.svg +1 -1
  285. package/icons/material-symbols/github-logo.svg +1 -1
  286. package/icons/material-symbols/globe.svg +1 -1
  287. package/icons/material-symbols/google-logo.svg +1 -1
  288. package/icons/material-symbols/graduation-cap.svg +1 -1
  289. package/icons/material-symbols/hammer.svg +1 -1
  290. package/icons/material-symbols/hand-heart.svg +1 -1
  291. package/icons/material-symbols/handshake.svg +1 -1
  292. package/icons/material-symbols/hard-drives.svg +1 -1
  293. package/icons/material-symbols/heart.svg +1 -1
  294. package/icons/material-symbols/house.svg +1 -1
  295. package/icons/material-symbols/image-square.svg +1 -1
  296. package/icons/material-symbols/image.svg +1 -1
  297. package/icons/material-symbols/info.svg +1 -1
  298. package/icons/material-symbols/keyboard.svg +1 -1
  299. package/icons/material-symbols/leaf.svg +1 -1
  300. package/icons/material-symbols/lifebuoy.svg +1 -1
  301. package/icons/material-symbols/lightbulb.svg +1 -1
  302. package/icons/material-symbols/link-break.svg +1 -1
  303. package/icons/material-symbols/link-simple.svg +1 -1
  304. package/icons/material-symbols/list-bullets.svg +1 -1
  305. package/icons/material-symbols/list-checks.svg +1 -1
  306. package/icons/material-symbols/list-numbers.svg +1 -1
  307. package/icons/material-symbols/list.svg +1 -1
  308. package/icons/material-symbols/lock-simple-open.svg +1 -1
  309. package/icons/material-symbols/lock-simple.svg +1 -1
  310. package/icons/material-symbols/magnifying-glass.svg +1 -1
  311. package/icons/material-symbols/map-pin.svg +1 -1
  312. package/icons/material-symbols/map-trifold.svg +1 -1
  313. package/icons/material-symbols/medal.svg +1 -1
  314. package/icons/material-symbols/megaphone.svg +1 -1
  315. package/icons/material-symbols/minus.svg +1 -1
  316. package/icons/material-symbols/moon.svg +1 -1
  317. package/icons/material-symbols/newspaper.svg +1 -1
  318. package/icons/material-symbols/pack.json +29 -29
  319. package/icons/material-symbols/paint-brush-broad.svg +1 -1
  320. package/icons/material-symbols/palette.svg +1 -1
  321. package/icons/material-symbols/paper-plane-tilt.svg +1 -1
  322. package/icons/material-symbols/pencil-simple.svg +1 -1
  323. package/icons/material-symbols/phone.svg +1 -1
  324. package/icons/material-symbols/play-fill.svg +1 -1
  325. package/icons/material-symbols/plus.svg +1 -1
  326. package/icons/material-symbols/prohibit.svg +1 -1
  327. package/icons/material-symbols/puzzle-piece.svg +1 -1
  328. package/icons/material-symbols/question.svg +1 -1
  329. package/icons/material-symbols/quotes.svg +1 -1
  330. package/icons/material-symbols/rows.svg +1 -1
  331. package/icons/material-symbols/ruler.svg +1 -1
  332. package/icons/material-symbols/scan.svg +1 -1
  333. package/icons/material-symbols/shapes.svg +1 -1
  334. package/icons/material-symbols/share-network.svg +1 -1
  335. package/icons/material-symbols/shield-check.svg +1 -1
  336. package/icons/material-symbols/sidebar-simple.svg +1 -1
  337. package/icons/material-symbols/sign-out.svg +1 -1
  338. package/icons/material-symbols/signpost.svg +1 -1
  339. package/icons/material-symbols/sliders-horizontal.svg +1 -1
  340. package/icons/material-symbols/smiley.svg +1 -1
  341. package/icons/material-symbols/sparkle.svg +1 -1
  342. package/icons/material-symbols/square-half-bottom.svg +1 -1
  343. package/icons/material-symbols/square.svg +1 -1
  344. package/icons/material-symbols/squares-four.svg +1 -1
  345. package/icons/material-symbols/sticker.svg +1 -1
  346. package/icons/material-symbols/storefront.svg +1 -1
  347. package/icons/material-symbols/sun.svg +1 -1
  348. package/icons/material-symbols/swatches.svg +1 -1
  349. package/icons/material-symbols/tag.svg +1 -1
  350. package/icons/material-symbols/text-aa.svg +1 -1
  351. package/icons/material-symbols/text-align-left.svg +1 -1
  352. package/icons/material-symbols/text-b.svg +1 -1
  353. package/icons/material-symbols/text-h-one.svg +1 -1
  354. package/icons/material-symbols/text-h-three.svg +1 -1
  355. package/icons/material-symbols/text-h-two.svg +1 -1
  356. package/icons/material-symbols/text-italic.svg +1 -1
  357. package/icons/material-symbols/text-t.svg +1 -1
  358. package/icons/material-symbols/ticket.svg +1 -1
  359. package/icons/material-symbols/toggle-right.svg +1 -1
  360. package/icons/material-symbols/train.svg +1 -1
  361. package/icons/material-symbols/trash.svg +1 -1
  362. package/icons/material-symbols/upload-simple.svg +1 -1
  363. package/icons/material-symbols/user-circle.svg +1 -1
  364. package/icons/material-symbols/user.svg +1 -1
  365. package/icons/material-symbols/users-three.svg +1 -1
  366. package/icons/material-symbols/users.svg +1 -1
  367. package/icons/material-symbols/video-camera.svg +1 -1
  368. package/icons/material-symbols/warning-circle.svg +1 -1
  369. package/icons/material-symbols/warning.svg +1 -1
  370. package/icons/material-symbols/wave-sine.svg +1 -1
  371. package/icons/material-symbols/wheelchair.svg +1 -1
  372. package/icons/material-symbols/wrench.svg +1 -1
  373. package/icons/material-symbols/x.svg +1 -1
  374. package/icons/phosphor/pack.json +8 -8
  375. package/lib/apps.mjs +142 -139
  376. package/lib/apps.test.d.mts +1 -0
  377. package/lib/apps.test.mjs +50 -0
  378. package/lib/blocks.mjs +90 -90
  379. package/lib/caseCollisions.d.mts +4 -0
  380. package/lib/caseCollisions.mjs +62 -0
  381. package/lib/caseCollisions.test.d.mts +1 -0
  382. package/lib/caseCollisions.test.mjs +74 -0
  383. package/lib/colors.ts +86 -86
  384. package/lib/contactBar.ts +18 -18
  385. package/lib/contracts.d.mts +15 -0
  386. package/lib/contracts.mjs +17 -0
  387. package/lib/cookieCategories.mjs +28 -28
  388. package/lib/crop.mjs +83 -83
  389. package/lib/csp.mjs +130 -130
  390. package/lib/cspSources.mjs +60 -60
  391. package/lib/dynamic-colors.ts +426 -426
  392. package/lib/git.mjs +64 -64
  393. package/lib/hooks.ts +51 -51
  394. package/lib/inline.ts +20 -20
  395. package/lib/license-texts/Apache-2.0.txt +190 -190
  396. package/lib/license-texts/BSD-2-Clause.txt +24 -24
  397. package/lib/license-texts/BSD-3-Clause.txt +28 -28
  398. package/lib/license-texts/ISC.txt +15 -15
  399. package/lib/license-texts/MIT.txt +21 -21
  400. package/lib/licenses.d.mts +1 -1
  401. package/lib/licenses.mjs +683 -683
  402. package/lib/markdown.ts +42 -42
  403. package/lib/motion-schemes.mjs +5 -5
  404. package/lib/motion.ts +131 -131
  405. package/lib/notice.mjs +34 -34
  406. package/lib/scheduled.mjs +37 -37
  407. package/lib/snackbar.ts +149 -149
  408. package/lib/status.mjs +18 -18
  409. package/lib/storeEntries.d.mts +18 -0
  410. package/lib/storeEntries.mjs +64 -0
  411. package/lib/storeEntries.test.d.mts +1 -0
  412. package/lib/storeEntries.test.mjs +71 -0
  413. package/lib/svg.mjs +231 -231
  414. package/lib/text-colors.mjs +43 -43
  415. package/lib/video-id.mjs +72 -72
  416. package/lib/video.mjs +91 -91
  417. package/package.json +136 -131
  418. package/pages/404.astro +10 -10
  419. package/pages/[...slug].astro +51 -51
  420. package/pages/_headers.txt +31 -31
  421. package/pages/blog/index.astro +10 -10
  422. package/pages/blog/kategori/[category].astro +18 -18
  423. package/pages/editor/code-images.json.js +25 -25
  424. package/pages/editor/index.astro +75 -75
  425. package/pages/editor/manifest.webmanifest.js +23 -23
  426. package/pages/editor/sw.js +33 -33
  427. package/pages/editor/sw.js.js +4 -4
  428. package/pages/editor/thumbnails.json.js +21 -21
  429. package/pages/editor/version.json.js +22 -22
  430. package/pages/headers.js +4 -4
  431. package/pages/index.astro +10 -10
  432. package/pages/ny.astro +6 -6
  433. package/pages/robots.txt.js +3 -3
  434. package/pages/rss.xml.js +20 -20
  435. package/scripts/app-screenshots.mjs +164 -164
  436. package/scripts/app-workers.mjs +6 -6
  437. package/scripts/bin.mjs +12 -12
  438. package/scripts/built-site.mjs +134 -99
  439. package/scripts/check-consent.mjs +113 -113
  440. package/scripts/check-content.mjs +151 -149
  441. package/scripts/check-demo.mjs +24 -24
  442. package/scripts/check-store.mjs +160 -0
  443. package/scripts/check-themes.mjs +45 -45
  444. package/scripts/check-worker.mjs +569 -569
  445. package/scripts/compare-html.mjs +81 -81
  446. package/scripts/declarations.mjs +10 -0
  447. package/scripts/declarations.test.mjs +32 -0
  448. package/scripts/demo-site.mjs +42 -42
  449. package/scripts/editor-icons.mjs +56 -56
  450. package/scripts/editor-roundtrip.mjs +134 -134
  451. package/scripts/editor-screens.mjs +101 -101
  452. package/scripts/git-env.mjs +9 -9
  453. package/scripts/icon-packs.mjs +151 -151
  454. package/scripts/link-counts.mjs +22 -22
  455. package/scripts/page-colors.mjs +42 -42
  456. package/scripts/releases.mjs +80 -80
  457. package/scripts/responsive-images.mjs +94 -94
  458. package/scripts/scheduled-list.mjs +15 -15
  459. package/scripts/theme-screenshots.mjs +88 -88
  460. package/scripts/types.mjs +17 -21
  461. package/scripts/video-thumbnails.mjs +89 -89
  462. package/scripts/worker-modules.mjs +34 -34
  463. package/site/appCookies.mjs +74 -74
  464. package/site/apps.ts +21 -21
  465. package/site/autolinks.mjs +200 -200
  466. package/site/blockScripts.ts +31 -31
  467. package/site/categories.ts +16 -16
  468. package/site/consent.ts +26 -26
  469. package/site/content.config.ts +84 -84
  470. package/site/content.ts +104 -104
  471. package/site/cookieList.ts +17 -17
  472. package/site/defineSite.d.mts +2 -14
  473. package/site/defineSite.mjs +131 -136
  474. package/site/directives/interact.mjs +31 -31
  475. package/site/editor-version.mjs +26 -26
  476. package/site/fill.ts +13 -13
  477. package/site/format.ts +11 -11
  478. package/site/home.ts +66 -66
  479. package/site/iconPacks.mjs +43 -43
  480. package/site/icons.mjs +605 -605
  481. package/site/images.mjs +157 -157
  482. package/site/motion.ts +13 -13
  483. package/site/noindex.mjs +21 -21
  484. package/site/pageColors.ts +110 -110
  485. package/site/popups.ts +98 -98
  486. package/site/schema.ts +189 -189
  487. package/site/sections.ts +3 -3
  488. package/site/seo.ts +28 -28
  489. package/site/site.ts +76 -76
  490. package/site/siteConfig.mjs +8 -8
  491. package/site/siteCsp.mjs +75 -75
  492. package/site/siteModules.mjs +27 -27
  493. package/site/standardPages.ts +59 -59
  494. package/site/storeTheme.d.mts +6 -0
  495. package/site/storeTheme.mjs +29 -0
  496. package/site/storeTheme.test.d.mts +1 -0
  497. package/site/storeTheme.test.mjs +53 -0
  498. package/site/testimonials.ts +48 -48
  499. package/site/text.ts +43 -43
  500. package/site/theme.mjs +483 -472
  501. package/site/tracking.client.ts +225 -225
  502. package/site/tracking.ts +9 -9
  503. package/src/ActionParts.tsx +205 -205
  504. package/src/Advanced.tsx +152 -152
  505. package/src/App.tsx +901 -904
  506. package/src/AppList.tsx +1362 -1345
  507. package/src/BlockDialog.tsx +360 -360
  508. package/src/BlockParts.tsx +652 -652
  509. package/src/BlockSettings.tsx +533 -533
  510. package/src/BrandForm.tsx +164 -164
  511. package/src/Colors.tsx +476 -476
  512. package/src/CommunicationParts.tsx +199 -199
  513. package/src/CompanyForm.tsx +209 -209
  514. package/src/Consents.tsx +175 -175
  515. package/src/ContainmentParts.tsx +185 -185
  516. package/src/Crop.tsx +152 -152
  517. package/src/DataForm.tsx +434 -434
  518. package/src/Deleted.tsx +177 -177
  519. package/src/EntryForm.tsx +740 -740
  520. package/src/FileView.tsx +30 -30
  521. package/src/FormFrame.tsx +237 -237
  522. package/src/Keywords.tsx +225 -225
  523. package/src/Library.tsx +1563 -1563
  524. package/src/Licenses.tsx +336 -336
  525. package/src/LinkSheet.tsx +138 -138
  526. package/src/MarkdownEditor.tsx +1075 -1075
  527. package/src/Media.tsx +677 -677
  528. package/src/NavigationParts.tsx +350 -350
  529. package/src/NavigationRestParts.tsx +247 -247
  530. package/src/Notifications.tsx +59 -59
  531. package/src/PagePicker.tsx +136 -136
  532. package/src/Parts.tsx +991 -991
  533. package/src/PartsShown.tsx +168 -168
  534. package/src/PickerParts.tsx +183 -183
  535. package/src/Redirects.tsx +450 -450
  536. package/src/Screen.tsx +184 -184
  537. package/src/SectionsField.tsx +65 -65
  538. package/src/SelectionParts.tsx +134 -134
  539. package/src/SeoScores.tsx +184 -184
  540. package/src/Sheet.tsx +35 -35
  541. package/src/ThemeStore.tsx +376 -376
  542. package/src/Tokens.tsx +346 -346
  543. package/src/Versions.tsx +214 -214
  544. package/src/addresses.ts +75 -75
  545. package/src/allIcons.ts +7 -7
  546. package/src/appFiles.ts +29 -29
  547. package/src/apps.ts +281 -281
  548. package/src/ask.tsx +123 -123
  549. package/src/blocks.ts +251 -251
  550. package/src/brand.ts +153 -153
  551. package/src/cache.ts +42 -42
  552. package/src/check.ts +285 -285
  553. package/src/checkSite.ts +256 -256
  554. package/src/{consents.ts → consentData.ts} +26 -26
  555. package/src/cookieList.ts +70 -70
  556. package/src/countries.ts +59 -59
  557. package/src/deploy.ts +155 -155
  558. package/src/editor.css +602 -602
  559. package/src/examples.ts +85 -85
  560. package/src/fields.tsx +942 -942
  561. package/src/frontmatter.mjs +42 -42
  562. package/src/github.ts +376 -376
  563. package/src/i18n/da-DK/advanced.ts +28 -28
  564. package/src/i18n/da-DK/app.ts +71 -71
  565. package/src/i18n/da-DK/apps.ts +90 -90
  566. package/src/i18n/da-DK/blockSettings.ts +38 -38
  567. package/src/i18n/da-DK/blocks.ts +408 -408
  568. package/src/i18n/da-DK/check.ts +25 -25
  569. package/src/i18n/da-DK/colors.ts +64 -64
  570. package/src/i18n/da-DK/common.ts +118 -118
  571. package/src/i18n/da-DK/company.ts +24 -24
  572. package/src/i18n/da-DK/consents.ts +23 -23
  573. package/src/i18n/da-DK/forms.ts +116 -116
  574. package/src/i18n/da-DK/history.ts +35 -35
  575. package/src/i18n/da-DK/index.ts +49 -49
  576. package/src/i18n/da-DK/keywords.ts +19 -19
  577. package/src/i18n/da-DK/library.ts +135 -135
  578. package/src/i18n/da-DK/licenses.ts +25 -25
  579. package/src/i18n/da-DK/media.ts +79 -79
  580. package/src/i18n/da-DK/parts.ts +696 -696
  581. package/src/i18n/da-DK/preview.ts +13 -13
  582. package/src/i18n/da-DK/redirects.ts +51 -51
  583. package/src/i18n/da-DK/seo.ts +20 -20
  584. package/src/i18n/da-DK/text.ts +35 -35
  585. package/src/i18n/da-DK/theme.ts +41 -41
  586. package/src/i18n/en-US/advanced.ts +32 -32
  587. package/src/i18n/en-US/app.ts +84 -84
  588. package/src/i18n/en-US/apps.ts +134 -134
  589. package/src/i18n/en-US/blockSettings.ts +48 -48
  590. package/src/i18n/en-US/blocks.ts +441 -441
  591. package/src/i18n/en-US/check.ts +31 -31
  592. package/src/i18n/en-US/colors.ts +82 -82
  593. package/src/i18n/en-US/common.ts +144 -144
  594. package/src/i18n/en-US/company.ts +25 -25
  595. package/src/i18n/en-US/consents.ts +25 -25
  596. package/src/i18n/en-US/forms.ts +145 -145
  597. package/src/i18n/en-US/history.ts +43 -43
  598. package/src/i18n/en-US/index.ts +51 -51
  599. package/src/i18n/en-US/keywords.ts +24 -24
  600. package/src/i18n/en-US/library.ts +176 -176
  601. package/src/i18n/en-US/licenses.ts +36 -36
  602. package/src/i18n/en-US/media.ts +80 -80
  603. package/src/i18n/en-US/parts.ts +718 -718
  604. package/src/i18n/en-US/preview.ts +15 -15
  605. package/src/i18n/en-US/redirects.ts +66 -66
  606. package/src/i18n/en-US/seo.ts +26 -26
  607. package/src/i18n/en-US/text.ts +41 -41
  608. package/src/i18n/en-US/theme.ts +41 -41
  609. package/src/i18n/index.ts +124 -124
  610. package/src/icon.tsx +160 -160
  611. package/src/iconPacks.ts +89 -89
  612. package/src/images.ts +163 -163
  613. package/src/{licenses.ts → licenseData.ts} +79 -79
  614. package/src/markdown.mjs +204 -204
  615. package/src/nav.ts +68 -68
  616. package/src/notFound.ts +28 -28
  617. package/src/{notifications.ts → notificationData.ts} +223 -223
  618. package/src/pagePreview.tsx +204 -204
  619. package/src/r2Caching.ts +55 -55
  620. package/src/{redirects.ts → redirectData.ts} +149 -149
  621. package/src/registry.tsx +188 -188
  622. package/src/schema.ts +417 -417
  623. package/src/sections.mjs +303 -303
  624. package/src/seo.ts +333 -333
  625. package/src/shared.ts +44 -44
  626. package/src/sidebar.ts +31 -31
  627. package/src/site.ts +317 -317
  628. package/src/standard/Block.astro +19 -19
  629. package/src/standard/BlockSite.astro +18 -18
  630. package/src/standard/accordion/index.tsx +47 -47
  631. package/src/standard/accordion/load.ts +23 -23
  632. package/src/standard/accordion/shared.ts +15 -15
  633. package/src/standard/accordion/view.ts +32 -32
  634. package/src/standard/buttons/fields.ts +98 -98
  635. package/src/standard/buttons/index.tsx +23 -23
  636. package/src/standard/buttons/load.ts +34 -34
  637. package/src/standard/buttons/shared.ts +12 -12
  638. package/src/standard/buttons/view.ts +30 -30
  639. package/src/standard/cards/index.tsx +71 -71
  640. package/src/standard/cards/load.ts +17 -17
  641. package/src/standard/cards/shared.ts +27 -27
  642. package/src/standard/cards/view.ts +29 -29
  643. package/src/standard/checklist/index.tsx +27 -27
  644. package/src/standard/checklist/load.ts +5 -5
  645. package/src/standard/checklist/view.ts +13 -13
  646. package/src/standard/cookies/index.tsx +17 -17
  647. package/src/standard/cookies/list.ts +56 -56
  648. package/src/standard/cookies/load.ts +11 -11
  649. package/src/standard/cookies/shared.ts +20 -20
  650. package/src/standard/cookies/view.ts +28 -28
  651. package/src/standard/faq/index.tsx +29 -29
  652. package/src/standard/faq/load.ts +14 -14
  653. package/src/standard/faq/view.ts +21 -21
  654. package/src/standard/head.ts +23 -23
  655. package/src/standard/hero/fields.ts +48 -48
  656. package/src/standard/hero/index.tsx +57 -57
  657. package/src/standard/hero/load.ts +23 -23
  658. package/src/standard/hero/view.ts +38 -38
  659. package/src/standard/links/index.tsx +41 -41
  660. package/src/standard/links/load.ts +17 -17
  661. package/src/standard/links/view.ts +25 -25
  662. package/src/standard/list/index.tsx +50 -50
  663. package/src/standard/list/load.ts +5 -5
  664. package/src/standard/list/view.ts +18 -18
  665. package/src/standard/load.ts +7 -7
  666. package/src/standard/notice/index.tsx +30 -30
  667. package/src/standard/notice/load.ts +16 -16
  668. package/src/standard/notice/view.ts +10 -10
  669. package/src/standard/points/index.tsx +42 -42
  670. package/src/standard/points/load.ts +5 -5
  671. package/src/standard/points/view.ts +12 -12
  672. package/src/standard/posts/index.tsx +132 -132
  673. package/src/standard/posts/load.ts +36 -36
  674. package/src/standard/posts/shared.ts +21 -21
  675. package/src/standard/posts/view.ts +63 -63
  676. package/src/standard/pricecards/index.tsx +57 -57
  677. package/src/standard/pricecards/load.ts +11 -11
  678. package/src/standard/pricecards/view.ts +50 -50
  679. package/src/standard/sharedTexts.ts +6 -6
  680. package/src/standard/site.ts +124 -124
  681. package/src/standard/siteLooks.ts +19 -19
  682. package/src/standard/sites.ts +13 -13
  683. package/src/standard/steps/index.tsx +28 -28
  684. package/src/standard/steps/load.ts +5 -5
  685. package/src/standard/steps/view.ts +11 -11
  686. package/src/standard/testimonials/index.tsx +87 -87
  687. package/src/standard/testimonials/list.ts +43 -43
  688. package/src/standard/testimonials/load.ts +58 -58
  689. package/src/standard/testimonials/shared.ts +13 -13
  690. package/src/standard/testimonials/view.ts +76 -76
  691. package/src/standard/themeBlocks.ts +13 -13
  692. package/src/standard/video/index.tsx +23 -23
  693. package/src/standard/video/load.ts +10 -10
  694. package/src/standard/video/view.ts +42 -42
  695. package/src/standard/view.tsx +105 -105
  696. package/src/standard/views.ts +37 -37
  697. package/src/store.ts +479 -499
  698. package/src/theme.ts +90 -90
  699. package/src/themeUi.ts +97 -97
  700. package/src/themes.ts +91 -91
  701. package/src/ui.tsx +3402 -3402
  702. package/src/virtual.d.ts +5 -5
  703. package/src/when.ts +22 -22
  704. package/starter/.githooks/pre-push +4 -4
  705. package/starter/.nvmrc +1 -1
  706. package/starter/.prettierignore +11 -11
  707. package/starter/.prettierrc.json +7 -7
  708. package/starter/README.md +27 -26
  709. package/starter/astro.config.mjs +5 -5
  710. package/starter/package.json +67 -67
  711. package/starter/public/_redirects +1 -1
  712. package/starter/public/favicon.svg +1 -1
  713. package/starter/public/logo.svg +1 -1
  714. package/starter/src/content/pages/blog.md +8 -8
  715. package/starter/src/content/pages/forside.md +9 -9
  716. package/starter/src/content/pages/kontakt.md +7 -7
  717. package/starter/src/content/pages/privatlivspolitik.md +9 -9
  718. package/starter/src/content/pages/siden-findes-ikke.md +7 -7
  719. package/starter/src/content.config.ts +2 -2
  720. package/starter/src/data/apps.json +1 -1
  721. package/starter/src/data/block-settings.json +3 -3
  722. package/starter/src/data/blocks.json +1 -1
  723. package/starter/src/data/booking.json +6 -6
  724. package/starter/src/data/colors.json +70 -70
  725. package/starter/src/data/contact.json +8 -8
  726. package/starter/src/data/cookies.json +21 -21
  727. package/starter/src/data/csp.json +1 -1
  728. package/starter/src/data/footer.json +15 -15
  729. package/starter/src/data/internal-links.json +4 -4
  730. package/starter/src/data/menu.json +4 -4
  731. package/starter/src/data/mobile-menu.json +4 -4
  732. package/starter/src/data/old-addresses.json +1 -1
  733. package/starter/src/data/redirects.json +1 -1
  734. package/starter/src/data/standard-pages.json +8 -8
  735. package/starter/src/data/theme.json +1 -1
  736. package/starter/src/env.d.ts +2 -2
  737. package/starter/src/site/config.ts +13 -13
  738. package/starter/src/site/worker.js +14 -14
  739. package/starter/tsconfig.json +17 -17
  740. package/starter/worker/apps.js +6 -6
  741. package/starter/wrangler.jsonc +39 -39
  742. package/theme/LICENSE +21 -21
  743. package/theme/blocks/ArrowLink.tsx +14 -14
  744. package/theme/blocks/BlockHead.tsx +26 -26
  745. package/theme/blocks/Panel.tsx +32 -32
  746. package/theme/blocks/Person.tsx +26 -26
  747. package/theme/blocks/accordion/PageRow.tsx +25 -25
  748. package/theme/blocks/accordion/View.tsx +17 -17
  749. package/theme/blocks/buttons/Buttons.tsx +28 -28
  750. package/theme/blocks/buttons/View.tsx +12 -12
  751. package/theme/blocks/cards/LinkCards.tsx +72 -72
  752. package/theme/blocks/cards/View.tsx +20 -20
  753. package/theme/blocks/checklist/Checks.tsx +15 -15
  754. package/theme/blocks/checklist/View.tsx +14 -14
  755. package/theme/blocks/cookies/View.tsx +36 -36
  756. package/theme/blocks/faq/Accordion.tsx +34 -34
  757. package/theme/blocks/faq/View.tsx +16 -16
  758. package/theme/blocks/faq/script.ts +56 -56
  759. package/theme/blocks/hero/View.tsx +44 -44
  760. package/theme/blocks/links/LinkGroups.tsx +24 -24
  761. package/theme/blocks/links/View.tsx +17 -17
  762. package/theme/blocks/list/Rows.tsx +24 -24
  763. package/theme/blocks/list/View.tsx +14 -14
  764. package/theme/blocks/notice/View.tsx +13 -13
  765. package/theme/blocks/points/PointList.tsx +34 -34
  766. package/theme/blocks/points/View.tsx +14 -14
  767. package/theme/blocks/posts/View.tsx +26 -26
  768. package/theme/blocks/pricecards/View.tsx +40 -40
  769. package/theme/blocks/steps/StepList.tsx +23 -23
  770. package/theme/blocks/steps/View.tsx +14 -14
  771. package/theme/blocks/testimonials/List.tsx +46 -46
  772. package/theme/blocks/testimonials/Slider.tsx +44 -44
  773. package/theme/blocks/testimonials/Testimonial.tsx +124 -124
  774. package/theme/blocks/testimonials/View.tsx +21 -21
  775. package/theme/blocks/testimonials/script.ts +52 -52
  776. package/theme/blocks/video/View.tsx +41 -41
  777. package/theme/components/ActionBar.astro +63 -63
  778. package/theme/components/AppSlot.astro +21 -21
  779. package/theme/components/ArrowLink.tsx +21 -21
  780. package/theme/components/BlogIndex.astro +48 -48
  781. package/theme/components/BlogPosts.astro +18 -18
  782. package/theme/components/BlogPosts.tsx +45 -45
  783. package/theme/components/BookButton.tsx +22 -22
  784. package/theme/components/Container.astro +11 -11
  785. package/theme/components/CookieConsent.astro +121 -121
  786. package/theme/components/EndBlock.astro +21 -21
  787. package/theme/components/FontPreload.astro +6 -6
  788. package/theme/components/Footer.astro +85 -85
  789. package/theme/components/Header.astro +186 -186
  790. package/theme/components/Icon.astro +16 -16
  791. package/theme/components/Img.astro +29 -29
  792. package/theme/components/Img.tsx +33 -33
  793. package/theme/components/Inline.astro +11 -11
  794. package/theme/components/Logo.astro +23 -23
  795. package/theme/components/LogoMark.astro +10 -10
  796. package/theme/components/Markdown.astro +17 -17
  797. package/theme/components/MobileMenu.tsx +224 -224
  798. package/theme/components/MobileNav.astro +33 -33
  799. package/theme/components/PageHeader.astro +22 -22
  800. package/theme/components/PageSection.astro +24 -24
  801. package/theme/components/PhoneButton.tsx +11 -11
  802. package/theme/components/Popup.astro +145 -145
  803. package/theme/components/PopupButton.tsx +24 -24
  804. package/theme/components/PopupView.tsx +48 -48
  805. package/theme/components/PostList.tsx +58 -58
  806. package/theme/components/PostMeta.tsx +17 -17
  807. package/theme/components/RichText.astro +28 -28
  808. package/theme/components/Section.astro +29 -29
  809. package/theme/components/SectionHeading.tsx +8 -8
  810. package/theme/components/TextSection.astro +16 -16
  811. package/theme/components/home/PageBlock.astro +19 -19
  812. package/theme/components/home/Text.astro +13 -13
  813. package/theme/components/loadPopup.ts +22 -22
  814. package/theme/components/loadPosts.ts +16 -16
  815. package/theme/components/posts.ts +15 -15
  816. package/theme/editor/looks.mjs +7 -7
  817. package/theme/editor/previews.tsx +56 -56
  818. package/theme/layouts/Base.astro +273 -273
  819. package/theme/layouts/PageLayout.astro +126 -126
  820. package/theme/layouts/PostLayout.astro +137 -137
  821. package/theme/scripts/motion.ts +29 -29
  822. package/theme/styles/base.css +320 -320
  823. package/theme/styles/blocks.css +1808 -1808
  824. package/theme/styles/components.css +206 -206
  825. package/theme/styles/global.css +1302 -1302
  826. package/theme/styles/ui.css +6544 -6544
  827. package/theme/templates/Blog.astro +38 -38
  828. package/theme/templates/Category.astro +19 -19
  829. package/theme/templates/Home.astro +36 -36
  830. package/theme/templates/New.astro +68 -68
  831. package/theme/templates/NotFound.astro +117 -117
  832. package/theme/theme.json +28 -28
  833. package/theme/ui/Badge.tsx +45 -45
  834. package/theme/ui/BottomSheet.tsx +148 -148
  835. package/theme/ui/Button.tsx +79 -79
  836. package/theme/ui/ButtonGroup.tsx +31 -31
  837. package/theme/ui/Card.tsx +45 -45
  838. package/theme/ui/Carousel.tsx +124 -124
  839. package/theme/ui/Checkbox.tsx +59 -59
  840. package/theme/ui/Chip.tsx +101 -101
  841. package/theme/ui/ChipSet.tsx +27 -27
  842. package/theme/ui/DatePicker.tsx +149 -149
  843. package/theme/ui/DatePickerContainer.tsx +316 -316
  844. package/theme/ui/Dialog.tsx +100 -100
  845. package/theme/ui/Divider.tsx +27 -27
  846. package/theme/ui/ExposedDropdownMenu.tsx +77 -77
  847. package/theme/ui/Fab.tsx +88 -88
  848. package/theme/ui/FabMenu.tsx +67 -67
  849. package/theme/ui/IconButton.tsx +78 -78
  850. package/theme/ui/List.tsx +287 -287
  851. package/theme/ui/LoadingIndicator.tsx +29 -29
  852. package/theme/ui/Menu.tsx +278 -278
  853. package/theme/ui/NavigationBar.tsx +62 -62
  854. package/theme/ui/NavigationDrawer.tsx +80 -80
  855. package/theme/ui/NavigationRail.tsx +154 -154
  856. package/theme/ui/ProgressIndicator.tsx +162 -162
  857. package/theme/ui/RadioButton.tsx +50 -50
  858. package/theme/ui/Search.tsx +129 -129
  859. package/theme/ui/SegmentedButton.tsx +49 -49
  860. package/theme/ui/SideSheet.tsx +54 -54
  861. package/theme/ui/Slider.tsx +155 -155
  862. package/theme/ui/Snackbar.tsx +67 -67
  863. package/theme/ui/SplitButton.tsx +67 -67
  864. package/theme/ui/Switch.tsx +60 -60
  865. package/theme/ui/Tabs.tsx +114 -114
  866. package/theme/ui/TextField.tsx +278 -278
  867. package/theme/ui/TimePicker.tsx +128 -128
  868. package/theme/ui/TimePickerContainer.tsx +234 -234
  869. package/theme/ui/Toolbar.tsx +67 -67
  870. package/theme/ui/Tooltip.tsx +58 -58
  871. package/theme/ui/TopAppBar.tsx +77 -77
  872. package/theme/ui/bottomSheet.script.ts +8 -8
  873. package/theme/ui/{bottomSheet.ts → bottomSheetControl.ts} +211 -211
  874. package/theme/ui/carousel.script.ts +28 -28
  875. package/theme/ui/carouselLayout.ts +229 -229
  876. package/theme/ui/checkbox.script.ts +8 -8
  877. package/theme/ui/datePicker.script.ts +302 -302
  878. package/theme/ui/dates.ts +185 -185
  879. package/theme/ui/{dialog.ts → dialogControl.ts} +48 -48
  880. package/theme/ui/dropdownMenu.script.ts +166 -166
  881. package/theme/ui/fabMenu.script.ts +57 -57
  882. package/theme/ui/navigationRail.script.ts +47 -47
  883. package/theme/ui/ripple.script.ts +159 -159
  884. package/theme/ui/search.script.ts +92 -92
  885. package/theme/ui/{sideSheet.ts → sideSheetControl.ts} +48 -48
  886. package/theme/ui/slider.script.ts +12 -12
  887. package/theme/ui/sliderUpdate.ts +52 -52
  888. package/theme/ui/snackbar.script.ts +16 -16
  889. package/theme/ui/splitButton.script.ts +63 -63
  890. package/theme/ui/tabs.script.ts +48 -48
  891. package/theme/ui/textField.script.ts +17 -17
  892. package/theme/ui/textFieldUpdate.ts +44 -44
  893. package/theme/ui/timePicker.script.ts +248 -248
  894. package/theme/ui/toolbar.script.ts +43 -43
  895. package/theme/ui/tooltip.script.ts +68 -68
  896. package/worker/consent.js +141 -141
  897. package/worker/editor-github.js +167 -167
  898. package/worker/editor-host.js +74 -74
  899. package/worker/files.js +401 -401
  900. package/worker/github.js +36 -36
  901. package/worker/index.js +188 -184
  902. package/worker/not-found.js +97 -97
  903. package/worker/oauth.js +95 -95
  904. package/worker/publish.js +52 -52
  905. package/worker/push.js +270 -270
  906. package/worker/r2-status.js +50 -50
  907. package/worker/session.js +58 -58
  908. package/worker/store.js +46 -0
@@ -1,200 +1,200 @@
1
- // Automatic internal links. The words come from the pages and posts themselves: their keywords
2
- // (`keyword`, the primary one, and `keywords`, more separated by commas; under
3
- // "Søgemaskiner" in the editor; the front page's link to / and the blog page's to /blog/, where they are shown, and the
4
- // 404 page's to nowhere). src/data/internal-links.json, under "Søgemaskineoptimering" ›
5
- // "Interne links" in the editor (packages/editor/defaults/internalLinks.ts): `enabled` turns the links on or off, `maxPerPage` is the
6
- // most per page. A word links to the page it is a
7
- // keyword of. Unlike linking every occurrence of a word, a target is
8
- // linked once per page, at most `maxPerPage` links per page, never to the page itself, never inside
9
- // headings or existing links, and never as part of a word joined with a hyphen (not "web" in "web-design"). Used by the Markdown pipeline (packages/editor/astro.mjs) and by an import
10
- // script, which removes the old plugin links so they are not doubled. Each link has data-link="auto", so how many there
11
- // are of each word can be counted after the build (packages/editor/scripts/link-counts.mjs, /editor/links.json).
12
- import { createHash } from 'node:crypto';
13
- import fs from 'node:fs';
14
- import path from 'node:path';
15
- import { parse } from 'yaml';
16
- import { isPreview, livePath } from './noindex.mjs';
17
- import { stateOf } from '@morphemecms/cms/lib/status.mjs';
18
-
19
- const FILE = path.resolve('src/data/internal-links.json');
20
- // The front page, the blog page and the 404 page ("Indstillinger" › "Udseende" › "Standardsider",
21
- // packages/editor/defaults/standardPages.ts): the front page's address sends on to /, the blog page's to /blog/, and the 404 page has none.
22
- const STANDARD = path.resolve('src/data/standard-pages.json');
23
- const PAGES = path.resolve('src/content/pages');
24
- const POSTS = path.resolve('src/content/blog');
25
- // What a word may not touch to be linked: a letter, a digit, or a hyphen joining it to another word.
26
- const LETTER = '\\p{L}\\p{N}-';
27
- const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
28
- const split = (text) =>
29
- String(text ?? '')
30
- .split(',')
31
- .map((w) => w.trim())
32
- .filter(Boolean);
33
-
34
- let standard;
35
- /** A page's address as it is linked to: the front page's is /, the blog page's /blog/, and the 404 page's none (null). */
36
- function linked(href) {
37
- standard ??= (() => {
38
- try {
39
- return JSON.parse(fs.readFileSync(STANDARD, 'utf8'));
40
- } catch {
41
- return {};
42
- }
43
- })();
44
- if (href === standard.front) return '/';
45
- if (href === standard.blog) return '/blog/';
46
- return href === standard.notFound ? null : href;
47
- }
48
-
49
- /** The .md files in a folder and its subfolders, as paths relative to it (none when there is no folder). */
50
- const files = (dir) =>
51
- fs.existsSync(dir) ? fs.readdirSync(dir, { recursive: true, encoding: 'utf8' }).filter((f) => f.endsWith('.md')) : [];
52
- const frontmatter = (file) => parse(fs.readFileSync(file, 'utf8').match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1] ?? '') ?? {};
53
-
54
- /** The keywords of the pages and posts: [{ href, primary, secondary }]. A page's address is its
55
- * `path`, or else its file name (getPages() in packages/editor/site/content.ts); a new version of a page (/ny/…)
56
- * gives its keywords to the page it is for, when that page exists. Only published ones are linked to
57
- * (packages/editor/lib/status.mjs). */
58
- function keywordRules() {
59
- const entries = [
60
- ...files(PAGES).map((f) => {
61
- const data = frontmatter(path.join(PAGES, f));
62
- const id = f
63
- .replace(/\\/g, '/')
64
- .replace(/\.md$/, '')
65
- .replace(/(^|\/)index$/, '');
66
- return { href: data.path || `/${id}/`, data };
67
- }),
68
- ...files(POSTS).map((f) => ({ href: `/${path.basename(f, '.md')}/`, data: frontmatter(path.join(POSTS, f)) })),
69
- ].filter((e) => stateOf(e.data) === 'published');
70
- const live = new Set(
71
- entries
72
- .map((e) => e.href)
73
- .filter((href) => !isPreview(href))
74
- .map(linked),
75
- );
76
- return entries
77
- .map(({ href, data }) => ({ href: linked(livePath(href)), primary: split(data.keyword), secondary: split(data.keywords) }))
78
- .filter((r) => r.href && live.has(r.href) && (r.primary.length || r.secondary.length))
79
- .sort((a, b) => a.href.localeCompare(b.href));
80
- }
81
-
82
- let cached;
83
- /** { enabled, maxPerPage, words: Map<lowercase word, href>, pattern } */
84
- export function loadLinks() {
85
- if (cached) return cached;
86
- const data = JSON.parse(fs.readFileSync(FILE, 'utf8'));
87
- const enabled = data.enabled !== false;
88
- const maxPerPage = Number.isFinite(data.maxPerPage) ? data.maxPerPage : 8;
89
- // A word used for two pages links to the one it is the primary keyword of, then to the one it is
90
- // a secondary keyword of; between equals, to the first by address.
91
- const rules = keywordRules();
92
- const ranked = [...rules.map((r) => ({ href: r.href, words: r.primary })), ...rules.map((r) => ({ href: r.href, words: r.secondary }))];
93
- const words = new Map();
94
- for (const { href, words: list } of ranked)
95
- for (const word of list) {
96
- const key = word.toLowerCase();
97
- if (!words.has(key)) words.set(key, href);
98
- else if (words.get(key) !== href) console.warn(`interne links: "${word}" linker til ${words.get(key)}, ikke ${href}`);
99
- }
100
- // One regex for all words, longest first so "tryg tilknytning" wins over shorter matches.
101
- const all = [...words.keys()].sort((a, b) => b.length - a.length).map(escape);
102
- const pattern = new RegExp(`(?<![${LETTER}])(${all.join('|')})(?![${LETTER}])`, 'giu');
103
- cached = { enabled, maxPerPage, words, pattern };
104
- return cached;
105
- }
106
-
107
- // Not inside links, headings, code, or the offer and price boxes.
108
- const SKIP = new Set(['aside', 'a', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'code', 'pre', 'button', 'figcaption', 'dl']);
109
-
110
- /** The URL of the page being rendered: front matter `path` (pages) or /<file name>/ (posts). A new
111
- * version of a page (/ny/…) counts as the page it is for, so it links as it will once it replaces it. */
112
- function pagePath(file) {
113
- const fm = file.data?.astro?.frontmatter;
114
- if (fm?.path) return linked(livePath(fm.path));
115
- const name = path.basename(file.path ?? '', '.md');
116
- return name ? linked(`/${name}/`) : '';
117
- }
118
-
119
- /** The pages a block in the text links to (packages/editor/lib/blocks.mjs): its `href` fields (emner, priskort,
120
- * knapper, Kort), the links in its texts (spørgsmål og svar) and the posts it picks. */
121
- function blockLinks(node) {
122
- let props;
123
- try {
124
- props = JSON.parse(String(node.properties.dataProps ?? '{}'));
125
- } catch {
126
- return [];
127
- }
128
- const links = [];
129
- const visit = (value, key) => {
130
- if (typeof value === 'string') {
131
- if (key === 'href' && value.startsWith('/')) links.push(value.split('#')[0]);
132
- for (const m of value.matchAll(/\]\((\/[^)\s#]*)/g)) links.push(m[1]);
133
- } else if (Array.isArray(value)) value.forEach((v) => visit(v, key));
134
- else if (value && typeof value === 'object') Object.entries(value).forEach(([k, v]) => visit(v, k));
135
- };
136
- visit(props);
137
- if (node.properties.dataBlock === 'posts' && Array.isArray(props.picked)) links.push(...props.picked.map((id) => `/${id}/`));
138
- return links;
139
- }
140
-
141
- /** What every page's links are made from: the words and where each links to, whether they are on and how many there
142
- * are per page, and this file. Given to the plugin in packages/editor/astro.mjs, so it is in Astro's config: a page's text is
143
- * kept rendered between builds (node_modules/.astro) until it or the config changes, and a keyword changed on one page
144
- * changes the links on the others, so then every page is rendered again. */
145
- export function linksDigest() {
146
- const { enabled, maxPerPage, words } = loadLinks();
147
- const text = JSON.stringify([enabled, maxPerPage, [...words], fs.readFileSync(new URL(import.meta.url), 'utf8')]);
148
- return createHash('sha256').update(text).digest('hex').slice(0, 16);
149
- }
150
-
151
- /** Rehype plugin; `digest` (linksDigest) is not used here. */
152
- export function rehypeAutoLinks() {
153
- return (tree, file) => {
154
- const { enabled, maxPerPage, words, pattern } = loadLinks();
155
- if (!enabled || !words.size) return;
156
- const self = pagePath(file);
157
- const used = new Set([self]);
158
- // Targets the text already links to by hand, or a block on the page links to, are not linked again.
159
- const collect = (node) => {
160
- if (node.type === 'element' && node.tagName === 'a') used.add(String(node.properties?.href ?? '').split('#')[0]);
161
- if (node.type === 'element' && node.properties?.dataBlock) blockLinks(node).forEach((href) => used.add(href));
162
- node.children?.forEach(collect);
163
- };
164
- collect(tree);
165
- let count = 0;
166
-
167
- const walk = (node) => {
168
- if (!node.children || count >= maxPerPage) return;
169
- if (node.type === 'element' && SKIP.has(node.tagName)) return;
170
- const out = [];
171
- for (const child of node.children) {
172
- if (child.type !== 'text' || count >= maxPerPage) {
173
- walk(child);
174
- out.push(child);
175
- continue;
176
- }
177
- let last = 0;
178
- for (const m of child.value.matchAll(pattern)) {
179
- const href = words.get(m[1].toLowerCase());
180
- if (used.has(href) || count >= maxPerPage) continue;
181
- used.add(href);
182
- count++;
183
- if (m.index > last) out.push({ type: 'text', value: child.value.slice(last, m.index) });
184
- // data-link="auto": counted after the build (packages/editor/scripts/link-counts.mjs), for the editor's list of keywords.
185
- out.push({ type: 'element', tagName: 'a', properties: { href, dataLink: 'auto' }, children: [{ type: 'text', value: m[1] }] });
186
- last = m.index + m[1].length;
187
- }
188
- if (last < child.value.length) out.push({ type: 'text', value: child.value.slice(last) });
189
- }
190
- node.children = out;
191
- };
192
- walk(tree);
193
- };
194
- }
195
-
196
- /** For the migration: turn links whose text is one of the words back into plain text. */
197
- export function unlinkAutoWords(markdown) {
198
- const { words } = loadLinks();
199
- return markdown.replace(/(?<!!)\[([^\]\[]+)\]\((\/[^)\s]*)\)/g, (all, text) => (words.has(text.trim().toLowerCase()) ? text : all));
200
- }
1
+ // Automatic internal links. The words come from the pages and posts themselves: their keywords
2
+ // (`keyword`, the primary one, and `keywords`, more separated by commas; under
3
+ // "Søgemaskiner" in the editor; the front page's link to / and the blog page's to /blog/, where they are shown, and the
4
+ // 404 page's to nowhere). src/data/internal-links.json, under "Søgemaskineoptimering" ›
5
+ // "Interne links" in the editor (packages/editor/defaults/internalLinks.ts): `enabled` turns the links on or off, `maxPerPage` is the
6
+ // most per page. A word links to the page it is a
7
+ // keyword of. Unlike linking every occurrence of a word, a target is
8
+ // linked once per page, at most `maxPerPage` links per page, never to the page itself, never inside
9
+ // headings or existing links, and never as part of a word joined with a hyphen (not "web" in "web-design"). Used by the Markdown pipeline (packages/editor/astro.mjs) and by an import
10
+ // script, which removes the old plugin links so they are not doubled. Each link has data-link="auto", so how many there
11
+ // are of each word can be counted after the build (packages/editor/scripts/link-counts.mjs, /editor/links.json).
12
+ import { createHash } from 'node:crypto';
13
+ import fs from 'node:fs';
14
+ import path from 'node:path';
15
+ import { parse } from 'yaml';
16
+ import { isPreview, livePath } from './noindex.mjs';
17
+ import { stateOf } from '@morphemecms/cms/lib/status.mjs';
18
+
19
+ const FILE = path.resolve('src/data/internal-links.json');
20
+ // The front page, the blog page and the 404 page ("Indstillinger" › "Udseende" › "Standardsider",
21
+ // packages/editor/defaults/standardPages.ts): the front page's address sends on to /, the blog page's to /blog/, and the 404 page has none.
22
+ const STANDARD = path.resolve('src/data/standard-pages.json');
23
+ const PAGES = path.resolve('src/content/pages');
24
+ const POSTS = path.resolve('src/content/blog');
25
+ // What a word may not touch to be linked: a letter, a digit, or a hyphen joining it to another word.
26
+ const LETTER = '\\p{L}\\p{N}-';
27
+ const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
28
+ const split = (text) =>
29
+ String(text ?? '')
30
+ .split(',')
31
+ .map((w) => w.trim())
32
+ .filter(Boolean);
33
+
34
+ let standard;
35
+ /** A page's address as it is linked to: the front page's is /, the blog page's /blog/, and the 404 page's none (null). */
36
+ function linked(href) {
37
+ standard ??= (() => {
38
+ try {
39
+ return JSON.parse(fs.readFileSync(STANDARD, 'utf8'));
40
+ } catch {
41
+ return {};
42
+ }
43
+ })();
44
+ if (href === standard.front) return '/';
45
+ if (href === standard.blog) return '/blog/';
46
+ return href === standard.notFound ? null : href;
47
+ }
48
+
49
+ /** The .md files in a folder and its subfolders, as paths relative to it (none when there is no folder). */
50
+ const files = (dir) =>
51
+ fs.existsSync(dir) ? fs.readdirSync(dir, { recursive: true, encoding: 'utf8' }).filter((f) => f.endsWith('.md')) : [];
52
+ const frontmatter = (file) => parse(fs.readFileSync(file, 'utf8').match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1] ?? '') ?? {};
53
+
54
+ /** The keywords of the pages and posts: [{ href, primary, secondary }]. A page's address is its
55
+ * `path`, or else its file name (getPages() in packages/editor/site/content.ts); a new version of a page (/ny/…)
56
+ * gives its keywords to the page it is for, when that page exists. Only published ones are linked to
57
+ * (packages/editor/lib/status.mjs). */
58
+ function keywordRules() {
59
+ const entries = [
60
+ ...files(PAGES).map((f) => {
61
+ const data = frontmatter(path.join(PAGES, f));
62
+ const id = f
63
+ .replace(/\\/g, '/')
64
+ .replace(/\.md$/, '')
65
+ .replace(/(^|\/)index$/, '');
66
+ return { href: data.path || `/${id}/`, data };
67
+ }),
68
+ ...files(POSTS).map((f) => ({ href: `/${path.basename(f, '.md')}/`, data: frontmatter(path.join(POSTS, f)) })),
69
+ ].filter((e) => stateOf(e.data) === 'published');
70
+ const live = new Set(
71
+ entries
72
+ .map((e) => e.href)
73
+ .filter((href) => !isPreview(href))
74
+ .map(linked),
75
+ );
76
+ return entries
77
+ .map(({ href, data }) => ({ href: linked(livePath(href)), primary: split(data.keyword), secondary: split(data.keywords) }))
78
+ .filter((r) => r.href && live.has(r.href) && (r.primary.length || r.secondary.length))
79
+ .sort((a, b) => a.href.localeCompare(b.href));
80
+ }
81
+
82
+ let cached;
83
+ /** { enabled, maxPerPage, words: Map<lowercase word, href>, pattern } */
84
+ export function loadLinks() {
85
+ if (cached) return cached;
86
+ const data = JSON.parse(fs.readFileSync(FILE, 'utf8'));
87
+ const enabled = data.enabled !== false;
88
+ const maxPerPage = Number.isFinite(data.maxPerPage) ? data.maxPerPage : 8;
89
+ // A word used for two pages links to the one it is the primary keyword of, then to the one it is
90
+ // a secondary keyword of; between equals, to the first by address.
91
+ const rules = keywordRules();
92
+ const ranked = [...rules.map((r) => ({ href: r.href, words: r.primary })), ...rules.map((r) => ({ href: r.href, words: r.secondary }))];
93
+ const words = new Map();
94
+ for (const { href, words: list } of ranked)
95
+ for (const word of list) {
96
+ const key = word.toLowerCase();
97
+ if (!words.has(key)) words.set(key, href);
98
+ else if (words.get(key) !== href) console.warn(`interne links: "${word}" linker til ${words.get(key)}, ikke ${href}`);
99
+ }
100
+ // One regex for all words, longest first so "tryg tilknytning" wins over shorter matches.
101
+ const all = [...words.keys()].sort((a, b) => b.length - a.length).map(escape);
102
+ const pattern = new RegExp(`(?<![${LETTER}])(${all.join('|')})(?![${LETTER}])`, 'giu');
103
+ cached = { enabled, maxPerPage, words, pattern };
104
+ return cached;
105
+ }
106
+
107
+ // Not inside links, headings, code, or the offer and price boxes.
108
+ const SKIP = new Set(['aside', 'a', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'code', 'pre', 'button', 'figcaption', 'dl']);
109
+
110
+ /** The URL of the page being rendered: front matter `path` (pages) or /<file name>/ (posts). A new
111
+ * version of a page (/ny/…) counts as the page it is for, so it links as it will once it replaces it. */
112
+ function pagePath(file) {
113
+ const fm = file.data?.astro?.frontmatter;
114
+ if (fm?.path) return linked(livePath(fm.path));
115
+ const name = path.basename(file.path ?? '', '.md');
116
+ return name ? linked(`/${name}/`) : '';
117
+ }
118
+
119
+ /** The pages a block in the text links to (packages/editor/lib/blocks.mjs): its `href` fields (emner, priskort,
120
+ * knapper, Kort), the links in its texts (spørgsmål og svar) and the posts it picks. */
121
+ function blockLinks(node) {
122
+ let props;
123
+ try {
124
+ props = JSON.parse(String(node.properties.dataProps ?? '{}'));
125
+ } catch {
126
+ return [];
127
+ }
128
+ const links = [];
129
+ const visit = (value, key) => {
130
+ if (typeof value === 'string') {
131
+ if (key === 'href' && value.startsWith('/')) links.push(value.split('#')[0]);
132
+ for (const m of value.matchAll(/\]\((\/[^)\s#]*)/g)) links.push(m[1]);
133
+ } else if (Array.isArray(value)) value.forEach((v) => visit(v, key));
134
+ else if (value && typeof value === 'object') Object.entries(value).forEach(([k, v]) => visit(v, k));
135
+ };
136
+ visit(props);
137
+ if (node.properties.dataBlock === 'posts' && Array.isArray(props.picked)) links.push(...props.picked.map((id) => `/${id}/`));
138
+ return links;
139
+ }
140
+
141
+ /** What every page's links are made from: the words and where each links to, whether they are on and how many there
142
+ * are per page, and this file. Given to the plugin in packages/editor/astro.mjs, so it is in Astro's config: a page's text is
143
+ * kept rendered between builds (node_modules/.astro) until it or the config changes, and a keyword changed on one page
144
+ * changes the links on the others, so then every page is rendered again. */
145
+ export function linksDigest() {
146
+ const { enabled, maxPerPage, words } = loadLinks();
147
+ const text = JSON.stringify([enabled, maxPerPage, [...words], fs.readFileSync(new URL(import.meta.url), 'utf8')]);
148
+ return createHash('sha256').update(text).digest('hex').slice(0, 16);
149
+ }
150
+
151
+ /** Rehype plugin; `digest` (linksDigest) is not used here. */
152
+ export function rehypeAutoLinks() {
153
+ return (tree, file) => {
154
+ const { enabled, maxPerPage, words, pattern } = loadLinks();
155
+ if (!enabled || !words.size) return;
156
+ const self = pagePath(file);
157
+ const used = new Set([self]);
158
+ // Targets the text already links to by hand, or a block on the page links to, are not linked again.
159
+ const collect = (node) => {
160
+ if (node.type === 'element' && node.tagName === 'a') used.add(String(node.properties?.href ?? '').split('#')[0]);
161
+ if (node.type === 'element' && node.properties?.dataBlock) blockLinks(node).forEach((href) => used.add(href));
162
+ node.children?.forEach(collect);
163
+ };
164
+ collect(tree);
165
+ let count = 0;
166
+
167
+ const walk = (node) => {
168
+ if (!node.children || count >= maxPerPage) return;
169
+ if (node.type === 'element' && SKIP.has(node.tagName)) return;
170
+ const out = [];
171
+ for (const child of node.children) {
172
+ if (child.type !== 'text' || count >= maxPerPage) {
173
+ walk(child);
174
+ out.push(child);
175
+ continue;
176
+ }
177
+ let last = 0;
178
+ for (const m of child.value.matchAll(pattern)) {
179
+ const href = words.get(m[1].toLowerCase());
180
+ if (used.has(href) || count >= maxPerPage) continue;
181
+ used.add(href);
182
+ count++;
183
+ if (m.index > last) out.push({ type: 'text', value: child.value.slice(last, m.index) });
184
+ // data-link="auto": counted after the build (packages/editor/scripts/link-counts.mjs), for the editor's list of keywords.
185
+ out.push({ type: 'element', tagName: 'a', properties: { href, dataLink: 'auto' }, children: [{ type: 'text', value: m[1] }] });
186
+ last = m.index + m[1].length;
187
+ }
188
+ if (last < child.value.length) out.push({ type: 'text', value: child.value.slice(last) });
189
+ }
190
+ node.children = out;
191
+ };
192
+ walk(tree);
193
+ };
194
+ }
195
+
196
+ /** For the migration: turn links whose text is one of the words back into plain text. */
197
+ export function unlinkAutoWords(markdown) {
198
+ const { words } = loadLinks();
199
+ return markdown.replace(/(?<!!)\[([^\]\[]+)\]\((\/[^)\s]*)\)/g, (all, text) => (words.has(text.trim().toLowerCase()) ? text : all));
200
+ }
@@ -1,31 +1,31 @@
1
- // What the blocks do in a browser on the site: script.ts in a theme's blocks/<type>/ (the rows that fold out, the
2
- // testimonials' "Læs mere" …; the theme in use's, else the standard theme's, as their look, sites.ts), what the theme's
3
- // UI components do (ui/<name>.script.ts: a carousel's page indicator, by `ui/<name>`), in an app's
4
- // block (src/apps/<app>/blocks/<type>/), and in an app's part of a list's entries (src/apps/<app>/<list>/: Mailchimp's
5
- // signup in a pop-up). Each is a function that finds its blocks on the page and does nothing without them; the theme's
6
- // Base.astro runs them all on every page, so they also work where a site or an app shows a block's parts of its own
7
- // (this site's front page).
8
- type Script = () => void;
9
-
10
- const byType = (found: Record<string, Script>) =>
11
- Object.fromEntries(Object.entries(found).map(([file, run]) => [file.split('/').at(-2)!, run]));
12
-
13
- // The theme's UI components' by their name (ui/carousel.script.ts: ui/carousel).
14
- const byUi = (found: Record<string, Script>) =>
15
- Object.fromEntries(Object.entries(found).map(([file, run]) => [`ui/${file.split('/').at(-1)!.replace('.script.ts', '')}`, run]));
16
-
17
- /** What each block does in a browser, by its type. */
18
- export const blockScripts: Record<string, Script> = {
19
- ...byType(import.meta.glob<Script>('@saturn/blocks/*/script.ts', { eager: true, import: 'default' })),
20
- ...byType(import.meta.glob<Script>('@theme/blocks/*/script.ts', { eager: true, import: 'default' })),
21
- ...byUi(import.meta.glob<Script>('@saturn/ui/*.script.ts', { eager: true, import: 'default' })),
22
- ...byUi(import.meta.glob<Script>('@theme/ui/*.script.ts', { eager: true, import: 'default' })),
23
- ...byType(import.meta.glob<Script>('/src/apps/*/blocks/*/script.ts', { eager: true, import: 'default' })),
24
- // An app's part of its kind of a list's entries (Mailchimp's signup in a pop-up), by the app and the list.
25
- ...Object.fromEntries(
26
- Object.entries(import.meta.glob<Script>('/src/apps/*/*/script.ts', { eager: true, import: 'default' })).map(([file, run]) => [
27
- file.split('/').slice(-3, -1).join('/'),
28
- run,
29
- ]),
30
- ),
31
- };
1
+ // What the blocks do in a browser on the site: script.ts in a theme's blocks/<type>/ (the rows that fold out, the
2
+ // testimonials' "Læs mere" …; the theme in use's, else the standard theme's, as their look, sites.ts), what the theme's
3
+ // UI components do (ui/<name>.script.ts: a carousel's page indicator, by `ui/<name>`), in an app's
4
+ // block (src/apps/<app>/blocks/<type>/), and in an app's part of a list's entries (src/apps/<app>/<list>/: Mailchimp's
5
+ // signup in a pop-up). Each is a function that finds its blocks on the page and does nothing without them; the theme's
6
+ // Base.astro runs them all on every page, so they also work where a site or an app shows a block's parts of its own
7
+ // (this site's front page).
8
+ type Script = () => void;
9
+
10
+ const byType = (found: Record<string, Script>) =>
11
+ Object.fromEntries(Object.entries(found).map(([file, run]) => [file.split('/').at(-2)!, run]));
12
+
13
+ // The theme's UI components' by their name (ui/carousel.script.ts: ui/carousel).
14
+ const byUi = (found: Record<string, Script>) =>
15
+ Object.fromEntries(Object.entries(found).map(([file, run]) => [`ui/${file.split('/').at(-1)!.replace('.script.ts', '')}`, run]));
16
+
17
+ /** What each block does in a browser, by its type. */
18
+ export const blockScripts: Record<string, Script> = {
19
+ ...byType(import.meta.glob<Script>('@saturn/blocks/*/script.ts', { eager: true, import: 'default' })),
20
+ ...byType(import.meta.glob<Script>('@theme/blocks/*/script.ts', { eager: true, import: 'default' })),
21
+ ...byUi(import.meta.glob<Script>('@saturn/ui/*.script.ts', { eager: true, import: 'default' })),
22
+ ...byUi(import.meta.glob<Script>('@theme/ui/*.script.ts', { eager: true, import: 'default' })),
23
+ ...byType(import.meta.glob<Script>('/src/apps/*/blocks/*/script.ts', { eager: true, import: 'default' })),
24
+ // An app's part of its kind of a list's entries (Mailchimp's signup in a pop-up), by the app and the list.
25
+ ...Object.fromEntries(
26
+ Object.entries(import.meta.glob<Script>('/src/apps/*/*/script.ts', { eager: true, import: 'default' })).map(([file, run]) => [
27
+ file.split('/').slice(-3, -1).join('/'),
28
+ run,
29
+ ]),
30
+ ),
31
+ };
@@ -1,16 +1,16 @@
1
- // Tags (called categories in the code): one JSON file per tag in src/data/categories/, edited in the
2
- // editor (/editor/, "Tags"). The file name is the slug: the address /blog/kategori/<slug>/ and the
3
- // value stored in the `categories` of the blog posts and the testimonials. Only a blog category
4
- // (`blogCategory`, "Blogkategori" in the editor) is shown on the blog: a pill on the blog index and
5
- // on its posts, and its own page. The others only pick posts and testimonials.
6
- type CategoryData = { name: string; blogCategory?: boolean; seoTitle?: string; seoDescription?: string; shareImage?: string };
7
-
8
- const files = import.meta.glob<CategoryData>('@data/categories/*.json', { eager: true, import: 'default' });
9
-
10
- export const categories = Object.entries(files)
11
- .map(([file, c]) => ({ slug: file.replace(/^.*\/|\.json$/g, ''), ...c }))
12
- .sort((a, b) => a.slug.localeCompare(b.slug));
13
-
14
- const notOnBlog = new Set(categories.filter((c) => c.blogCategory === false).map((c) => c.slug));
15
- /** Whether the tag is shown on the blog (a tag without a file, or from before the field, is). */
16
- export const isBlogCategory = (slug: string) => !notOnBlog.has(slug);
1
+ // Tags (called categories in the code): one JSON file per tag in src/data/categories/, edited in the
2
+ // editor (/editor/, "Tags"). The file name is the slug: the address /blog/kategori/<slug>/ and the
3
+ // value stored in the `categories` of the blog posts and the testimonials. Only a blog category
4
+ // (`blogCategory`, "Blogkategori" in the editor) is shown on the blog: a pill on the blog index and
5
+ // on its posts, and its own page. The others only pick posts and testimonials.
6
+ type CategoryData = { name: string; blogCategory?: boolean; seoTitle?: string; seoDescription?: string; shareImage?: string };
7
+
8
+ const files = import.meta.glob<CategoryData>('@data/categories/*.json', { eager: true, import: 'default' });
9
+
10
+ export const categories = Object.entries(files)
11
+ .map(([file, c]) => ({ slug: file.replace(/^.*\/|\.json$/g, ''), ...c }))
12
+ .sort((a, b) => a.slug.localeCompare(b.slug));
13
+
14
+ const notOnBlog = new Set(categories.filter((c) => c.blogCategory === false).map((c) => c.slug));
15
+ /** Whether the tag is shown on the blog (a tag without a file, or from before the field, is). */
16
+ export const isBlogCategory = (slug: string) => !notOnBlog.has(slug);
package/site/consent.ts CHANGED
@@ -1,26 +1,26 @@
1
- // What the cookie banner asks about: the categories of cookies (@morphemecms/cms/lib/cookieCategories.mjs) of what the
2
- // installed apps load with their settings (`cookies` in their index.ts: Google Analytics statistics, Google Ads
3
- // marketing, Google Tag Manager both), each a yes or no of its own; and whether the site has the banner (and
4
- // "Cookieindstillinger" in the footer) at all: when it is switched on ("Privatliv" › "Cookiebanner",
5
- // src/data/cookies.json) and there is something to ask about. For the theme (Base.astro, Footer.astro,
6
- // CookieConsent.astro), which knows no app by name.
7
- import type { AppDefinition } from '../src/apps';
8
- import { appIdOf } from '../src/apps';
9
- import { CONSENT_CATEGORIES, type ConsentCategory } from '../lib/cookieCategories.mjs';
10
- import cookies from '@data/cookies.json';
11
- import { installed, settingsOf } from './apps';
12
-
13
- // Only the apps' index.ts, without their blocks (as opens.ts).
14
- const appFiles = import.meta.glob<{ default: AppDefinition }>('/src/apps/*/index.ts', { eager: true });
15
-
16
- const asked = new Set(
17
- Object.entries(appFiles).flatMap(([path, { default: app }]) => {
18
- const id = appIdOf(path);
19
- return installed.includes(id) ? (app.cookies?.(settingsOf(id, app.settings?.values)) ?? []) : [];
20
- }),
21
- );
22
-
23
- /** The categories the banner asks about, in its order. */
24
- export const consentCategories: ConsentCategory[] = CONSENT_CATEGORIES.filter((c) => asked.has(c));
25
-
26
- export const cookieBanner = cookies.enabled && consentCategories.length > 0;
1
+ // What the cookie banner asks about: the categories of cookies (@morphemecms/cms/lib/cookieCategories.mjs) of what the
2
+ // installed apps load with their settings (`cookies` in their index.ts: Google Analytics statistics, Google Ads
3
+ // marketing, Google Tag Manager both), each a yes or no of its own; and whether the site has the banner (and
4
+ // "Cookieindstillinger" in the footer) at all: when it is switched on ("Privatliv" › "Cookiebanner",
5
+ // src/data/cookies.json) and there is something to ask about. For the theme (Base.astro, Footer.astro,
6
+ // CookieConsent.astro), which knows no app by name.
7
+ import type { AppDefinition } from '../src/apps';
8
+ import { appIdOf } from '../src/apps';
9
+ import { CONSENT_CATEGORIES, type ConsentCategory } from '../lib/cookieCategories.mjs';
10
+ import cookies from '@data/cookies.json';
11
+ import { installed, settingsOf } from './apps';
12
+
13
+ // Only the apps' index.ts, without their blocks (as opens.ts).
14
+ const appFiles = import.meta.glob<{ default: AppDefinition }>('/src/apps/*/index.ts', { eager: true });
15
+
16
+ const asked = new Set(
17
+ Object.entries(appFiles).flatMap(([path, { default: app }]) => {
18
+ const id = appIdOf(path);
19
+ return installed.includes(id) ? (app.cookies?.(settingsOf(id, app.settings?.values)) ?? []) : [];
20
+ }),
21
+ );
22
+
23
+ /** The categories the banner asks about, in its order. */
24
+ export const consentCategories: ConsentCategory[] = CONSENT_CATEGORIES.filter((c) => asked.has(c));
25
+
26
+ export const cookieBanner = cookies.enabled && consentCategories.length > 0;