@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
@@ -0,0 +1,683 @@
1
+ // The licences of the third-party work the site and the editor are made with, for "Licenser" under "Indstillinger"
2
+ // (packages/editor/src/Licenses.tsx), found, not written by hand:
3
+ // - What is shipped: the npm packages whose code, styles or files end up in what visitors and editors download. That
4
+ // is the browser's bundle (the site's scripts, its islands and the editor), the styles of every page (a package a
5
+ // stylesheet imports: Tailwind's preflight and typography, a font's @font-face) and the files they bring (the
6
+ // fonts), with the bundler's helpers and Astro's script that wakes the islands, which the build writes into the pages
7
+ // (licensesIntegration). A package only the build runs (Astro's compiler, Vite, Tailwind's engine, the Markdown
8
+ // pipeline on the server, sharp) puts nothing of its own in a page: the HTML it renders is the site's own content,
9
+ // so it is not shipped, and neither is the Worker's code (it runs at Cloudflare and is not handed to anyone).
10
+ // - The icon packs (IconPack; the site gives them, iconPacks, from each pack's manifest): the system's (Material
11
+ // Symbols, Phosphor and Lucide), shipped or not, since any of them can be chosen, each with the sets it takes icons
12
+ // from besides its own (Material Design Icons), and those a theme brings, under it.
13
+ // - What each app (`license` and `thirdParty` in its defineApp) and each theme (the same in its theme.json) declares:
14
+ // its own licence and the third-party work it brings (declaredWorks), shipped or not.
15
+ // A package's licence is its package.json's `license`, its text its LICENSE files (with its NOTICE, which the Apache
16
+ // License asks to be passed on), else the licence's standard text (license-texts/<SPDX>.txt) with who made it; who made
17
+ // it is its `author`, else its first contributor, the holder its licence's copyright line names, its first maintainer or
18
+ // the owner of its repository.
19
+ // The build writes dist/editor/licenses.json (LicensesFile in src/licenses.ts), which the editor fetches, and stops when
20
+ // something shipped has no licence it can show. npm run check:content checks, before a build: every package the site's
21
+ // and the editor's code imports, and what they depend on (codePackageProblems, more than is shipped, so nothing shipped
22
+ // slips through) and each app's and theme's declaration (declarationProblems); the icon packs' manifests and licences
23
+ // are checked with the packs (packProblems in packages/editor/site/icons.mjs).
24
+ // No TypeScript here: the build and the scripts read it.
25
+ import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from 'node:fs';
26
+ import { builtinModules } from 'node:module';
27
+ import { dirname, isAbsolute, join, relative, sep } from 'node:path';
28
+ import { fileURLToPath } from 'node:url';
29
+ import { appIds, installedApps } from './apps.mjs';
30
+
31
+ const posix = (path) => path.split(sep).join('/');
32
+ const read = (file) => readFileSync(file, 'utf8').replace(/\r\n/g, '\n').trim();
33
+
34
+ /** The kinds of third-party work: a font, icons, code (a library, styles too) and pictures. */
35
+ export const LICENSE_KINDS = ['font', 'icons', 'library', 'image'];
36
+
37
+ /** The licence of one's own work that grants nothing ("all rights reserved"), as npm writes it. */
38
+ export const UNLICENSED = 'UNLICENSED';
39
+
40
+ /** The file with the licence of an app's or a theme's own work, in its folder, when it is not UNLICENSED. */
41
+ export const OWN_LICENSE_FILE = 'LICENSE';
42
+
43
+ /** A package's name from what is imported (`@scope/name/sub/file.js` → `@scope/name`, `name/x` → `name`). */
44
+ export const packageName = (specifier) => {
45
+ const parts = specifier.split(/[?#]/)[0].split('/');
46
+ return specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
47
+ };
48
+
49
+ /** The folder of an npm package that a file is in: up to its name after the last node_modules/ in its real path. */
50
+ export function packageDirOf(file) {
51
+ let path;
52
+ try {
53
+ path = posix(realpathSync(file));
54
+ } catch {
55
+ path = posix(file);
56
+ }
57
+ return path.match(/^(.*\/node_modules\/(?:@[^/]+\/[^/]+|[^/@][^/]*))(?:\/|$)/)?.[1] ?? null;
58
+ }
59
+
60
+ /** The folder of a package by its name, as Node finds it from a folder: in node_modules/ there or above. */
61
+ export function packageDir(name, from) {
62
+ for (let dir = from; ; dir = dirname(dir)) {
63
+ const candidate = join(dir, 'node_modules', name);
64
+ if (existsSync(join(candidate, 'package.json'))) return realpathSync(candidate);
65
+ if (dirname(dir) === dir) return null;
66
+ }
67
+ }
68
+
69
+ // ---------------------------------------------------------------------------------------------------
70
+ // A package's licence
71
+
72
+ /** Whom a licence's copyright line names (`Copyright (c) 2015-present Titus Wormer <…>` → `Titus Wormer`). */
73
+ function holderIn(text) {
74
+ const line = text?.match(/^[ \t]*(?:portions[ \t]+)?copyright\b[ \t]*(.*)$/im)?.[1];
75
+ const holder = line
76
+ ?.replace(/\(c\)|©/gi, ' ')
77
+ .replace(/\b\d{4}\b(?:\s*[-–,]\s*(?:\d{4}\b|present\b))*/gi, ' ')
78
+ .replace(/^\s*(?:by\s+)?/i, '')
79
+ .replace(/[<(].*$/, '')
80
+ .replace(/\s*all rights reserved\.?/i, '')
81
+ .replace(/[.,;:\s]+$/, '')
82
+ .trim();
83
+ return holder || null;
84
+ }
85
+
86
+ /** A person as package.json writes one: `Name <mail> (url)`, or { name }. */
87
+ const personName = (p) => (typeof p === 'string' ? p.replace(/\s*[<(].*$/, '').trim() : p?.name?.trim()) || null;
88
+
89
+ /** The owner of a package's repository (`github:owner/name`, `owner/name`, a GitHub address). */
90
+ function repositoryOwner(pkg) {
91
+ const url = typeof pkg.repository === 'string' ? pkg.repository : pkg.repository?.url;
92
+ return url?.match(/^(?:github:)?([\w.-]+)\/[\w.-]+$/)?.[1] ?? url?.match(/github\.com[/:]([\w.-]+)\//)?.[1] ?? null;
93
+ }
94
+
95
+ /** Who made a package (see the top of this file). */
96
+ const authorOf = (pkg, text) =>
97
+ personName(pkg.author) ?? personName(pkg.contributors?.[0]) ?? holderIn(text) ?? personName(pkg.maintainers?.[0]) ?? repositoryOwner(pkg);
98
+
99
+ /** A package's licence by its package.json: `license` (an SPDX expression), or the old `licenses` list. */
100
+ const licenseOf = (pkg) =>
101
+ typeof pkg.license === 'string'
102
+ ? pkg.license
103
+ : (pkg.license?.type ??
104
+ (Array.isArray(pkg.licenses) && pkg.licenses.length ? pkg.licenses.map((l) => l.type ?? l).join(' OR ') : null));
105
+
106
+ const LICENSE_FILE = /^(licen[cs]e|copying|copyright|notice|ofl)([-_.][\w.-]*)?$/i;
107
+ const CODE = /\.(m?[jt]sx?|cjs|astro|css|json|map)$/;
108
+
109
+ /** The texts of a package's licence: its LICENSE files (LICENSE, LICENSE.md, LICENSE-MIT, LICENCE.txt, COPYING …) and its
110
+ * NOTICE. */
111
+ function licenseFileText(dir) {
112
+ const texts = readdirSync(dir, { withFileTypes: true })
113
+ .filter((e) => e.isFile() && LICENSE_FILE.test(e.name) && !CODE.test(e.name))
114
+ .map((e) => e.name)
115
+ .sort()
116
+ .map((f) => read(join(dir, f)))
117
+ .filter(Boolean);
118
+ return texts.length ? texts.join('\n\n') : null;
119
+ }
120
+
121
+ /** A licence's standard text (license-texts/<SPDX>.txt) with its copyright line naming the holder, for a work without a
122
+ * text of its own; null when the editor has none for it, or it needs a holder and has none. */
123
+ export function standardText(license, holder) {
124
+ if (!/^[\w.+-]+$/.test(license ?? '')) return null;
125
+ const file = fileURLToPath(new URL(`./license-texts/${license}.txt`, import.meta.url));
126
+ if (!existsSync(file)) return null;
127
+ const text = read(file);
128
+ if (text.includes('{{copyright}}') && !holder) return null;
129
+ return text.replace('{{copyright}}', holder ?? '');
130
+ }
131
+
132
+ /** An npm package as "Licenser" shows it, from its folder: its name, version, who made it, its licence and its text
133
+ * (`standard`: the licence's standard text, as the package has none of its own). */
134
+ export function packageInfo(dir) {
135
+ const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
136
+ const own = licenseFileText(dir);
137
+ const author = authorOf(pkg, own);
138
+ const license = licenseOf(pkg);
139
+ const text = own ?? standardText(license, author);
140
+ return { name: pkg.name, version: pkg.version ?? null, author, license, text, ...(own || !text ? {} : { standard: true }) };
141
+ }
142
+
143
+ /** What is missing for a work's licence to be shown, as sentences (`at`: where it is from): its licence, its text, who
144
+ * made it. */
145
+ export function workProblems(work, at) {
146
+ const problems = [];
147
+ if (!work.license) problems.push(`${at}: ${work.name} siger ikke, hvilken licens den har (license i dens package.json).`);
148
+ else if (!work.text)
149
+ problems.push(
150
+ `${at}: ${work.name} har ingen licenstekst (en LICENSE-fil), og editoren har ingen standardtekst for ${work.license} (packages/editor/lib/license-texts/${work.license}.txt).`,
151
+ );
152
+ if (!work.author) problems.push(`${at}: der står ingen steder i ${work.name}, hvem der har lavet den.`);
153
+ return problems;
154
+ }
155
+
156
+ // ---------------------------------------------------------------------------------------------------
157
+ // The icon packs
158
+
159
+ /** An icon set's licence as the site gives it: its name, version, who made it, its licence's name (SPDX) and the file
160
+ * with its text (from the site's folder, or absolute).
161
+ * @typedef {{ name: string, version?: string | null, author: string, license: string, file: string }} IconSetLicense */
162
+
163
+ /** An icon pack as the site gives it (licensesIntegration's `iconPacks`, from each pack's manifest): its id (a system
164
+ * pack's folder in packages/editor/icons/, a theme's `<theme>/<pack>`), its own licence, the theme it came with (none for the
165
+ * system's own), and the sets it takes icons from besides its own (`includes`: Material Design Icons' logos), each with
166
+ * its licence; and whether the site and the editor draw with it (`inUse`).
167
+ * @typedef {IconSetLicense & { id: string, theme?: string, inUse?: boolean, includes?: IconSetLicense[] }} IconPack */
168
+
169
+ const inRoot = (root, file) => (isAbsolute(file) ? file : join(root, file));
170
+
171
+ /** The works an icon pack is (as "Licenser" shows them): the pack itself (its id `ikoner/<pack id>`), and each set it
172
+ * takes icons from besides its own (`ikoner/<the set's name>`, once for all the packs that take from it, `via` them).
173
+ * @param {IconPack} pack @param {string} root */
174
+ export function iconPackWorks(pack, root) {
175
+ const work = (set, id, via) => ({
176
+ id,
177
+ name: set.name,
178
+ version: set.version ?? null,
179
+ author: set.author,
180
+ license: set.license,
181
+ kind: 'icons',
182
+ text: set.file && existsSync(inRoot(root, set.file)) ? read(inRoot(root, set.file)) : null,
183
+ where: [],
184
+ ...(via ? { via: [via] } : {}),
185
+ });
186
+ return [work(pack, `ikoner/${pack.id}`), ...(pack.includes ?? []).map((set) => work(set, `ikoner/${slug(set.name)}`, pack.name))];
187
+ }
188
+
189
+ // ---------------------------------------------------------------------------------------------------
190
+ // What an app or a theme imports and declares
191
+
192
+ /** A package's peerDependencies but the optional ones (peerDependenciesMeta): those it needs installed beside it. This
193
+ * package's optional ones are the tools its commands run with (bin/morpheme.mjs), not code it is built on. */
194
+ const requiredPeers = (pkg) => Object.keys(pkg.peerDependencies ?? {}).filter((name) => !pkg.peerDependenciesMeta?.[name]?.optional);
195
+
196
+ /** The packages that are the system (the editor and what it is built on: its required peerDependencies), which an app
197
+ * or a theme uses without declaring them: their licences are under the editor's. */
198
+ export function systemPackages() {
199
+ const editor = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
200
+ return new Set([editor.name, ...requiredPeers(editor)]);
201
+ }
202
+
203
+ const SOURCE = /\.(m?[jt]sx?|astro|css)$/;
204
+ const builtins = new Set(builtinModules);
205
+
206
+ /** The packages a folder's code imports by name (`from 'motion'`, `import('…')`, CSS `@import '…'` and `@plugin '…'`;
207
+ * not `import type`, which ships nothing), each with the files that import it: not node's own, the site's aliases
208
+ * (@theme/, @site/, @data/, @saturn/) or Vite's and Astro's virtual modules. */
209
+ export function importsIn(folder) {
210
+ const found = new Map();
211
+ if (!existsSync(folder)) return found;
212
+ for (const entry of readdirSync(folder, { recursive: true, withFileTypes: true })) {
213
+ if (!entry.isFile() || !SOURCE.test(entry.name)) continue;
214
+ const file = join(entry.parentPath, entry.name);
215
+ // Not the packages inside the folder (the folder itself may be a package's: the CMS's standard theme).
216
+ if (posix(relative(folder, file)).split('/').includes('node_modules')) continue;
217
+ // Without comments, so an import in a sentence about it is not one.
218
+ const code = readFileSync(file, 'utf8')
219
+ .replace(/\/\*[\s\S]*?\*\//g, '')
220
+ .replace(/(^|[^:'"`\\])\/\/.*$/gm, '$1');
221
+ const specifiers = [
222
+ ...code.matchAll(/\b(?:import|export)\s+(?!type\b)[\w*{}\s,$]*?\bfrom\s*['"]([^'"]+)['"]/g),
223
+ ...code.matchAll(/\bimport\s*['"]([^'"]+)['"]/g),
224
+ ...code.matchAll(/\bimport\(\s*['"]([^'"]+)['"]\s*\)/g),
225
+ ...code.matchAll(/@(?:import|plugin)\s+(?:url\()?\s*['"]([^'"]+)['"]/g),
226
+ ].map((m) => m[1]);
227
+ for (const specifier of specifiers) {
228
+ if (/^(\.|\/|node:|@theme\/|@site\/|@data\/|@saturn\/|virtual:|astro:|https?:|data:|\$)/.test(specifier) || specifier.startsWith('#'))
229
+ continue;
230
+ const name = packageName(specifier);
231
+ if (builtins.has(name)) continue;
232
+ if (!found.has(name)) found.set(name, []);
233
+ found.get(name).push(file);
234
+ }
235
+ }
236
+ return found;
237
+ }
238
+
239
+ /** An app's or a theme's id among the licences ("Licenser": its group, its own licence's page), and where it brings
240
+ * something (a shipped package's `where`): `app/<id>`, `tema/<id>`. */
241
+ export const ownerId = (kind, id) => `${kind === 'app' ? 'app' : 'tema'}/${id}`;
242
+
243
+ /** A text's id in an address (`Pictogrammers Free License` → `pictogrammers-free-license`). */
244
+ const slug = (text) =>
245
+ text
246
+ .toLowerCase()
247
+ .normalize('NFKD')
248
+ .replace(/[̀-ͯ]/g, '')
249
+ .replace(/[^a-z0-9]+/g, '-')
250
+ .replace(/^-|-$/g, '');
251
+
252
+ /** A work an app or a theme declares (an entry of its `thirdParty`), as "Licenser" shows it, with its licence's text:
253
+ * an npm package's from its folder (its id its name), with the `author` and the licence `file` (in the app's or the
254
+ * theme's folder) it declares in place of what the package does not have; another work's as declared, with the text of
255
+ * its licence file (its id `<owner>/<its name>`). A theme's icon packs are not declared: their manifests say it
256
+ * (iconPackWorks). @param {object} entry @param {{ folder: string, owner: string }} where */
257
+ export function declaredWork(entry, { folder, owner }) {
258
+ const own = (file) => (typeof file === 'string' && existsSync(join(folder, file)) ? read(join(folder, file)) : null);
259
+ if (entry.package) {
260
+ const dir = packageDir(entry.package, folder);
261
+ const info = dir ? packageInfo(dir) : { name: entry.package, version: null, author: null, license: null, text: null };
262
+ const author = entry.author ?? info.author;
263
+ // A package without a text of its own: the licence's standard text, with the author it declares.
264
+ const fromFile = typeof entry.file === 'string';
265
+ const text = fromFile ? own(entry.file) : info.standard || !info.text ? standardText(info.license, author) : info.text;
266
+ return {
267
+ name: info.name,
268
+ version: info.version,
269
+ license: info.license,
270
+ id: entry.package,
271
+ author,
272
+ text,
273
+ kind: entry.kind,
274
+ ...(!fromFile && text && (info.standard || !info.text) ? { standard: true } : {}),
275
+ };
276
+ }
277
+ return {
278
+ id: `${owner}/${slug(String(entry.name ?? ''))}`,
279
+ name: entry.name,
280
+ version: entry.version ?? null,
281
+ author: entry.author,
282
+ license: entry.license,
283
+ kind: entry.kind,
284
+ text: own(entry.file),
285
+ };
286
+ }
287
+
288
+ /** An app's or a theme's own licence (with its text, LICENSE in its folder, when it is not UNLICENSED) and the works it
289
+ * declares, as "Licenser" and the store show them. */
290
+ export function declaredWorks({ license, thirdParty }, where) {
291
+ const file = join(where.folder, OWN_LICENSE_FILE);
292
+ const text = license && license !== UNLICENSED && existsSync(file) ? read(file) : null;
293
+ return { license, text, works: (Array.isArray(thirdParty) ? thirdParty : []).map((entry) => declaredWork(entry, where)) };
294
+ }
295
+
296
+ /** What is wrong with what an app or a theme declares (`license`, its own licence, and `thirdParty`, the third-party
297
+ * work it brings), as sentences for npm run check:content: a declaration that is missing or not as it must be, a
298
+ * package it imports that is not declared (or one declared it does not import), a work without a licence it can show,
299
+ * and a licence file that is not there. `where`: the file it is declared in; `what`: the app or the theme, as a sentence
300
+ * names it; `owner`: its id (ownerId).
301
+ * @param {{ license: unknown, thirdParty: unknown, folder: string, where: string, what: string, owner: string,
302
+ * root: string }} declared */
303
+ export function declarationProblems({ license, thirdParty, folder, where, what, owner, root }) {
304
+ const problems = [];
305
+ const fix = `Skriv det i ${where}.`;
306
+ const rel = (file) => posix(relative(root, join(folder, file)));
307
+ if (typeof license !== 'string' || !license.trim())
308
+ problems.push(
309
+ `${where}: licensen for ${what} selv mangler (license: "${UNLICENSED}", når alle rettigheder er forbeholdt, ellers fx "MIT"). ${fix}`,
310
+ );
311
+ else if (license !== UNLICENSED && !existsSync(join(folder, OWN_LICENSE_FILE)))
312
+ problems.push(`${where}: ${what} har licensen ${license}, men ${rel(OWN_LICENSE_FILE)} med licensens tekst findes ikke.`);
313
+ if (!Array.isArray(thirdParty)) {
314
+ problems.push(
315
+ `${where}: thirdParty mangler, listen over det, ${what} har med fra andre: skrifter, ikoner, biblioteker og billeder ([], når der intet er). ${fix}`,
316
+ );
317
+ return problems;
318
+ }
319
+ const system = systemPackages();
320
+ const declared = new Set();
321
+ for (const [i, entry] of thirdParty.entries()) {
322
+ const at = `${where}: thirdParty[${i}]`;
323
+ if (!entry || typeof entry !== 'object') {
324
+ problems.push(`${at} er ikke et værk: { "package", "kind" } eller { "name", "author", "license", "file", "kind" }.`);
325
+ continue;
326
+ }
327
+ if (!LICENSE_KINDS.includes(entry.kind)) problems.push(`${at}: kind skal være ${LICENSE_KINDS.join(', ')}.`);
328
+ if (typeof entry.file === 'string' && !existsSync(join(folder, entry.file)))
329
+ problems.push(`${at}: licensfilen ${rel(entry.file)} findes ikke.`);
330
+ if (entry.package) {
331
+ declared.add(entry.package);
332
+ if (system.has(entry.package))
333
+ problems.push(
334
+ `${at}: ${entry.package} er en del af editoren (dens peerDependencies), og dens licens står allerede under editoren. Tag den ud.`,
335
+ );
336
+ else if (!packageDir(entry.package, folder)) problems.push(`${at}: pakken ${entry.package} er ikke installeret (npm install).`);
337
+ else
338
+ problems.push(
339
+ ...workProblems(declaredWork(entry, { folder, owner }), at).map((p) =>
340
+ p.includes('licenstekst')
341
+ ? `${p} Læg licensens tekst i en fil i mappen, og skriv den som file.`
342
+ : p.includes('hvem der')
343
+ ? `${p} Skriv det som author.`
344
+ : p,
345
+ ),
346
+ );
347
+ } else {
348
+ for (const key of ['name', 'author', 'license', 'file'])
349
+ if (typeof entry[key] !== 'string' || !entry[key].trim())
350
+ problems.push(
351
+ `${at}: et værk, der ikke er en npm-pakke, har ${key}: dets navn, hvem der har lavet det, licensens navn og filen med licensen.`,
352
+ );
353
+ }
354
+ }
355
+ const imported = importsIn(folder);
356
+ for (const [name, files] of imported) {
357
+ if (system.has(name) || declared.has(name)) continue;
358
+ problems.push(
359
+ `${posix(relative(root, files[0]))}: ${what} bruger pakken ${name}, men den står ikke i thirdParty i ${where}, så dens licens kan ikke vises. Skriv { "package": "${name}", "kind": "…" } dér.`,
360
+ );
361
+ }
362
+ for (const name of declared)
363
+ if (!imported.has(name) && !system.has(name))
364
+ problems.push(`${where}: ${what} har ${name} i thirdParty, men bruger den ikke. Tag den ud.`);
365
+ return problems;
366
+ }
367
+
368
+ // ---------------------------------------------------------------------------------------------------
369
+ // What the site's and the editor's code uses (npm run check:content)
370
+
371
+ /** What is missing for the licences of the packages the site's and the editor's code imports (in `folders`, from the
372
+ * site's folder) and those they depend on to be shown, as sentences: more than the build ships (a package the server
373
+ * or the build alone runs too), so that whatever is shipped has one. `skip`: the packages an app or a theme declares,
374
+ * checked with what it gives in place of what a package lacks (declarationProblems); those they depend on are not.
375
+ * @param {string} root @param {string[]} folders @param {Set<string>} [skip] */
376
+ export function codePackageProblems(root, folders, skip = new Set()) {
377
+ const problems = [];
378
+ const seen = new Set();
379
+ const walk = (name, from, by) => {
380
+ const dir = packageDir(name, from);
381
+ if (!dir || seen.has(dir)) return;
382
+ seen.add(dir);
383
+ const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
384
+ // A program for one kind of computer (`os`, `cpu`: sharp's libvips) runs where the site is built, never in a browser.
385
+ if (pkg.os || pkg.cpu) return;
386
+ if (!pkg.private && !skip.has(name)) problems.push(...workProblems(packageInfo(dir), by));
387
+ for (const next of [...Object.keys({ ...pkg.dependencies, ...pkg.optionalDependencies }), ...requiredPeers(pkg)])
388
+ walk(next, dir, `${by.split(':')[0]}: pakken ${name}`);
389
+ };
390
+ for (const folder of folders)
391
+ for (const [name, files] of importsIn(join(root, folder))) walk(name, dirname(files[0]), posix(relative(root, files[0])));
392
+ return problems;
393
+ }
394
+
395
+ // ---------------------------------------------------------------------------------------------------
396
+ // What the build ships
397
+
398
+ // This package's folder: in the site's packages/editor/ or in node_modules/@morphemecms/cms/.
399
+ const PACKAGE = fileURLToPath(new URL('..', import.meta.url));
400
+ /** Whether a file is this package's own (not one of the packages it uses). @param {string} file */
401
+ const isOwn = (file) => {
402
+ const path = posix(relative(PACKAGE, file));
403
+ return !path.startsWith('../') && !isAbsolute(path) && !path.split('/').includes('node_modules');
404
+ };
405
+ /** The folder of the package a file of the bundle is in, but none for this package's own: those are where the editor,
406
+ * the site's pages or the standard theme bring what they use. @param {string} file */
407
+ const libraryDirOf = (file) => (isOwn(file) ? null : packageDirOf(file));
408
+
409
+ /** Who brings a file of the site, by its folder: the standard theme (this package's theme/), the site's pages and
410
+ * what they read (this package's pages/ but /editor/, and site/), the rest of the editor (this package), a theme
411
+ * (src/themes/<id>/), an app (src/apps/<id>/), or the site's own code (the rest). */
412
+ function whereOf(file, root) {
413
+ const inPackage = posix(relative(PACKAGE, file));
414
+ if (isOwn(file)) {
415
+ if (inPackage.startsWith('theme/')) return ownerId('theme', 'saturn');
416
+ if (/^(site|pages|defaults)\//.test(inPackage) && !inPackage.startsWith('pages/editor/')) return 'site';
417
+ return 'editor';
418
+ }
419
+ const path = posix(relative(root, file));
420
+ const own = path.match(/^src\/(themes|apps)\/([^/]+)\//);
421
+ if (own) return ownerId(own[1] === 'apps' ? 'app' : 'theme', own[2]);
422
+ return 'site';
423
+ }
424
+
425
+ /** The bundler's helpers that it writes into the bundle (Vite's and Rolldown's virtual modules): their package. The
426
+ * site's own virtual modules (the apps' folders, the theme's icons) are made of its own files. */
427
+ const HELPERS = [
428
+ [/^\0vite\//, 'vite'],
429
+ [/^\0rolldown\//, 'rolldown'],
430
+ ];
431
+ const OWN_VIRTUAL = [/^\0virtual:app-folders$/, /^\0site-theme-icons?(:|$)/];
432
+
433
+ /** An app or a theme as licensesIntegration takes it: its kind and id, its name, version and who made it, its manifest
434
+ * (its defineApp or its theme.json, with `license` and `thirdParty`), its folder, and whether the site is built with it
435
+ * (an app installed; the theme in use, and the standard theme it builds on).
436
+ * @typedef {{ kind: 'app' | 'theme', id: string, name: string, version?: string | null, author: string,
437
+ * manifest: { license?: string, thirdParty?: object[] }, folder: string, inUse: boolean }} Owner */
438
+
439
+ /** The apps (all in src/apps/, their defineApp as `load` loads it) and the themes (all in src/themes/, their
440
+ * theme.json) as licensesIntegration takes them; `themesInUse`: those the site is built with.
441
+ * @param {string} root @param {(id: string) => Promise<any>} load @param {string[]} themesInUse
442
+ * @returns {Promise<Owner[]>} */
443
+ export async function siteOwners(root, load, themesInUse) {
444
+ const installed = installedApps(root);
445
+ const apps = [];
446
+ for (const id of appIds(root).filter((x) => existsSync(join(root, 'src/apps', x, 'index.ts')))) {
447
+ const app = await load(id);
448
+ apps.push({
449
+ kind: 'app',
450
+ id,
451
+ name: app.label,
452
+ version: app.version ?? null,
453
+ author: app.publisher,
454
+ manifest: app,
455
+ folder: join(root, 'src/apps', id),
456
+ inUse: installed.includes(id),
457
+ });
458
+ }
459
+ // The standard theme, this package's theme/ (STANDARD_THEME in site/theme.mjs), and the site's in src/themes/.
460
+ const dir = join(root, 'src/themes');
461
+ const folders = [
462
+ { id: 'saturn', folder: fileURLToPath(new URL('../theme', import.meta.url)) },
463
+ ...(existsSync(dir) ? readdirSync(dir, { withFileTypes: true }) : [])
464
+ .filter((d) => d.isDirectory() && existsSync(join(dir, d.name, 'theme.json')))
465
+ .map((d) => ({ id: d.name, folder: join(dir, d.name) })),
466
+ ];
467
+ const themes = folders.map(({ id, folder }) => {
468
+ const manifest = JSON.parse(readFileSync(join(folder, 'theme.json'), 'utf8'));
469
+ return {
470
+ kind: 'theme',
471
+ id,
472
+ name: manifest.name,
473
+ version: manifest.version ?? null,
474
+ author: manifest.author,
475
+ manifest,
476
+ folder,
477
+ inUse: themesInUse.includes(id),
478
+ };
479
+ });
480
+ return [...apps, ...themes];
481
+ }
482
+
483
+ /** The Astro integration that finds the licences of what the build ships and writes them, with the icon sets' and the
484
+ * apps' and themes' own and declared, to dist/editor/licenses.json (see the top of this file). `iconPacks`: the icon
485
+ * packs there are, the system's and the themes' (IconPack); `owners`: the apps and the themes (Owner, siteOwners).
486
+ * Stops the build when
487
+ * something shipped has no licence it can show, or comes from somewhere the list cannot name.
488
+ * @param {{ root: string, iconPacks: () => IconPack[], owners: () => Promise<Owner[]> }} options
489
+ * @returns {import('astro').AstroIntegration} */
490
+ export function licensesIntegration({ root, iconPacks, owners }) {
491
+ // Each package shipped: its folder, the kinds it is shipped as, who brings it and through which packages.
492
+ const shipped = new Map();
493
+ const unknown = new Set();
494
+ const note = (dir, kind, where, via) => {
495
+ if (!shipped.has(dir)) shipped.set(dir, { kinds: new Set(), where: new Set(), via: new Set() });
496
+ const x = shipped.get(dir);
497
+ x.kinds.add(kind);
498
+ if (where) x.where.add(where);
499
+ if (via && via !== dir) x.via.add(via);
500
+ };
501
+ const helperOf = (id) => HELPERS.find(([re]) => re.test(id))?.[1];
502
+
503
+ /** The packages a stylesheet of the site imports, followed through its own @imports (a theme's global.css → the
504
+ * standard theme's base.css → tailwindcss), each with the file that imports it. */
505
+ const cssImports = (file, seen = new Set()) => {
506
+ if (seen.has(file) || !existsSync(file)) return [];
507
+ seen.add(file);
508
+ const css = readFileSync(file, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '');
509
+ return [...css.matchAll(/@(?:import|plugin)\s+(?:url\()?\s*['"]([^'"]+)['"]/g)].flatMap(([, spec]) =>
510
+ spec.startsWith('.') ? cssImports(join(dirname(file), spec), seen) : /^(\/|https?:|data:)/.test(spec) ? [] : [{ spec, file }],
511
+ );
512
+ };
513
+
514
+ const plugin = {
515
+ name: 'site-licenses',
516
+ generateBundle(_, bundle) {
517
+ const client = this.environment?.name === 'client';
518
+ const info = (id) => this.getModuleInfo(id);
519
+ // The site's files that import a module of a package first (its importers, up to the site's own files): who
520
+ // brings it, and through which package.
521
+ const usersOf = (id) => {
522
+ const found = [];
523
+ const seen = new Set([id]);
524
+ let next = [id];
525
+ while (next.length && found.length < 50) {
526
+ const after = [];
527
+ for (const m of next)
528
+ for (const by of [...(info(m)?.importers ?? []), ...(info(m)?.dynamicImporters ?? [])]) {
529
+ if (seen.has(by)) continue;
530
+ seen.add(by);
531
+ if (by.startsWith('\0') || libraryDirOf(by)) after.push(by);
532
+ else found.push({ where: whereOf(by.split('?')[0], root), via: libraryDirOf(m) });
533
+ }
534
+ next = after;
535
+ }
536
+ return found;
537
+ };
538
+ for (const file of Object.values(bundle)) {
539
+ if (file.type === 'asset') {
540
+ // A file a package brings (a font its stylesheet points to), from either build.
541
+ for (const original of file.originalFileNames ?? []) {
542
+ const dir = original.includes('node_modules/') ? packageDirOf(join(root, original)) : null;
543
+ if (dir) note(dir, /\.(woff2?|ttf|otf|eot)$/i.test(original) ? 'font' : 'library', null);
544
+ }
545
+ continue;
546
+ }
547
+ for (const id of file.moduleIds ?? Object.keys(file.modules)) {
548
+ const path = id.split('?')[0];
549
+ // The pages' styles are in the server's build too (they are written into the pages): its stylesheets'.
550
+ if (/\.css$/.test(path) && (!path.includes('/node_modules/') || isOwn(path)) && !id.startsWith('\0'))
551
+ for (const { spec, file: by } of cssImports(path)) {
552
+ const dir = packageDir(packageName(spec), dirname(by));
553
+ if (dir) note(dir, 'library', whereOf(by, root));
554
+ else unknown.add(`${posix(relative(root, by))}: ${spec}`);
555
+ }
556
+ // Only the browser's bundle is downloaded as code.
557
+ if (!client) continue;
558
+ if (id.startsWith('\0')) {
559
+ const helper = helperOf(id);
560
+ if (helper) note(packageDir(helper, root), 'library', 'site');
561
+ else if (!OWN_VIRTUAL.some((re) => re.test(id))) unknown.add(id.slice(1));
562
+ continue;
563
+ }
564
+ // This package itself (the CMS, MIT), where its own code is shipped.
565
+ if (isOwn(path)) {
566
+ note(realpathSync(PACKAGE), 'library', whereOf(path, root));
567
+ continue;
568
+ }
569
+ const dir = packageDirOf(path);
570
+ if (!dir) continue;
571
+ const users = usersOf(id);
572
+ if (!users.length) note(dir, 'library', 'site');
573
+ for (const { where, via } of users) note(dir, 'library', where, via);
574
+ }
575
+ }
576
+ },
577
+ };
578
+
579
+ return {
580
+ name: 'site-licenses',
581
+ hooks: {
582
+ 'astro:config:setup': ({ updateConfig }) => updateConfig({ vite: { plugins: [plugin] } }),
583
+ 'astro:build:done': async ({ dir, logger }) => {
584
+ const built = fileURLToPath(dir);
585
+ // Astro's islands: the script that wakes them, which Astro writes into every page with one.
586
+ const pages = readdirSync(built, { recursive: true, encoding: 'utf8' }).filter((f) => f.endsWith('.html'));
587
+ if (pages.some((f) => readFileSync(join(built, f), 'utf8').includes('<astro-island')))
588
+ note(packageDir('astro', root), 'library', 'site');
589
+ const problems = [...unknown].map(
590
+ (id) =>
591
+ `${id}: kommer med på sitet, men ikke fra en pakke, så licensen kan ikke findes. Skriv i packages/editor/lib/licenses.mjs, hvor det kommer fra.`,
592
+ );
593
+
594
+ const works = new Map();
595
+ const add = (work) => {
596
+ const had = works.get(work.id);
597
+ works.set(work.id, had ? { ...work, ...had, where: [...new Set([...had.where, ...work.where])].sort() } : work);
598
+ };
599
+ // What is shipped: a package that brings a font is the font.
600
+ for (const [dir, x] of shipped) {
601
+ const info = packageInfo(dir);
602
+ const via = [...x.via].map((d) => packageInfo(d).name).filter((n) => n !== info.name);
603
+ const work = {
604
+ ...info,
605
+ id: info.name,
606
+ kind: x.kinds.has('font') ? 'font' : 'library',
607
+ where: [...x.where].sort(),
608
+ ...(via.length ? { via: [...new Set(via)].sort() } : {}),
609
+ };
610
+ problems.push(...workProblems(work, 'Licenser'));
611
+ add(work);
612
+ }
613
+ // The icon packs, each with the sets it takes icons from besides its own; a theme's under it (its packs).
614
+ const packs = iconPacks();
615
+ const packWorks = new Map();
616
+ for (const pack of packs) {
617
+ const own = iconPackWorks(pack, root);
618
+ // The pack the site and the editor draw with is used there; a theme's own is the theme's.
619
+ own[0].where = [...(pack.inUse ? ['editor', 'site'] : []), ...(pack.theme ? [ownerId('theme', pack.theme)] : [])];
620
+ for (const work of own) {
621
+ problems.push(...workProblems(work, `Ikonpakken ${pack.name}`));
622
+ const had = works.get(work.id);
623
+ works.set(work.id, had ? { ...had, via: [...new Set([...(had.via ?? []), ...(work.via ?? [])])].sort() } : work);
624
+ }
625
+ if (pack.theme) packWorks.set(pack.theme, [...(packWorks.get(pack.theme) ?? []), ...own.map((w) => w.id)]);
626
+ }
627
+
628
+ // The apps' and the themes' own licences and what they declare (checked by npm run check:content, with what they
629
+ // give in place of what a package lacks), shipped or not; and what is shipped through them alone.
630
+ const owned = [];
631
+ for (const o of await owners()) {
632
+ const id = ownerId(o.kind, o.id);
633
+ const { license, text, works: declared } = declaredWorks(o.manifest, { folder: o.folder, owner: id });
634
+ for (const work of declared) {
635
+ const shippedAs = works.get(work.id);
636
+ // A declared package that is shipped keeps what the bundle says of it, and its declaration's kind.
637
+ if (shippedAs && work.kind !== 'icons') works.set(work.id, { ...shippedAs, kind: work.kind });
638
+ // Not downloaded though the site is built with it (the Worker's, the build's, a font another theme's replaces).
639
+ else if (!shippedAs) add({ ...work, where: [], ...(o.inUse ? { shipped: false } : {}) });
640
+ if (o.inUse) add({ ...works.get(work.id), where: [id] });
641
+ }
642
+ const through = [...works.values()].filter(
643
+ (w) => w.where.includes(id) && !w.where.some((x) => x === 'editor' || x === 'site') && !declared.some((d) => d.id === w.id),
644
+ );
645
+ owned.push({
646
+ id,
647
+ kind: o.kind,
648
+ key: o.id,
649
+ name: o.name,
650
+ version: o.version ?? null,
651
+ author: o.author,
652
+ license: license ?? null,
653
+ text,
654
+ works: [
655
+ ...declared.map((w) => w.id),
656
+ ...through.map((w) => w.id).sort(),
657
+ ...(o.kind === 'theme' ? (packWorks.get(o.id) ?? []) : []),
658
+ ],
659
+ inUse: o.inUse,
660
+ });
661
+ }
662
+ if (problems.length) throw new Error(`Licenserne kan ikke vises:\n${[...new Set(problems)].join('\n')}`);
663
+ const all = [...works.values()].sort((a, b) => a.name.localeCompare(b.name));
664
+ mkdirSync(join(built, 'editor'), { recursive: true });
665
+ writeFileSync(join(built, 'editor', 'licenses.json'), `${JSON.stringify({ works: all, owners: owned })}\n`);
666
+ logger.info(
667
+ `${shipped.size} pakker på sitet og i editoren, ${packs.length} ikonpakker og ${owned.length} apps og temaer med deres licenser i editor/licenses.json.`,
668
+ );
669
+ },
670
+ },
671
+ };
672
+ }
673
+
674
+ // ---------------------------------------------------------------------------------------------------
675
+ // The store
676
+
677
+ /** An app's or a theme's licences as the store's catalog has them (StoreLicenses in src/licenses.ts): its own licence's
678
+ * name, and each work's name, version, who made it, its licence's name and kind, without the texts.
679
+ * @param {{ license?: string, thirdParty?: object[] }} manifest @param {{ folder: string, owner: string }} where */
680
+ export function storeLicenses(manifest, where) {
681
+ const { license, works } = declaredWorks(manifest, where);
682
+ return { license, works: works.map(({ name, version, author, license, kind }) => ({ name, version, author, license, kind })) };
683
+ }