@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/worker/github.js CHANGED
@@ -1,36 +1,36 @@
1
- // The Worker's own saves to the repository on GitHub (no one signed in): the planned pages and posts it publishes
2
- // (packages/editor/worker/publish.js) and what an app saves itself (`github` in the tools an app's part of the Worker is given,
3
- // packages/editor/worker/index.js), each in one commit on the site's branch, which builds the site. With the Worker secret
4
- // GITHUB_PUBLISH_TOKEN: a GitHub token with Contents: Read and write on the repository (docs/editor.md, Opsætning).
5
- // Through the cache of the site's files in R2, like the editor's (packages/editor/worker/files.js): the files are read from it, and
6
- // what is saved goes into it. `ctx`: the request's, so R2 is written after the answer has gone. `token`: another sign-in
7
- // than the Worker's own (someone signed in to the editor who asked for it, packages/editor/worker/index.js), whose name the commit is in.
8
- import { filesOf, toBase64 } from './files.js';
9
-
10
- /** The branch's head and the files at it, by their paths (a file that is not there: undefined). */
11
- export async function readFiles(env, paths, ctx, token = env.GITHUB_PUBLISH_TOKEN) {
12
- const files = filesOf(env, token, ctx);
13
- try {
14
- const at = await files.head();
15
- const entries = await files.entriesAt(at.tree, paths);
16
- const texts = await files.texts(entries.flatMap((e) => (e?.type === 'blob' ? [e.oid] : [])));
17
- return { head: at.commit, texts: entries.map((e) => (e?.type === 'blob' ? (texts.get(e.oid) ?? null) : undefined)) };
18
- } finally {
19
- await files.finish('Workeren læser');
20
- }
21
- }
22
-
23
- /** Saves the files (`{ path, text }`) in one commit on the branch, if its head is still `head`. */
24
- export async function commitFiles(env, head, headline, changes, ctx, token = env.GITHUB_PUBLISH_TOKEN) {
25
- const files = filesOf(env, token, ctx);
26
- try {
27
- const at = { commit: head, tree: await files.rootOf(head) };
28
- await files.save(
29
- at,
30
- headline,
31
- changes.map((f) => ({ path: f.path, contents: toBase64(new TextEncoder().encode(f.text)) })),
32
- );
33
- } finally {
34
- await files.finish('Workeren gemmer');
35
- }
36
- }
1
+ // The Worker's own saves to the repository on GitHub (no one signed in): the planned pages and posts it publishes
2
+ // (packages/editor/worker/publish.js) and what an app saves itself (`github` in the tools an app's part of the Worker is given,
3
+ // packages/editor/worker/index.js), each in one commit on the site's branch, which builds the site. With the Worker secret
4
+ // GITHUB_PUBLISH_TOKEN: a GitHub token with Contents: Read and write on the repository (docs/editor.md, Opsætning).
5
+ // Through the cache of the site's files in R2, like the editor's (packages/editor/worker/files.js): the files are read from it, and
6
+ // what is saved goes into it. `ctx`: the request's, so R2 is written after the answer has gone. `token`: another sign-in
7
+ // than the Worker's own (someone signed in to the editor who asked for it, packages/editor/worker/index.js), whose name the commit is in.
8
+ import { filesOf, toBase64 } from './files.js';
9
+
10
+ /** The branch's head and the files at it, by their paths (a file that is not there: undefined). */
11
+ export async function readFiles(env, paths, ctx, token = env.GITHUB_PUBLISH_TOKEN) {
12
+ const files = filesOf(env, token, ctx);
13
+ try {
14
+ const at = await files.head();
15
+ const entries = await files.entriesAt(at.tree, paths);
16
+ const texts = await files.texts(entries.flatMap((e) => (e?.type === 'blob' ? [e.oid] : [])));
17
+ return { head: at.commit, texts: entries.map((e) => (e?.type === 'blob' ? (texts.get(e.oid) ?? null) : undefined)) };
18
+ } finally {
19
+ await files.finish('Workeren læser');
20
+ }
21
+ }
22
+
23
+ /** Saves the files (`{ path, text }`) in one commit on the branch, if its head is still `head`. */
24
+ export async function commitFiles(env, head, headline, changes, ctx, token = env.GITHUB_PUBLISH_TOKEN) {
25
+ const files = filesOf(env, token, ctx);
26
+ try {
27
+ const at = { commit: head, tree: await files.rootOf(head) };
28
+ await files.save(
29
+ at,
30
+ headline,
31
+ changes.map((f) => ({ path: f.path, contents: toBase64(new TextEncoder().encode(f.text)) })),
32
+ );
33
+ } finally {
34
+ await files.finish('Workeren gemmer');
35
+ }
36
+ }
package/worker/index.js CHANGED
@@ -1,184 +1,188 @@
1
- // A thin Worker in front of the static site (dist/), the same for every site: what it has of the site comes from
2
- // `@site/config` and `@site/worker` (the aliases in the site's wrangler.jsonc; this site's are src/site/config.ts and
3
- // src/site/worker.js). Everything is served from the assets, including the rules in public/_redirects. The Worker
4
- // only adds what static files cannot:
5
- // - noindex on the staging hostname (*.workers.dev). NEVER on the site's own domain.
6
- // - the site's redirects from its old addresses (`oldAddresses`, `{ ids, paths }`), e.g. from WordPress: files in
7
- // all sizes, attachment pages and ?attachment_id= / ?p= / ?page_id= (query strings, which _redirects cannot match).
8
- // - redirects for pages and posts that got a new address in the editor (src/data/redirects.json,
9
- // packages/editor/src/addresses.ts), followed to where they end, also after one of the redirects above or
10
- // in public/_redirects, so a visitor is sent on once.
11
- // - the own addresses of the pages that are the front page and the blog page (src/data/standard-pages.json) to / and
12
- // /blog/, where they are shown, also at the end of a redirect.
13
- // - GitHub sign-in for the editor at /editor/ (/oauth/*, packages/editor/worker/oauth.js), kept in a cookie only the Worker reads
14
- // (packages/editor/worker/session.js), and what the editor asks of GitHub with it (/api/github/*, packages/editor/worker/editor-github.js), the site's
15
- // files through the cache in R2 (packages/editor/worker/files.js).
16
- // - the addresses visitors came to that do not exist, for the editor (/api/not-found, packages/editor/worker/not-found.js).
17
- // - the visitors' answers in the cookie banner, the consent log (/api/consent, packages/editor/worker/consent.js, in D1), and each hour
18
- // those older than two years deleted.
19
- // - whether R2 caching can be turned on in the editor: whether Cloudflare has its bucket (/api/r2, packages/editor/worker/r2-status.js).
20
- // - the editor on its own address when EDITOR_HOST is set (packages/editor/worker/editor-host.js); noindex there too.
21
- // - each hour, the pages and posts that are Planlagt published once their time has come (scheduled, packages/editor/worker/publish.js).
22
- // - the editor's notifications on the phone, also when the editor is closed (/api/push, packages/editor/worker/push.js): each minute,
23
- // whether the site has been built with a save, and an app's notifications (`notify` in its tools).
24
- // - the apps' own parts (src/apps/<app>/worker.js, worker/apps.js), while they are installed: their addresses under
25
- // /api/<app>/ and what they do each hour (scheduled), e.g. Cookiescanner's scan of the site's cookies, and their texts
26
- // for their notifications. What the apps
27
- // put in the build (dist/_apps/<app>/, packages/editor/lib/apps.mjs) is served to no one; the apps read it.
28
- import { apps, appTexts, appWorkers, moved, oldAddresses as map, standard } from '@site/worker';
29
- import { handleOAuth } from './oauth.js';
30
- import { editorHost } from './editor-host.js';
31
- import { handleNotFound, isVisit, json, recordNotFound } from './not-found.js';
32
- import { forgetOldConsents, handleConsent } from './consent.js';
33
- import { access, mayEdit } from './session.js';
34
- import { handleGitHub } from './editor-github.js';
35
- import { handleR2 } from './r2-status.js';
36
- import { publishScheduled, SCHEDULED_LIST } from './publish.js';
37
- import { commitFiles, readFiles } from './github.js';
38
- import { handlePush, notifyAll, waitForBuilds } from './push.js';
39
-
40
- const STAGING = /\.workers\.dev$/i;
41
- // The cron in wrangler.jsonc that runs each minute.
42
- const EACH_MINUTE = '* * * * *';
43
-
44
- // The parts of the Worker of the apps installed (src/data/apps.json), by the app's id.
45
- const installed = Object.fromEntries(Object.entries(appWorkers).filter(([id]) => apps.installed?.includes(id)));
46
- // What an app is given, besides the request: whether its sender can save the site (signed in with GitHub), an answer
47
- // in JSON, the Worker's own saves to the repository (`github`, packages/editor/worker/github.js: `read` and `commit`, with the request's
48
- // `ctx`, so the cache in R2 is written after the answer has gone; given a request as the last argument, with its sender's
49
- // sign-in instead, in their name, when they can save the site: a save they asked for in the editor) and its notifications on the phone
50
- // (`notify(env, { type, id, text, error, to })`, packages/editor/worker/push.js: `type` one of the types in `notifications` in its
51
- // index.ts, `text` as written in the site's language, `to` the editor's screen it opens).
52
- const tools = (app, ctx) => ({
53
- mayEdit,
54
- json,
55
- github: {
56
- read: async (env, paths, as) => readFiles(env, paths, ctx, as && (await signedIn(as))),
57
- commit: async (env, head, headline, files, as) => commitFiles(env, head, headline, files, ctx, as && (await signedIn(as))),
58
- },
59
- notify: (env, n) => notifyAll(env, { ...n, type: `${app}/${n.type}` }, appTexts[app]),
60
- });
61
-
62
- /** The sign-in of a request from someone who can save the site, for a save they asked for; else it fails. */
63
- async function signedIn(request) {
64
- const signIn = await access(request);
65
- if (!signIn?.push) throw new Error('Kun en, der kan gemme hjemmesiden, kan gemme.');
66
- return signIn.token;
67
- }
68
-
69
- /** The answer of an installed app's part of the Worker at its address (/api/<app>/…), or undefined for another one. */
70
- function appAnswer(request, url, env, ctx) {
71
- const id = /^\/api\/([\w-]+)(?:\/|$)/.exec(url.pathname)?.[1];
72
- if (!id || !(id in appWorkers)) return undefined;
73
- const app = installed[id];
74
- return app?.fetch ? app.fetch(request, env, ctx, tools(id, ctx)) : json({ error: 'not installed' }, 404);
75
- }
76
-
77
- // Where the front page and the blog page are shown, by their own addresses.
78
- const shownAt = (pages) => ({ [pages.front]: '/', [pages.blog]: '/blog/' });
79
-
80
- // Where an address ends after the editor's redirects (at most ten, against a loop; the editor checks
81
- // for them before it saves), and the front page's and the blog page's own addresses at / and /blog/.
82
- export function onward(target, redirects = moved, pages = standard) {
83
- let to = target;
84
- for (let i = 0; i < 10 && redirects[to.split('#')[0]]; i++) to = redirects[to.split('#')[0]];
85
- const [path, hash] = to.split('#');
86
- const at = shownAt(pages)[path];
87
- return at ? `${at}${hash === undefined ? '' : `#${hash}`}` : to;
88
- }
89
-
90
- export function redirectFor(url) {
91
- // WordPress answered these on the front page only: /?attachment_id=123, /?p=123, /?page_id=123.
92
- const id =
93
- url.pathname === '/' && (url.searchParams.get('attachment_id') ?? url.searchParams.get('p') ?? url.searchParams.get('page_id'));
94
- if (id && map.ids[id]) return onward(map.ids[id]);
95
- const path = decoded(url.pathname);
96
- const at = shownAt(standard)[path];
97
- if (at) return at;
98
- const target = moved[path] ?? map.paths[path];
99
- return target && onward(target);
100
- }
101
-
102
- // An address with a broken %-sign (/%E0%A4%A/) cannot be decoded; it is looked up as it is (and ends
103
- // on the 404 page) rather than making the Worker fail.
104
- function decoded(path) {
105
- try {
106
- return decodeURIComponent(path);
107
- } catch {
108
- return path;
109
- }
110
- }
111
-
112
- // Old links without the trailing slash (/kontakt instead of /kontakt/): the assets only redirect those
113
- // for pages that exist, and _redirects rules only match the exact address. Look up the address with
114
- // the slash and send straight to where that ends, so there is one redirect and no 404.
115
- async function withSlash(url, request, env) {
116
- if (url.pathname.endsWith('/') || /\.[a-z0-9]+$/i.test(url.pathname)) return undefined;
117
- const slashed = new URL(url);
118
- slashed.pathname += '/';
119
- const mapped = redirectFor(slashed);
120
- if (mapped) return mapped;
121
- const res = await env.ASSETS.fetch(new Request(slashed, { method: 'HEAD', headers: request.headers, redirect: 'manual' }));
122
- if (res.status >= 300 && res.status < 400) return onwardOf(res.headers.get('location'), url) ?? undefined;
123
- return res.ok ? slashed.pathname + slashed.search : undefined;
124
- }
125
-
126
- // A redirect from the assets (public/_redirects) to an address the editor has sent on: straight on.
127
- function onwardOf(location, url) {
128
- if (!location) return location;
129
- const to = new URL(location, url.origin);
130
- const end = to.origin === url.origin ? onward(to.pathname + to.hash) : to.pathname + to.hash;
131
- return end === to.pathname + to.hash ? location : end;
132
- }
133
-
134
- export default {
135
- async fetch(request, env, ctx) {
136
- const url = new URL(request.url);
137
- // The editor on its own address: what belongs on the other one is sent there.
138
- const elsewhere = editorHost(url, env, request);
139
- if (elsewhere) return elsewhere;
140
- // Sign-in for /editor/ first: /oauth/auth has no trailing slash and must not be redirected.
141
- const oauth = url.pathname.startsWith('/oauth/') ? await handleOAuth(request, env) : null;
142
- if (url.pathname === '/api/not-found') return handleNotFound(request, env);
143
- if (url.pathname === '/api/consent') return handleConsent(request, env);
144
- if (url.pathname === '/api/r2') return handleR2(request, env);
145
- if (url.pathname.startsWith('/api/github/')) return handleGitHub(request, env, ctx);
146
- if (/^\/api\/push(\/wait)?\/?$/.test(url.pathname)) return handlePush(request, env);
147
- const answer = appAnswer(request, url, env, ctx);
148
- if (answer) return answer;
149
- // The build's lists (what is Planlagt) and the apps' files (what the cookie scan visits) are the Worker's own.
150
- if (url.pathname === SCHEDULED_LIST || url.pathname.startsWith('/_apps/')) return new Response('Not found', { status: 404 });
151
- const target = oauth ? undefined : (redirectFor(url) ?? (await withSlash(url, request, env)));
152
- let response = target
153
- ? new Response(null, { status: 301, headers: { location: new URL(target, url.origin).href } })
154
- : (oauth ?? (await env.ASSETS.fetch(request)));
155
- const location = !target && !oauth && response.status >= 300 && response.status < 400 && response.headers.get('location');
156
- const end = location && onwardOf(location, url);
157
- if (end && end !== location)
158
- response = new Response(null, { status: response.status, headers: { location: new URL(end, url.origin).href } });
159
-
160
- const editor = url.hostname === env.EDITOR_HOST?.trim().toLowerCase();
161
- const staging = STAGING.test(url.hostname) || editor;
162
- // A visitor on the site's 404 page: the address is kept for the editor, after the answer has gone.
163
- // Also on *.workers.dev, the site's address until its own domain points here; the previews of
164
- // branches have no storage and keep nothing.
165
- if (!editor && response.status === 404 && isVisit(request, url)) ctx.waitUntil(recordNotFound(request, url, env));
166
- if (!staging) return response;
167
- const staged = new Response(response.body, response);
168
- staged.headers.set('X-Robots-Tag', 'noindex, nofollow');
169
- return staged;
170
- },
171
-
172
- // The crons in wrangler.jsonc: each minute, whether the site has been built with a save (packages/editor/worker/push.js); each hour,
173
- // the rest (also the answers in the consent log older than two years deleted).
174
- async scheduled(controller, env, ctx) {
175
- if (controller.cron === EACH_MINUTE) return ctx.waitUntil(waitForBuilds(env));
176
- ctx.waitUntil(
177
- Promise.all([
178
- publishScheduled(env),
179
- forgetOldConsents(env),
180
- ...Object.entries(installed).map(([id, app]) => app.scheduled?.(env, ctx, tools(id, ctx))),
181
- ]),
182
- );
183
- },
184
- };
1
+ // A thin Worker in front of the static site (dist/), the same for every site: what it has of the site comes from
2
+ // `@site/config` and `@site/worker` (the aliases in the site's wrangler.jsonc; this site's are src/site/config.ts and
3
+ // src/site/worker.js). Everything is served from the assets, including the rules in public/_redirects. The Worker
4
+ // only adds what static files cannot:
5
+ // - noindex on the staging hostname (*.workers.dev). NEVER on the site's own domain.
6
+ // - the site's redirects from its old addresses (`oldAddresses`, `{ ids, paths }`), e.g. from WordPress: files in
7
+ // all sizes, attachment pages and ?attachment_id= / ?p= / ?page_id= (query strings, which _redirects cannot match).
8
+ // - redirects for pages and posts that got a new address in the editor (src/data/redirects.json,
9
+ // packages/editor/src/addresses.ts), followed to where they end, also after one of the redirects above or
10
+ // in public/_redirects, so a visitor is sent on once.
11
+ // - the own addresses of the pages that are the front page and the blog page (src/data/standard-pages.json) to / and
12
+ // /blog/, where they are shown, also at the end of a redirect.
13
+ // - GitHub sign-in for the editor at /editor/ (/oauth/*, packages/editor/worker/oauth.js), kept in a cookie only the Worker reads
14
+ // (packages/editor/worker/session.js), and what the editor asks of GitHub with it (/api/github/*, packages/editor/worker/editor-github.js), the site's
15
+ // files through the cache in R2 (packages/editor/worker/files.js).
16
+ // - what the editor asks of the app store (/api/store/catalog and /api/store/files/<oid>, packages/editor/worker/store.js), with the
17
+ // site's key (MORPHEME_STORE_KEY) that never leaves the Worker.
18
+ // - the addresses visitors came to that do not exist, for the editor (/api/not-found, packages/editor/worker/not-found.js).
19
+ // - the visitors' answers in the cookie banner, the consent log (/api/consent, packages/editor/worker/consent.js, in D1), and each hour
20
+ // those older than two years deleted.
21
+ // - whether R2 caching can be turned on in the editor: whether Cloudflare has its bucket (/api/r2, packages/editor/worker/r2-status.js).
22
+ // - the editor on its own address when EDITOR_HOST is set (packages/editor/worker/editor-host.js); noindex there too.
23
+ // - each hour, the pages and posts that are Planlagt published once their time has come (scheduled, packages/editor/worker/publish.js).
24
+ // - the editor's notifications on the phone, also when the editor is closed (/api/push, packages/editor/worker/push.js): each minute,
25
+ // whether the site has been built with a save, and an app's notifications (`notify` in its tools).
26
+ // - the apps' own parts (src/apps/<app>/worker.js, worker/apps.js), while they are installed: their addresses under
27
+ // /api/<app>/ and what they do each hour (scheduled), e.g. Cookiescanner's scan of the site's cookies, and their texts
28
+ // for their notifications. What the apps
29
+ // put in the build (dist/_apps/<app>/, packages/editor/lib/apps.mjs) is served to no one; the apps read it.
30
+ import { apps, appTexts, appWorkers, moved, oldAddresses as map, standard } from '@site/worker';
31
+ import { handleOAuth } from './oauth.js';
32
+ import { editorHost } from './editor-host.js';
33
+ import { handleNotFound, isVisit, json, recordNotFound } from './not-found.js';
34
+ import { forgetOldConsents, handleConsent } from './consent.js';
35
+ import { access, mayEdit } from './session.js';
36
+ import { handleGitHub } from './editor-github.js';
37
+ import { handleStore } from './store.js';
38
+ import { handleR2 } from './r2-status.js';
39
+ import { publishScheduled, SCHEDULED_LIST } from './publish.js';
40
+ import { commitFiles, readFiles } from './github.js';
41
+ import { handlePush, notifyAll, waitForBuilds } from './push.js';
42
+
43
+ const STAGING = /\.workers\.dev$/i;
44
+ // The cron in wrangler.jsonc that runs each minute.
45
+ const EACH_MINUTE = '* * * * *';
46
+
47
+ // The parts of the Worker of the apps installed (src/data/apps.json), by the app's id.
48
+ const installed = Object.fromEntries(Object.entries(appWorkers).filter(([id]) => apps.installed?.includes(id)));
49
+ // What an app is given, besides the request: whether its sender can save the site (signed in with GitHub), an answer
50
+ // in JSON, the Worker's own saves to the repository (`github`, packages/editor/worker/github.js: `read` and `commit`, with the request's
51
+ // `ctx`, so the cache in R2 is written after the answer has gone; given a request as the last argument, with its sender's
52
+ // sign-in instead, in their name, when they can save the site: a save they asked for in the editor) and its notifications on the phone
53
+ // (`notify(env, { type, id, text, error, to })`, packages/editor/worker/push.js: `type` one of the types in `notifications` in its
54
+ // index.ts, `text` as written in the site's language, `to` the editor's screen it opens).
55
+ const tools = (app, ctx) => ({
56
+ mayEdit,
57
+ json,
58
+ github: {
59
+ read: async (env, paths, as) => readFiles(env, paths, ctx, as && (await signedIn(as))),
60
+ commit: async (env, head, headline, files, as) => commitFiles(env, head, headline, files, ctx, as && (await signedIn(as))),
61
+ },
62
+ notify: (env, n) => notifyAll(env, { ...n, type: `${app}/${n.type}` }, appTexts[app]),
63
+ });
64
+
65
+ /** The sign-in of a request from someone who can save the site, for a save they asked for; else it fails. */
66
+ async function signedIn(request) {
67
+ const signIn = await access(request);
68
+ if (!signIn?.push) throw new Error('Kun en, der kan gemme hjemmesiden, kan gemme.');
69
+ return signIn.token;
70
+ }
71
+
72
+ /** The answer of an installed app's part of the Worker at its address (/api/<app>/…), or undefined for another one. */
73
+ function appAnswer(request, url, env, ctx) {
74
+ const id = /^\/api\/([\w-]+)(?:\/|$)/.exec(url.pathname)?.[1];
75
+ if (!id || !(id in appWorkers)) return undefined;
76
+ const app = installed[id];
77
+ return app?.fetch ? app.fetch(request, env, ctx, tools(id, ctx)) : json({ error: 'not installed' }, 404);
78
+ }
79
+
80
+ // Where the front page and the blog page are shown, by their own addresses.
81
+ const shownAt = (pages) => ({ [pages.front]: '/', [pages.blog]: '/blog/' });
82
+
83
+ // Where an address ends after the editor's redirects (at most ten, against a loop; the editor checks
84
+ // for them before it saves), and the front page's and the blog page's own addresses at / and /blog/.
85
+ export function onward(target, redirects = moved, pages = standard) {
86
+ let to = target;
87
+ for (let i = 0; i < 10 && redirects[to.split('#')[0]]; i++) to = redirects[to.split('#')[0]];
88
+ const [path, hash] = to.split('#');
89
+ const at = shownAt(pages)[path];
90
+ return at ? `${at}${hash === undefined ? '' : `#${hash}`}` : to;
91
+ }
92
+
93
+ export function redirectFor(url) {
94
+ // WordPress answered these on the front page only: /?attachment_id=123, /?p=123, /?page_id=123.
95
+ const id =
96
+ url.pathname === '/' && (url.searchParams.get('attachment_id') ?? url.searchParams.get('p') ?? url.searchParams.get('page_id'));
97
+ if (id && map.ids[id]) return onward(map.ids[id]);
98
+ const path = decoded(url.pathname);
99
+ const at = shownAt(standard)[path];
100
+ if (at) return at;
101
+ const target = moved[path] ?? map.paths[path];
102
+ return target && onward(target);
103
+ }
104
+
105
+ // An address with a broken %-sign (/%E0%A4%A/) cannot be decoded; it is looked up as it is (and ends
106
+ // on the 404 page) rather than making the Worker fail.
107
+ function decoded(path) {
108
+ try {
109
+ return decodeURIComponent(path);
110
+ } catch {
111
+ return path;
112
+ }
113
+ }
114
+
115
+ // Old links without the trailing slash (/kontakt instead of /kontakt/): the assets only redirect those
116
+ // for pages that exist, and _redirects rules only match the exact address. Look up the address with
117
+ // the slash and send straight to where that ends, so there is one redirect and no 404.
118
+ async function withSlash(url, request, env) {
119
+ if (url.pathname.endsWith('/') || /\.[a-z0-9]+$/i.test(url.pathname)) return undefined;
120
+ const slashed = new URL(url);
121
+ slashed.pathname += '/';
122
+ const mapped = redirectFor(slashed);
123
+ if (mapped) return mapped;
124
+ const res = await env.ASSETS.fetch(new Request(slashed, { method: 'HEAD', headers: request.headers, redirect: 'manual' }));
125
+ if (res.status >= 300 && res.status < 400) return onwardOf(res.headers.get('location'), url) ?? undefined;
126
+ return res.ok ? slashed.pathname + slashed.search : undefined;
127
+ }
128
+
129
+ // A redirect from the assets (public/_redirects) to an address the editor has sent on: straight on.
130
+ function onwardOf(location, url) {
131
+ if (!location) return location;
132
+ const to = new URL(location, url.origin);
133
+ const end = to.origin === url.origin ? onward(to.pathname + to.hash) : to.pathname + to.hash;
134
+ return end === to.pathname + to.hash ? location : end;
135
+ }
136
+
137
+ export default {
138
+ async fetch(request, env, ctx) {
139
+ const url = new URL(request.url);
140
+ // The editor on its own address: what belongs on the other one is sent there.
141
+ const elsewhere = editorHost(url, env, request);
142
+ if (elsewhere) return elsewhere;
143
+ // Sign-in for /editor/ first: /oauth/auth has no trailing slash and must not be redirected.
144
+ const oauth = url.pathname.startsWith('/oauth/') ? await handleOAuth(request, env) : null;
145
+ if (url.pathname === '/api/not-found') return handleNotFound(request, env);
146
+ if (url.pathname === '/api/consent') return handleConsent(request, env);
147
+ if (url.pathname === '/api/r2') return handleR2(request, env);
148
+ if (url.pathname.startsWith('/api/github/')) return handleGitHub(request, env, ctx);
149
+ if (url.pathname.startsWith('/api/store/')) return handleStore(request, env, ctx);
150
+ if (/^\/api\/push(\/wait)?\/?$/.test(url.pathname)) return handlePush(request, env);
151
+ const answer = appAnswer(request, url, env, ctx);
152
+ if (answer) return answer;
153
+ // The build's lists (what is Planlagt) and the apps' files (what the cookie scan visits) are the Worker's own.
154
+ if (url.pathname === SCHEDULED_LIST || url.pathname.startsWith('/_apps/')) return new Response('Not found', { status: 404 });
155
+ const target = oauth ? undefined : (redirectFor(url) ?? (await withSlash(url, request, env)));
156
+ let response = target
157
+ ? new Response(null, { status: 301, headers: { location: new URL(target, url.origin).href } })
158
+ : (oauth ?? (await env.ASSETS.fetch(request)));
159
+ const location = !target && !oauth && response.status >= 300 && response.status < 400 && response.headers.get('location');
160
+ const end = location && onwardOf(location, url);
161
+ if (end && end !== location)
162
+ response = new Response(null, { status: response.status, headers: { location: new URL(end, url.origin).href } });
163
+
164
+ const editor = url.hostname === env.EDITOR_HOST?.trim().toLowerCase();
165
+ const staging = STAGING.test(url.hostname) || editor;
166
+ // A visitor on the site's 404 page: the address is kept for the editor, after the answer has gone.
167
+ // Also on *.workers.dev, the site's address until its own domain points here; the previews of
168
+ // branches have no storage and keep nothing.
169
+ if (!editor && response.status === 404 && isVisit(request, url)) ctx.waitUntil(recordNotFound(request, url, env));
170
+ if (!staging) return response;
171
+ const staged = new Response(response.body, response);
172
+ staged.headers.set('X-Robots-Tag', 'noindex, nofollow');
173
+ return staged;
174
+ },
175
+
176
+ // The crons in wrangler.jsonc: each minute, whether the site has been built with a save (packages/editor/worker/push.js); each hour,
177
+ // the rest (also the answers in the consent log older than two years deleted).
178
+ async scheduled(controller, env, ctx) {
179
+ if (controller.cron === EACH_MINUTE) return ctx.waitUntil(waitForBuilds(env));
180
+ ctx.waitUntil(
181
+ Promise.all([
182
+ publishScheduled(env),
183
+ forgetOldConsents(env),
184
+ ...Object.entries(installed).map(([id, app]) => app.scheduled?.(env, ctx, tools(id, ctx))),
185
+ ]),
186
+ );
187
+ },
188
+ };