@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/src/schema.ts CHANGED
@@ -1,417 +1,417 @@
1
- // The kinds of things the editor edits, which a site describes its content with (packages/editor/defaults/collections.ts):
2
- // collections of files and their fields, the blocks of a fixed page and the rules of a text (Template),
3
- // and the small helpers for them that do not depend on a site.
4
- // markdown: a folder of .md files (front matter + text): blog posts and pages.
5
- // folder: a folder of .json files, one entry per file: categories, prices, testimonials.
6
- // files: single .json files: the pages built in code (fixed pages) and the menu.
7
- import type { Icon } from '@phosphor-icons/react';
8
- import type { ComponentType, ReactNode } from 'react';
9
- import type { BlockData } from './blocks';
10
- import type { AppCategory } from './store';
11
- import type { SiteData } from '@site/editor';
12
- import { locale } from './i18n';
13
-
14
- /** What a relation field picks from: one of the lists the site makes of its files (relationsOf in
15
- * packages/editor/defaults/editor.ts), e.g. 'pages', 'blog', 'categories', 'files' (the PDFs). 'fixed': the fixed pages, only offered
16
- * together with the pages (a field with `fixed`). */
17
- export type Relation = string;
18
-
19
- export type Field = {
20
- name: string;
21
- label: string;
22
- type:
23
- | 'string'
24
- | 'text'
25
- | 'number'
26
- | 'date'
27
- | 'datetime'
28
- | 'boolean'
29
- | 'image'
30
- | 'readonly'
31
- | 'select'
32
- | 'relation'
33
- | 'object'
34
- | 'list'
35
- | 'blocks'
36
- | 'markdown';
37
- hint?: string;
38
- /** An address on the site (string), written as one when it is typed (addressOf in addresses.ts):
39
- * a page's may have more parts, a post's only one. */
40
- address?: 'page' | 'post';
41
- /** What is used when it is empty, shown greyed in it (string, text). */
42
- placeholder?: (site: SiteData) => string;
43
- /** Edited elsewhere: a link there under the label. */
44
- edit?: Edit;
45
- required?: boolean;
46
- /** Most characters (string, text). */
47
- max?: number;
48
- /** A regular expression the text must match, and the message when it does not. */
49
- pattern?: [string, string];
50
- /** A number written with its digits in pairs, as "30 64 16 12": typed any way, it is written so
51
- * (inPairs in check.ts); a number of digits: it must have that many. */
52
- digitsInPairs?: number | true;
53
- /** A phone number, with its country code picked before it in a sheet (PhoneField): the site's own
54
- * country code ("+45"). A number with it is saved without it ("30 64 16 12"), one with another with
55
- * that before it ("+46 70 123 45 67"); only the site's own is written in pairs and has its digits
56
- * counted (digitsInPairs). */
57
- phone?: string;
58
- /** string: words typed as chips (ChipField), saved separated by commas: 'one', one word, the field gone while it has
59
- * it (a primary keyword); 'many', any number of them. */
60
- chips?: 'one' | 'many';
61
- /** select */
62
- /** `icon`: shown before its name (only with `segments`). `hint`: shown under the label while it is
63
- * chosen, in place of the field's own (the status of a page: what each one means). `onPage`: offered only while
64
- * that relation has a choice on the page being edited (a button that opens a promotion); chosen, it is still shown. */
65
- options?: { label: string; value: string; icon?: Icon; hint?: string; onPage?: Relation }[];
66
- /** select: the options are icons (their names, `icons`), shown as the icons to tap (fields.tsx). */
67
- icons?: boolean;
68
- /** select: the options side by side in a bar, the chosen one raised (SegmentedButton in ui.tsx), for two or
69
- * three short ones. */
70
- segments?: boolean;
71
- /** select: shown as what is chosen, with its hint, and not changed here (the kind of an entry,
72
- * picked when it is made). */
73
- locked?: boolean;
74
- /** select: the choices on a page of their own under the form, at its address with the field's name after it
75
- * (#apps/content-colors/indstillinger/variant), in place of the sheet, drawn by this with what each gives (a picture of
76
- * it); the field links there. Only a field of a part's own form (CompanyForm.tsx: an app's settings), not one in a
77
- * group or a list; elsewhere the choices are in the sheet. */
78
- page?: ComponentType<FieldPageProps>;
79
- /** relation: what is picked. Pages are stored by their path, the others by their file name. */
80
- to?: Relation;
81
- multiple?: boolean;
82
- /** relation, multiple: the text of the pill that opens the sheet to pick one ("Tilføj tag"). */
83
- add?: string;
84
- /** relation to pages: the fixed pages can be picked too (the menu). */
85
- fixed?: boolean;
86
- /** relation: only the choices shown on the page being edited (Option.on, FieldContext.page); where no page is
87
- * edited (the shared buttons), only those shown on every page. */
88
- onPage?: boolean;
89
- /** relation with `multiple`, and list: at most this many. */
90
- maxItems?: number;
91
- /** object, and list of objects */
92
- fields?: Field[];
93
- /** list of single values */
94
- field?: Field;
95
- /** list: the field shown as the title of each item; of several, the first filled in (a button's text or a text). */
96
- summary?: string | string[];
97
- singular?: string;
98
- /** The value in a new entry. */
99
- default?: unknown;
100
- /** The value of a saved entry that has none (saved before the field was there, or with its empty choice, which is
101
- * not written), when it is not `default`: a banner from before it could go across the whole width is as wide as
102
- * the text. */
103
- missing?: unknown;
104
- /** Shown, checked and saved only while another field next to it (a select) has one of these values,
105
- * and that field is itself in use. */
106
- only?: { field: string; is: string[] };
107
- /** boolean: shown as a switch, with what it says when on and when off. */
108
- toggle?: [string, string];
109
- /** Its value changes how the page is laid out (a page across the whole width): "Forhåndsvis" shows a page whose value
110
- * is changed in another page saved with the same value (EntryForm.tsx). */
111
- layout?: boolean;
112
- /** blocks: a list where each item has a `type`, one of these, which gives its fields. */
113
- blocks?: Block[];
114
- /** blocks: also every block a page can have (the standard ones and the apps', not HTML), after its own; one of
115
- * its own by the same type wins (withPageBlocks in registry.tsx). */
116
- pageBlocks?: boolean;
117
- /** blocks: the page's field (its introduction) written as the text at the top, above the sections. */
118
- intro?: string;
119
- /** blocks: the lead of a block a page can have, by its type, on this page (a fixed page's sections: the front page's
120
- * headings and texts, written in the text above their cards, sections.mjs); its own blocks have theirs (Block.lead). */
121
- leads?: Record<string, Lead>;
122
- /** blocks: what the page may have of them (Template). markdown: the blocks that can be put in its text with "+", and
123
- * how many (Template `blocks` and `max`; 'image' a picture); without it, none. */
124
- template?: Template;
125
- };
126
-
127
- /** What a field's page of its own (Field.page) is given: the field, what is chosen, the form's other values as they are
128
- * now (not saved yet) and the choice, which goes back to the form with it. */
129
- export type FieldPageProps = {
130
- field: Field;
131
- value: string;
132
- values: Record<string, unknown>;
133
- onChange: (value: string) => void;
134
- };
135
-
136
- /** What a text may have of blocks: the developer's rules for a page's blocks (MarkdownCollection) or a
137
- * fixed page's sections (a `blocks` field), by type. The editor keeps to them (what can be put in,
138
- * hidden, moved and removed), checks them before it saves, and so does the site before it is built
139
- * (templateProblems in check.ts). */
140
- export type Template = {
141
- /** The blocks that can be put in; all of them when left out. */
142
- blocks?: string[];
143
- /** At most this many of a type, hidden ones too. */
144
- max?: Record<string, number>;
145
- /** On the page, shown: the last one cannot be hidden or removed. */
146
- required?: string[];
147
- /** Stays where it is, shown: it can be edited, but not moved, hidden or removed, and nothing moves
148
- * past it (the front page's top). */
149
- locked?: string[];
150
- /** The blocks a new page starts with, in order, with no fields filled in (a page collection). */
151
- start?: string[];
152
- };
153
-
154
- /** What a button can open of an entry of a list shown on the pages (a promotion), offered by its kind: `label`, what
155
- * opens, in the site's language ("Pop op-vindue", "Bookingarket"), the choice named after it with the entry's name in
156
- * parentheses; `as`, a target of the buttons (`buttonTargets`) it stands for, which the button then does (the booking
157
- * bar opens the booking sheet, as "Book en tid" does), else the entry itself opens. */
158
- export type Opens = { label: string; as?: string };
159
-
160
- /** A place in the editor (a route, e.g. 'virksomheden/kontakt') and the text of the link to it. */
161
- export type Edit = { to: string; text: string };
162
-
163
- // A kind of item in a list of blocks (a fixed page's sections; in the editor cards in its text, SectionsField.tsx).
164
- export type Block = {
165
- type: string;
166
- label: string;
167
- /** What the block is, where one is picked. */
168
- hint?: string;
169
- /** Edited elsewhere: "Ret" goes there (without fields), or a link there over its fields. */
170
- edit?: Edit;
171
- fields: Field[];
172
- /** Its own text and picture are written in the page's text, above its card (sections.mjs): */
173
- lead?: Lead;
174
- };
175
-
176
- /** heading: the field of the heading (an "Overskrift", H2); body: the field of the text under it, one
177
- * text (paragraphs) or, with `list`, one item per paragraph; image: a picture (`image`, `imageAlt`, `imageDecorative`)
178
- * above the heading, in place of the design's own; upTo: only the body's text before its first block of this type is
179
- * written above the card (the front page's "Banner": its "Knapper" block), the block and the text after it stay in the
180
- * field, which the card has too. */
181
- export type Lead = { heading?: string; body?: string; list?: boolean; image?: boolean; upTo?: string };
182
-
183
- type Base = {
184
- id: string;
185
- label: string;
186
- singular: string;
187
- /** The button for a new entry ("Nyt blogindlæg"); without it, no new entries are made here. */
188
- create?: string;
189
- };
190
-
191
- export type MarkdownCollection = Base & {
192
- kind: 'markdown';
193
- folder: string;
194
- fields: Field[];
195
- deletable?: boolean;
196
- /** The site's blocks can be put in the text (src/apps/<app>/blocks/). */
197
- blocks?: boolean;
198
- /** What a text may have of them. */
199
- template?: Template;
200
- };
201
-
202
- export type FolderCollection = Base & {
203
- kind: 'folder';
204
- folder: string;
205
- fields: Field[];
206
- deletable?: boolean;
207
- /** Entries have an `order` (first in the file), changed with the arrows in the list. */
208
- orderable?: boolean;
209
- /** The field the file name is made from when the entry is created; of several, the first filled in
210
- * (a pop-up's heading, or the name of a kind without one). */
211
- slugFrom: string | string[];
212
- /** The entries are of kinds: the name of the select field that says which (`locked`), which the apps
213
- * add kinds to (apps.ts withKinds). With more than one, "+" opens a sheet to pick the kind. */
214
- kinds?: string;
215
- /** What the list shows for an entry. */
216
- summary: (data: Record<string, unknown>) => string;
217
- /** What the list shows under it, smaller (a cookie's name under who sets it), and is searched with it. */
218
- detail?: (data: Record<string, unknown>) => string;
219
- /** The fields the list can be filtered by (the funnel, Library.tsx List), each among the values its entries have:
220
- * a select by its options' names, another by the value itself (a cookie's provider); `all`: the choice that shows
221
- * them all ("Alle udbydere"). */
222
- filters?: { field: string; all: string }[];
223
- /** The entries are shown on pages of the site: the field with their addresses, the field with the tags
224
- * whose posts they are on, and the field and value that say an entry is on every page. The list can
225
- * then be filtered by a page or a tag (Library.tsx List). */
226
- shownOn?: { pages: string; tags?: string; everywhere?: { field: string; is: string } };
227
- /** What a button can open of an entry of one of the list's own kinds, by the kind, as AppKind.opens for an app's
228
- * kinds: a pop-up opens itself; a kind left out offers nothing (the action bar). */
229
- opens?: Record<string, Opens>;
230
- /** The boolean field that turns an entry on and off (a promotion's "Slået til"/"Slået fra"): the list
231
- * can then be filtered by it, the choices its `toggle` (Library.tsx List). */
232
- onOff?: string;
233
- /** The list's own fields one of its own kinds does not have, by the kind (a bar has no picture or
234
- * heading), as AppKind.omit for an app's kinds (apps.ts withKinds). */
235
- omit?: Record<string, string[]>;
236
- /** How an entry of one of the list's own kinds looks on the site, by the kind, drawn beside its form
237
- * with the fields as they are now (a pop-up); an app's kinds have their own (AppKind.draw). */
238
- draws?: Record<string, (values: Record<string, any>, data: BlockData) => ReactNode>;
239
- /** How an entry of an app's kind with a part (AppKind.part) looks on the site: the list's own drawing (a pop-up's box)
240
- * with the app's part in it, the same as on the site (kindDraw in apps.ts). */
241
- drawPart?: (values: Record<string, any>, data: BlockData, part: KindPart) => ReactNode;
242
- /** Entries something else added (the app "Cookiescanner" a cookie it found), not yet looked through: the field in the
243
- * file that says so (`true`, not one of `fields`), the heading they are under at the top of the list (Library.tsx
244
- * List), what each says in the accent colour in it and at the top of its form (`label`, by its data: "Ny", "Mangler
245
- * formål"), what the form says of it (`notice`) and its button that takes the field away (`approve`). Saving the entry
246
- * takes it away too (DataForm.tsx). */
247
- fresh?: { field: string; heading: string; label: (data: Record<string, unknown>) => string; notice: string; approve: string };
248
- /** An entry as saved before the list changed (of a kind that is gone: a contact bar, now an action bar), as the list
249
- * has it now, from its data and the site's files: read so in the list, the form (and saved so) and the check of the
250
- * site (entryData: Library.tsx, DataForm.tsx, checkSite.ts). */
251
- upgrade?: (data: Record<string, unknown>, files: { path: string; text: string }[]) => Record<string, unknown>;
252
- };
253
-
254
- /** An entry's data from its file's text, as the list has it now (FolderCollection.upgrade). */
255
- export const entryData = (collection: FolderCollection, text: string, files: { path: string; text: string }[]) => {
256
- const data = JSON.parse(text) as Record<string, unknown>;
257
- return collection.upgrade ? collection.upgrade(data, files) : data;
258
- };
259
-
260
- /** An entry's name on its own screen and among those deleted: what its list shows, with the line under it after it
261
- * ("Google Analytics · _ga"). */
262
- export const entryName = (collection: FolderCollection, data: Record<string, unknown>) =>
263
- [collection.summary(data), collection.detail?.(data)].filter(Boolean).join(' · ');
264
-
265
- /** An app's part of an entry of its kind, drawn in the list's own drawing (a Mailchimp signup in a pop-up's box), on the
266
- * site and in the editor alike: its drawing (`View`, given its view and the entry's own button to show where it wants)
267
- * and what makes its view in the editor (`viewOf`, as a block's view.ts). */
268
- export type KindPart = {
269
- View: ComponentType<{ view: any; button: ReactNode }>;
270
- viewOf: (values: Record<string, any>, data: BlockData) => unknown;
271
- };
272
-
273
- /** A list a standard block or an app brings ("Udtalelser", "Priser"), as the site's own, with its icon under "Lister". */
274
- export type OwnedList = FolderCollection & {
275
- icon: Icon;
276
- /** Made-up rows, as the files have them, for the parts under "Dele" and an app's pictures for the store (examples.ts). */
277
- examples?: Record<string, unknown>[];
278
- };
279
-
280
- export type DataFile = {
281
- file: string;
282
- label: string;
283
- /** Where it is seen on the site. */
284
- view: string;
285
- fields: Field[];
286
- /** The file is a list (the menus): this field holds it in the form. With `fields` ("Aktiveret"), the file holds
287
- * them and the list under this field's name, and the form shows them above the list. */
288
- root?: Field;
289
- /** A fixed page called by its label, not its H1 (the front page). */
290
- byLabel?: boolean;
291
- };
292
-
293
- /** A fixed page's name in the editor: its H1 (`heading`), as the page has it now; the front page
294
- * (byLabel) and the about page, whose file has none, by their label. `data`: the file's content, or its text. */
295
- export function fixedName(file: DataFile, data?: string | Record<string, unknown>): string {
296
- if (file.byLabel) return file.label;
297
- try {
298
- const heading = (typeof data === 'string' ? JSON.parse(data) : data)?.heading;
299
- return typeof heading === 'string' && heading.trim() ? heading.trim() : file.label;
300
- } catch {
301
- return file.label;
302
- }
303
- }
304
-
305
- export type FilesCollection = Base & {
306
- kind: 'files';
307
- files: DataFile[];
308
- /** Its files are pages of the site (the fixed pages): each form says when it was last saved, as a page's. */
309
- pages?: boolean;
310
- };
311
-
312
- export type Collection = MarkdownCollection | FolderCollection | FilesCollection;
313
-
314
- // The collection a file belongs to, and for single files its entry.
315
- export function collectionOf(collections: Collection[], path: string): { collection: Collection; dataFile?: DataFile } | null {
316
- for (const collection of collections) {
317
- if (collection.kind === 'files') {
318
- const dataFile = collection.files.find((f) => f.file === path);
319
- if (dataFile) return { collection, dataFile };
320
- } else if (path.startsWith(`${collection.folder}/`)) {
321
- return { collection };
322
- }
323
- }
324
- return null;
325
- }
326
-
327
- // A file's name in its folder, without .md or .json (and /index): a post's address, an entry's slug.
328
- export const slugOf = (path: string, folder: string) => path.slice(folder.length + 1).replace(/(\/index)?\.(md|json)$/, '');
329
-
330
- // Titles in alphabetical order, in the editor's language (Danish: æ, ø, å last), without the quotation marks and other signs
331
- // some begin with: “Livet med og efter bipolar lidelse” under L.
332
- const sortable = (title: string) => title.replace(/^[^\p{L}\p{N}]+/u, '');
333
- export const byText = (a: string, b: string) => sortable(a).localeCompare(sortable(b), locale);
334
-
335
- // Addresses and file names from a title, spelled like the existing ones: æ -> ae, ø -> oe, å -> aa.
336
- export const slugify = (title: string) =>
337
- title
338
- .toLowerCase()
339
- .replace(/æ/g, 'ae')
340
- .replace(/ø/g, 'oe')
341
- .replace(/å/g, 'aa')
342
- .normalize('NFKD')
343
- .replace(/[̀-ͯ]/g, '')
344
- .replace(/[^a-z0-9]+/g, '-')
345
- .replace(/^-|-$/g, '');
346
-
347
- /** A screen of the site's own with parts (PartScreen), "Virksomheden" or "Blokke" (CompanyForm.tsx): a
348
- * part of one data file. */
349
- export type Part = {
350
- id: string;
351
- label: string;
352
- icon: Icon;
353
- /** The fields and the file they are in, at the top level or under `at`; without them, a part is only a
354
- * row that opens its own screen (the ones under "Udseende", Library.tsx). */
355
- file?: string;
356
- at?: string;
357
- fields?: Field[];
358
- /** The values before any are saved (a block's shared.ts). */
359
- defaults?: Record<string, unknown>;
360
- /** A block drawn under the fields with them as they are now (its draw, src/apps/<app>/blocks/): its type, and props
361
- * for when no page has the block (the first one on a page is drawn). shared: always with `props`,
362
- * as a copy that has nothing of its own (the shared buttons). variants: drawn once for each, under its
363
- * name, always with `props` and the variant's over them (the designs of "Kort"). */
364
- preview?: {
365
- type: string;
366
- props?: Record<string, unknown>;
367
- shared?: boolean;
368
- variants?: PreviewVariant[];
369
- };
370
- /** Where its row opens, when not its own screen under the one it is on (the front page under "Udseende"). */
371
- href?: string;
372
- /** At the end of its row, before the arrow: the theme in use, by "Temaer" under "Udseende". */
373
- detail?: string;
374
- /** At the end of its row, after `detail` and before the arrow: the site's primary, secondary and tertiary colours by
375
- * "Farver" under "Udseende" (ColorSwatches). */
376
- trailing?: ReactNode;
377
- /** Where its screen goes back to: "Virksomheden", or "Blokke" (blockTexts.ts, site.ts). */
378
- back?: { href: string; label: string };
379
- /** What the commit says was edited, in the site's language, when not its name in lower case (an
380
- * app's settings, AppList.tsx: "indstillinger for Mailchimp"). */
381
- commit?: string;
382
- /** Parts of its own, instead of fields: a row that opens a screen with them, each at
383
- * #<screen>/<id>/<part> and going back to it ("Virksomheden" › "Betaling" with "Bank"). */
384
- parts?: Part[];
385
- /** With `parts`: the settings of the apps installed of these kinds (AppDefinition.category) come after them, each at
386
- * #<screen>/<id>/<app> ("Betaling" with MobilePay; AppList.tsx appPartsIn). */
387
- apps?: AppCategory[];
388
- /** One of the editor's own lists, drawn under its fields: "keywords", every keyword of the pages, posts and fixed
389
- * pages ("Interne links", Keywords.tsx). */
390
- below?: 'keywords';
391
- /** One of the editor's own screens, instead of a form: "consents", the visitors' answers in the cookie banner
392
- * ("Samtykker" under "Privatliv", Consents.tsx). */
393
- opens?: 'consents';
394
- /** Its fields, which pick a page (`relation`), as the rows of a list, each opening the sheet with the pages (FieldRows):
395
- * "Standardsider" and "Privatlivssider". */
396
- rows?: boolean;
397
- };
398
-
399
- /** A part of the start screen that is a screen with parts, each a screen of its own at #<id>/<part>
400
- * (Library.tsx PartsScreen, CompanyForm.tsx): "Privatliv" with the cookie banner and the privacy pages. With `apps`, the
401
- * settings of the apps installed of those kinds (AppDefinition.category) come after its own parts, each at
402
- * #<id>/<app> ("Analytics" with Google Analytics; AppList.tsx appPartsIn). */
403
- export type PartScreen = { id: string; label: string; parts: Part[]; apps?: AppCategory[] };
404
-
405
- /** One way a block's screen under "Blokke" draws it (Part.preview): its name and its own props. */
406
- export type PreviewVariant = { label: string; props: Record<string, unknown> };
407
-
408
- /** What a block on the site is given by RichText.astro (BlockSite.astro gives it to its load.ts): its props (as written in its line in the
409
- * text), its place among the parts of the text, the page's address, whether the page is a new
410
- * version of a page (/ny/), and its shared texts (shared.ts, with those saved over them). */
411
- export type SiteProps<P = Record<string, any>> = {
412
- props: P;
413
- index: number;
414
- path?: string;
415
- preview?: boolean;
416
- texts?: Record<string, any>;
417
- };
1
+ // The kinds of things the editor edits, which a site describes its content with (packages/editor/defaults/collections.ts):
2
+ // collections of files and their fields, the blocks of a fixed page and the rules of a text (Template),
3
+ // and the small helpers for them that do not depend on a site.
4
+ // markdown: a folder of .md files (front matter + text): blog posts and pages.
5
+ // folder: a folder of .json files, one entry per file: categories, prices, testimonials.
6
+ // files: single .json files: the pages built in code (fixed pages) and the menu.
7
+ import type { Icon } from '@phosphor-icons/react';
8
+ import type { ComponentType, ReactNode } from 'react';
9
+ import type { BlockData } from './blocks';
10
+ import type { AppCategory } from './store';
11
+ import type { SiteData } from '@site/editor';
12
+ import { locale } from './i18n';
13
+
14
+ /** What a relation field picks from: one of the lists the site makes of its files (relationsOf in
15
+ * packages/editor/defaults/editor.ts), e.g. 'pages', 'blog', 'categories', 'files' (the PDFs). 'fixed': the fixed pages, only offered
16
+ * together with the pages (a field with `fixed`). */
17
+ export type Relation = string;
18
+
19
+ export type Field = {
20
+ name: string;
21
+ label: string;
22
+ type:
23
+ | 'string'
24
+ | 'text'
25
+ | 'number'
26
+ | 'date'
27
+ | 'datetime'
28
+ | 'boolean'
29
+ | 'image'
30
+ | 'readonly'
31
+ | 'select'
32
+ | 'relation'
33
+ | 'object'
34
+ | 'list'
35
+ | 'blocks'
36
+ | 'markdown';
37
+ hint?: string;
38
+ /** An address on the site (string), written as one when it is typed (addressOf in addresses.ts):
39
+ * a page's may have more parts, a post's only one. */
40
+ address?: 'page' | 'post';
41
+ /** What is used when it is empty, shown greyed in it (string, text). */
42
+ placeholder?: (site: SiteData) => string;
43
+ /** Edited elsewhere: a link there under the label. */
44
+ edit?: Edit;
45
+ required?: boolean;
46
+ /** Most characters (string, text). */
47
+ max?: number;
48
+ /** A regular expression the text must match, and the message when it does not. */
49
+ pattern?: [string, string];
50
+ /** A number written with its digits in pairs, as "30 64 16 12": typed any way, it is written so
51
+ * (inPairs in check.ts); a number of digits: it must have that many. */
52
+ digitsInPairs?: number | true;
53
+ /** A phone number, with its country code picked before it in a sheet (PhoneField): the site's own
54
+ * country code ("+45"). A number with it is saved without it ("30 64 16 12"), one with another with
55
+ * that before it ("+46 70 123 45 67"); only the site's own is written in pairs and has its digits
56
+ * counted (digitsInPairs). */
57
+ phone?: string;
58
+ /** string: words typed as chips (ChipField), saved separated by commas: 'one', one word, the field gone while it has
59
+ * it (a primary keyword); 'many', any number of them. */
60
+ chips?: 'one' | 'many';
61
+ /** select */
62
+ /** `icon`: shown before its name (only with `segments`). `hint`: shown under the label while it is
63
+ * chosen, in place of the field's own (the status of a page: what each one means). `onPage`: offered only while
64
+ * that relation has a choice on the page being edited (a button that opens a promotion); chosen, it is still shown. */
65
+ options?: { label: string; value: string; icon?: Icon; hint?: string; onPage?: Relation }[];
66
+ /** select: the options are icons (their names, `icons`), shown as the icons to tap (fields.tsx). */
67
+ icons?: boolean;
68
+ /** select: the options side by side in a bar, the chosen one raised (SegmentedButton in ui.tsx), for two or
69
+ * three short ones. */
70
+ segments?: boolean;
71
+ /** select: shown as what is chosen, with its hint, and not changed here (the kind of an entry,
72
+ * picked when it is made). */
73
+ locked?: boolean;
74
+ /** select: the choices on a page of their own under the form, at its address with the field's name after it
75
+ * (#apps/content-colors/indstillinger/variant), in place of the sheet, drawn by this with what each gives (a picture of
76
+ * it); the field links there. Only a field of a part's own form (CompanyForm.tsx: an app's settings), not one in a
77
+ * group or a list; elsewhere the choices are in the sheet. */
78
+ page?: ComponentType<FieldPageProps>;
79
+ /** relation: what is picked. Pages are stored by their path, the others by their file name. */
80
+ to?: Relation;
81
+ multiple?: boolean;
82
+ /** relation, multiple: the text of the pill that opens the sheet to pick one ("Tilføj tag"). */
83
+ add?: string;
84
+ /** relation to pages: the fixed pages can be picked too (the menu). */
85
+ fixed?: boolean;
86
+ /** relation: only the choices shown on the page being edited (Option.on, FieldContext.page); where no page is
87
+ * edited (the shared buttons), only those shown on every page. */
88
+ onPage?: boolean;
89
+ /** relation with `multiple`, and list: at most this many. */
90
+ maxItems?: number;
91
+ /** object, and list of objects */
92
+ fields?: Field[];
93
+ /** list of single values */
94
+ field?: Field;
95
+ /** list: the field shown as the title of each item; of several, the first filled in (a button's text or a text). */
96
+ summary?: string | string[];
97
+ singular?: string;
98
+ /** The value in a new entry. */
99
+ default?: unknown;
100
+ /** The value of a saved entry that has none (saved before the field was there, or with its empty choice, which is
101
+ * not written), when it is not `default`: a banner from before it could go across the whole width is as wide as
102
+ * the text. */
103
+ missing?: unknown;
104
+ /** Shown, checked and saved only while another field next to it (a select) has one of these values,
105
+ * and that field is itself in use. */
106
+ only?: { field: string; is: string[] };
107
+ /** boolean: shown as a switch, with what it says when on and when off. */
108
+ toggle?: [string, string];
109
+ /** Its value changes how the page is laid out (a page across the whole width): "Forhåndsvis" shows a page whose value
110
+ * is changed in another page saved with the same value (EntryForm.tsx). */
111
+ layout?: boolean;
112
+ /** blocks: a list where each item has a `type`, one of these, which gives its fields. */
113
+ blocks?: Block[];
114
+ /** blocks: also every block a page can have (the standard ones and the apps', not HTML), after its own; one of
115
+ * its own by the same type wins (withPageBlocks in registry.tsx). */
116
+ pageBlocks?: boolean;
117
+ /** blocks: the page's field (its introduction) written as the text at the top, above the sections. */
118
+ intro?: string;
119
+ /** blocks: the lead of a block a page can have, by its type, on this page (a fixed page's sections: the front page's
120
+ * headings and texts, written in the text above their cards, sections.mjs); its own blocks have theirs (Block.lead). */
121
+ leads?: Record<string, Lead>;
122
+ /** blocks: what the page may have of them (Template). markdown: the blocks that can be put in its text with "+", and
123
+ * how many (Template `blocks` and `max`; 'image' a picture); without it, none. */
124
+ template?: Template;
125
+ };
126
+
127
+ /** What a field's page of its own (Field.page) is given: the field, what is chosen, the form's other values as they are
128
+ * now (not saved yet) and the choice, which goes back to the form with it. */
129
+ export type FieldPageProps = {
130
+ field: Field;
131
+ value: string;
132
+ values: Record<string, unknown>;
133
+ onChange: (value: string) => void;
134
+ };
135
+
136
+ /** What a text may have of blocks: the developer's rules for a page's blocks (MarkdownCollection) or a
137
+ * fixed page's sections (a `blocks` field), by type. The editor keeps to them (what can be put in,
138
+ * hidden, moved and removed), checks them before it saves, and so does the site before it is built
139
+ * (templateProblems in check.ts). */
140
+ export type Template = {
141
+ /** The blocks that can be put in; all of them when left out. */
142
+ blocks?: string[];
143
+ /** At most this many of a type, hidden ones too. */
144
+ max?: Record<string, number>;
145
+ /** On the page, shown: the last one cannot be hidden or removed. */
146
+ required?: string[];
147
+ /** Stays where it is, shown: it can be edited, but not moved, hidden or removed, and nothing moves
148
+ * past it (the front page's top). */
149
+ locked?: string[];
150
+ /** The blocks a new page starts with, in order, with no fields filled in (a page collection). */
151
+ start?: string[];
152
+ };
153
+
154
+ /** What a button can open of an entry of a list shown on the pages (a promotion), offered by its kind: `label`, what
155
+ * opens, in the site's language ("Pop op-vindue", "Bookingarket"), the choice named after it with the entry's name in
156
+ * parentheses; `as`, a target of the buttons (`buttonTargets`) it stands for, which the button then does (the booking
157
+ * bar opens the booking sheet, as "Book en tid" does), else the entry itself opens. */
158
+ export type Opens = { label: string; as?: string };
159
+
160
+ /** A place in the editor (a route, e.g. 'virksomheden/kontakt') and the text of the link to it. */
161
+ export type Edit = { to: string; text: string };
162
+
163
+ // A kind of item in a list of blocks (a fixed page's sections; in the editor cards in its text, SectionsField.tsx).
164
+ export type Block = {
165
+ type: string;
166
+ label: string;
167
+ /** What the block is, where one is picked. */
168
+ hint?: string;
169
+ /** Edited elsewhere: "Ret" goes there (without fields), or a link there over its fields. */
170
+ edit?: Edit;
171
+ fields: Field[];
172
+ /** Its own text and picture are written in the page's text, above its card (sections.mjs): */
173
+ lead?: Lead;
174
+ };
175
+
176
+ /** heading: the field of the heading (an "Overskrift", H2); body: the field of the text under it, one
177
+ * text (paragraphs) or, with `list`, one item per paragraph; image: a picture (`image`, `imageAlt`, `imageDecorative`)
178
+ * above the heading, in place of the design's own; upTo: only the body's text before its first block of this type is
179
+ * written above the card (the front page's "Banner": its "Knapper" block), the block and the text after it stay in the
180
+ * field, which the card has too. */
181
+ export type Lead = { heading?: string; body?: string; list?: boolean; image?: boolean; upTo?: string };
182
+
183
+ type Base = {
184
+ id: string;
185
+ label: string;
186
+ singular: string;
187
+ /** The button for a new entry ("Nyt blogindlæg"); without it, no new entries are made here. */
188
+ create?: string;
189
+ };
190
+
191
+ export type MarkdownCollection = Base & {
192
+ kind: 'markdown';
193
+ folder: string;
194
+ fields: Field[];
195
+ deletable?: boolean;
196
+ /** The site's blocks can be put in the text (src/apps/<app>/blocks/). */
197
+ blocks?: boolean;
198
+ /** What a text may have of them. */
199
+ template?: Template;
200
+ };
201
+
202
+ export type FolderCollection = Base & {
203
+ kind: 'folder';
204
+ folder: string;
205
+ fields: Field[];
206
+ deletable?: boolean;
207
+ /** Entries have an `order` (first in the file), changed with the arrows in the list. */
208
+ orderable?: boolean;
209
+ /** The field the file name is made from when the entry is created; of several, the first filled in
210
+ * (a pop-up's heading, or the name of a kind without one). */
211
+ slugFrom: string | string[];
212
+ /** The entries are of kinds: the name of the select field that says which (`locked`), which the apps
213
+ * add kinds to (apps.ts withKinds). With more than one, "+" opens a sheet to pick the kind. */
214
+ kinds?: string;
215
+ /** What the list shows for an entry. */
216
+ summary: (data: Record<string, unknown>) => string;
217
+ /** What the list shows under it, smaller (a cookie's name under who sets it), and is searched with it. */
218
+ detail?: (data: Record<string, unknown>) => string;
219
+ /** The fields the list can be filtered by (the funnel, Library.tsx List), each among the values its entries have:
220
+ * a select by its options' names, another by the value itself (a cookie's provider); `all`: the choice that shows
221
+ * them all ("Alle udbydere"). */
222
+ filters?: { field: string; all: string }[];
223
+ /** The entries are shown on pages of the site: the field with their addresses, the field with the tags
224
+ * whose posts they are on, and the field and value that say an entry is on every page. The list can
225
+ * then be filtered by a page or a tag (Library.tsx List). */
226
+ shownOn?: { pages: string; tags?: string; everywhere?: { field: string; is: string } };
227
+ /** What a button can open of an entry of one of the list's own kinds, by the kind, as AppKind.opens for an app's
228
+ * kinds: a pop-up opens itself; a kind left out offers nothing (the action bar). */
229
+ opens?: Record<string, Opens>;
230
+ /** The boolean field that turns an entry on and off (a promotion's "Slået til"/"Slået fra"): the list
231
+ * can then be filtered by it, the choices its `toggle` (Library.tsx List). */
232
+ onOff?: string;
233
+ /** The list's own fields one of its own kinds does not have, by the kind (a bar has no picture or
234
+ * heading), as AppKind.omit for an app's kinds (apps.ts withKinds). */
235
+ omit?: Record<string, string[]>;
236
+ /** How an entry of one of the list's own kinds looks on the site, by the kind, drawn beside its form
237
+ * with the fields as they are now (a pop-up); an app's kinds have their own (AppKind.draw). */
238
+ draws?: Record<string, (values: Record<string, any>, data: BlockData) => ReactNode>;
239
+ /** How an entry of an app's kind with a part (AppKind.part) looks on the site: the list's own drawing (a pop-up's box)
240
+ * with the app's part in it, the same as on the site (kindDraw in apps.ts). */
241
+ drawPart?: (values: Record<string, any>, data: BlockData, part: KindPart) => ReactNode;
242
+ /** Entries something else added (the app "Cookiescanner" a cookie it found), not yet looked through: the field in the
243
+ * file that says so (`true`, not one of `fields`), the heading they are under at the top of the list (Library.tsx
244
+ * List), what each says in the accent colour in it and at the top of its form (`label`, by its data: "Ny", "Mangler
245
+ * formål"), what the form says of it (`notice`) and its button that takes the field away (`approve`). Saving the entry
246
+ * takes it away too (DataForm.tsx). */
247
+ fresh?: { field: string; heading: string; label: (data: Record<string, unknown>) => string; notice: string; approve: string };
248
+ /** An entry as saved before the list changed (of a kind that is gone: a contact bar, now an action bar), as the list
249
+ * has it now, from its data and the site's files: read so in the list, the form (and saved so) and the check of the
250
+ * site (entryData: Library.tsx, DataForm.tsx, checkSite.ts). */
251
+ upgrade?: (data: Record<string, unknown>, files: { path: string; text: string }[]) => Record<string, unknown>;
252
+ };
253
+
254
+ /** An entry's data from its file's text, as the list has it now (FolderCollection.upgrade). */
255
+ export const entryData = (collection: FolderCollection, text: string, files: { path: string; text: string }[]) => {
256
+ const data = JSON.parse(text) as Record<string, unknown>;
257
+ return collection.upgrade ? collection.upgrade(data, files) : data;
258
+ };
259
+
260
+ /** An entry's name on its own screen and among those deleted: what its list shows, with the line under it after it
261
+ * ("Google Analytics · _ga"). */
262
+ export const entryName = (collection: FolderCollection, data: Record<string, unknown>) =>
263
+ [collection.summary(data), collection.detail?.(data)].filter(Boolean).join(' · ');
264
+
265
+ /** An app's part of an entry of its kind, drawn in the list's own drawing (a Mailchimp signup in a pop-up's box), on the
266
+ * site and in the editor alike: its drawing (`View`, given its view and the entry's own button to show where it wants)
267
+ * and what makes its view in the editor (`viewOf`, as a block's view.ts). */
268
+ export type KindPart = {
269
+ View: ComponentType<{ view: any; button: ReactNode }>;
270
+ viewOf: (values: Record<string, any>, data: BlockData) => unknown;
271
+ };
272
+
273
+ /** A list a standard block or an app brings ("Udtalelser", "Priser"), as the site's own, with its icon under "Lister". */
274
+ export type OwnedList = FolderCollection & {
275
+ icon: Icon;
276
+ /** Made-up rows, as the files have them, for the parts under "Dele" and an app's pictures for the store (examples.ts). */
277
+ examples?: Record<string, unknown>[];
278
+ };
279
+
280
+ export type DataFile = {
281
+ file: string;
282
+ label: string;
283
+ /** Where it is seen on the site. */
284
+ view: string;
285
+ fields: Field[];
286
+ /** The file is a list (the menus): this field holds it in the form. With `fields` ("Aktiveret"), the file holds
287
+ * them and the list under this field's name, and the form shows them above the list. */
288
+ root?: Field;
289
+ /** A fixed page called by its label, not its H1 (the front page). */
290
+ byLabel?: boolean;
291
+ };
292
+
293
+ /** A fixed page's name in the editor: its H1 (`heading`), as the page has it now; the front page
294
+ * (byLabel) and the about page, whose file has none, by their label. `data`: the file's content, or its text. */
295
+ export function fixedName(file: DataFile, data?: string | Record<string, unknown>): string {
296
+ if (file.byLabel) return file.label;
297
+ try {
298
+ const heading = (typeof data === 'string' ? JSON.parse(data) : data)?.heading;
299
+ return typeof heading === 'string' && heading.trim() ? heading.trim() : file.label;
300
+ } catch {
301
+ return file.label;
302
+ }
303
+ }
304
+
305
+ export type FilesCollection = Base & {
306
+ kind: 'files';
307
+ files: DataFile[];
308
+ /** Its files are pages of the site (the fixed pages): each form says when it was last saved, as a page's. */
309
+ pages?: boolean;
310
+ };
311
+
312
+ export type Collection = MarkdownCollection | FolderCollection | FilesCollection;
313
+
314
+ // The collection a file belongs to, and for single files its entry.
315
+ export function collectionOf(collections: Collection[], path: string): { collection: Collection; dataFile?: DataFile } | null {
316
+ for (const collection of collections) {
317
+ if (collection.kind === 'files') {
318
+ const dataFile = collection.files.find((f) => f.file === path);
319
+ if (dataFile) return { collection, dataFile };
320
+ } else if (path.startsWith(`${collection.folder}/`)) {
321
+ return { collection };
322
+ }
323
+ }
324
+ return null;
325
+ }
326
+
327
+ // A file's name in its folder, without .md or .json (and /index): a post's address, an entry's slug.
328
+ export const slugOf = (path: string, folder: string) => path.slice(folder.length + 1).replace(/(\/index)?\.(md|json)$/, '');
329
+
330
+ // Titles in alphabetical order, in the editor's language (Danish: æ, ø, å last), without the quotation marks and other signs
331
+ // some begin with: “Livet med og efter bipolar lidelse” under L.
332
+ const sortable = (title: string) => title.replace(/^[^\p{L}\p{N}]+/u, '');
333
+ export const byText = (a: string, b: string) => sortable(a).localeCompare(sortable(b), locale);
334
+
335
+ // Addresses and file names from a title, spelled like the existing ones: æ -> ae, ø -> oe, å -> aa.
336
+ export const slugify = (title: string) =>
337
+ title
338
+ .toLowerCase()
339
+ .replace(/æ/g, 'ae')
340
+ .replace(/ø/g, 'oe')
341
+ .replace(/å/g, 'aa')
342
+ .normalize('NFKD')
343
+ .replace(/[̀-ͯ]/g, '')
344
+ .replace(/[^a-z0-9]+/g, '-')
345
+ .replace(/^-|-$/g, '');
346
+
347
+ /** A screen of the site's own with parts (PartScreen), "Virksomheden" or "Blokke" (CompanyForm.tsx): a
348
+ * part of one data file. */
349
+ export type Part = {
350
+ id: string;
351
+ label: string;
352
+ icon: Icon;
353
+ /** The fields and the file they are in, at the top level or under `at`; without them, a part is only a
354
+ * row that opens its own screen (the ones under "Udseende", Library.tsx). */
355
+ file?: string;
356
+ at?: string;
357
+ fields?: Field[];
358
+ /** The values before any are saved (a block's shared.ts). */
359
+ defaults?: Record<string, unknown>;
360
+ /** A block drawn under the fields with them as they are now (its draw, src/apps/<app>/blocks/): its type, and props
361
+ * for when no page has the block (the first one on a page is drawn). shared: always with `props`,
362
+ * as a copy that has nothing of its own (the shared buttons). variants: drawn once for each, under its
363
+ * name, always with `props` and the variant's over them (the designs of "Kort"). */
364
+ preview?: {
365
+ type: string;
366
+ props?: Record<string, unknown>;
367
+ shared?: boolean;
368
+ variants?: PreviewVariant[];
369
+ };
370
+ /** Where its row opens, when not its own screen under the one it is on (the front page under "Udseende"). */
371
+ href?: string;
372
+ /** At the end of its row, before the arrow: the theme in use, by "Temaer" under "Udseende". */
373
+ detail?: string;
374
+ /** At the end of its row, after `detail` and before the arrow: the site's primary, secondary and tertiary colours by
375
+ * "Farver" under "Udseende" (ColorSwatches). */
376
+ trailing?: ReactNode;
377
+ /** Where its screen goes back to: "Virksomheden", or "Blokke" (blockTexts.ts, site.ts). */
378
+ back?: { href: string; label: string };
379
+ /** What the commit says was edited, in the site's language, when not its name in lower case (an
380
+ * app's settings, AppList.tsx: "indstillinger for Mailchimp"). */
381
+ commit?: string;
382
+ /** Parts of its own, instead of fields: a row that opens a screen with them, each at
383
+ * #<screen>/<id>/<part> and going back to it ("Virksomheden" › "Betaling" with "Bank"). */
384
+ parts?: Part[];
385
+ /** With `parts`: the settings of the apps installed of these kinds (AppDefinition.category) come after them, each at
386
+ * #<screen>/<id>/<app> ("Betaling" with MobilePay; AppList.tsx appPartsIn). */
387
+ apps?: AppCategory[];
388
+ /** One of the editor's own lists, drawn under its fields: "keywords", every keyword of the pages, posts and fixed
389
+ * pages ("Interne links", Keywords.tsx). */
390
+ below?: 'keywords';
391
+ /** One of the editor's own screens, instead of a form: "consents", the visitors' answers in the cookie banner
392
+ * ("Samtykker" under "Privatliv", Consents.tsx). */
393
+ opens?: 'consents';
394
+ /** Its fields, which pick a page (`relation`), as the rows of a list, each opening the sheet with the pages (FieldRows):
395
+ * "Standardsider" and "Privatlivssider". */
396
+ rows?: boolean;
397
+ };
398
+
399
+ /** A part of the start screen that is a screen with parts, each a screen of its own at #<id>/<part>
400
+ * (Library.tsx PartsScreen, CompanyForm.tsx): "Privatliv" with the cookie banner and the privacy pages. With `apps`, the
401
+ * settings of the apps installed of those kinds (AppDefinition.category) come after its own parts, each at
402
+ * #<id>/<app> ("Analytics" with Google Analytics; AppList.tsx appPartsIn). */
403
+ export type PartScreen = { id: string; label: string; parts: Part[]; apps?: AppCategory[] };
404
+
405
+ /** One way a block's screen under "Blokke" draws it (Part.preview): its name and its own props. */
406
+ export type PreviewVariant = { label: string; props: Record<string, unknown> };
407
+
408
+ /** What a block on the site is given by RichText.astro (BlockSite.astro gives it to its load.ts): its props (as written in its line in the
409
+ * text), its place among the parts of the text, the page's address, whether the page is a new
410
+ * version of a page (/ny/), and its shared texts (shared.ts, with those saved over them). */
411
+ export type SiteProps<P = Record<string, any>> = {
412
+ props: P;
413
+ index: number;
414
+ path?: string;
415
+ preview?: boolean;
416
+ texts?: Record<string, any>;
417
+ };