@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/images.ts ADDED
@@ -0,0 +1,163 @@
1
+ // Pictures added in the editor. Before upload they are made at most 2000 px and WebP (JPEG in
2
+ // browsers that cannot write WebP, like Safari), as the old editor did; packages/editor/scripts/responsive-images.mjs
3
+ // makes the smaller sizes when the site is built. They go in public/images/uploads/<year>/<month>/
4
+ // like imported pictures, and are saved in the same commit as the page that uses them (on
5
+ // their own from Filer, Media.tsx). PDFs, videos and zip files, from Filer, are saved as they are, in
6
+ // public/filer/ (prepareFile).
7
+ import { useState } from 'react';
8
+ import { slugify } from './schema';
9
+ import { sourceColorsOf } from '../lib/dynamic-colors';
10
+ import { config } from '@site/config';
11
+ import type { Status } from './FormFrame';
12
+ import { t } from './i18n';
13
+
14
+ const MAX = 2000;
15
+
16
+ // url: a temporary address of the picture in this browser, shown until the site is rebuilt.
17
+ export type Upload = { url: string; path: string; bytes: Uint8Array; saved: boolean };
18
+
19
+ // The pictures made ready in this visit, by their address on the site: shown from the browser
20
+ // (shownAt), as the site has them only once it has been rebuilt.
21
+ const fresh = new Map<string, string>();
22
+ export const shownAt = (src: string) => fresh.get(src) ?? src;
23
+ // A picture renamed in this visit is shown from its old address until the site is rebuilt.
24
+ export const showMoved = (from: string, to: string) => fresh.set(to, shownAt(from));
25
+
26
+ /** What a file in the site's folder of files is, by its ending: a PDF, a video or a zip file. */
27
+ export type FileKind = 'pdf' | 'video' | 'zip';
28
+
29
+ // The endings of each kind, with the type a browser shows it as.
30
+ const ENDINGS: Record<string, [FileKind, string]> = {
31
+ pdf: ['pdf', 'application/pdf'],
32
+ mp4: ['video', 'video/mp4'],
33
+ m4v: ['video', 'video/mp4'],
34
+ mov: ['video', 'video/quicktime'],
35
+ webm: ['video', 'video/webm'],
36
+ zip: ['zip', 'application/zip'],
37
+ };
38
+ const endingOf = (name: string) => /\.([^./]+)$/.exec(name)?.[1].toLowerCase() ?? '';
39
+
40
+ /** A file's kind by its name or address, or null for one that is not a PDF, a video or a zip file. */
41
+ export const fileKindOf = (name: string): FileKind | null => ENDINGS[endingOf(name)]?.[0] ?? null;
42
+
43
+ /** The type a browser shows a file as, by its name ('' for a picture). */
44
+ export const typeOf = (name: string) => ENDINGS[endingOf(name)]?.[1] ?? '';
45
+
46
+ // A picked file's ending: its own, or for one without it the first of its type ("Guide" from a phone,
47
+ // application/pdf, as pdf); '' for another kind of file.
48
+ const pickedEnding = (file: File) =>
49
+ ENDINGS[endingOf(file.name)] ? endingOf(file.name) : (Object.keys(ENDINGS).find((e) => ENDINGS[e][1] === file.type) ?? '');
50
+
51
+ /** A picked file's kind, by its ending or else its type, or null for one that is not a PDF, a video or a zip file. */
52
+ export const pickedKindOf = (file: File): FileKind | null => ENDINGS[pickedEnding(file)]?.[0] ?? null;
53
+
54
+ /** A file picked on the phone or computer: a picture, or (`all`, in Filer) a picture, a PDF, a video or a
55
+ * zip file. */
56
+ export function pickImage(all = false): Promise<File | null> {
57
+ return new Promise((resolve) => {
58
+ const input = document.createElement('input');
59
+ input.type = 'file';
60
+ input.accept = all
61
+ ? ['image/*', ...new Set(Object.values(ENDINGS).map(([, type]) => type)), ...Object.keys(ENDINGS).map((e) => `.${e}`)].join(',')
62
+ : 'image/*';
63
+ input.addEventListener('change', () => resolve(input.files?.[0] ?? null));
64
+ input.addEventListener('cancel', () => resolve(null));
65
+ input.click();
66
+ });
67
+ }
68
+
69
+ /** The colours in a picture that are best as a source colour (dynamic colour, sourceColorsOf), best first: one on the
70
+ * phone or computer (it is not uploaded), or one at an address of the editor's own. Read small, which is enough and quick. */
71
+ export async function colorsInPicture(file: Blob): Promise<string[]> {
72
+ const bitmap = await createImageBitmap(file);
73
+ const scale = Math.min(1, 128 / Math.max(bitmap.width, bitmap.height));
74
+ const canvas = document.createElement('canvas');
75
+ canvas.width = Math.max(1, Math.round(bitmap.width * scale));
76
+ canvas.height = Math.max(1, Math.round(bitmap.height * scale));
77
+ const context = canvas.getContext('2d')!;
78
+ context.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
79
+ bitmap.close();
80
+ return sourceColorsOf(context.getImageData(0, 0, canvas.width, canvas.height).data);
81
+ }
82
+
83
+ export async function prepareImage(file: File): Promise<Upload> {
84
+ const bitmap = await createImageBitmap(file, { imageOrientation: 'from-image' }).catch(() => {
85
+ throw new Error(t.app.pictureNotOpened);
86
+ });
87
+ const scale = Math.min(1, MAX / Math.max(bitmap.width, bitmap.height));
88
+ const canvas = document.createElement('canvas');
89
+ canvas.width = Math.round(bitmap.width * scale);
90
+ canvas.height = Math.round(bitmap.height * scale);
91
+ canvas.getContext('2d')!.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
92
+ bitmap.close();
93
+ const encode = (type: string) => new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, type, 0.82));
94
+ let blob = await encode('image/webp');
95
+ if (blob?.type !== 'image/webp') blob = await encode('image/jpeg');
96
+ if (!blob) throw new Error(t.app.pictureNotReady);
97
+
98
+ const now = new Date();
99
+ const folder = `${config.folders.media}/${now.getFullYear()}/${String(now.getMonth() + 1).padStart(2, '0')}`;
100
+ // A short random ending, so two pictures called IMG_1234 do not get the same name.
101
+ const name = `${slugify(file.name.replace(/\.[^.]*$/, '')) || 'billede'}-${Math.random().toString(36).slice(2, 6)}`;
102
+ const ext = blob.type === 'image/webp' ? 'webp' : 'jpg';
103
+ const upload = {
104
+ url: URL.createObjectURL(blob),
105
+ path: `${folder}/${name}.${ext}`,
106
+ bytes: new Uint8Array(await blob.arrayBuffer()),
107
+ saved: false,
108
+ };
109
+ fresh.set(publicPath(upload.path), upload.url);
110
+ return upload;
111
+ }
112
+
113
+ /** The most a PDF, a video or a zip file may weigh, in MB: it goes to GitHub in one request with the commit. */
114
+ export const FILE_MAX_MB = 10;
115
+
116
+ /** A PDF, a video or a zip file as it is, in the site's folder of files (`config.folders.files`, /filer/ on
117
+ * the site), named by its own name as an address ("Stress guide.pdf" as stress-guide.pdf, the ending in
118
+ * small letters), with -2, -3 … when the name is taken (`taken`: the paths there are). */
119
+ export async function prepareFile(file: File, taken: string[]): Promise<Upload> {
120
+ if (file.size > FILE_MAX_MB * 1024 * 1024) throw new Error(t.media.tooBig(FILE_MAX_MB));
121
+ const folder = config.folders.files;
122
+ const stem = slugify(file.name.replace(/\.[^.]*$/, '')) || 'fil';
123
+ const ending = pickedEnding(file);
124
+ let path = `${folder}/${stem}.${ending}`;
125
+ for (let n = 2; taken.includes(path); n++) path = `${folder}/${stem}-${n}.${ending}`;
126
+ const upload = { url: URL.createObjectURL(file), path, bytes: new Uint8Array(await file.arrayBuffer()), saved: false };
127
+ fresh.set(publicPath(upload.path), upload.url);
128
+ return upload;
129
+ }
130
+
131
+ // The address of an uploaded picture on the site.
132
+ export const publicPath = (path: string) => path.replace(/^public/, '');
133
+
134
+ // The pictures added in a form (a page, a fixed page), kept in the browser until "Gem", which saves
135
+ // them in the same commit. upload: pick one and make it ready; added: those not saved yet, newest
136
+ // first (offered in the gallery, MediaPicker.tsx); saving: the pictures a text uses.
137
+ export function useUploads(notify: (status: Status) => void) {
138
+ const [uploads, setUploads] = useState<Upload[]>([]);
139
+
140
+ async function upload(): Promise<Upload | null> {
141
+ const file = await pickImage();
142
+ if (!file) return null;
143
+ notify({ text: t.app.preparingPicture });
144
+ try {
145
+ const prepared = await prepareImage(file);
146
+ setUploads((u) => [...u, prepared]);
147
+ notify(null);
148
+ return prepared;
149
+ } catch (e) {
150
+ notify({ text: (e as Error).message, error: true });
151
+ return null;
152
+ }
153
+ }
154
+
155
+ const added = uploads.filter((u) => !u.saved).reverse();
156
+ /** The pictures not saved yet that a text uses. */
157
+ const usedIn = (text: string) => uploads.filter((u) => !u.saved && text.includes(publicPath(u.path)));
158
+ const markSaved = (pictures: Upload[]) => setUploads((all) => all.map((u) => (pictures.includes(u) ? { ...u, saved: true } : u)));
159
+
160
+ return { upload, added, usedIn, markSaved };
161
+ }
162
+
163
+ export type Uploads = ReturnType<typeof useUploads>;
@@ -0,0 +1,79 @@
1
+ // The licences of the third-party work the site and the editor are made with ("Licenser" under "Indstillinger",
2
+ // Licenses.tsx), as the build finds them (/editor/licenses.json, licensesIntegration in packages/editor/lib/licenses.mjs),
3
+ // what an app (defineApp) and a theme (theme.json) declare (their own licence and the third-party work they bring), and
4
+ // what the store's catalog has of them (scripts/store-release.mjs, storeLicenses).
5
+
6
+ /** What a third-party work is to the site: a font, icons, code (a library, also styles) or pictures. */
7
+ export type LicenseKind = 'font' | 'icons' | 'library' | 'image';
8
+
9
+ /** A third-party work an app or a theme brings, as it declares it (`thirdParty`): an npm package it imports (its
10
+ * version, who made it, its licence and its text are its folder's; `author`, and `file`, a file in the app's or the
11
+ * theme's folder with the licence's text, for a package that has neither); or another work (a font or pictures in its
12
+ * folder), with its name, who made it, its licence's name and the file in its folder with its text. A theme's icon
13
+ * packs (icon-packs/) are not declared here: each pack's manifest says its licence. */
14
+ export type ThirdParty =
15
+ | { package: string; kind: LicenseKind; author?: string; file?: string }
16
+ | { name: string; version?: string; author: string; license: string; file: string; kind: LicenseKind };
17
+
18
+ /** The licence of one's own work that grants nothing ("all rights reserved"), as npm writes it. */
19
+ export const UNLICENSED = 'UNLICENSED';
20
+
21
+ /** Who brings a work: the editor, the site's own code, or an app or a theme (`app/<id>`, `tema/<id>`, LicenseOwner.id). */
22
+ export type LicenseWhere = 'editor' | 'site' | `app/${string}` | `tema/${string}`;
23
+
24
+ /** A third-party work as the build found it: its id (a package's name; `ikoner/<id>` for an icon set; `<owner>/<name>`
25
+ * for another work an app or a theme declares), its name, version, who made it, its licence's name and text (`standard`:
26
+ * the licence's standard text, as the package has none of its own), what it is, who brings it (`where`, none for an
27
+ * icon set or a work only an app or a theme not in use brings) and through which packages (`via`, when the site does not
28
+ * import it itself). `shipped: false`: brought by an app or a theme the site is built with, but not in what is downloaded (the Worker's, the
29
+ * build's). */
30
+ export type LicensedWork = {
31
+ id: string;
32
+ name: string;
33
+ version: string | null;
34
+ author: string;
35
+ license: string;
36
+ text: string;
37
+ standard?: boolean;
38
+ kind: LicenseKind;
39
+ where: LicenseWhere[];
40
+ via?: string[];
41
+ shipped?: false;
42
+ };
43
+
44
+ /** An app or a theme with its own licence (`text`: LICENSE in its folder, none when it is UNLICENSED) and the works it
45
+ * brings (their ids: those it declares, and those shipped through them alone), and whether the site is built with it. */
46
+ export type LicenseOwner = {
47
+ id: `app/${string}` | `tema/${string}`;
48
+ kind: 'app' | 'theme';
49
+ /** Its folder's name in src/apps/ or src/themes/. */
50
+ key: string;
51
+ name: string;
52
+ version: string | null;
53
+ author: string;
54
+ license: string;
55
+ text: string | null;
56
+ works: string[];
57
+ inUse: boolean;
58
+ };
59
+
60
+ /** What the build wrote (/editor/licenses.json). */
61
+ export type LicensesFile = { works: LicensedWork[]; owners: LicenseOwner[] };
62
+
63
+ /** A work an app or a theme declares, as the store's catalog has it: without its text. */
64
+ export type StoreLicense = Pick<LicensedWork, 'name' | 'version' | 'author' | 'license' | 'kind'>;
65
+
66
+ /** An app's or a theme's licences as the store's catalog has them: its own licence's name and what it brings. */
67
+ export type StoreLicenses = { license: string; works: StoreLicense[] };
68
+
69
+ // The file, fetched once each time the editor opens: undefined while it loads, null when there is none (the site is not
70
+ // built since it came, or the editor is offline).
71
+ let loaded: Promise<LicensesFile | null> | undefined;
72
+
73
+ /** The licences as the site was last built (/editor/licenses.json). */
74
+ export function loadLicenses(): Promise<LicensesFile | null> {
75
+ loaded ??= fetch('/editor/licenses.json', { cache: 'no-store' })
76
+ .then((res) => (res.ok ? (res.json() as Promise<LicensesFile>) : null))
77
+ .catch(() => null);
78
+ return loaded;
79
+ }
@@ -0,0 +1,12 @@
1
+ /** A Milkdown editor of the text, in root (not created yet). @param {HTMLElement | null} root @param {string} markdown
2
+ * @returns {import('@milkdown/kit/core').Editor} */
3
+ export function makeEditor(root: HTMLElement | null, markdown: string): import("@milkdown/kit/core").Editor;
4
+ export function partsOf(ctx: any): any[];
5
+ export function markdownOf(ctx: any): any;
6
+ export const HTML: "html";
7
+ /** @type {import('@milkdown/kit/utils').$NodeSchema<'siteBlock'>} */
8
+ export const siteBlockSchema: import("@milkdown/kit/utils").$NodeSchema<"siteBlock">;
9
+ /** @type {import('@milkdown/kit/utils').$MarkSchema<'textColor'>} */
10
+ export const textColorSchema: import("@milkdown/kit/utils").$MarkSchema<"textColor">;
11
+ /** @type {import('@milkdown/kit/utils').$Prose} */
12
+ export const spacing: import("@milkdown/kit/utils").$Prose;
@@ -0,0 +1,204 @@
1
+ // The Milkdown setup shared by the editor (/editor/) and packages/editor/scripts/editor-roundtrip.mjs, so the check
2
+ // runs the same Markdown parser and writer as the browser.
3
+ import { Editor, editorViewCtx, rootCtx, defaultValueCtx, remarkStringifyOptionsCtx, serializerCtx } from '@milkdown/kit/core';
4
+ import { commonmark } from '@milkdown/kit/preset/commonmark';
5
+ import { gfm } from '@milkdown/kit/preset/gfm';
6
+ import { $markSchema, $nodeSchema, $prose, $remark } from '@milkdown/kit/utils';
7
+ import { Plugin } from '@milkdown/kit/prose/state';
8
+ import { blockHtml, parseBlock } from '../lib/blocks.mjs';
9
+ import { COLOR_CLOSE, TEXT_COLORS, colorClass, colorOpen, colorOpened } from '../lib/text-colors.mjs';
10
+
11
+ // Write Markdown the way imported files are written: "- " bullets and
12
+ // "* * *" rules, so a save changes as few lines as possible.
13
+ const stringify = { bullet: '-', listItemIndent: 'tab', rule: '*', ruleSpaces: true };
14
+
15
+ // The site's blocks in the text (packages/editor/lib/blocks.mjs), read from and written back as their line of HTML.
16
+ // Milkdown puts HTML at the top of the text in a paragraph; a paragraph that is only a block becomes
17
+ // a siteBlock node (with its type and props) before the text is read. Any type is read: the sections
18
+ // of the fixed pages are blocks too (sections.mjs); the site shows only its own (RichText.astro).
19
+ // Other HTML on a line of its own (YouTube, Vimeo, Calendly, an imported table) is a block too, of the
20
+ // type HTML, with the HTML as it is as its `code`, and written back as it was.
21
+ export const HTML = 'html';
22
+ const remarkSiteBlocks = $remark('remarkSiteBlocks', () => () => (tree) => {
23
+ tree.children = tree.children.map((child) => {
24
+ const only = child.type === 'paragraph' && child.children?.length === 1 ? child.children[0] : child;
25
+ if (only.type !== 'html') return child;
26
+ const block = parseBlock(String(only.value), null);
27
+ return block
28
+ ? { type: 'siteBlock', blockType: block.type, props: block.props }
29
+ : { type: 'siteBlock', blockType: HTML, props: { code: String(only.value) } };
30
+ });
31
+ });
32
+
33
+ // One node per block, with its type and its props. How it looks in the editor: MarkdownEditor.tsx.
34
+ /** @type {import('@milkdown/kit/utils').$NodeSchema<'siteBlock'>} */
35
+ export const siteBlockSchema = $nodeSchema('siteBlock', () => ({
36
+ group: 'block',
37
+ atom: true,
38
+ selectable: true,
39
+ attrs: { type: { default: '' }, props: { default: {} } },
40
+ parseDOM: [{ tag: 'div[data-site-block]', getAttrs: (dom) => parseBlock(dom.dataset.siteBlock ?? '', null) ?? false }],
41
+ toDOM: (node) => ['div', { 'data-site-block': blockHtml(node.attrs.type, node.attrs.props) }],
42
+ parseMarkdown: {
43
+ match: (node) => node.type === 'siteBlock',
44
+ runner: (state, node, type) => {
45
+ state.addNode(type, { type: node.blockType, props: node.props });
46
+ },
47
+ },
48
+ toMarkdown: {
49
+ match: (node) => node.type.name === 'siteBlock',
50
+ runner: (state, node) => {
51
+ const { type, props } = node.attrs;
52
+ state.addNode('html', undefined, type === HTML ? String(props.code ?? '') : blockHtml(type, props));
53
+ },
54
+ },
55
+ }));
56
+
57
+ // A word or more in one of the site's colours (packages/editor/lib/text-colors.mjs): in the Markdown the HTML around
58
+ // it, <span class="color-accent">…</span>, which Milkdown would read as two pieces of HTML with the text between them;
59
+ // read as the text with the colour (a mark), and written back as the same HTML. A piece of HTML without its end, or
60
+ // another span, stays HTML.
61
+ function colorRuns(children) {
62
+ const out = [];
63
+ for (let i = 0; i < children.length; i++) {
64
+ const color = children[i].type === 'html' ? colorOpened(children[i].value) : null;
65
+ let end = -1;
66
+ for (let j = i + 1, depth = 0; color && j < children.length && end < 0; j++) {
67
+ const node = children[j];
68
+ if (node.type !== 'html') continue;
69
+ if (/^<span\b/.test(node.value)) depth++;
70
+ else if (node.value === COLOR_CLOSE && depth-- === 0) end = j;
71
+ }
72
+ if (end < 0) out.push(children[i]);
73
+ else {
74
+ out.push({ type: 'textColor', color, children: children.slice(i + 1, end) });
75
+ i = end;
76
+ }
77
+ }
78
+ return out;
79
+ }
80
+
81
+ function textColorMarkdown(node, _, state, info) {
82
+ const tracker = state.createTracker(info);
83
+ let value = tracker.move(colorOpen(node.color));
84
+ value += tracker.move(state.containerPhrasing(node, { ...tracker.current(), before: '>', after: '<' }));
85
+ return value + tracker.move(COLOR_CLOSE);
86
+ }
87
+ textColorMarkdown.peek = () => '<';
88
+
89
+ const remarkTextColors = $remark(
90
+ 'remarkTextColors',
91
+ () =>
92
+ function () {
93
+ const data = this.data();
94
+ (data.toMarkdownExtensions ??= []).push({ handlers: { textColor: textColorMarkdown } });
95
+ const walk = (node) => {
96
+ if (!node.children) return;
97
+ node.children = colorRuns(node.children);
98
+ node.children.forEach(walk);
99
+ };
100
+ return walk;
101
+ },
102
+ );
103
+
104
+ /** @type {import('@milkdown/kit/utils').$MarkSchema<'textColor'>} */
105
+ export const textColorSchema = $markSchema('textColor', () => ({
106
+ attrs: { color: { default: TEXT_COLORS[0] } },
107
+ parseDOM: TEXT_COLORS.map((color) => ({ tag: `span.${colorClass(color)}`, attrs: { color } })),
108
+ toDOM: (mark) => ['span', { class: colorClass(mark.attrs.color) }],
109
+ parseMarkdown: {
110
+ match: (node) => node.type === 'textColor',
111
+ runner: (state, node, markType) => {
112
+ state.openMark(markType, { color: node.color });
113
+ state.next(node.children);
114
+ state.closeMark(markType);
115
+ },
116
+ },
117
+ toMarkdown: {
118
+ match: (mark) => mark.type.name === 'textColor',
119
+ runner: (state, mark) => {
120
+ state.withMark(mark, 'textColor', undefined, { color: mark.attrs.color });
121
+ },
122
+ },
123
+ }));
124
+
125
+ /** A Milkdown editor of the text, in root (not created yet). @param {HTMLElement | null} root @param {string} markdown
126
+ * @returns {import('@milkdown/kit/core').Editor} */
127
+ export function makeEditor(root, markdown) {
128
+ return Editor.make()
129
+ .config((ctx) => {
130
+ ctx.set(rootCtx, root);
131
+ ctx.set(defaultValueCtx, markdown);
132
+ ctx.update(remarkStringifyOptionsCtx, (options) => ({ ...options, ...stringify }));
133
+ })
134
+ .use(commonmark)
135
+ .use(gfm)
136
+ .use(remarkSiteBlocks)
137
+ .use(siteBlockSchema)
138
+ .use(remarkTextColors)
139
+ .use(textColorSchema);
140
+ }
141
+
142
+ // The text in parts, for a fixed page's sections (sections.mjs): each block, each heading at the top
143
+ // level ("Overskrift", H2), and the Markdown of the text between them. Empty paragraphs (the lines
144
+ // kept free between two blocks to write in), empty headings (left when one is deleted) and the page's H1
145
+ // (no section's) are left out.
146
+ export function partsOf(ctx) {
147
+ const doc = ctx.get(editorViewCtx).state.doc;
148
+ const serialize = ctx.get(serializerCtx);
149
+ const parts = [];
150
+ let run = [];
151
+ const flush = () => {
152
+ const markdown = run.length ? serialize(doc.type.create(null, run)).trim() : '';
153
+ if (markdown) parts.push({ markdown });
154
+ run = [];
155
+ };
156
+ doc.forEach((node) => {
157
+ // HTML in a section's text stays in its text.
158
+ if (node.type.name === 'siteBlock' && node.attrs.type !== HTML) {
159
+ flush();
160
+ parts.push({ block: { type: node.attrs.type, props: node.attrs.props } });
161
+ } else if (node.type.name === 'heading' && node.attrs.level === 2) {
162
+ flush();
163
+ parts.push({ heading: node.textContent.trim() });
164
+ } else if (node.type.name === 'heading' && node.attrs.level === 1) {
165
+ flush();
166
+ } else if (!((node.type.name === 'paragraph' || node.type.name === 'heading') && !node.textContent.trim() && !node.childCount))
167
+ run.push(node);
168
+ });
169
+ flush();
170
+ return parts;
171
+ }
172
+
173
+ // Keeps a free line (an empty paragraph) between two blocks and before and after them, so there is
174
+ // always a place to write a text between them. Not part of undo. Used by the editor (MarkdownEditor.tsx)
175
+ // and the check, which writes the text back with the free lines in it.
176
+ /** @type {import('@milkdown/kit/utils').$Prose} */
177
+ export const spacing = $prose(
178
+ () =>
179
+ new Plugin({
180
+ appendTransaction: (_, __, state) => {
181
+ const gaps = [];
182
+ let before = null;
183
+ state.doc.forEach((node, at) => {
184
+ if (node.type.name === 'siteBlock' && (!before || before.type.name === 'siteBlock')) gaps.push(at);
185
+ before = node;
186
+ });
187
+ if (state.doc.lastChild?.type.name === 'siteBlock') gaps.push(state.doc.content.size);
188
+ if (!gaps.length) return null;
189
+ const tr = state.tr;
190
+ for (const at of gaps.reverse()) tr.insert(at, state.schema.nodes.paragraph.create());
191
+ return tr.setMeta('addToHistory', false);
192
+ },
193
+ }),
194
+ );
195
+
196
+ // The Markdown of the text, without its empty paragraphs (the free lines between the blocks).
197
+ export function markdownOf(ctx) {
198
+ const doc = ctx.get(editorViewCtx).state.doc;
199
+ const kept = [];
200
+ doc.forEach((node) => {
201
+ if (!(node.type.name === 'paragraph' && node.content.size === 0)) kept.push(node);
202
+ });
203
+ return ctx.get(serializerCtx)(doc.type.create(null, kept));
204
+ }
package/src/nav.ts ADDED
@@ -0,0 +1,68 @@
1
+ // How the editor goes between its screens (the address after the "#") in the browser's history, so
2
+ // that the back arrow and the phone's back gesture go the same way. The back arrow goes to the screen
3
+ // above (Screen.tsx `back`); when that is the screen before it in the history, it goes back there, as
4
+ // the gesture does, and otherwise the screen above takes the place of this one. No step is added, so
5
+ // the gesture never brings back a screen that was left with the arrow. Every step in the history knows
6
+ // its place and the screen before it (`history.state`).
7
+
8
+ type Step = { at: number; prev: string | null };
9
+
10
+ const step = () => history.state as Step | null;
11
+
12
+ /** The screen of an address ("#liste/sider" → "liste/sider", "#" → ""); one with a broken %-sign is
13
+ * the start screen. */
14
+ export function screenOf(hash: string) {
15
+ try {
16
+ return decodeURIComponent(hash.replace(/^#/, ''));
17
+ } catch {
18
+ return '';
19
+ }
20
+ }
21
+
22
+ // The place of the screen that is shown, and while a step is undone (arrived), the place it goes back to.
23
+ let at = step()?.at ?? 0;
24
+ let undoing: number | null = null;
25
+ if (!step()) history.replaceState({ at, prev: null } satisfies Step, '');
26
+
27
+ /** Called by the app on every new address, with the screen it came from: null when it is a step back
28
+ * that `undo` asked for, else how to undo the step (back to the screen it came from) and take it again
29
+ * (when the owner leaves without saving). */
30
+ export function arrived(from: string): { undo: () => void; redo: () => void } | null {
31
+ const now = step();
32
+ if (undoing !== null && now?.at === undoing) {
33
+ at = undoing;
34
+ undoing = null;
35
+ return null;
36
+ }
37
+ undoing = null;
38
+ const before = at;
39
+ // A step that was there (back, forward): its own place.
40
+ if (now) {
41
+ at = now.at;
42
+ return {
43
+ undo: () => ((undoing = before), history.go(before - now.at)),
44
+ redo: () => history.go(now.at - before),
45
+ };
46
+ }
47
+ // A new step (a link, or the address typed): after this one.
48
+ const href = location.hash;
49
+ at = before + 1;
50
+ history.replaceState({ at, prev: from } satisfies Step, '');
51
+ return {
52
+ undo: () => ((undoing = before), history.back()),
53
+ redo: () => (location.hash = href),
54
+ };
55
+ }
56
+
57
+ /** Puts another screen in the place of this one (no new step in the history). */
58
+ export function replace(href: string) {
59
+ history.replaceState({ at, prev: step()?.prev ?? null } satisfies Step, '', href);
60
+ dispatchEvent(new HashChangeEvent('hashchange'));
61
+ }
62
+
63
+ /** The back arrow: to the screen above, `href`. Back in the history when that is the screen before,
64
+ * else in the place of this one. */
65
+ export function up(href: string) {
66
+ if (step()?.prev === screenOf(href)) history.back();
67
+ else replace(href);
68
+ }
@@ -0,0 +1,28 @@
1
+ // The addresses visitors came to that do not exist, as the site's Worker keeps them (packages/editor/worker/not-found.js,
2
+ // /api/not-found on the editor's own address), for "Ikke fundet" under "Videresendelser" (Redirects.tsx).
3
+ // Asked with the GitHub sign-in (the Worker's cookie, sent with the request): the Worker lets only someone who can save
4
+ // the site see them.
5
+
6
+ /** An address that does not exist: how many visits, the first and the last (ISO dates), and where the
7
+ * last visitor came from (an address of the site, another site's name, or ''). */
8
+ export type Missing = { path: string; count: number; first: string; last: string; from: string };
9
+
10
+ const API = '/api/not-found';
11
+
12
+ /** The addresses, most visits first; null when the site does not keep them (no Worker, no storage). */
13
+ export async function loadNotFound(): Promise<Missing[] | null> {
14
+ const res = await fetch(API, { cache: 'no-store' });
15
+ if (res.status === 503 || !res.headers.get('content-type')?.includes('application/json')) return null;
16
+ if (!res.ok) throw new Error(String(res.status));
17
+ return ((await res.json()) as { entries: Missing[] }).entries;
18
+ }
19
+
20
+ /** Takes the addresses off the list (they now send on, or are not worth it). */
21
+ export async function forgetNotFound(paths: string[]): Promise<void> {
22
+ const res = await fetch(API, {
23
+ method: 'DELETE',
24
+ headers: { 'content-type': 'application/json' },
25
+ body: JSON.stringify({ paths }),
26
+ });
27
+ if (!res.ok) throw new Error(String(res.status));
28
+ }