@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
package/theme/ui/Chip.tsx CHANGED
@@ -1,101 +1,101 @@
1
- // A chip (m3.material.io/components/chips, .chip in ../styles/ui.css): a short label (`label`), evt. an icon before it
2
- // (`icon`), or a person's picture (`avatar`: its address, on an input chip) and one after it (`trailingIcon`). Its kind
3
- // (`kind`) is Material's name; how each looks is the theme's: assist (the default: a link to something related, a post's
4
- // tag), filter (one of a few that choose what is shown: `selected` is the chosen one, aria-pressed on a button,
5
- // aria-current="page" on a link; it has a check before its label, which a theme shows on the chosen one or not), input
6
- // (something entered, evt. selected and with a button after it that removes it, `removeLabel`, its name for screen
7
- // readers, and what it does in the editor, `onRemove`) and suggestion (evt. selected). Assist, filter and suggestion chips can be `elevated` (with a shadow
8
- // instead of the edge, on a picture or a colour). Its states: `selected`, `disabled` (it cannot be used: a button
9
- // disabled, a link only shown) and `dragged` (while it is dragged to another place, with the shadow that lifts it).
10
- // With `href` it is a link (Link: on the site; in the editor only drawn), with `plain` only shown (a tag without a
11
- // page), else a <button type="button">; an input chip with `removeLabel` is the chip (a <span>) with its own button and
12
- // the button that removes it. Other attributes (data-…, aria-…, onClick) go on the button or the link, and `className`
13
- // after its own classes. The label is a prop, not children, so an Astro component shows it as it is (BlogIndex.astro).
14
- import type { ReactNode } from 'react';
15
- import { Glyph, Svg, type IconRef } from '@morphemecms/cms/src/icon';
16
- import { Link } from '@morphemecms/cms/src/standard/view';
17
-
18
- export type ChipKind = 'assist' | 'filter' | 'input' | 'suggestion';
19
-
20
- /** The kinds of a chip, as Material 3 names them. */
21
- export const chipKinds: ChipKind[] = ['assist', 'filter', 'input', 'suggestion'];
22
-
23
- /** A chip's classes: its kind's, and evt. elevated (not an input chip), dragged, and with a button that removes it. */
24
- export const chipClass = (kind: ChipKind = 'assist', { elevated = false, dragged = false, removable = false } = {}) =>
25
- ['chip', `chip-${kind}`, elevated && kind !== 'input' && 'chip-elevated', dragged && 'chip-dragged', removable && 'chip-removable']
26
- .filter(Boolean)
27
- .join(' ');
28
-
29
- export default function Chip({
30
- label,
31
- kind = 'assist',
32
- selected,
33
- elevated,
34
- disabled,
35
- dragged,
36
- icon,
37
- avatar,
38
- trailingIcon,
39
- removeLabel,
40
- onRemove,
41
- href,
42
- plain,
43
- className,
44
- ...rest
45
- }: {
46
- label: ReactNode;
47
- kind?: ChipKind;
48
- selected?: boolean;
49
- elevated?: boolean;
50
- disabled?: boolean;
51
- dragged?: boolean;
52
- icon?: IconRef;
53
- avatar?: string;
54
- trailingIcon?: IconRef;
55
- removeLabel?: string;
56
- onRemove?: () => void;
57
- href?: string;
58
- plain?: boolean;
59
- className?: string;
60
- } & Record<string, unknown>) {
61
- const removable = kind === 'input' && Boolean(removeLabel);
62
- const classes = [chipClass(kind, { elevated, dragged, removable }), className].filter(Boolean).join(' ');
63
- // Chosen: a filter, an input or a suggestion chip that is a button (a filter chip that is a link: the open page).
64
- const pressed = kind === 'assist' ? undefined : kind === 'filter' ? Boolean(selected) : selected;
65
- const content = (
66
- <>
67
- {kind === 'filter' && <Svg name="check" size={18} className="chip-check" />}
68
- {avatar ? <img src={avatar} alt="" className="chip-avatar" /> : icon && <Glyph icon={icon} size={18} />}
69
- {label}
70
- {trailingIcon && !removable && <Glyph icon={trailingIcon} size={18} className="chip-trailing-icon" />}
71
- </>
72
- );
73
- if (removable)
74
- return (
75
- <span className={classes} data-selected={selected ? '' : undefined} aria-disabled={disabled || undefined}>
76
- <button type="button" className="chip-action" aria-pressed={pressed} disabled={disabled} {...rest}>
77
- {content}
78
- </button>
79
- <button type="button" className="chip-remove" aria-label={removeLabel} disabled={disabled} onClick={onRemove}>
80
- <Glyph icon={trailingIcon ?? 'x'} size={18} />
81
- </button>
82
- </span>
83
- );
84
- if (href !== undefined && !disabled)
85
- return (
86
- <Link href={href} className={classes} aria-current={selected ? 'page' : undefined} {...rest}>
87
- {content}
88
- </Link>
89
- );
90
- if (plain || href !== undefined)
91
- return (
92
- <span className={classes} aria-disabled={disabled || undefined} {...rest}>
93
- {content}
94
- </span>
95
- );
96
- return (
97
- <button type="button" className={classes} aria-pressed={pressed} disabled={disabled} {...rest}>
98
- {content}
99
- </button>
100
- );
101
- }
1
+ // A chip (m3.material.io/components/chips, .chip in ../styles/ui.css): a short label (`label`), evt. an icon before it
2
+ // (`icon`), or a person's picture (`avatar`: its address, on an input chip) and one after it (`trailingIcon`). Its kind
3
+ // (`kind`) is Material's name; how each looks is the theme's: assist (the default: a link to something related, a post's
4
+ // tag), filter (one of a few that choose what is shown: `selected` is the chosen one, aria-pressed on a button,
5
+ // aria-current="page" on a link; it has a check before its label, which a theme shows on the chosen one or not), input
6
+ // (something entered, evt. selected and with a button after it that removes it, `removeLabel`, its name for screen
7
+ // readers, and what it does in the editor, `onRemove`) and suggestion (evt. selected). Assist, filter and suggestion chips can be `elevated` (with a shadow
8
+ // instead of the edge, on a picture or a colour). Its states: `selected`, `disabled` (it cannot be used: a button
9
+ // disabled, a link only shown) and `dragged` (while it is dragged to another place, with the shadow that lifts it).
10
+ // With `href` it is a link (Link: on the site; in the editor only drawn), with `plain` only shown (a tag without a
11
+ // page), else a <button type="button">; an input chip with `removeLabel` is the chip (a <span>) with its own button and
12
+ // the button that removes it. Other attributes (data-…, aria-…, onClick) go on the button or the link, and `className`
13
+ // after its own classes. The label is a prop, not children, so an Astro component shows it as it is (BlogIndex.astro).
14
+ import type { ReactNode } from 'react';
15
+ import { Glyph, Svg, type IconRef } from '@morphemecms/cms/src/icon';
16
+ import { Link } from '@morphemecms/cms/src/standard/view';
17
+
18
+ export type ChipKind = 'assist' | 'filter' | 'input' | 'suggestion';
19
+
20
+ /** The kinds of a chip, as Material 3 names them. */
21
+ export const chipKinds: ChipKind[] = ['assist', 'filter', 'input', 'suggestion'];
22
+
23
+ /** A chip's classes: its kind's, and evt. elevated (not an input chip), dragged, and with a button that removes it. */
24
+ export const chipClass = (kind: ChipKind = 'assist', { elevated = false, dragged = false, removable = false } = {}) =>
25
+ ['chip', `chip-${kind}`, elevated && kind !== 'input' && 'chip-elevated', dragged && 'chip-dragged', removable && 'chip-removable']
26
+ .filter(Boolean)
27
+ .join(' ');
28
+
29
+ export default function Chip({
30
+ label,
31
+ kind = 'assist',
32
+ selected,
33
+ elevated,
34
+ disabled,
35
+ dragged,
36
+ icon,
37
+ avatar,
38
+ trailingIcon,
39
+ removeLabel,
40
+ onRemove,
41
+ href,
42
+ plain,
43
+ className,
44
+ ...rest
45
+ }: {
46
+ label: ReactNode;
47
+ kind?: ChipKind;
48
+ selected?: boolean;
49
+ elevated?: boolean;
50
+ disabled?: boolean;
51
+ dragged?: boolean;
52
+ icon?: IconRef;
53
+ avatar?: string;
54
+ trailingIcon?: IconRef;
55
+ removeLabel?: string;
56
+ onRemove?: () => void;
57
+ href?: string;
58
+ plain?: boolean;
59
+ className?: string;
60
+ } & Record<string, unknown>) {
61
+ const removable = kind === 'input' && Boolean(removeLabel);
62
+ const classes = [chipClass(kind, { elevated, dragged, removable }), className].filter(Boolean).join(' ');
63
+ // Chosen: a filter, an input or a suggestion chip that is a button (a filter chip that is a link: the open page).
64
+ const pressed = kind === 'assist' ? undefined : kind === 'filter' ? Boolean(selected) : selected;
65
+ const content = (
66
+ <>
67
+ {kind === 'filter' && <Svg name="check" size={18} className="chip-check" />}
68
+ {avatar ? <img src={avatar} alt="" className="chip-avatar" /> : icon && <Glyph icon={icon} size={18} />}
69
+ {label}
70
+ {trailingIcon && !removable && <Glyph icon={trailingIcon} size={18} className="chip-trailing-icon" />}
71
+ </>
72
+ );
73
+ if (removable)
74
+ return (
75
+ <span className={classes} data-selected={selected ? '' : undefined} aria-disabled={disabled || undefined}>
76
+ <button type="button" className="chip-action" aria-pressed={pressed} disabled={disabled} {...rest}>
77
+ {content}
78
+ </button>
79
+ <button type="button" className="chip-remove" aria-label={removeLabel} disabled={disabled} onClick={onRemove}>
80
+ <Glyph icon={trailingIcon ?? 'x'} size={18} />
81
+ </button>
82
+ </span>
83
+ );
84
+ if (href !== undefined && !disabled)
85
+ return (
86
+ <Link href={href} className={classes} aria-current={selected ? 'page' : undefined} {...rest}>
87
+ {content}
88
+ </Link>
89
+ );
90
+ if (plain || href !== undefined)
91
+ return (
92
+ <span className={classes} aria-disabled={disabled || undefined} {...rest}>
93
+ {content}
94
+ </span>
95
+ );
96
+ return (
97
+ <button type="button" className={classes} aria-pressed={pressed} disabled={disabled} {...rest}>
98
+ {content}
99
+ </button>
100
+ );
101
+ }
@@ -1,27 +1,27 @@
1
- // A chip set (Material's chips side by side, as Material's own web components group them, md-chip-set; .chip-set in
2
- // ../styles/ui.css): the theme's chips (`children`: Chip) in a group with its name (`label`, read by screen readers).
3
- // Its layout (`layout`): wrap (the default: on as many lines as they need) or scroll (on one line that scrolls sideways
4
- // when they are wider than it, as Material's chips do on a phone, without a scrollbar). Other attributes (data-…) go on
5
- // the group, and `className` after its own classes. An Astro component gives an element the same classes with
6
- // chipSetClass.
7
- import type { ReactNode } from 'react';
8
-
9
- export const chipSetLayouts = ['wrap', 'scroll'] as const;
10
- export type ChipSetLayout = (typeof chipSetLayouts)[number];
11
-
12
- /** A chip set's classes: its layout's. */
13
- export const chipSetClass = (layout: ChipSetLayout = 'wrap') => `chip-set chip-set-${layout}`;
14
-
15
- export default function ChipSet({
16
- layout,
17
- label,
18
- className,
19
- children,
20
- ...rest
21
- }: { layout?: ChipSetLayout; label: string; className?: string; children: ReactNode } & Record<string, unknown>) {
22
- return (
23
- <div role="group" aria-label={label} className={[chipSetClass(layout), className].filter(Boolean).join(' ')} {...rest}>
24
- {children}
25
- </div>
26
- );
27
- }
1
+ // A chip set (Material's chips side by side, as Material's own web components group them, md-chip-set; .chip-set in
2
+ // ../styles/ui.css): the theme's chips (`children`: Chip) in a group with its name (`label`, read by screen readers).
3
+ // Its layout (`layout`): wrap (the default: on as many lines as they need) or scroll (on one line that scrolls sideways
4
+ // when they are wider than it, as Material's chips do on a phone, without a scrollbar). Other attributes (data-…) go on
5
+ // the group, and `className` after its own classes. An Astro component gives an element the same classes with
6
+ // chipSetClass.
7
+ import type { ReactNode } from 'react';
8
+
9
+ export const chipSetLayouts = ['wrap', 'scroll'] as const;
10
+ export type ChipSetLayout = (typeof chipSetLayouts)[number];
11
+
12
+ /** A chip set's classes: its layout's. */
13
+ export const chipSetClass = (layout: ChipSetLayout = 'wrap') => `chip-set chip-set-${layout}`;
14
+
15
+ export default function ChipSet({
16
+ layout,
17
+ label,
18
+ className,
19
+ children,
20
+ ...rest
21
+ }: { layout?: ChipSetLayout; label: string; className?: string; children: ReactNode } & Record<string, unknown>) {
22
+ return (
23
+ <div role="group" aria-label={label} className={[chipSetClass(layout), className].filter(Boolean).join(' ')} {...rest}>
24
+ {children}
25
+ </div>
26
+ );
27
+ }
@@ -1,149 +1,149 @@
1
- // A date picker (m3.material.io/components/date-pickers, .date-picker in ../styles/ui.css): a text field to type a
2
- // date in (in the site's language's order, 02.11.2026), with a calendar button that opens the picker
3
- // (DatePickerContainer.tsx), and what a form sends, the day as ISO (2026-11-02), in a hidden input named `name` (and,
4
- // with `range`, the last day in one named `endName`). `kind`: docked (the picker opens under the field) or modal (in a
5
- // dialog in the middle of the screen, also with a keyboard input mode); a range is always modal. `value`, `endValue`:
6
- // the day(s) it starts with; `min`, `max`: the first and last day that can be picked; `label`, `supporting`, `error`:
7
- // the field's name, the line under it (else the date's format) and what is wrong with it (the field marked);
8
- // `required`, `id` and the rest go on the field's input, and `className` on the field. On the site datePicker.script.ts opens it, draws the picker in its <dialog>, writes the
9
- // day picked into the inputs and closes it; in the editor's previews it is only drawn, and with `onChange` (the editor's
10
- // own fields) it works the same way, here, and says the day(s) picked (or '' for none). Its fixed texts
11
- // (datePickerTexts) are the site's own, in @site/texts, unless `texts` gives them (the editor's, in its language).
12
- import { useEffect, useRef, type ReactNode } from 'react';
13
- import { siteText, locale } from '@morphemecms/cms/src/i18n';
14
- import { datePickerField } from '@theme/ui/datePicker.script';
15
- import IconButton from '@theme/ui/IconButton';
16
- import TextField from '@theme/ui/TextField';
17
- import { dateOf, dayTyped } from '@theme/ui/dates';
18
- import type { DatePickerKind, DatePickerTexts } from '@theme/ui/DatePickerContainer';
19
-
20
- /** A date picker's fixed texts, in the language its dates are written in. */
21
- export const datePickerTexts = (): DatePickerTexts => ({
22
- locale,
23
- select: siteText('Vælg dato'),
24
- selectRange: siteText('Vælg datoer'),
25
- enter: siteText('Skriv dato'),
26
- enterRange: siteText('Skriv datoer'),
27
- date: siteText('Dato'),
28
- start: siteText('Startdato'),
29
- end: siteText('Slutdato'),
30
- format: siteText('dd.mm.åååå'),
31
- wrongFormat: siteText('Skriv datoen som dd.mm.åååå.'),
32
- notAllowed: siteText('Datoen kan ikke vælges.'),
33
- endBeforeStart: siteText('Slutdatoen er før startdatoen.'),
34
- previousMonth: siteText('Forrige måned'),
35
- nextMonth: siteText('Næste måned'),
36
- previousYear: siteText('Forrige år'),
37
- nextYear: siteText('Næste år'),
38
- chooseMonth: siteText('Vælg måned'),
39
- chooseYear: siteText('Vælg år'),
40
- toInput: siteText('Skift til at skrive'),
41
- toCalendar: siteText('Skift til kalenderen'),
42
- cancel: siteText('Annuller'),
43
- ok: siteText('OK'),
44
- });
45
-
46
- /** What a date picker's script is told by its field: the fixed texts and what can be picked. */
47
- export type DatePickerSettings = { texts: DatePickerTexts; kind: DatePickerKind; range: boolean; min: string; max: string };
48
-
49
- export default function DatePicker({
50
- label,
51
- name,
52
- endName,
53
- value = '',
54
- endValue = '',
55
- kind = 'docked',
56
- range = false,
57
- min = '',
58
- max = '',
59
- supporting,
60
- error,
61
- texts: given,
62
- onChange,
63
- className,
64
- ...rest
65
- }: {
66
- label: string;
67
- name: string;
68
- endName?: string;
69
- value?: string;
70
- endValue?: string;
71
- kind?: DatePickerKind;
72
- range?: boolean;
73
- min?: string;
74
- max?: string;
75
- supporting?: ReactNode;
76
- error?: string | boolean;
77
- texts?: DatePickerTexts;
78
- onChange?: (value: string, endValue: string) => void;
79
- className?: string;
80
- } & Record<string, unknown>) {
81
- const texts = given ?? datePickerTexts();
82
- const modal = kind === 'modal' || range;
83
- const settings: DatePickerSettings = { texts, kind: modal ? 'modal' : 'docked', range, min, max };
84
- const typed = [value, range ? endValue : '']
85
- .filter((d) => dateOf(d))
86
- .map((d) => dayTyped(d, texts.locale))
87
- .join(' – ');
88
- const format = range ? `${texts.format} – ${texts.format}` : texts.format;
89
- const title = range ? texts.selectRange : texts.select;
90
- const box = useWorking(onChange, [value, endValue], typed);
91
- return (
92
- <div ref={box} className={['date-picker-field', className].filter(Boolean).join(' ')} data-date-picker={JSON.stringify(settings)}>
93
- <TextField
94
- label={label}
95
- supporting={supporting ?? format}
96
- error={error}
97
- placeholder={format}
98
- defaultValue={typed}
99
- inputMode="numeric"
100
- autoComplete="off"
101
- data-date-picker-text=""
102
- {...rest}
103
- />
104
- <IconButton
105
- icon="calendar-blank"
106
- label={title}
107
- className="date-picker-field-button"
108
- aria-haspopup="dialog"
109
- aria-expanded="false"
110
- data-date-picker-open=""
111
- />
112
- <input type="hidden" name={name} defaultValue={dateOf(value) ? value : ''} data-date-picker-value="0" />
113
- {range && <input type="hidden" name={endName} defaultValue={dateOf(endValue) ? endValue : ''} data-date-picker-value="1" />}
114
- <dialog
115
- className={modal ? 'dialog-modal date-picker-dialog' : 'date-picker-popover'}
116
- aria-label={title}
117
- data-date-picker-dialog=""
118
- ></dialog>
119
- </div>
120
- );
121
- }
122
-
123
- // A picker the editor changes (`onChange`): made to work here as on the site, telling the editor what is picked, and
124
- // showing what the editor's value is when it changes from outside (a version restored).
125
- function useWorking(onChange: ((value: string, endValue: string) => void) | undefined, values: string[], typed: string) {
126
- const box = useRef<HTMLDivElement>(null);
127
- const told = useRef(onChange);
128
- told.current = onChange;
129
- const working = onChange !== undefined;
130
- useEffect(() => {
131
- const field = box.current;
132
- if (!working || !field) return;
133
- datePickerField(field);
134
- const inputs = [...field.querySelectorAll<HTMLInputElement>('[data-date-picker-value]')];
135
- const changed = () => told.current?.(inputs[0]?.value ?? '', inputs[1]?.value ?? '');
136
- inputs.forEach((i) => i.addEventListener('change', changed));
137
- return () => inputs.forEach((i) => i.removeEventListener('change', changed));
138
- }, [working]);
139
- useEffect(() => {
140
- const field = box.current;
141
- if (!working || !field) return;
142
- const inputs = [...field.querySelectorAll<HTMLInputElement>('[data-date-picker-value]')];
143
- if (inputs.every((input, i) => input.value === (dateOf(values[i] ?? '') ? values[i] : ''))) return;
144
- inputs.forEach((input, i) => (input.value = dateOf(values[i] ?? '') ? values[i]! : ''));
145
- const text = field.querySelector<HTMLInputElement>('[data-date-picker-text]');
146
- if (text) text.value = typed;
147
- }, [working, ...values]);
148
- return box;
149
- }
1
+ // A date picker (m3.material.io/components/date-pickers, .date-picker in ../styles/ui.css): a text field to type a
2
+ // date in (in the site's language's order, 02.11.2026), with a calendar button that opens the picker
3
+ // (DatePickerContainer.tsx), and what a form sends, the day as ISO (2026-11-02), in a hidden input named `name` (and,
4
+ // with `range`, the last day in one named `endName`). `kind`: docked (the picker opens under the field) or modal (in a
5
+ // dialog in the middle of the screen, also with a keyboard input mode); a range is always modal. `value`, `endValue`:
6
+ // the day(s) it starts with; `min`, `max`: the first and last day that can be picked; `label`, `supporting`, `error`:
7
+ // the field's name, the line under it (else the date's format) and what is wrong with it (the field marked);
8
+ // `required`, `id` and the rest go on the field's input, and `className` on the field. On the site datePicker.script.ts opens it, draws the picker in its <dialog>, writes the
9
+ // day picked into the inputs and closes it; in the editor's previews it is only drawn, and with `onChange` (the editor's
10
+ // own fields) it works the same way, here, and says the day(s) picked (or '' for none). Its fixed texts
11
+ // (datePickerTexts) are the site's own, in @site/texts, unless `texts` gives them (the editor's, in its language).
12
+ import { useEffect, useRef, type ReactNode } from 'react';
13
+ import { siteText, locale } from '@morphemecms/cms/src/i18n';
14
+ import { datePickerField } from '@theme/ui/datePicker.script';
15
+ import IconButton from '@theme/ui/IconButton';
16
+ import TextField from '@theme/ui/TextField';
17
+ import { dateOf, dayTyped } from '@theme/ui/dates';
18
+ import type { DatePickerKind, DatePickerTexts } from '@theme/ui/DatePickerContainer';
19
+
20
+ /** A date picker's fixed texts, in the language its dates are written in. */
21
+ export const datePickerTexts = (): DatePickerTexts => ({
22
+ locale,
23
+ select: siteText('Vælg dato'),
24
+ selectRange: siteText('Vælg datoer'),
25
+ enter: siteText('Skriv dato'),
26
+ enterRange: siteText('Skriv datoer'),
27
+ date: siteText('Dato'),
28
+ start: siteText('Startdato'),
29
+ end: siteText('Slutdato'),
30
+ format: siteText('dd.mm.åååå'),
31
+ wrongFormat: siteText('Skriv datoen som dd.mm.åååå.'),
32
+ notAllowed: siteText('Datoen kan ikke vælges.'),
33
+ endBeforeStart: siteText('Slutdatoen er før startdatoen.'),
34
+ previousMonth: siteText('Forrige måned'),
35
+ nextMonth: siteText('Næste måned'),
36
+ previousYear: siteText('Forrige år'),
37
+ nextYear: siteText('Næste år'),
38
+ chooseMonth: siteText('Vælg måned'),
39
+ chooseYear: siteText('Vælg år'),
40
+ toInput: siteText('Skift til at skrive'),
41
+ toCalendar: siteText('Skift til kalenderen'),
42
+ cancel: siteText('Annuller'),
43
+ ok: siteText('OK'),
44
+ });
45
+
46
+ /** What a date picker's script is told by its field: the fixed texts and what can be picked. */
47
+ export type DatePickerSettings = { texts: DatePickerTexts; kind: DatePickerKind; range: boolean; min: string; max: string };
48
+
49
+ export default function DatePicker({
50
+ label,
51
+ name,
52
+ endName,
53
+ value = '',
54
+ endValue = '',
55
+ kind = 'docked',
56
+ range = false,
57
+ min = '',
58
+ max = '',
59
+ supporting,
60
+ error,
61
+ texts: given,
62
+ onChange,
63
+ className,
64
+ ...rest
65
+ }: {
66
+ label: string;
67
+ name: string;
68
+ endName?: string;
69
+ value?: string;
70
+ endValue?: string;
71
+ kind?: DatePickerKind;
72
+ range?: boolean;
73
+ min?: string;
74
+ max?: string;
75
+ supporting?: ReactNode;
76
+ error?: string | boolean;
77
+ texts?: DatePickerTexts;
78
+ onChange?: (value: string, endValue: string) => void;
79
+ className?: string;
80
+ } & Record<string, unknown>) {
81
+ const texts = given ?? datePickerTexts();
82
+ const modal = kind === 'modal' || range;
83
+ const settings: DatePickerSettings = { texts, kind: modal ? 'modal' : 'docked', range, min, max };
84
+ const typed = [value, range ? endValue : '']
85
+ .filter((d) => dateOf(d))
86
+ .map((d) => dayTyped(d, texts.locale))
87
+ .join(' – ');
88
+ const format = range ? `${texts.format} – ${texts.format}` : texts.format;
89
+ const title = range ? texts.selectRange : texts.select;
90
+ const box = useWorking(onChange, [value, endValue], typed);
91
+ return (
92
+ <div ref={box} className={['date-picker-field', className].filter(Boolean).join(' ')} data-date-picker={JSON.stringify(settings)}>
93
+ <TextField
94
+ label={label}
95
+ supporting={supporting ?? format}
96
+ error={error}
97
+ placeholder={format}
98
+ defaultValue={typed}
99
+ inputMode="numeric"
100
+ autoComplete="off"
101
+ data-date-picker-text=""
102
+ {...rest}
103
+ />
104
+ <IconButton
105
+ icon="calendar-blank"
106
+ label={title}
107
+ className="date-picker-field-button"
108
+ aria-haspopup="dialog"
109
+ aria-expanded="false"
110
+ data-date-picker-open=""
111
+ />
112
+ <input type="hidden" name={name} defaultValue={dateOf(value) ? value : ''} data-date-picker-value="0" />
113
+ {range && <input type="hidden" name={endName} defaultValue={dateOf(endValue) ? endValue : ''} data-date-picker-value="1" />}
114
+ <dialog
115
+ className={modal ? 'dialog-modal date-picker-dialog' : 'date-picker-popover'}
116
+ aria-label={title}
117
+ data-date-picker-dialog=""
118
+ ></dialog>
119
+ </div>
120
+ );
121
+ }
122
+
123
+ // A picker the editor changes (`onChange`): made to work here as on the site, telling the editor what is picked, and
124
+ // showing what the editor's value is when it changes from outside (a version restored).
125
+ function useWorking(onChange: ((value: string, endValue: string) => void) | undefined, values: string[], typed: string) {
126
+ const box = useRef<HTMLDivElement>(null);
127
+ const told = useRef(onChange);
128
+ told.current = onChange;
129
+ const working = onChange !== undefined;
130
+ useEffect(() => {
131
+ const field = box.current;
132
+ if (!working || !field) return;
133
+ datePickerField(field);
134
+ const inputs = [...field.querySelectorAll<HTMLInputElement>('[data-date-picker-value]')];
135
+ const changed = () => told.current?.(inputs[0]?.value ?? '', inputs[1]?.value ?? '');
136
+ inputs.forEach((i) => i.addEventListener('change', changed));
137
+ return () => inputs.forEach((i) => i.removeEventListener('change', changed));
138
+ }, [working]);
139
+ useEffect(() => {
140
+ const field = box.current;
141
+ if (!working || !field) return;
142
+ const inputs = [...field.querySelectorAll<HTMLInputElement>('[data-date-picker-value]')];
143
+ if (inputs.every((input, i) => input.value === (dateOf(values[i] ?? '') ? values[i] : ''))) return;
144
+ inputs.forEach((input, i) => (input.value = dateOf(values[i] ?? '') ? values[i]! : ''));
145
+ const text = field.querySelector<HTMLInputElement>('[data-date-picker-text]');
146
+ if (text) text.value = typed;
147
+ }, [working, ...values]);
148
+ return box;
149
+ }