@morphemecms/cms 0.0.0-stage → 0.1.0

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 (1106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +51 -3
  3. package/astro.d.mts +2 -0
  4. package/astro.mjs +162 -0
  5. package/bin/morpheme.mjs +38 -0
  6. package/client.d.ts +10 -0
  7. package/defaults/blockTexts.ts +33 -0
  8. package/defaults/collections.ts +774 -0
  9. package/defaults/colors.ts +125 -0
  10. package/defaults/company.ts +20 -0
  11. package/defaults/editor.ts +178 -0
  12. package/defaults/internalLinks.ts +30 -0
  13. package/defaults/opens.ts +18 -0
  14. package/defaults/popup.tsx +93 -0
  15. package/defaults/privacy.ts +79 -0
  16. package/defaults/rules.ts +450 -0
  17. package/defaults/schema.ts +16 -0
  18. package/defaults/sitedata.ts +129 -0
  19. package/defaults/standard.ts +106 -0
  20. package/defaults/standardPages.ts +87 -0
  21. package/defaults/texts.ts +481 -0
  22. package/demo/README.md +26 -0
  23. package/demo/public/apple-touch-icon.png +0 -0
  24. package/demo/public/editor/apple-touch-icon.png +0 -0
  25. package/demo/public/editor/icon-192.png +0 -0
  26. package/demo/public/editor/icon-512.png +0 -0
  27. package/demo/public/editor/icon-maskable-512.png +0 -0
  28. package/demo/public/favicon.ico +0 -0
  29. package/demo/public/favicon.svg +1 -0
  30. package/demo/public/images/uploads/2026/10/andromeda.webp +0 -0
  31. package/demo/public/images/uploads/2026/10/earth-from-space.webp +0 -0
  32. package/demo/public/images/uploads/2026/10/editor-blog.webp +0 -0
  33. package/demo/public/images/uploads/2026/10/editor-colors.webp +0 -0
  34. package/demo/public/images/uploads/2026/10/editor-home.webp +0 -0
  35. package/demo/public/images/uploads/2026/10/editor-page.webp +0 -0
  36. package/demo/public/images/uploads/2026/10/editor-pages.webp +0 -0
  37. package/demo/public/images/uploads/2026/10/editor-seo.webp +0 -0
  38. package/demo/public/images/uploads/2026/10/editor-start.webp +0 -0
  39. package/demo/public/images/uploads/2026/10/editor-themes.webp +0 -0
  40. package/demo/public/images/uploads/2026/10/moon.webp +0 -0
  41. package/demo/public/images/uploads/2026/10/saturn.webp +0 -0
  42. package/demo/public/logo.svg +1 -0
  43. package/demo/src/content/blog/build-a-page-from-blocks.md +19 -0
  44. package/demo/src/content/blog/colors-everyone-can-read.md +19 -0
  45. package/demo/src/content/blog/edit-your-website-from-your-phone.md +21 -0
  46. package/demo/src/content/blog/every-save-is-a-version.md +21 -0
  47. package/demo/src/content/blog/schedule-a-post.md +17 -0
  48. package/demo/src/content/blog/secure-from-day-one.md +17 -0
  49. package/demo/src/content/blog/seo-without-the-guesswork.md +23 -0
  50. package/demo/src/content/blog/switch-themes-without-losing-anything.md +23 -0
  51. package/demo/src/content/blog/the-app-store.md +21 -0
  52. package/demo/src/content/pages/about.md +22 -0
  53. package/demo/src/content/pages/app-store.md +30 -0
  54. package/demo/src/content/pages/blocks.md +98 -0
  55. package/demo/src/content/pages/blog-page.md +11 -0
  56. package/demo/src/content/pages/contact.md +16 -0
  57. package/demo/src/content/pages/get-started.md +20 -0
  58. package/demo/src/content/pages/home.md +26 -0
  59. package/demo/src/content/pages/page-not-found.md +11 -0
  60. package/demo/src/content/pages/privacy-policy.md +24 -0
  61. package/demo/src/data/blocks.json +25 -0
  62. package/demo/src/data/booking.json +6 -0
  63. package/demo/src/data/categories/apps.json +6 -0
  64. package/demo/src/data/categories/design.json +6 -0
  65. package/demo/src/data/categories/editing.json +6 -0
  66. package/demo/src/data/categories/security.json +6 -0
  67. package/demo/src/data/categories/seo.json +6 -0
  68. package/demo/src/data/colors.json +75 -0
  69. package/demo/src/data/contact.json +8 -0
  70. package/demo/src/data/cookies.json +21 -0
  71. package/demo/src/data/footer.json +27 -0
  72. package/demo/src/data/menu.json +35 -0
  73. package/demo/src/data/mobile-menu.json +25 -0
  74. package/demo/src/data/popups/booking-bar.json +13 -0
  75. package/demo/src/data/popups/try-the-editor.json +16 -0
  76. package/demo/src/data/standard-pages.json +8 -0
  77. package/demo/src/data/testimonials/sample-bakery.json +10 -0
  78. package/demo/src/data/testimonials/sample-clinic.json +10 -0
  79. package/demo/src/data/testimonials/sample-studio.json +10 -0
  80. package/demo/src/site/colors.ts +11 -0
  81. package/demo/src/site/config.ts +19 -0
  82. package/icons/lucide/LICENSE +43 -0
  83. package/icons/lucide/LICENSE-material-design-icons +20 -0
  84. package/icons/lucide/address-book.svg +1 -0
  85. package/icons/lucide/app-window.svg +1 -0
  86. package/icons/lucide/arrow-counter-clockwise.svg +1 -0
  87. package/icons/lucide/arrow-down.svg +1 -0
  88. package/icons/lucide/arrow-left.svg +1 -0
  89. package/icons/lucide/arrow-right.svg +1 -0
  90. package/icons/lucide/arrow-square-out.svg +1 -0
  91. package/icons/lucide/arrow-u-up-left.svg +1 -0
  92. package/icons/lucide/arrow-u-up-right.svg +1 -0
  93. package/icons/lucide/arrow-up-right.svg +1 -0
  94. package/icons/lucide/arrow-up.svg +1 -0
  95. package/icons/lucide/arrows-down-up.svg +1 -0
  96. package/icons/lucide/arrows-in-line-horizontal.svg +1 -0
  97. package/icons/lucide/arrows-out-line-horizontal.svg +1 -0
  98. package/icons/lucide/article.svg +1 -0
  99. package/icons/lucide/bank.svg +1 -0
  100. package/icons/lucide/bell.svg +1 -0
  101. package/icons/lucide/bicycle.svg +1 -0
  102. package/icons/lucide/binoculars.svg +1 -0
  103. package/icons/lucide/book-open-text.svg +1 -0
  104. package/icons/lucide/book-open.svg +1 -0
  105. package/icons/lucide/browser.svg +1 -0
  106. package/icons/lucide/buildings.svg +1 -0
  107. package/icons/lucide/bus.svg +1 -0
  108. package/icons/lucide/calendar-blank.svg +1 -0
  109. package/icons/lucide/calendar-check.svg +1 -0
  110. package/icons/lucide/car.svg +1 -0
  111. package/icons/lucide/cards.svg +1 -0
  112. package/icons/lucide/caret-down.svg +1 -0
  113. package/icons/lucide/caret-left.svg +1 -0
  114. package/icons/lucide/caret-right.svg +1 -0
  115. package/icons/lucide/caret-up.svg +1 -0
  116. package/icons/lucide/certificate.svg +1 -0
  117. package/icons/lucide/chart-line-up.svg +1 -0
  118. package/icons/lucide/chats.svg +1 -0
  119. package/icons/lucide/check-circle.svg +1 -0
  120. package/icons/lucide/check.svg +1 -0
  121. package/icons/lucide/circle-half.svg +1 -0
  122. package/icons/lucide/circle.svg +1 -0
  123. package/icons/lucide/clock-counter-clockwise.svg +1 -0
  124. package/icons/lucide/clock.svg +1 -0
  125. package/icons/lucide/code.svg +1 -0
  126. package/icons/lucide/coffee.svg +1 -0
  127. package/icons/lucide/columns.svg +1 -0
  128. package/icons/lucide/cookie.svg +1 -0
  129. package/icons/lucide/copy.svg +1 -0
  130. package/icons/lucide/credit-card.svg +1 -0
  131. package/icons/lucide/currency-circle-dollar.svg +1 -0
  132. package/icons/lucide/cursor-click.svg +1 -0
  133. package/icons/lucide/database.svg +1 -0
  134. package/icons/lucide/desktop.svg +1 -0
  135. package/icons/lucide/device-mobile.svg +1 -0
  136. package/icons/lucide/door-open.svg +1 -0
  137. package/icons/lucide/download-simple.svg +1 -0
  138. package/icons/lucide/envelope-simple.svg +1 -0
  139. package/icons/lucide/eye-slash.svg +1 -0
  140. package/icons/lucide/eye.svg +1 -0
  141. package/icons/lucide/file-pdf.svg +1 -0
  142. package/icons/lucide/file-text.svg +1 -0
  143. package/icons/lucide/file-video.svg +1 -0
  144. package/icons/lucide/file-zip.svg +1 -0
  145. package/icons/lucide/flower-lotus.svg +1 -0
  146. package/icons/lucide/folder-simple.svg +1 -0
  147. package/icons/lucide/funnel.svg +1 -0
  148. package/icons/lucide/gauge.svg +1 -0
  149. package/icons/lucide/gear.svg +1 -0
  150. package/icons/lucide/github-logo.svg +1 -0
  151. package/icons/lucide/globe.svg +1 -0
  152. package/icons/lucide/google-logo.svg +1 -0
  153. package/icons/lucide/graduation-cap.svg +1 -0
  154. package/icons/lucide/hammer.svg +1 -0
  155. package/icons/lucide/hand-heart.svg +1 -0
  156. package/icons/lucide/handshake.svg +1 -0
  157. package/icons/lucide/hard-drives.svg +1 -0
  158. package/icons/lucide/heart.svg +1 -0
  159. package/icons/lucide/house.svg +1 -0
  160. package/icons/lucide/image-square.svg +1 -0
  161. package/icons/lucide/image.svg +1 -0
  162. package/icons/lucide/info.svg +1 -0
  163. package/icons/lucide/keyboard.svg +1 -0
  164. package/icons/lucide/leaf.svg +1 -0
  165. package/icons/lucide/lifebuoy.svg +1 -0
  166. package/icons/lucide/lightbulb.svg +1 -0
  167. package/icons/lucide/link-break.svg +1 -0
  168. package/icons/lucide/link-simple.svg +1 -0
  169. package/icons/lucide/list-bullets.svg +1 -0
  170. package/icons/lucide/list-checks.svg +1 -0
  171. package/icons/lucide/list-numbers.svg +1 -0
  172. package/icons/lucide/list.svg +1 -0
  173. package/icons/lucide/lock-simple-open.svg +1 -0
  174. package/icons/lucide/lock-simple.svg +1 -0
  175. package/icons/lucide/magnifying-glass.svg +1 -0
  176. package/icons/lucide/map-pin.svg +1 -0
  177. package/icons/lucide/map-trifold.svg +1 -0
  178. package/icons/lucide/medal.svg +1 -0
  179. package/icons/lucide/megaphone.svg +1 -0
  180. package/icons/lucide/minus.svg +1 -0
  181. package/icons/lucide/moon.svg +1 -0
  182. package/icons/lucide/newspaper.svg +1 -0
  183. package/icons/lucide/pack.json +23 -0
  184. package/icons/lucide/paint-brush-broad.svg +1 -0
  185. package/icons/lucide/palette.svg +1 -0
  186. package/icons/lucide/paper-plane-tilt.svg +1 -0
  187. package/icons/lucide/pencil-simple.svg +1 -0
  188. package/icons/lucide/phone.svg +1 -0
  189. package/icons/lucide/play-fill.svg +1 -0
  190. package/icons/lucide/plus.svg +1 -0
  191. package/icons/lucide/prohibit.svg +1 -0
  192. package/icons/lucide/puzzle-piece.svg +1 -0
  193. package/icons/lucide/question.svg +1 -0
  194. package/icons/lucide/quotes.svg +1 -0
  195. package/icons/lucide/rows.svg +1 -0
  196. package/icons/lucide/ruler.svg +1 -0
  197. package/icons/lucide/scan.svg +1 -0
  198. package/icons/lucide/shapes.svg +1 -0
  199. package/icons/lucide/share-network.svg +1 -0
  200. package/icons/lucide/shield-check.svg +1 -0
  201. package/icons/lucide/sidebar-simple.svg +1 -0
  202. package/icons/lucide/sign-out.svg +1 -0
  203. package/icons/lucide/signpost.svg +1 -0
  204. package/icons/lucide/sliders-horizontal.svg +1 -0
  205. package/icons/lucide/smiley.svg +1 -0
  206. package/icons/lucide/sparkle.svg +1 -0
  207. package/icons/lucide/square-half-bottom.svg +1 -0
  208. package/icons/lucide/square.svg +1 -0
  209. package/icons/lucide/squares-four.svg +1 -0
  210. package/icons/lucide/sticker.svg +1 -0
  211. package/icons/lucide/storefront.svg +1 -0
  212. package/icons/lucide/sun.svg +1 -0
  213. package/icons/lucide/swatches.svg +1 -0
  214. package/icons/lucide/tag.svg +1 -0
  215. package/icons/lucide/text-aa.svg +1 -0
  216. package/icons/lucide/text-align-left.svg +1 -0
  217. package/icons/lucide/text-b.svg +1 -0
  218. package/icons/lucide/text-h-one.svg +1 -0
  219. package/icons/lucide/text-h-three.svg +1 -0
  220. package/icons/lucide/text-h-two.svg +1 -0
  221. package/icons/lucide/text-italic.svg +1 -0
  222. package/icons/lucide/text-t.svg +1 -0
  223. package/icons/lucide/ticket.svg +1 -0
  224. package/icons/lucide/toggle-right.svg +1 -0
  225. package/icons/lucide/train.svg +1 -0
  226. package/icons/lucide/trash.svg +1 -0
  227. package/icons/lucide/upload-simple.svg +1 -0
  228. package/icons/lucide/user-circle.svg +1 -0
  229. package/icons/lucide/user.svg +1 -0
  230. package/icons/lucide/users-three.svg +1 -0
  231. package/icons/lucide/users.svg +1 -0
  232. package/icons/lucide/video-camera.svg +1 -0
  233. package/icons/lucide/warning-circle.svg +1 -0
  234. package/icons/lucide/warning.svg +1 -0
  235. package/icons/lucide/wave-sine.svg +1 -0
  236. package/icons/lucide/wheelchair.svg +1 -0
  237. package/icons/lucide/wrench.svg +1 -0
  238. package/icons/lucide/x.svg +1 -0
  239. package/icons/material-symbols/LICENSE +201 -0
  240. package/icons/material-symbols/LICENSE-material-design-icons +20 -0
  241. package/icons/material-symbols/address-book.svg +1 -0
  242. package/icons/material-symbols/app-window.svg +1 -0
  243. package/icons/material-symbols/arrow-counter-clockwise.svg +1 -0
  244. package/icons/material-symbols/arrow-down.svg +1 -0
  245. package/icons/material-symbols/arrow-left.svg +1 -0
  246. package/icons/material-symbols/arrow-right.svg +1 -0
  247. package/icons/material-symbols/arrow-square-out.svg +1 -0
  248. package/icons/material-symbols/arrow-u-up-left.svg +1 -0
  249. package/icons/material-symbols/arrow-u-up-right.svg +1 -0
  250. package/icons/material-symbols/arrow-up-right.svg +1 -0
  251. package/icons/material-symbols/arrow-up.svg +1 -0
  252. package/icons/material-symbols/arrows-down-up.svg +1 -0
  253. package/icons/material-symbols/arrows-in-line-horizontal.svg +1 -0
  254. package/icons/material-symbols/arrows-out-line-horizontal.svg +1 -0
  255. package/icons/material-symbols/article.svg +1 -0
  256. package/icons/material-symbols/bank.svg +1 -0
  257. package/icons/material-symbols/bell.svg +1 -0
  258. package/icons/material-symbols/bicycle.svg +1 -0
  259. package/icons/material-symbols/binoculars.svg +1 -0
  260. package/icons/material-symbols/book-open-text.svg +1 -0
  261. package/icons/material-symbols/book-open.svg +1 -0
  262. package/icons/material-symbols/browser.svg +1 -0
  263. package/icons/material-symbols/buildings.svg +1 -0
  264. package/icons/material-symbols/bus.svg +1 -0
  265. package/icons/material-symbols/calendar-blank.svg +1 -0
  266. package/icons/material-symbols/calendar-check.svg +1 -0
  267. package/icons/material-symbols/car.svg +1 -0
  268. package/icons/material-symbols/cards.svg +1 -0
  269. package/icons/material-symbols/caret-down.svg +1 -0
  270. package/icons/material-symbols/caret-left.svg +1 -0
  271. package/icons/material-symbols/caret-right.svg +1 -0
  272. package/icons/material-symbols/caret-up.svg +1 -0
  273. package/icons/material-symbols/certificate.svg +1 -0
  274. package/icons/material-symbols/chart-line-up.svg +1 -0
  275. package/icons/material-symbols/chats.svg +1 -0
  276. package/icons/material-symbols/check-circle.svg +1 -0
  277. package/icons/material-symbols/check.svg +1 -0
  278. package/icons/material-symbols/circle-half.svg +1 -0
  279. package/icons/material-symbols/circle.svg +1 -0
  280. package/icons/material-symbols/clock-counter-clockwise.svg +1 -0
  281. package/icons/material-symbols/clock.svg +1 -0
  282. package/icons/material-symbols/code.svg +1 -0
  283. package/icons/material-symbols/coffee.svg +1 -0
  284. package/icons/material-symbols/columns.svg +1 -0
  285. package/icons/material-symbols/cookie.svg +1 -0
  286. package/icons/material-symbols/copy.svg +1 -0
  287. package/icons/material-symbols/credit-card.svg +1 -0
  288. package/icons/material-symbols/currency-circle-dollar.svg +1 -0
  289. package/icons/material-symbols/cursor-click.svg +1 -0
  290. package/icons/material-symbols/database.svg +1 -0
  291. package/icons/material-symbols/desktop.svg +1 -0
  292. package/icons/material-symbols/device-mobile.svg +1 -0
  293. package/icons/material-symbols/door-open.svg +1 -0
  294. package/icons/material-symbols/download-simple.svg +1 -0
  295. package/icons/material-symbols/envelope-simple.svg +1 -0
  296. package/icons/material-symbols/eye-slash.svg +1 -0
  297. package/icons/material-symbols/eye.svg +1 -0
  298. package/icons/material-symbols/file-pdf.svg +1 -0
  299. package/icons/material-symbols/file-text.svg +1 -0
  300. package/icons/material-symbols/file-video.svg +1 -0
  301. package/icons/material-symbols/file-zip.svg +1 -0
  302. package/icons/material-symbols/flower-lotus.svg +1 -0
  303. package/icons/material-symbols/folder-simple.svg +1 -0
  304. package/icons/material-symbols/funnel.svg +1 -0
  305. package/icons/material-symbols/gauge.svg +1 -0
  306. package/icons/material-symbols/gear.svg +1 -0
  307. package/icons/material-symbols/github-logo.svg +1 -0
  308. package/icons/material-symbols/globe.svg +1 -0
  309. package/icons/material-symbols/google-logo.svg +1 -0
  310. package/icons/material-symbols/graduation-cap.svg +1 -0
  311. package/icons/material-symbols/hammer.svg +1 -0
  312. package/icons/material-symbols/hand-heart.svg +1 -0
  313. package/icons/material-symbols/handshake.svg +1 -0
  314. package/icons/material-symbols/hard-drives.svg +1 -0
  315. package/icons/material-symbols/heart.svg +1 -0
  316. package/icons/material-symbols/house.svg +1 -0
  317. package/icons/material-symbols/image-square.svg +1 -0
  318. package/icons/material-symbols/image.svg +1 -0
  319. package/icons/material-symbols/info.svg +1 -0
  320. package/icons/material-symbols/keyboard.svg +1 -0
  321. package/icons/material-symbols/leaf.svg +1 -0
  322. package/icons/material-symbols/lifebuoy.svg +1 -0
  323. package/icons/material-symbols/lightbulb.svg +1 -0
  324. package/icons/material-symbols/link-break.svg +1 -0
  325. package/icons/material-symbols/link-simple.svg +1 -0
  326. package/icons/material-symbols/list-bullets.svg +1 -0
  327. package/icons/material-symbols/list-checks.svg +1 -0
  328. package/icons/material-symbols/list-numbers.svg +1 -0
  329. package/icons/material-symbols/list.svg +1 -0
  330. package/icons/material-symbols/lock-simple-open.svg +1 -0
  331. package/icons/material-symbols/lock-simple.svg +1 -0
  332. package/icons/material-symbols/magnifying-glass.svg +1 -0
  333. package/icons/material-symbols/map-pin.svg +1 -0
  334. package/icons/material-symbols/map-trifold.svg +1 -0
  335. package/icons/material-symbols/medal.svg +1 -0
  336. package/icons/material-symbols/megaphone.svg +1 -0
  337. package/icons/material-symbols/minus.svg +1 -0
  338. package/icons/material-symbols/moon.svg +1 -0
  339. package/icons/material-symbols/newspaper.svg +1 -0
  340. package/icons/material-symbols/pack.json +29 -0
  341. package/icons/material-symbols/paint-brush-broad.svg +1 -0
  342. package/icons/material-symbols/palette.svg +1 -0
  343. package/icons/material-symbols/paper-plane-tilt.svg +1 -0
  344. package/icons/material-symbols/pencil-simple.svg +1 -0
  345. package/icons/material-symbols/phone.svg +1 -0
  346. package/icons/material-symbols/play-fill.svg +1 -0
  347. package/icons/material-symbols/plus.svg +1 -0
  348. package/icons/material-symbols/prohibit.svg +1 -0
  349. package/icons/material-symbols/puzzle-piece.svg +1 -0
  350. package/icons/material-symbols/question.svg +1 -0
  351. package/icons/material-symbols/quotes.svg +1 -0
  352. package/icons/material-symbols/rows.svg +1 -0
  353. package/icons/material-symbols/ruler.svg +1 -0
  354. package/icons/material-symbols/scan.svg +1 -0
  355. package/icons/material-symbols/shapes.svg +1 -0
  356. package/icons/material-symbols/share-network.svg +1 -0
  357. package/icons/material-symbols/shield-check.svg +1 -0
  358. package/icons/material-symbols/sidebar-simple.svg +1 -0
  359. package/icons/material-symbols/sign-out.svg +1 -0
  360. package/icons/material-symbols/signpost.svg +1 -0
  361. package/icons/material-symbols/sliders-horizontal.svg +1 -0
  362. package/icons/material-symbols/smiley.svg +1 -0
  363. package/icons/material-symbols/sparkle.svg +1 -0
  364. package/icons/material-symbols/square-half-bottom.svg +1 -0
  365. package/icons/material-symbols/square.svg +1 -0
  366. package/icons/material-symbols/squares-four.svg +1 -0
  367. package/icons/material-symbols/sticker.svg +1 -0
  368. package/icons/material-symbols/storefront.svg +1 -0
  369. package/icons/material-symbols/sun.svg +1 -0
  370. package/icons/material-symbols/swatches.svg +1 -0
  371. package/icons/material-symbols/tag.svg +1 -0
  372. package/icons/material-symbols/text-aa.svg +1 -0
  373. package/icons/material-symbols/text-align-left.svg +1 -0
  374. package/icons/material-symbols/text-b.svg +1 -0
  375. package/icons/material-symbols/text-h-one.svg +1 -0
  376. package/icons/material-symbols/text-h-three.svg +1 -0
  377. package/icons/material-symbols/text-h-two.svg +1 -0
  378. package/icons/material-symbols/text-italic.svg +1 -0
  379. package/icons/material-symbols/text-t.svg +1 -0
  380. package/icons/material-symbols/ticket.svg +1 -0
  381. package/icons/material-symbols/toggle-right.svg +1 -0
  382. package/icons/material-symbols/train.svg +1 -0
  383. package/icons/material-symbols/trash.svg +1 -0
  384. package/icons/material-symbols/upload-simple.svg +1 -0
  385. package/icons/material-symbols/user-circle.svg +1 -0
  386. package/icons/material-symbols/user.svg +1 -0
  387. package/icons/material-symbols/users-three.svg +1 -0
  388. package/icons/material-symbols/users.svg +1 -0
  389. package/icons/material-symbols/video-camera.svg +1 -0
  390. package/icons/material-symbols/warning-circle.svg +1 -0
  391. package/icons/material-symbols/warning.svg +1 -0
  392. package/icons/material-symbols/wave-sine.svg +1 -0
  393. package/icons/material-symbols/wheelchair.svg +1 -0
  394. package/icons/material-symbols/wrench.svg +1 -0
  395. package/icons/material-symbols/x.svg +1 -0
  396. package/icons/phosphor/LICENSE +21 -0
  397. package/icons/phosphor/address-book.svg +1 -0
  398. package/icons/phosphor/app-window.svg +1 -0
  399. package/icons/phosphor/arrow-counter-clockwise.svg +1 -0
  400. package/icons/phosphor/arrow-down.svg +1 -0
  401. package/icons/phosphor/arrow-left.svg +1 -0
  402. package/icons/phosphor/arrow-right.svg +1 -0
  403. package/icons/phosphor/arrow-square-out.svg +1 -0
  404. package/icons/phosphor/arrow-u-up-left.svg +1 -0
  405. package/icons/phosphor/arrow-u-up-right.svg +1 -0
  406. package/icons/phosphor/arrow-up-right.svg +1 -0
  407. package/icons/phosphor/arrow-up.svg +1 -0
  408. package/icons/phosphor/arrows-down-up.svg +1 -0
  409. package/icons/phosphor/arrows-in-line-horizontal.svg +1 -0
  410. package/icons/phosphor/arrows-out-line-horizontal.svg +1 -0
  411. package/icons/phosphor/article.svg +1 -0
  412. package/icons/phosphor/bank.svg +1 -0
  413. package/icons/phosphor/bell.svg +1 -0
  414. package/icons/phosphor/bicycle.svg +1 -0
  415. package/icons/phosphor/binoculars.svg +1 -0
  416. package/icons/phosphor/book-open-text.svg +1 -0
  417. package/icons/phosphor/book-open.svg +1 -0
  418. package/icons/phosphor/browser.svg +1 -0
  419. package/icons/phosphor/buildings.svg +1 -0
  420. package/icons/phosphor/bus.svg +1 -0
  421. package/icons/phosphor/calendar-blank.svg +1 -0
  422. package/icons/phosphor/calendar-check.svg +1 -0
  423. package/icons/phosphor/car.svg +1 -0
  424. package/icons/phosphor/cards.svg +1 -0
  425. package/icons/phosphor/caret-down.svg +1 -0
  426. package/icons/phosphor/caret-left.svg +1 -0
  427. package/icons/phosphor/caret-right.svg +1 -0
  428. package/icons/phosphor/caret-up.svg +1 -0
  429. package/icons/phosphor/certificate.svg +1 -0
  430. package/icons/phosphor/chart-line-up.svg +1 -0
  431. package/icons/phosphor/chats.svg +1 -0
  432. package/icons/phosphor/check-circle.svg +1 -0
  433. package/icons/phosphor/check.svg +1 -0
  434. package/icons/phosphor/circle-half.svg +1 -0
  435. package/icons/phosphor/circle.svg +1 -0
  436. package/icons/phosphor/clock-counter-clockwise.svg +1 -0
  437. package/icons/phosphor/clock.svg +1 -0
  438. package/icons/phosphor/code.svg +1 -0
  439. package/icons/phosphor/coffee.svg +1 -0
  440. package/icons/phosphor/columns.svg +1 -0
  441. package/icons/phosphor/cookie.svg +1 -0
  442. package/icons/phosphor/copy.svg +1 -0
  443. package/icons/phosphor/credit-card.svg +1 -0
  444. package/icons/phosphor/currency-circle-dollar.svg +1 -0
  445. package/icons/phosphor/cursor-click.svg +1 -0
  446. package/icons/phosphor/database.svg +1 -0
  447. package/icons/phosphor/desktop.svg +1 -0
  448. package/icons/phosphor/device-mobile.svg +1 -0
  449. package/icons/phosphor/door-open.svg +1 -0
  450. package/icons/phosphor/download-simple.svg +1 -0
  451. package/icons/phosphor/envelope-simple.svg +1 -0
  452. package/icons/phosphor/eye-slash.svg +1 -0
  453. package/icons/phosphor/eye.svg +1 -0
  454. package/icons/phosphor/file-pdf.svg +1 -0
  455. package/icons/phosphor/file-text.svg +1 -0
  456. package/icons/phosphor/file-video.svg +1 -0
  457. package/icons/phosphor/file-zip.svg +1 -0
  458. package/icons/phosphor/flower-lotus.svg +1 -0
  459. package/icons/phosphor/folder-simple.svg +1 -0
  460. package/icons/phosphor/funnel.svg +1 -0
  461. package/icons/phosphor/gauge.svg +1 -0
  462. package/icons/phosphor/gear.svg +1 -0
  463. package/icons/phosphor/github-logo.svg +1 -0
  464. package/icons/phosphor/globe.svg +1 -0
  465. package/icons/phosphor/google-logo.svg +1 -0
  466. package/icons/phosphor/graduation-cap.svg +1 -0
  467. package/icons/phosphor/hammer.svg +1 -0
  468. package/icons/phosphor/hand-heart.svg +1 -0
  469. package/icons/phosphor/handshake.svg +1 -0
  470. package/icons/phosphor/hard-drives.svg +1 -0
  471. package/icons/phosphor/heart.svg +1 -0
  472. package/icons/phosphor/house.svg +1 -0
  473. package/icons/phosphor/image-square.svg +1 -0
  474. package/icons/phosphor/image.svg +1 -0
  475. package/icons/phosphor/info.svg +1 -0
  476. package/icons/phosphor/keyboard.svg +1 -0
  477. package/icons/phosphor/leaf.svg +1 -0
  478. package/icons/phosphor/lifebuoy.svg +1 -0
  479. package/icons/phosphor/lightbulb.svg +1 -0
  480. package/icons/phosphor/link-break.svg +1 -0
  481. package/icons/phosphor/link-simple.svg +1 -0
  482. package/icons/phosphor/list-bullets.svg +1 -0
  483. package/icons/phosphor/list-checks.svg +1 -0
  484. package/icons/phosphor/list-numbers.svg +1 -0
  485. package/icons/phosphor/list.svg +1 -0
  486. package/icons/phosphor/lock-simple-open.svg +1 -0
  487. package/icons/phosphor/lock-simple.svg +1 -0
  488. package/icons/phosphor/magnifying-glass.svg +1 -0
  489. package/icons/phosphor/map-pin.svg +1 -0
  490. package/icons/phosphor/map-trifold.svg +1 -0
  491. package/icons/phosphor/medal.svg +1 -0
  492. package/icons/phosphor/megaphone.svg +1 -0
  493. package/icons/phosphor/minus.svg +1 -0
  494. package/icons/phosphor/moon.svg +1 -0
  495. package/icons/phosphor/newspaper.svg +1 -0
  496. package/icons/phosphor/pack.json +8 -0
  497. package/icons/phosphor/paint-brush-broad.svg +1 -0
  498. package/icons/phosphor/palette.svg +1 -0
  499. package/icons/phosphor/paper-plane-tilt.svg +1 -0
  500. package/icons/phosphor/pencil-simple.svg +1 -0
  501. package/icons/phosphor/phone.svg +1 -0
  502. package/icons/phosphor/play-fill.svg +1 -0
  503. package/icons/phosphor/plus.svg +1 -0
  504. package/icons/phosphor/prohibit.svg +1 -0
  505. package/icons/phosphor/puzzle-piece.svg +1 -0
  506. package/icons/phosphor/question.svg +1 -0
  507. package/icons/phosphor/quotes.svg +1 -0
  508. package/icons/phosphor/rows.svg +1 -0
  509. package/icons/phosphor/ruler.svg +1 -0
  510. package/icons/phosphor/scan.svg +1 -0
  511. package/icons/phosphor/shapes.svg +1 -0
  512. package/icons/phosphor/share-network.svg +1 -0
  513. package/icons/phosphor/shield-check.svg +1 -0
  514. package/icons/phosphor/sidebar-simple.svg +1 -0
  515. package/icons/phosphor/sign-out.svg +1 -0
  516. package/icons/phosphor/signpost.svg +1 -0
  517. package/icons/phosphor/sliders-horizontal.svg +1 -0
  518. package/icons/phosphor/smiley.svg +1 -0
  519. package/icons/phosphor/sparkle.svg +1 -0
  520. package/icons/phosphor/square-half-bottom.svg +1 -0
  521. package/icons/phosphor/square.svg +1 -0
  522. package/icons/phosphor/squares-four.svg +1 -0
  523. package/icons/phosphor/sticker.svg +1 -0
  524. package/icons/phosphor/storefront.svg +1 -0
  525. package/icons/phosphor/sun.svg +1 -0
  526. package/icons/phosphor/swatches.svg +1 -0
  527. package/icons/phosphor/tag.svg +1 -0
  528. package/icons/phosphor/text-aa.svg +1 -0
  529. package/icons/phosphor/text-align-left.svg +1 -0
  530. package/icons/phosphor/text-b.svg +1 -0
  531. package/icons/phosphor/text-h-one.svg +1 -0
  532. package/icons/phosphor/text-h-three.svg +1 -0
  533. package/icons/phosphor/text-h-two.svg +1 -0
  534. package/icons/phosphor/text-italic.svg +1 -0
  535. package/icons/phosphor/text-t.svg +1 -0
  536. package/icons/phosphor/ticket.svg +1 -0
  537. package/icons/phosphor/toggle-right.svg +1 -0
  538. package/icons/phosphor/train.svg +1 -0
  539. package/icons/phosphor/trash.svg +1 -0
  540. package/icons/phosphor/upload-simple.svg +1 -0
  541. package/icons/phosphor/user-circle.svg +1 -0
  542. package/icons/phosphor/user.svg +1 -0
  543. package/icons/phosphor/users-three.svg +1 -0
  544. package/icons/phosphor/users.svg +1 -0
  545. package/icons/phosphor/video-camera.svg +1 -0
  546. package/icons/phosphor/warning-circle.svg +1 -0
  547. package/icons/phosphor/warning.svg +1 -0
  548. package/icons/phosphor/wave-sine.svg +1 -0
  549. package/icons/phosphor/wheelchair.svg +1 -0
  550. package/icons/phosphor/wrench.svg +1 -0
  551. package/icons/phosphor/x.svg +1 -0
  552. package/lib/apps.d.mts +28 -0
  553. package/lib/apps.mjs +139 -0
  554. package/lib/blocks.d.mts +23 -0
  555. package/lib/blocks.mjs +90 -0
  556. package/lib/colors.ts +86 -0
  557. package/lib/contactBar.ts +18 -0
  558. package/lib/cookieCategories.d.mts +17 -0
  559. package/lib/cookieCategories.mjs +28 -0
  560. package/lib/crop.d.mts +34 -0
  561. package/lib/crop.mjs +83 -0
  562. package/lib/csp.d.mts +22 -0
  563. package/lib/csp.mjs +130 -0
  564. package/lib/cspSources.d.mts +24 -0
  565. package/lib/cspSources.mjs +60 -0
  566. package/lib/dynamic-colors.ts +426 -0
  567. package/lib/git.d.mts +24 -0
  568. package/lib/git.mjs +64 -0
  569. package/lib/hooks.ts +51 -0
  570. package/lib/inline.ts +20 -0
  571. package/lib/license-texts/Apache-2.0.txt +191 -0
  572. package/lib/license-texts/BSD-2-Clause.txt +24 -0
  573. package/lib/license-texts/BSD-3-Clause.txt +28 -0
  574. package/lib/license-texts/ISC.txt +15 -0
  575. package/lib/license-texts/MIT.txt +21 -0
  576. package/lib/licenses.d.mts +190 -0
  577. package/lib/licenses.mjs +683 -0
  578. package/lib/markdown.ts +42 -0
  579. package/lib/motion-schemes.d.mts +2 -0
  580. package/lib/motion-schemes.mjs +5 -0
  581. package/lib/motion.ts +131 -0
  582. package/lib/notice.d.mts +3 -0
  583. package/lib/notice.mjs +34 -0
  584. package/lib/scheduled.d.mts +15 -0
  585. package/lib/scheduled.mjs +37 -0
  586. package/lib/snackbar.ts +149 -0
  587. package/lib/status.d.mts +7 -0
  588. package/lib/status.mjs +18 -0
  589. package/lib/svg.d.mts +22 -0
  590. package/lib/svg.mjs +231 -0
  591. package/lib/text-colors.d.mts +11 -0
  592. package/lib/text-colors.mjs +43 -0
  593. package/lib/video-id.d.mts +14 -0
  594. package/lib/video-id.mjs +72 -0
  595. package/lib/video.d.mts +20 -0
  596. package/lib/video.mjs +91 -0
  597. package/package.json +131 -6
  598. package/pages/404.astro +10 -0
  599. package/pages/[...slug].astro +51 -0
  600. package/pages/_headers.txt +31 -0
  601. package/pages/blog/index.astro +10 -0
  602. package/pages/blog/kategori/[category].astro +18 -0
  603. package/pages/editor/code-images.json.js +25 -0
  604. package/pages/editor/index.astro +75 -0
  605. package/pages/editor/manifest.webmanifest.js +23 -0
  606. package/pages/editor/sw.js +33 -0
  607. package/pages/editor/sw.js.js +4 -0
  608. package/pages/editor/thumbnails.json.js +21 -0
  609. package/pages/editor/version.json.js +22 -0
  610. package/pages/headers.js +4 -0
  611. package/pages/index.astro +10 -0
  612. package/pages/ny.astro +6 -0
  613. package/pages/robots.txt.js +3 -0
  614. package/pages/rss.xml.js +20 -0
  615. package/scripts/app-screenshots.mjs +164 -0
  616. package/scripts/app-workers.mjs +6 -0
  617. package/scripts/bin.mjs +12 -0
  618. package/scripts/built-site.mjs +99 -0
  619. package/scripts/check-consent.mjs +113 -0
  620. package/scripts/check-content.mjs +149 -0
  621. package/scripts/check-demo.mjs +24 -0
  622. package/scripts/check-themes.mjs +45 -0
  623. package/scripts/check-worker.mjs +569 -0
  624. package/scripts/compare-html.mjs +81 -0
  625. package/scripts/demo-site.mjs +42 -0
  626. package/scripts/editor-icons.mjs +56 -0
  627. package/scripts/editor-roundtrip.mjs +134 -0
  628. package/scripts/editor-screens.mjs +101 -0
  629. package/scripts/git-env.mjs +9 -0
  630. package/scripts/icon-packs.mjs +151 -0
  631. package/scripts/link-counts.mjs +22 -0
  632. package/scripts/page-colors.mjs +42 -0
  633. package/scripts/releases.d.mts +10 -0
  634. package/scripts/releases.mjs +80 -0
  635. package/scripts/responsive-images.mjs +94 -0
  636. package/scripts/scheduled-list.mjs +15 -0
  637. package/scripts/theme-screenshots.mjs +88 -0
  638. package/scripts/types.mjs +21 -0
  639. package/scripts/video-thumbnails.mjs +89 -0
  640. package/scripts/worker-modules.mjs +34 -0
  641. package/site/appCookies.d.mts +9 -0
  642. package/site/appCookies.mjs +74 -0
  643. package/site/apps.ts +21 -0
  644. package/site/autolinks.d.mts +11 -0
  645. package/site/autolinks.mjs +200 -0
  646. package/site/blockScripts.ts +31 -0
  647. package/site/categories.ts +16 -0
  648. package/site/consent.ts +26 -0
  649. package/site/content.config.ts +84 -0
  650. package/site/content.ts +104 -0
  651. package/site/cookieList.ts +17 -0
  652. package/site/defineSite.d.mts +142 -0
  653. package/site/defineSite.mjs +136 -0
  654. package/site/directives/interact.d.mts +2 -0
  655. package/site/directives/interact.mjs +31 -0
  656. package/site/editor-version.d.mts +1 -0
  657. package/site/editor-version.mjs +26 -0
  658. package/site/fill.ts +13 -0
  659. package/site/format.ts +11 -0
  660. package/site/home.ts +66 -0
  661. package/site/iconPacks.d.mts +20 -0
  662. package/site/iconPacks.mjs +43 -0
  663. package/site/icons.d.mts +693 -0
  664. package/site/icons.mjs +605 -0
  665. package/site/images.d.mts +43 -0
  666. package/site/images.mjs +157 -0
  667. package/site/motion.ts +13 -0
  668. package/site/noindex.d.mts +6 -0
  669. package/site/noindex.mjs +21 -0
  670. package/site/pageColors.ts +110 -0
  671. package/site/popups.ts +98 -0
  672. package/site/schema.ts +189 -0
  673. package/site/sections.ts +3 -0
  674. package/site/seo.ts +28 -0
  675. package/site/site.ts +76 -0
  676. package/site/siteConfig.d.mts +1 -0
  677. package/site/siteConfig.mjs +8 -0
  678. package/site/siteCsp.d.mts +10 -0
  679. package/site/siteCsp.mjs +75 -0
  680. package/site/siteModules.d.mts +7 -0
  681. package/site/siteModules.mjs +27 -0
  682. package/site/standardPages.ts +59 -0
  683. package/site/testimonials.ts +48 -0
  684. package/site/text.ts +43 -0
  685. package/site/theme.d.mts +83 -0
  686. package/site/theme.mjs +472 -0
  687. package/site/tracking.client.ts +225 -0
  688. package/site/tracking.ts +9 -0
  689. package/src/ActionParts.tsx +205 -0
  690. package/src/Advanced.tsx +152 -0
  691. package/src/App.tsx +904 -0
  692. package/src/AppList.tsx +1345 -0
  693. package/src/BlockDialog.tsx +360 -0
  694. package/src/BlockParts.tsx +652 -0
  695. package/src/BlockSettings.tsx +533 -0
  696. package/src/BrandForm.tsx +164 -0
  697. package/src/Colors.tsx +476 -0
  698. package/src/CommunicationParts.tsx +199 -0
  699. package/src/CompanyForm.tsx +209 -0
  700. package/src/Consents.tsx +175 -0
  701. package/src/ContainmentParts.tsx +185 -0
  702. package/src/Crop.tsx +152 -0
  703. package/src/DataForm.tsx +434 -0
  704. package/src/Deleted.tsx +177 -0
  705. package/src/EntryForm.tsx +740 -0
  706. package/src/FileView.tsx +30 -0
  707. package/src/FormFrame.tsx +237 -0
  708. package/src/Keywords.tsx +225 -0
  709. package/src/Library.tsx +1563 -0
  710. package/src/Licenses.tsx +336 -0
  711. package/src/LinkSheet.tsx +138 -0
  712. package/src/MarkdownEditor.tsx +1075 -0
  713. package/src/Media.tsx +677 -0
  714. package/src/NavigationParts.tsx +350 -0
  715. package/src/NavigationRestParts.tsx +247 -0
  716. package/src/Notifications.tsx +59 -0
  717. package/src/PagePicker.tsx +136 -0
  718. package/src/Parts.tsx +991 -0
  719. package/src/PartsShown.tsx +168 -0
  720. package/src/PickerParts.tsx +183 -0
  721. package/src/Redirects.tsx +450 -0
  722. package/src/Screen.tsx +184 -0
  723. package/src/SectionsField.tsx +65 -0
  724. package/src/SelectionParts.tsx +134 -0
  725. package/src/SeoScores.tsx +184 -0
  726. package/src/Sheet.tsx +35 -0
  727. package/src/ThemeStore.tsx +376 -0
  728. package/src/Tokens.tsx +346 -0
  729. package/src/Versions.tsx +214 -0
  730. package/src/addresses.ts +75 -0
  731. package/src/allIcons.ts +7 -0
  732. package/src/appFiles.ts +29 -0
  733. package/src/apps.ts +281 -0
  734. package/src/ask.tsx +123 -0
  735. package/src/blocks.ts +251 -0
  736. package/src/brand.ts +153 -0
  737. package/src/cache.ts +42 -0
  738. package/src/check.ts +285 -0
  739. package/src/checkSite.ts +256 -0
  740. package/src/consents.ts +26 -0
  741. package/src/cookieList.ts +70 -0
  742. package/src/countries.ts +59 -0
  743. package/src/deploy.ts +155 -0
  744. package/src/editor.css +602 -0
  745. package/src/examples.ts +85 -0
  746. package/src/fields.tsx +942 -0
  747. package/src/frontmatter.d.mts +6 -0
  748. package/src/frontmatter.mjs +42 -0
  749. package/src/github.ts +376 -0
  750. package/src/i18n/da-DK/advanced.ts +28 -0
  751. package/src/i18n/da-DK/app.ts +71 -0
  752. package/src/i18n/da-DK/apps.ts +90 -0
  753. package/src/i18n/da-DK/blockSettings.ts +38 -0
  754. package/src/i18n/da-DK/blocks.ts +408 -0
  755. package/src/i18n/da-DK/check.ts +25 -0
  756. package/src/i18n/da-DK/colors.ts +64 -0
  757. package/src/i18n/da-DK/common.ts +118 -0
  758. package/src/i18n/da-DK/company.ts +24 -0
  759. package/src/i18n/da-DK/consents.ts +23 -0
  760. package/src/i18n/da-DK/forms.ts +116 -0
  761. package/src/i18n/da-DK/history.ts +35 -0
  762. package/src/i18n/da-DK/index.ts +49 -0
  763. package/src/i18n/da-DK/keywords.ts +19 -0
  764. package/src/i18n/da-DK/library.ts +135 -0
  765. package/src/i18n/da-DK/licenses.ts +25 -0
  766. package/src/i18n/da-DK/media.ts +79 -0
  767. package/src/i18n/da-DK/parts.ts +696 -0
  768. package/src/i18n/da-DK/preview.ts +13 -0
  769. package/src/i18n/da-DK/redirects.ts +51 -0
  770. package/src/i18n/da-DK/seo.ts +20 -0
  771. package/src/i18n/da-DK/text.ts +35 -0
  772. package/src/i18n/da-DK/theme.ts +41 -0
  773. package/src/i18n/en-US/advanced.ts +32 -0
  774. package/src/i18n/en-US/app.ts +84 -0
  775. package/src/i18n/en-US/apps.ts +134 -0
  776. package/src/i18n/en-US/blockSettings.ts +48 -0
  777. package/src/i18n/en-US/blocks.ts +441 -0
  778. package/src/i18n/en-US/check.ts +31 -0
  779. package/src/i18n/en-US/colors.ts +82 -0
  780. package/src/i18n/en-US/common.ts +144 -0
  781. package/src/i18n/en-US/company.ts +25 -0
  782. package/src/i18n/en-US/consents.ts +25 -0
  783. package/src/i18n/en-US/forms.ts +145 -0
  784. package/src/i18n/en-US/history.ts +43 -0
  785. package/src/i18n/en-US/index.ts +51 -0
  786. package/src/i18n/en-US/keywords.ts +24 -0
  787. package/src/i18n/en-US/library.ts +176 -0
  788. package/src/i18n/en-US/licenses.ts +36 -0
  789. package/src/i18n/en-US/media.ts +80 -0
  790. package/src/i18n/en-US/parts.ts +718 -0
  791. package/src/i18n/en-US/preview.ts +15 -0
  792. package/src/i18n/en-US/redirects.ts +66 -0
  793. package/src/i18n/en-US/seo.ts +26 -0
  794. package/src/i18n/en-US/text.ts +41 -0
  795. package/src/i18n/en-US/theme.ts +41 -0
  796. package/src/i18n/index.ts +124 -0
  797. package/src/icon.tsx +160 -0
  798. package/src/iconPacks.ts +89 -0
  799. package/src/images.ts +163 -0
  800. package/src/licenses.ts +79 -0
  801. package/src/markdown.d.mts +12 -0
  802. package/src/markdown.mjs +204 -0
  803. package/src/nav.ts +68 -0
  804. package/src/notFound.ts +28 -0
  805. package/src/notifications.ts +223 -0
  806. package/src/pagePreview.tsx +204 -0
  807. package/src/r2Caching.ts +55 -0
  808. package/src/redirects.ts +149 -0
  809. package/src/registry.tsx +188 -0
  810. package/src/schema.ts +417 -0
  811. package/src/sections.d.mts +45 -0
  812. package/src/sections.mjs +303 -0
  813. package/src/seo.ts +333 -0
  814. package/src/shared.ts +44 -0
  815. package/src/sidebar.ts +31 -0
  816. package/src/site.ts +317 -0
  817. package/src/standard/Block.astro +19 -0
  818. package/src/standard/BlockSite.astro +18 -0
  819. package/src/standard/accordion/index.tsx +47 -0
  820. package/src/standard/accordion/load.ts +23 -0
  821. package/src/standard/accordion/shared.ts +15 -0
  822. package/src/standard/accordion/view.ts +32 -0
  823. package/src/standard/buttons/fields.ts +98 -0
  824. package/src/standard/buttons/index.tsx +23 -0
  825. package/src/standard/buttons/load.ts +34 -0
  826. package/src/standard/buttons/shared.ts +12 -0
  827. package/src/standard/buttons/view.ts +30 -0
  828. package/src/standard/cards/index.tsx +71 -0
  829. package/src/standard/cards/load.ts +17 -0
  830. package/src/standard/cards/shared.ts +27 -0
  831. package/src/standard/cards/view.ts +29 -0
  832. package/src/standard/checklist/index.tsx +27 -0
  833. package/src/standard/checklist/load.ts +5 -0
  834. package/src/standard/checklist/view.ts +13 -0
  835. package/src/standard/cookies/index.tsx +17 -0
  836. package/src/standard/cookies/list.ts +56 -0
  837. package/src/standard/cookies/load.ts +11 -0
  838. package/src/standard/cookies/shared.ts +20 -0
  839. package/src/standard/cookies/view.ts +28 -0
  840. package/src/standard/faq/index.tsx +29 -0
  841. package/src/standard/faq/load.ts +14 -0
  842. package/src/standard/faq/view.ts +21 -0
  843. package/src/standard/head.ts +23 -0
  844. package/src/standard/hero/fields.ts +48 -0
  845. package/src/standard/hero/index.tsx +57 -0
  846. package/src/standard/hero/load.ts +23 -0
  847. package/src/standard/hero/view.ts +38 -0
  848. package/src/standard/links/index.tsx +41 -0
  849. package/src/standard/links/load.ts +17 -0
  850. package/src/standard/links/view.ts +25 -0
  851. package/src/standard/list/index.tsx +50 -0
  852. package/src/standard/list/load.ts +5 -0
  853. package/src/standard/list/view.ts +18 -0
  854. package/src/standard/load.ts +7 -0
  855. package/src/standard/notice/index.tsx +30 -0
  856. package/src/standard/notice/load.ts +16 -0
  857. package/src/standard/notice/view.ts +10 -0
  858. package/src/standard/points/index.tsx +42 -0
  859. package/src/standard/points/load.ts +5 -0
  860. package/src/standard/points/view.ts +12 -0
  861. package/src/standard/posts/index.tsx +132 -0
  862. package/src/standard/posts/load.ts +36 -0
  863. package/src/standard/posts/shared.ts +21 -0
  864. package/src/standard/posts/view.ts +63 -0
  865. package/src/standard/pricecards/index.tsx +57 -0
  866. package/src/standard/pricecards/load.ts +11 -0
  867. package/src/standard/pricecards/view.ts +50 -0
  868. package/src/standard/sharedTexts.ts +6 -0
  869. package/src/standard/site.ts +124 -0
  870. package/src/standard/siteLooks.ts +19 -0
  871. package/src/standard/sites.ts +13 -0
  872. package/src/standard/steps/index.tsx +28 -0
  873. package/src/standard/steps/load.ts +5 -0
  874. package/src/standard/steps/view.ts +11 -0
  875. package/src/standard/testimonials/index.tsx +87 -0
  876. package/src/standard/testimonials/list.ts +43 -0
  877. package/src/standard/testimonials/load.ts +58 -0
  878. package/src/standard/testimonials/shared.ts +13 -0
  879. package/src/standard/testimonials/view.ts +76 -0
  880. package/src/standard/themeBlocks.ts +13 -0
  881. package/src/standard/video/index.tsx +23 -0
  882. package/src/standard/video/load.ts +10 -0
  883. package/src/standard/video/view.ts +42 -0
  884. package/src/standard/view.tsx +105 -0
  885. package/src/standard/views.ts +37 -0
  886. package/src/store.ts +499 -0
  887. package/src/theme.ts +90 -0
  888. package/src/themeUi.ts +97 -0
  889. package/src/themes.ts +91 -0
  890. package/src/ui.tsx +3402 -0
  891. package/src/virtual.d.ts +5 -0
  892. package/src/when.ts +22 -0
  893. package/starter/.githooks/pre-push +4 -0
  894. package/starter/.nvmrc +1 -0
  895. package/starter/.prettierignore +11 -0
  896. package/starter/.prettierrc.json +7 -0
  897. package/starter/README.md +26 -0
  898. package/starter/astro.config.mjs +5 -0
  899. package/starter/package.json +67 -0
  900. package/starter/public/_redirects +1 -0
  901. package/starter/public/apple-touch-icon.png +0 -0
  902. package/starter/public/editor/apple-touch-icon.png +0 -0
  903. package/starter/public/editor/icon-192.png +0 -0
  904. package/starter/public/editor/icon-512.png +0 -0
  905. package/starter/public/editor/icon-maskable-512.png +0 -0
  906. package/starter/public/favicon.ico +0 -0
  907. package/starter/public/favicon.svg +1 -0
  908. package/starter/public/logo.svg +1 -0
  909. package/starter/src/content/pages/blog.md +8 -0
  910. package/starter/src/content/pages/forside.md +9 -0
  911. package/starter/src/content/pages/kontakt.md +7 -0
  912. package/starter/src/content/pages/privatlivspolitik.md +9 -0
  913. package/starter/src/content/pages/siden-findes-ikke.md +7 -0
  914. package/starter/src/content.config.ts +2 -0
  915. package/starter/src/data/apps.json +1 -0
  916. package/starter/src/data/block-settings.json +3 -0
  917. package/starter/src/data/blocks.json +1 -0
  918. package/starter/src/data/booking.json +6 -0
  919. package/starter/src/data/colors.json +70 -0
  920. package/starter/src/data/contact.json +8 -0
  921. package/starter/src/data/cookies.json +21 -0
  922. package/starter/src/data/csp.json +1 -0
  923. package/starter/src/data/footer.json +15 -0
  924. package/starter/src/data/internal-links.json +4 -0
  925. package/starter/src/data/menu.json +4 -0
  926. package/starter/src/data/mobile-menu.json +4 -0
  927. package/starter/src/data/old-addresses.json +1 -0
  928. package/starter/src/data/redirects.json +1 -0
  929. package/starter/src/data/standard-pages.json +8 -0
  930. package/starter/src/data/theme.json +1 -0
  931. package/starter/src/env.d.ts +2 -0
  932. package/starter/src/site/config.ts +13 -0
  933. package/starter/src/site/worker.js +14 -0
  934. package/starter/tsconfig.json +17 -0
  935. package/starter/worker/apps.js +6 -0
  936. package/starter/wrangler.jsonc +39 -0
  937. package/theme/LICENSE +21 -0
  938. package/theme/blocks/ArrowLink.tsx +14 -0
  939. package/theme/blocks/BlockHead.tsx +26 -0
  940. package/theme/blocks/Panel.tsx +32 -0
  941. package/theme/blocks/Person.tsx +26 -0
  942. package/theme/blocks/accordion/PageRow.tsx +25 -0
  943. package/theme/blocks/accordion/View.tsx +17 -0
  944. package/theme/blocks/buttons/Buttons.tsx +28 -0
  945. package/theme/blocks/buttons/View.tsx +12 -0
  946. package/theme/blocks/cards/LinkCards.tsx +72 -0
  947. package/theme/blocks/cards/View.tsx +20 -0
  948. package/theme/blocks/checklist/Checks.tsx +15 -0
  949. package/theme/blocks/checklist/View.tsx +14 -0
  950. package/theme/blocks/cookies/View.tsx +36 -0
  951. package/theme/blocks/faq/Accordion.tsx +34 -0
  952. package/theme/blocks/faq/View.tsx +16 -0
  953. package/theme/blocks/faq/script.ts +56 -0
  954. package/theme/blocks/hero/View.tsx +44 -0
  955. package/theme/blocks/links/LinkGroups.tsx +24 -0
  956. package/theme/blocks/links/View.tsx +17 -0
  957. package/theme/blocks/list/Rows.tsx +24 -0
  958. package/theme/blocks/list/View.tsx +14 -0
  959. package/theme/blocks/notice/View.tsx +13 -0
  960. package/theme/blocks/points/PointList.tsx +34 -0
  961. package/theme/blocks/points/View.tsx +14 -0
  962. package/theme/blocks/posts/View.tsx +26 -0
  963. package/theme/blocks/pricecards/View.tsx +40 -0
  964. package/theme/blocks/steps/StepList.tsx +23 -0
  965. package/theme/blocks/steps/View.tsx +14 -0
  966. package/theme/blocks/testimonials/List.tsx +46 -0
  967. package/theme/blocks/testimonials/Slider.tsx +44 -0
  968. package/theme/blocks/testimonials/Testimonial.tsx +124 -0
  969. package/theme/blocks/testimonials/View.tsx +21 -0
  970. package/theme/blocks/testimonials/script.ts +52 -0
  971. package/theme/blocks/video/View.tsx +41 -0
  972. package/theme/components/ActionBar.astro +63 -0
  973. package/theme/components/AppSlot.astro +21 -0
  974. package/theme/components/ArrowLink.tsx +21 -0
  975. package/theme/components/BlogIndex.astro +48 -0
  976. package/theme/components/BlogPosts.astro +18 -0
  977. package/theme/components/BlogPosts.tsx +45 -0
  978. package/theme/components/BookButton.tsx +22 -0
  979. package/theme/components/Container.astro +11 -0
  980. package/theme/components/CookieConsent.astro +121 -0
  981. package/theme/components/EndBlock.astro +21 -0
  982. package/theme/components/FontPreload.astro +6 -0
  983. package/theme/components/Footer.astro +85 -0
  984. package/theme/components/Header.astro +186 -0
  985. package/theme/components/Icon.astro +16 -0
  986. package/theme/components/Img.astro +29 -0
  987. package/theme/components/Img.tsx +33 -0
  988. package/theme/components/Inline.astro +11 -0
  989. package/theme/components/Logo.astro +23 -0
  990. package/theme/components/LogoMark.astro +10 -0
  991. package/theme/components/Markdown.astro +17 -0
  992. package/theme/components/MobileMenu.tsx +224 -0
  993. package/theme/components/MobileNav.astro +33 -0
  994. package/theme/components/PageHeader.astro +22 -0
  995. package/theme/components/PageSection.astro +24 -0
  996. package/theme/components/PhoneButton.tsx +11 -0
  997. package/theme/components/Popup.astro +145 -0
  998. package/theme/components/PopupButton.tsx +24 -0
  999. package/theme/components/PopupView.tsx +48 -0
  1000. package/theme/components/PostList.tsx +58 -0
  1001. package/theme/components/PostMeta.tsx +17 -0
  1002. package/theme/components/RichText.astro +28 -0
  1003. package/theme/components/Section.astro +29 -0
  1004. package/theme/components/SectionHeading.tsx +8 -0
  1005. package/theme/components/TextSection.astro +16 -0
  1006. package/theme/components/home/PageBlock.astro +19 -0
  1007. package/theme/components/home/Text.astro +13 -0
  1008. package/theme/components/loadPopup.ts +22 -0
  1009. package/theme/components/loadPosts.ts +16 -0
  1010. package/theme/components/posts.ts +15 -0
  1011. package/theme/editor/looks.mjs +7 -0
  1012. package/theme/editor/previews.tsx +56 -0
  1013. package/theme/layouts/Base.astro +273 -0
  1014. package/theme/layouts/PageLayout.astro +126 -0
  1015. package/theme/layouts/PostLayout.astro +137 -0
  1016. package/theme/screenshots/1-front.jpg +0 -0
  1017. package/theme/screenshots/2-front-dark.jpg +0 -0
  1018. package/theme/screenshots/3-blog.jpg +0 -0
  1019. package/theme/screenshots/4-contact.jpg +0 -0
  1020. package/theme/scripts/motion.ts +29 -0
  1021. package/theme/styles/base.css +320 -0
  1022. package/theme/styles/blocks.css +1808 -0
  1023. package/theme/styles/components.css +206 -0
  1024. package/theme/styles/global.css +1302 -0
  1025. package/theme/styles/ui.css +6544 -0
  1026. package/theme/templates/Blog.astro +38 -0
  1027. package/theme/templates/Category.astro +19 -0
  1028. package/theme/templates/Home.astro +36 -0
  1029. package/theme/templates/New.astro +68 -0
  1030. package/theme/templates/NotFound.astro +117 -0
  1031. package/theme/theme.json +28 -0
  1032. package/theme/ui/Badge.tsx +45 -0
  1033. package/theme/ui/BottomSheet.tsx +148 -0
  1034. package/theme/ui/Button.tsx +79 -0
  1035. package/theme/ui/ButtonGroup.tsx +31 -0
  1036. package/theme/ui/Card.tsx +45 -0
  1037. package/theme/ui/Carousel.tsx +124 -0
  1038. package/theme/ui/Checkbox.tsx +59 -0
  1039. package/theme/ui/Chip.tsx +101 -0
  1040. package/theme/ui/ChipSet.tsx +27 -0
  1041. package/theme/ui/DatePicker.tsx +149 -0
  1042. package/theme/ui/DatePickerContainer.tsx +316 -0
  1043. package/theme/ui/Dialog.tsx +100 -0
  1044. package/theme/ui/Divider.tsx +27 -0
  1045. package/theme/ui/ExposedDropdownMenu.tsx +77 -0
  1046. package/theme/ui/Fab.tsx +88 -0
  1047. package/theme/ui/FabMenu.tsx +67 -0
  1048. package/theme/ui/IconButton.tsx +78 -0
  1049. package/theme/ui/List.tsx +287 -0
  1050. package/theme/ui/LoadingIndicator.tsx +29 -0
  1051. package/theme/ui/Menu.tsx +278 -0
  1052. package/theme/ui/NavigationBar.tsx +62 -0
  1053. package/theme/ui/NavigationDrawer.tsx +80 -0
  1054. package/theme/ui/NavigationRail.tsx +154 -0
  1055. package/theme/ui/ProgressIndicator.tsx +162 -0
  1056. package/theme/ui/RadioButton.tsx +50 -0
  1057. package/theme/ui/Search.tsx +129 -0
  1058. package/theme/ui/SegmentedButton.tsx +49 -0
  1059. package/theme/ui/SideSheet.tsx +54 -0
  1060. package/theme/ui/Slider.tsx +155 -0
  1061. package/theme/ui/Snackbar.tsx +67 -0
  1062. package/theme/ui/SplitButton.tsx +67 -0
  1063. package/theme/ui/Switch.tsx +60 -0
  1064. package/theme/ui/Tabs.tsx +114 -0
  1065. package/theme/ui/TextField.tsx +278 -0
  1066. package/theme/ui/TimePicker.tsx +128 -0
  1067. package/theme/ui/TimePickerContainer.tsx +234 -0
  1068. package/theme/ui/Toolbar.tsx +67 -0
  1069. package/theme/ui/Tooltip.tsx +58 -0
  1070. package/theme/ui/TopAppBar.tsx +77 -0
  1071. package/theme/ui/bottomSheet.script.ts +8 -0
  1072. package/theme/ui/bottomSheet.ts +211 -0
  1073. package/theme/ui/carousel.script.ts +28 -0
  1074. package/theme/ui/carouselLayout.ts +229 -0
  1075. package/theme/ui/checkbox.script.ts +8 -0
  1076. package/theme/ui/datePicker.script.ts +302 -0
  1077. package/theme/ui/dates.ts +185 -0
  1078. package/theme/ui/dialog.ts +48 -0
  1079. package/theme/ui/dropdownMenu.script.ts +166 -0
  1080. package/theme/ui/fabMenu.script.ts +57 -0
  1081. package/theme/ui/navigationRail.script.ts +47 -0
  1082. package/theme/ui/ripple.script.ts +159 -0
  1083. package/theme/ui/search.script.ts +92 -0
  1084. package/theme/ui/sideSheet.ts +48 -0
  1085. package/theme/ui/slider.script.ts +12 -0
  1086. package/theme/ui/sliderUpdate.ts +52 -0
  1087. package/theme/ui/snackbar.script.ts +16 -0
  1088. package/theme/ui/splitButton.script.ts +63 -0
  1089. package/theme/ui/tabs.script.ts +48 -0
  1090. package/theme/ui/textField.script.ts +17 -0
  1091. package/theme/ui/textFieldUpdate.ts +44 -0
  1092. package/theme/ui/timePicker.script.ts +248 -0
  1093. package/theme/ui/toolbar.script.ts +43 -0
  1094. package/theme/ui/tooltip.script.ts +68 -0
  1095. package/worker/consent.js +141 -0
  1096. package/worker/editor-github.js +167 -0
  1097. package/worker/editor-host.js +74 -0
  1098. package/worker/files.js +401 -0
  1099. package/worker/github.js +36 -0
  1100. package/worker/index.js +184 -0
  1101. package/worker/not-found.js +97 -0
  1102. package/worker/oauth.js +95 -0
  1103. package/worker/publish.js +52 -0
  1104. package/worker/push.js +270 -0
  1105. package/worker/r2-status.js +50 -0
  1106. package/worker/session.js +58 -0
package/src/store.ts ADDED
@@ -0,0 +1,499 @@
1
+ // The app store ("Indstillinger" › "Appstore", #indstillinger/appstore, AppList.tsx): the apps that are not in the site
2
+ // and can be installed. The store is a GitHub repository (config.store) with a catalog (catalog.json): each app with
3
+ // its id, its version and the version of the contract it is written to (APP_API), its name, who made it, its icon
4
+ // (Phosphor's name), what it does (in a sentence, and more fully), its category and the words it is found by, what it
5
+ // adds (its blocks, the lists it brings and its kinds of the site's lists), what it needs (needsOf), the cookies it
6
+ // sets, its pictures, what is new in each version (its release notes), its texts in the editor's other languages (as an app's texts.ts), its
7
+ // licence and those of the third-party work it brings (StoreLicenses), and where its folder is in the
8
+ // repository at which commit, file by file with their blob ids.
9
+ // Installing one copies its folder into the site's (config.apps.folder/<id>/, at that commit, each file checked
10
+ // against its id), with a note of where it came from (store.json, StoreRecord), and puts it among the apps installed,
11
+ // in one commit (appChanges); the site's next build has it. Updating copies the newer version over it, and
12
+ // uninstalling deletes the folder, also in one commit each. What was made with it (its settings, its entries) is the
13
+ // site's data and stays.
14
+ // The store has themes too (`themes` in the catalog): each with its id, its version and the version of the contract it
15
+ // is written to (THEME_API), its name, who made it, its picture, what it is and gives the site, its pictures of a site
16
+ // in it, and its folder file by file. Installing one copies its folder into the site's themes (config.themes/<id>/,
17
+ // with its store.json), and it can then be chosen under "Udseende" › "Temaer"; updating and uninstalling are as for
18
+ // an app (themeChanges), and the theme in use cannot be uninstalled.
19
+ // The catalog is what is released: an app's or a theme's entry is written from its folder by `npm run store:release
20
+ // -- <id>` (scripts/store-release.mjs) when the owner releases it, not by each merge (packages/editor/scripts/releases.mjs). Until the real store exists, it is this repository's own (store/catalog.json, with the apps' folders in
21
+ // src/apps/ and the themes' in src/themes/).
22
+ import { config } from '@site/config';
23
+ import { loadBytes, loadFrom, type Change, type RepoFile } from './github';
24
+ import { locale, t } from './i18n';
25
+ import { hooksOf, type AppHook } from '../lib/hooks';
26
+ import type { StoreLicenses } from './licenses';
27
+
28
+ /** The version of the contract between the editor and an app (apps.ts: defineApp, its folder, and the theme's parts it
29
+ * draws with: the standard blocks' and the UI components, @theme/blocks/… and @theme/ui/…, imported from
30
+ * @morphemecms/cms): an app in the store says which it is written to, and only those the editor can run are
31
+ * offered. Raised when an app written to the one before no longer works. */
32
+ export const APP_API = 1;
33
+
34
+ /** The version of the contract between the editor and a theme (what a theme must and may have, "Hvad et tema må" in
35
+ * CLAUDE.md, themeProblems in packages/editor/site/theme.mjs, the standard theme's UI parts with Material 3's names and
36
+ * variants, the motion scheme's --motion-* springs and motionSpring/motionTiming (@morphemecms/cms/lib/motion),
37
+ * and the classes it styles): only themes written to it are offered. Raised when a theme written to the one before no
38
+ * longer works. */
39
+ export const THEME_API = 2;
40
+
41
+ /** The kinds of apps, a filter in the store (t.apps.categories). */
42
+ export const appCategories = ['booking', 'newsletter', 'payment', 'analytics', 'content', 'design'] as const;
43
+ export type AppCategory = (typeof appCategories)[number];
44
+
45
+ /** A file of an app in the store: its path in the app's folder and its git blob id. */
46
+ export type StoreFile = { path: string; oid: string };
47
+
48
+ /** Something an app adds, as the catalog says it (its page before it is installed): its name, icon and what it is. */
49
+ export type StoreAdd = { label: string; icon: string; hint?: string };
50
+
51
+ /** What an app needs of the site, as its folder says (needsOf): its code on every page (slots/), what it loads from
52
+ * other addresses and where its forms send to (its csp.json, by host), its own part of the site's Worker (worker.js),
53
+ * a step when the site is built (build.mjs) and what it changes of what the site does itself (hooks/,
54
+ * @morphemecms/cms/lib/hooks.ts; not in a catalog written before there were any). Shown on its page under "Rettigheder",
55
+ * before it is installed. */
56
+ export type AppNeeds = { pages: boolean; loads: string[]; sends: string[]; server: boolean; build: boolean; changes?: AppHook[] };
57
+
58
+ /** What an app needs, from the paths of the files in its folder and its csp.json. */
59
+ export function needsOf(files: string[], csp: Partial<Record<string, string[]>> = {}): AppNeeds {
60
+ const hosts = (kinds: string[]) => [...new Set(kinds.flatMap((k) => csp[k] ?? []).map((a) => a.replace(/^https:\/\//, '')))].sort();
61
+ return {
62
+ pages: files.some((f) => f.startsWith('slots/')),
63
+ loads: hosts(['script', 'style', 'img', 'connect', 'frame']),
64
+ sends: hosts(['form']),
65
+ server: files.includes('worker.js'),
66
+ build: files.includes('build.mjs'),
67
+ changes: hooksOf(files).hooks,
68
+ };
69
+ }
70
+
71
+ /** A cookie an app sets (also one a service sets in its own frame, as Calendly's), from its cookies.json, on its page
72
+ * under "Cookies": its name (`_ga`, `_ga_*`; none for those a service decides itself, only on its page), what it is
73
+ * for and how long it lasts; with a name, also who sets it and its category (lib/cookieCategories.mjs: `necessary`,
74
+ * also without a yes in the cookie banner, or one the visitor says yes to; `when` in an app from before them, categoryOf),
75
+ * for the cookie list in the cookie policy (the site's packages/editor/site/appCookies.mjs). */
76
+ export type AppCookie = { name?: string; provider?: string; purpose: string; lasts?: string; category?: string; when?: string };
77
+
78
+ /** A picture of an app in its store page, picked to give an idea of it (`screenshots` in its index.ts, as a theme's):
79
+ * what it shows (`shows`: one of its blocks, `blok:<type>`; a variant of its kind of a list, `slags:<list>:<n>`, 0
80
+ * without variants; one of its lists, `liste:<id>`; its settings, `indstillinger`, with made-up `values`, never the
81
+ * site's own; its own page, `side`) and what it says under it (`label`, an app's text). Only made-up content, never the
82
+ * site's (packages/editor/scripts/app-screenshots.mjs takes them with the examples). */
83
+ export type AppShot = { shows: string; label: string; values?: Record<string, unknown> };
84
+
85
+ /** A picture of an app as the catalog has it: its file in the app's screenshots/ and what it says under it. */
86
+ export type AppScreenshot = { file: string; label: string };
87
+
88
+ /** What an app adds, as a picture of it can show it (shotOf). */
89
+ type Shown = {
90
+ kinds?: Record<string, { variants?: unknown[] }>;
91
+ lists?: { id: string }[];
92
+ settings?: unknown;
93
+ page?: unknown;
94
+ };
95
+
96
+ /** Whether a picture shows something the app has (AppShot.shows): one of its blocks (`blocks`: their types), a variant
97
+ * of its kind of a list, one of its lists, its settings or its own page. */
98
+ export function shotOf(shows: string, app: Shown, blocks: string[]): boolean {
99
+ const [what, key = '', n] = shows.split(':');
100
+ if (what === 'blok') return blocks.includes(key);
101
+ if (what === 'slags') {
102
+ const kind = app.kinds?.[key];
103
+ return !!kind && /^\d+$/.test(n ?? '') && Number(n) < Math.max(1, kind.variants?.length ?? 0);
104
+ }
105
+ if (what === 'liste') return !!app.lists?.some((l) => l.id === key);
106
+ if (what === 'indstillinger') return !!app.settings && !key;
107
+ return what === 'side' && !!app.page && !key;
108
+ }
109
+
110
+ /** The file of an app's picture in its screenshots/, by its place among them and what it shows. */
111
+ export const shotFile = (i: number, shows: string) => `${i + 1}-${shows.replace(/:/g, '-')}.jpg`;
112
+
113
+ /** The folder of an app's pictures. */
114
+ export const SCREENSHOTS = 'screenshots';
115
+
116
+ /** An app in the store's catalog. */
117
+ export type StoreApp = {
118
+ id: string;
119
+ version: string;
120
+ api: number;
121
+ label: string;
122
+ publisher: string;
123
+ icon: string;
124
+ hint: string;
125
+ description?: string;
126
+ /** What is new in each version, by the version (AppDefinition.releaseNotes): before it is updated (notesSince). */
127
+ releaseNotes?: Record<string, string>;
128
+ category?: AppCategory;
129
+ keywords?: string[];
130
+ /** What it needs of the site; the cookies it sets, and whether it asks in the cookie banner first (AppDefinition
131
+ * .cookies); its pictures. */
132
+ needs?: AppNeeds;
133
+ /** The names of the kinds of notifications it sends (AppDefinition.notifications). */
134
+ notifies?: string[];
135
+ cookies?: AppCookie[];
136
+ consent?: boolean;
137
+ screenshots?: AppScreenshot[];
138
+ /** Its own licence and the third-party work it brings, each with its licence (its `license` and `thirdParty`; not in
139
+ * a catalog written before they were). */
140
+ licenses?: StoreLicenses;
141
+ /** Its blocks, the lists it brings and its kinds of the site's lists (by the list's id). */
142
+ adds: { blocks: StoreAdd[]; lists: StoreAdd[]; kinds: (StoreAdd & { list: string })[] };
143
+ /** Its texts in the editor's other languages, by the text as it is written. */
144
+ texts?: Partial<Record<string, Record<string, string>>>;
145
+ /** Where its folder is in the store's repository, and at which commit. */
146
+ path: string;
147
+ ref: string;
148
+ files: StoreFile[];
149
+ };
150
+
151
+ /** A theme in the store's catalog: as its theme.json has it (its texts by the editor's language), its pictures of a
152
+ * site in it (screenshots/<n>-<key>.jpg, t.library.themeShots) and where its folder is in the store's repository. */
153
+ export type StoreTheme = {
154
+ id: string;
155
+ version: string;
156
+ api: number;
157
+ name: string;
158
+ author: string;
159
+ icon: string;
160
+ description?: Record<string, string>;
161
+ highlights?: Record<string, string[]>;
162
+ /** What is new in each version, by the language and then the version, as its theme.json has it. */
163
+ releaseNotes?: Record<string, Record<string, string>>;
164
+ screenshots?: { file: string; key: string }[];
165
+ /** Its own licence and the third-party work it brings, as its theme.json declares them (not in a catalog written
166
+ * before they were). */
167
+ licenses?: StoreLicenses;
168
+ /** The icon packs it brings (its icon-packs/<id>/, with their pack.json: name, who made it, licence), installed with it
169
+ * and chosen under "Udseende" › "Ikonpakker". */
170
+ iconPacks?: { id: string; name: string; author: string; license: string }[];
171
+ path: string;
172
+ ref: string;
173
+ files: StoreFile[];
174
+ };
175
+
176
+ /** A theme of the catalog as the editor shows it: its texts in the editor's language, and its words for the search. */
177
+ export type ShownTheme = Omit<StoreTheme, 'description' | 'highlights' | 'releaseNotes'> & {
178
+ description?: string;
179
+ highlights: string[];
180
+ releaseNotes?: Record<string, string>;
181
+ words: string;
182
+ };
183
+
184
+ /** An app of the catalog as the editor shows it: its texts in the editor's language, its name as the catalog writes
185
+ * it (for the commits), and all its words in both, for the search. */
186
+ export type ShownApp = StoreApp & { written: string; words: string };
187
+
188
+ /** Where an app installed from the store came from: its version, the store's commit and its files (store.json). */
189
+ export type StoreRecord = { version: string; ref: string; files: StoreFile[] };
190
+
191
+ /** The store's address in the editor, under "Indstillinger" (its apps; its themes at STORE_THEMES), its address
192
+ * before (STORE_BEFORE, which opens it, App.tsx MOVED), and that of a developer's page (DEVELOPER_ROUTE/<slug>); no
193
+ * app can have the ids of the last two. */
194
+ export const STORE_ROUTE = 'indstillinger/appstore';
195
+ export const STORE_THEMES = 'indstillinger/appstore/temaer';
196
+ export const STORE_BEFORE = 'apps/butik';
197
+ export const DEVELOPER_ROUTE = 'apps/udvikler';
198
+
199
+ /** An app's folder in the site, and the note in it of where it came from. */
200
+ export const appFolder = (id: string) => `${config.apps.folder}/${id}`;
201
+ /** A theme's folder in the site; the standard theme's is always there. */
202
+ export const themeFolder = (id: string) => `${config.themes}/${id}`;
203
+ export const STANDARD_THEME = 'saturn';
204
+ export const RECORD = 'store.json';
205
+
206
+ /** Whether a version is newer than another ("1.10.0" than "1.9.2"). */
207
+ export function newer(a: string, b: string): boolean {
208
+ const parts = (v: string) => v.split(/[.-]/).map((n) => Number.parseInt(n, 10) || 0);
209
+ const [x, y] = [parts(a), parts(b)];
210
+ for (let i = 0; i < Math.max(x.length, y.length); i++) if ((x[i] ?? 0) !== (y[i] ?? 0)) return (x[i] ?? 0) > (y[i] ?? 0);
211
+ return false;
212
+ }
213
+
214
+ /** Whether a version has a higher first number than another ("2.0.0" than "1.9.2"): it has changes that can break
215
+ * something, so it is not updated to on its own (autoUpdate in AppList.tsx). */
216
+ export const breaking = (a: string, b: string) => (Number.parseInt(a, 10) || 0) > (Number.parseInt(b, 10) || 0);
217
+
218
+ /** What an update brings: the release notes of the versions after the one installed (`from`) up to the new one (`to`),
219
+ * the newest first. */
220
+ export function notesSince(notes: Record<string, string> | undefined, from: string, to: string): { version: string; text: string }[] {
221
+ return Object.entries(notes ?? {})
222
+ .filter(([v, text]) => isText(text) && newer(v, from) && !newer(v, to))
223
+ .sort(([a], [b]) => (newer(a, b) ? -1 : 1))
224
+ .map(([version, text]) => ({ version, text }));
225
+ }
226
+
227
+ // Release notes as the catalog has them: only texts, by their version.
228
+ const notesOf = (x: unknown) =>
229
+ x && typeof x === 'object' && !Array.isArray(x)
230
+ ? Object.fromEntries(Object.entries(x).filter((e): e is [string, string] => isText(e[1])))
231
+ : undefined;
232
+
233
+ const isText = (v: unknown): v is string => typeof v === 'string' && v.trim() !== '';
234
+ const isAdd = (v: any) => isText(v?.label) && isText(v?.icon);
235
+ const ID = /^[a-z0-9][a-z0-9-]*$/;
236
+ // A file's path in an app's folder: only within it.
237
+ const isPath = (v: unknown) => isText(v) && v.split('/').every((part) => part !== '' && part !== '.' && part !== '..');
238
+
239
+ /** Whether an entry of the catalog has what an app needs, written to the contract the editor runs, with files only in
240
+ * its own folder, and not the store's own address. */
241
+ function valid(a: any): a is StoreApp {
242
+ return (
243
+ ID.test(a?.id ?? '') &&
244
+ ![STORE_BEFORE, DEVELOPER_ROUTE].includes(`apps/${a.id}`) &&
245
+ isText(a.version) &&
246
+ a.api === APP_API &&
247
+ [a.label, a.publisher, a.icon, a.hint, a.path, a.ref].every(isText) &&
248
+ Array.isArray(a.files) &&
249
+ a.files.length > 0 &&
250
+ a.files.every((f: any) => isText(f?.oid) && isPath(f?.path) && f.path !== RECORD) &&
251
+ ['blocks', 'lists', 'kinds'].every((k) => Array.isArray(a.adds?.[k]) && a.adds[k].every(isAdd))
252
+ );
253
+ }
254
+
255
+ /** The apps in a catalog (catalog.json, as text) the editor can install, with their texts in its language. */
256
+ export function catalogApps(text: string): ShownApp[] {
257
+ let json: any;
258
+ try {
259
+ json = JSON.parse(text);
260
+ } catch {
261
+ return [];
262
+ }
263
+ const apps: unknown[] = Array.isArray(json?.apps) ? json.apps : [];
264
+ return apps.filter(valid).map((a) => {
265
+ const own = a.texts?.[locale];
266
+ const say = (s: string) => own?.[s] ?? s;
267
+ const add = <A extends StoreAdd>(x: A): A => ({ ...x, label: say(x.label), ...(x.hint ? { hint: say(x.hint) } : {}) });
268
+ const keywords = a.keywords ?? [];
269
+ return {
270
+ ...a,
271
+ label: say(a.label),
272
+ hint: say(a.hint),
273
+ ...(a.description ? { description: say(a.description) } : {}),
274
+ releaseNotes: Object.fromEntries(Object.entries(notesOf(a.releaseNotes) ?? {}).map(([v, x]) => [v, say(x)])),
275
+ keywords: keywords.map(say),
276
+ notifies: (Array.isArray(a.notifies) ? a.notifies : []).filter(isText).map(say),
277
+ cookies: (Array.isArray(a.cookies) ? a.cookies : [])
278
+ .filter((c) => isText(c?.purpose))
279
+ .map((c) => ({
280
+ ...c,
281
+ purpose: say(c.purpose),
282
+ ...(c.lasts ? { lasts: say(c.lasts) } : {}),
283
+ })),
284
+ screenshots: (Array.isArray(a.screenshots) ? a.screenshots : [])
285
+ .filter((x) => isText(x?.file) && isText(x?.label) && a.files.some((f) => f.path === `${SCREENSHOTS}/${x.file}`))
286
+ .map((x) => ({ ...x, label: say(x.label) })),
287
+ adds: { blocks: a.adds.blocks.map(add), lists: a.adds.lists.map(add), kinds: a.adds.kinds.map(add) },
288
+ written: a.label,
289
+ words: [a.label, a.hint, a.publisher, ...keywords, ...[a.label, a.hint, ...keywords].map(say)].join(' ').toLowerCase(),
290
+ };
291
+ });
292
+ }
293
+
294
+ /** Whether an entry of the catalog has what a theme needs, written to the contract the editor runs, with files only
295
+ * in its own folder; never the standard theme, which every site has. */
296
+ function validTheme(x: any): x is StoreTheme {
297
+ return (
298
+ ID.test(x?.id ?? '') &&
299
+ x.id !== STANDARD_THEME &&
300
+ x.api === THEME_API &&
301
+ [x.version, x.name, x.author, x.icon, x.path, x.ref].every(isText) &&
302
+ Array.isArray(x.files) &&
303
+ x.files.length > 0 &&
304
+ x.files.every((f: any) => isText(f?.oid) && isPath(f?.path) && f.path !== RECORD)
305
+ );
306
+ }
307
+
308
+ /** The themes in a catalog (catalog.json, as text) the editor can install, with their texts in its language (else the
309
+ * first they have). */
310
+ export function catalogThemes(text: string): ShownTheme[] {
311
+ let json: any;
312
+ try {
313
+ json = JSON.parse(text);
314
+ } catch {
315
+ return [];
316
+ }
317
+ const themes: unknown[] = Array.isArray(json?.themes) ? json.themes : [];
318
+ const inLocale = <T>(x?: Record<string, T>) => x && (x[locale] ?? Object.values(x)[0]);
319
+ return themes.filter(validTheme).map((x) => {
320
+ const description = inLocale(x.description);
321
+ const highlights = inLocale(x.highlights) ?? [];
322
+ return {
323
+ ...x,
324
+ description: typeof description === 'string' ? description : undefined,
325
+ highlights: Array.isArray(highlights) ? highlights.filter(isText) : [],
326
+ releaseNotes: notesOf(inLocale(x.releaseNotes)),
327
+ screenshots: (Array.isArray(x.screenshots) ? x.screenshots : []).filter(
328
+ (s) => isText(s?.file) && isText(s?.key) && x.files.some((f) => f.path === `${SCREENSHOTS}/${s.file}`),
329
+ ),
330
+ iconPacks: (Array.isArray(x.iconPacks) ? x.iconPacks : []).filter(
331
+ (p) => [p?.id, p?.name, p?.author, p?.license].every(isText) && x.files.some((f) => f.path === `icon-packs/${p.id}/pack.json`),
332
+ ),
333
+ words: [x.name, x.author, ...Object.values(x.description ?? {}), ...Object.values(x.highlights ?? {}).flat()].join(' ').toLowerCase(),
334
+ };
335
+ });
336
+ }
337
+
338
+ // The catalog, read once while the editor is open (again after it could not be read).
339
+ let catalog: Promise<string> | null = null;
340
+
341
+ /** Whether the site has an app store (config.store); without one, "Appstore" has only the site's own apps and themes. */
342
+ export const hasStore = !!config.store;
343
+
344
+ // The store's repository; only asked for what is in its catalog, so never without one.
345
+ const storeRepo = () => {
346
+ if (!config.store) throw new Error(t.apps.noStore);
347
+ return config.store;
348
+ };
349
+
350
+ function catalogText(): Promise<string> {
351
+ if (!config.store) return Promise.resolve('{}');
352
+ catalog ??= loadFrom(config.store, config.store.branch, [config.store.catalog]).then(([file]) => {
353
+ if (file?.text == null) throw new Error(t.apps.storeFailed);
354
+ return file.text;
355
+ });
356
+ catalog.catch(() => (catalog = null));
357
+ return catalog;
358
+ }
359
+
360
+ /** The store's apps. Fails when the catalog cannot be read. */
361
+ export const readCatalog = (): Promise<ShownApp[]> => catalogText().then(catalogApps);
362
+
363
+ /** The store's themes. Fails when the catalog cannot be read. */
364
+ export const readThemes = (): Promise<ShownTheme[]> => catalogText().then(catalogThemes);
365
+
366
+ /** An app's (or a theme's) files from the store (its folder at the catalog's commit), each checked against its blob id. */
367
+ export async function readApp(app: {
368
+ path: string;
369
+ ref: string;
370
+ files: StoreFile[];
371
+ label?: string;
372
+ name?: string;
373
+ }): Promise<{ path: string; content: string | Uint8Array }[]> {
374
+ const found = await loadFrom(
375
+ storeRepo(),
376
+ app.ref,
377
+ app.files.map((f) => `${app.path}/${f.path}`),
378
+ );
379
+ return Promise.all(
380
+ app.files.map(async (f) => {
381
+ const file = found.find((x) => x.path === `${app.path}/${f.path}`);
382
+ if (!file || file.oid !== f.oid) throw new Error(t.apps.storeBroken(app.label ?? app.name ?? app.path));
383
+ return { path: f.path, content: file.text ?? (await loadBytes(f.oid, undefined, storeRepo())) };
384
+ }),
385
+ );
386
+ }
387
+
388
+ /** An app's pictures from the store (its screenshots/, AppScreenshot), each as an address in this browser (a blob:)
389
+ * with what it shows; one that cannot be read is left out. */
390
+ export async function readScreenshots(app: StoreApp): Promise<{ src: string; label: string }[]> {
391
+ const types: Record<string, string> = { jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', webp: 'image/webp' };
392
+ const read = await Promise.all(
393
+ (app.screenshots ?? []).map(async (x) => {
394
+ const oid = app.files.find((f) => f.path === `${SCREENSHOTS}/${x.file}`)?.oid;
395
+ const type = types[x.file.split('.').pop()!.toLowerCase()];
396
+ if (!oid || !type) return null;
397
+ try {
398
+ const bytes = await loadBytes(oid, undefined, storeRepo());
399
+ return { src: URL.createObjectURL(new Blob([bytes as BlobPart], { type })), label: x.label };
400
+ } catch {
401
+ return null;
402
+ }
403
+ }),
404
+ );
405
+ return read.filter((x) => !!x);
406
+ }
407
+
408
+ /** A theme's pictures of a site in it from the store (its screenshots/), each as an address in this browser (a blob:)
409
+ * with what it shows (its key, t.library.themeShots); one that cannot be read is left out. */
410
+ export async function readThemeScreenshots(theme: Pick<StoreTheme, 'screenshots' | 'files'>): Promise<{ key: string; src: string }[]> {
411
+ const read = await Promise.all(
412
+ (theme.screenshots ?? []).map(async (x) => {
413
+ const oid = theme.files.find((f) => f.path === `${SCREENSHOTS}/${x.file}`)?.oid;
414
+ if (!oid) return null;
415
+ try {
416
+ const bytes = await loadBytes(oid, undefined, storeRepo());
417
+ return { key: x.key, src: URL.createObjectURL(new Blob([bytes as BlobPart], { type: 'image/jpeg' })) };
418
+ } catch {
419
+ return null;
420
+ }
421
+ }),
422
+ );
423
+ return read.filter((x) => !!x);
424
+ }
425
+
426
+ /** The changes that make a theme's folder in the site (`current`, its files now) the store's version, with the note of
427
+ * where it came from, or remove it (`next` null: uninstalling). In one commit. */
428
+ export function themeChanges(
429
+ id: string,
430
+ current: RepoFile[],
431
+ next: { files: { path: string; content: string | Uint8Array }[]; record: StoreRecord } | null,
432
+ ): Change[] {
433
+ return folderChanges(themeFolder(id), current, next);
434
+ }
435
+
436
+ /** The changes that make a folder in the site (`current`, its files now) the store's version of an app or a theme, with
437
+ * the note of where it came from, or remove it (`next` null). */
438
+ function folderChanges(
439
+ folder: string,
440
+ current: RepoFile[],
441
+ next: { files: { path: string; content: string | Uint8Array }[]; record: StoreRecord } | null,
442
+ ): Change[] {
443
+ const now = new Map(current.map((f) => [f.path, f.oid]));
444
+ const wanted: { path: string; content: string | Uint8Array; oid?: string }[] = next
445
+ ? [
446
+ ...next.files.map((f) => ({
447
+ path: `${folder}/${f.path}`,
448
+ content: f.content,
449
+ oid: next.record.files.find((r) => r.path === f.path)?.oid,
450
+ })),
451
+ { path: `${folder}/${RECORD}`, content: `${JSON.stringify(next.record, null, 2)}\n` },
452
+ ]
453
+ : [];
454
+ return [
455
+ // A file the site has as it is in the store is left as it is.
456
+ ...wanted
457
+ .filter((w) => !w.oid || now.get(w.path) !== w.oid)
458
+ .map((w) => ({ path: w.path, content: w.content, oid: now.get(w.path) ?? null })),
459
+ ...current.filter((f) => !wanted.some((w) => w.path === f.path)).map((f) => ({ path: f.path, content: null, oid: f.oid })),
460
+ ];
461
+ }
462
+
463
+ /** The changes that make an app's folder in the site (`current`, its files now) the store's version, with the note of
464
+ * where it came from, or remove it (`next` null: uninstalling); and the site's file of apps with it among those
465
+ * installed or not (`installed`: their ids now, `file`: the file). In one commit. */
466
+ export function appChanges(
467
+ id: string,
468
+ current: RepoFile[],
469
+ next: { files: { path: string; content: string | Uint8Array }[]; record: StoreRecord } | null,
470
+ installed: string[],
471
+ file: RepoFile | undefined,
472
+ ): Change[] {
473
+ const changes = folderChanges(appFolder(id), current, next);
474
+ const ids = [...new Set(installed.filter((x) => x !== id).concat(next ? [id] : []))].sort();
475
+ const text = `${JSON.stringify({ installed: ids }, null, 2)}\n`;
476
+ if (text !== file?.text) changes.push({ path: config.apps.installed, content: text, oid: file?.oid || null });
477
+ return changes;
478
+ }
479
+
480
+ /** The note in an app's (or a theme's) folder of where it came from (store.json), from its files now (`current`). */
481
+ export function recordIn(current: RepoFile[], root: string): StoreRecord | undefined {
482
+ try {
483
+ const record = JSON.parse(current.find((f) => f.path === `${root}/${RECORD}`)?.text ?? '');
484
+ return isText(record?.version) && Array.isArray(record.files) ? record : undefined;
485
+ } catch {
486
+ return undefined;
487
+ }
488
+ }
489
+
490
+ /** The files of an app installed from the store that were changed in the site since (in its folder, `current`, not
491
+ * as its note says), by their paths in the folder: an update writes over them. */
492
+ export function changedFiles(id: string, record: StoreRecord, current: RepoFile[], root = appFolder(id)): string[] {
493
+ const folder = `${root}/`;
494
+ const own = current.map((f) => ({ path: f.path.slice(folder.length), oid: f.oid }));
495
+ return [
496
+ ...own.filter((f) => f.path !== RECORD && record.files.find((r) => r.path === f.path)?.oid !== f.oid).map((f) => f.path),
497
+ ...record.files.filter((r) => !own.some((f) => f.path === r.path)).map((r) => r.path),
498
+ ];
499
+ }
package/src/theme.ts ADDED
@@ -0,0 +1,90 @@
1
+ // Light or dark: as the phone or computer is set (auto), or always light or dark, picked on the account
2
+ // and kept in this browser. It is set on <html> as data-theme, which the site's colours follow
3
+ // (the theme's styles/global.css); the script in the head of packages/editor/pages/editor/index.astro does the same
4
+ // before the page is drawn, so it does not flash in the other colours. Its own key, so the site's
5
+ // choice (`theme`) is not changed by the editor's.
6
+ import { colorsCss, isColor, type Colors } from '../lib/colors';
7
+ import { motionCss, type MotionScheme } from '../lib/motion';
8
+
9
+ export type Theme = 'light' | 'auto' | 'dark';
10
+
11
+ const KEY = 'editor-theme';
12
+
13
+ export function savedTheme(): Theme {
14
+ try {
15
+ const t = localStorage.getItem(KEY);
16
+ return t === 'light' || t === 'dark' ? t : 'auto';
17
+ } catch {
18
+ return 'auto';
19
+ }
20
+ }
21
+
22
+ export function setTheme(theme: Theme) {
23
+ try {
24
+ if (theme === 'auto') localStorage.removeItem(KEY);
25
+ else localStorage.setItem(KEY, theme);
26
+ } catch {}
27
+ applyTheme(theme);
28
+ }
29
+
30
+ // The colour of the phone's top bar (the theme-color tags) follows a chosen theme too: each tag has the
31
+ // colour of its own mode in data-color (packages/editor/pages/editor/index.astro), and a picked mode puts its
32
+ // colour in both.
33
+ const bars = () => Array.from(document.querySelectorAll<HTMLMetaElement>('meta[name="theme-color"]'));
34
+ const isDark = (m: HTMLMetaElement) => m.media.includes('dark');
35
+
36
+ // A screen that shows one mode at a time (Farver) holds the editor in it while it is open, whatever is
37
+ // picked on the account; null lets go again. A change of the site's colours meanwhile (applyColors)
38
+ // keeps it.
39
+ let held: 'light' | 'dark' | null = null;
40
+
41
+ export function holdTheme(mode: 'light' | 'dark' | null) {
42
+ held = mode;
43
+ applyTheme(savedTheme());
44
+ }
45
+
46
+ /** The mode the editor is shown in now: the one picked, or, on Auto, the phone's or computer's. */
47
+ export function shownMode(): 'light' | 'dark' {
48
+ const theme = held ?? savedTheme();
49
+ if (theme !== 'auto') return theme;
50
+ return matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
51
+ }
52
+
53
+ export function applyTheme(chosen: Theme) {
54
+ const theme = held ?? chosen;
55
+ const root = document.documentElement;
56
+ if (theme === 'auto') delete root.dataset.theme;
57
+ else root.dataset.theme = theme;
58
+ const all = bars();
59
+ const picked = all.find((m) => isDark(m) === (theme === 'dark'));
60
+ for (const m of all) m.content = (theme === 'auto' ? m.dataset.color : picked?.dataset.color) ?? m.content;
61
+ }
62
+
63
+ // The site's colours (colors.json, "Farver") as the editor has loaded them, in place of the ones its page
64
+ // was built with, so a change shows at once, before the site is built again: the CSS (colorsCss) in the
65
+ // <style> of the page, and the top bar in the background's colour.
66
+ export function applyColors(colors: Colors) {
67
+ let css: string;
68
+ try {
69
+ css = colorsCss(colors);
70
+ } catch {
71
+ return;
72
+ }
73
+ const style = document.getElementById('site-colors');
74
+ if (style && style.textContent !== css) style.textContent = css;
75
+ for (const m of bars()) {
76
+ const bg = colors[isDark(m) ? 'dark' : 'light'].bg;
77
+ if (isColor(bg)) m.dataset.color = bg;
78
+ }
79
+ applyTheme(savedTheme());
80
+ }
81
+
82
+ // How the site moves ("Bevægelse") as the editor has loaded it, in place of the scheme its page was built with, so a new
83
+ // choice shows at once, before the site is built again: its springs (motionCss) in the <style> of the page, and its name
84
+ // on <html> for what animates in a script.
85
+ export function applyMotion(scheme: MotionScheme) {
86
+ const css = motionCss(scheme);
87
+ const style = document.getElementById('site-motion');
88
+ if (style && style.textContent !== css) style.textContent = css;
89
+ document.documentElement.dataset.motionScheme = scheme;
90
+ }