@morphemecms/cms 0.1.0 → 0.2.0-next-20261104150211

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (908) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -21
  3. package/README.md +51 -51
  4. package/astro.mjs +162 -162
  5. package/bin/morpheme.mjs +38 -38
  6. package/client.d.ts +10 -10
  7. package/defaults/blockTexts.ts +33 -33
  8. package/defaults/collections.ts +774 -774
  9. package/defaults/colors.ts +125 -125
  10. package/defaults/company.ts +20 -20
  11. package/defaults/editor.ts +178 -178
  12. package/defaults/internalLinks.ts +30 -30
  13. package/defaults/opens.ts +18 -18
  14. package/defaults/popup.tsx +93 -93
  15. package/defaults/privacy.ts +79 -79
  16. package/defaults/rules.ts +450 -450
  17. package/defaults/schema.ts +16 -16
  18. package/defaults/sitedata.ts +129 -129
  19. package/defaults/standard.ts +106 -106
  20. package/defaults/standardPages.ts +87 -87
  21. package/defaults/texts.ts +481 -481
  22. package/demo/README.md +26 -26
  23. package/demo/src/content/blog/build-a-page-from-blocks.md +19 -19
  24. package/demo/src/content/blog/colors-everyone-can-read.md +19 -19
  25. package/demo/src/content/blog/edit-your-website-from-your-phone.md +21 -21
  26. package/demo/src/content/blog/every-save-is-a-version.md +21 -21
  27. package/demo/src/content/blog/schedule-a-post.md +17 -17
  28. package/demo/src/content/blog/secure-from-day-one.md +17 -17
  29. package/demo/src/content/blog/seo-without-the-guesswork.md +23 -23
  30. package/demo/src/content/blog/switch-themes-without-losing-anything.md +23 -23
  31. package/demo/src/content/blog/the-app-store.md +21 -21
  32. package/demo/src/content/pages/about.md +22 -22
  33. package/demo/src/content/pages/app-store.md +30 -30
  34. package/demo/src/content/pages/blocks.md +98 -98
  35. package/demo/src/content/pages/blog-page.md +11 -11
  36. package/demo/src/content/pages/contact.md +16 -16
  37. package/demo/src/content/pages/get-started.md +20 -20
  38. package/demo/src/content/pages/home.md +26 -26
  39. package/demo/src/content/pages/page-not-found.md +11 -11
  40. package/demo/src/content/pages/privacy-policy.md +24 -24
  41. package/demo/src/data/blocks.json +25 -25
  42. package/demo/src/data/booking.json +6 -6
  43. package/demo/src/data/categories/apps.json +6 -6
  44. package/demo/src/data/categories/design.json +6 -6
  45. package/demo/src/data/categories/editing.json +6 -6
  46. package/demo/src/data/categories/security.json +6 -6
  47. package/demo/src/data/categories/seo.json +6 -6
  48. package/demo/src/data/colors.json +75 -75
  49. package/demo/src/data/contact.json +8 -8
  50. package/demo/src/data/cookies.json +21 -21
  51. package/demo/src/data/footer.json +27 -27
  52. package/demo/src/data/menu.json +35 -35
  53. package/demo/src/data/mobile-menu.json +25 -25
  54. package/demo/src/data/popups/booking-bar.json +13 -13
  55. package/demo/src/data/popups/try-the-editor.json +16 -16
  56. package/demo/src/data/standard-pages.json +8 -8
  57. package/demo/src/data/testimonials/sample-bakery.json +10 -10
  58. package/demo/src/data/testimonials/sample-clinic.json +10 -10
  59. package/demo/src/data/testimonials/sample-studio.json +10 -10
  60. package/demo/src/site/colors.ts +11 -11
  61. package/demo/src/site/config.ts +19 -19
  62. package/icons/lucide/LICENSE +43 -43
  63. package/icons/lucide/address-book.svg +1 -1
  64. package/icons/lucide/app-window.svg +1 -1
  65. package/icons/lucide/arrow-counter-clockwise.svg +1 -1
  66. package/icons/lucide/arrow-down.svg +1 -1
  67. package/icons/lucide/arrow-left.svg +1 -1
  68. package/icons/lucide/arrow-right.svg +1 -1
  69. package/icons/lucide/arrow-square-out.svg +1 -1
  70. package/icons/lucide/arrow-u-up-left.svg +1 -1
  71. package/icons/lucide/arrow-u-up-right.svg +1 -1
  72. package/icons/lucide/arrow-up-right.svg +1 -1
  73. package/icons/lucide/arrow-up.svg +1 -1
  74. package/icons/lucide/arrows-down-up.svg +1 -1
  75. package/icons/lucide/arrows-in-line-horizontal.svg +1 -1
  76. package/icons/lucide/arrows-out-line-horizontal.svg +1 -1
  77. package/icons/lucide/article.svg +1 -1
  78. package/icons/lucide/bank.svg +1 -1
  79. package/icons/lucide/bell.svg +1 -1
  80. package/icons/lucide/bicycle.svg +1 -1
  81. package/icons/lucide/binoculars.svg +1 -1
  82. package/icons/lucide/book-open-text.svg +1 -1
  83. package/icons/lucide/book-open.svg +1 -1
  84. package/icons/lucide/browser.svg +1 -1
  85. package/icons/lucide/buildings.svg +1 -1
  86. package/icons/lucide/bus.svg +1 -1
  87. package/icons/lucide/calendar-blank.svg +1 -1
  88. package/icons/lucide/calendar-check.svg +1 -1
  89. package/icons/lucide/car.svg +1 -1
  90. package/icons/lucide/cards.svg +1 -1
  91. package/icons/lucide/caret-down.svg +1 -1
  92. package/icons/lucide/caret-left.svg +1 -1
  93. package/icons/lucide/caret-right.svg +1 -1
  94. package/icons/lucide/caret-up.svg +1 -1
  95. package/icons/lucide/certificate.svg +1 -1
  96. package/icons/lucide/chart-line-up.svg +1 -1
  97. package/icons/lucide/chats.svg +1 -1
  98. package/icons/lucide/check-circle.svg +1 -1
  99. package/icons/lucide/check.svg +1 -1
  100. package/icons/lucide/circle-half.svg +1 -1
  101. package/icons/lucide/circle.svg +1 -1
  102. package/icons/lucide/clock-counter-clockwise.svg +1 -1
  103. package/icons/lucide/clock.svg +1 -1
  104. package/icons/lucide/code.svg +1 -1
  105. package/icons/lucide/coffee.svg +1 -1
  106. package/icons/lucide/columns.svg +1 -1
  107. package/icons/lucide/cookie.svg +1 -1
  108. package/icons/lucide/copy.svg +1 -1
  109. package/icons/lucide/credit-card.svg +1 -1
  110. package/icons/lucide/currency-circle-dollar.svg +1 -1
  111. package/icons/lucide/cursor-click.svg +1 -1
  112. package/icons/lucide/database.svg +1 -1
  113. package/icons/lucide/desktop.svg +1 -1
  114. package/icons/lucide/device-mobile.svg +1 -1
  115. package/icons/lucide/door-open.svg +1 -1
  116. package/icons/lucide/download-simple.svg +1 -1
  117. package/icons/lucide/envelope-simple.svg +1 -1
  118. package/icons/lucide/eye-slash.svg +1 -1
  119. package/icons/lucide/eye.svg +1 -1
  120. package/icons/lucide/file-pdf.svg +1 -1
  121. package/icons/lucide/file-text.svg +1 -1
  122. package/icons/lucide/file-video.svg +1 -1
  123. package/icons/lucide/file-zip.svg +1 -1
  124. package/icons/lucide/flower-lotus.svg +1 -1
  125. package/icons/lucide/folder-simple.svg +1 -1
  126. package/icons/lucide/funnel.svg +1 -1
  127. package/icons/lucide/gauge.svg +1 -1
  128. package/icons/lucide/gear.svg +1 -1
  129. package/icons/lucide/github-logo.svg +1 -1
  130. package/icons/lucide/globe.svg +1 -1
  131. package/icons/lucide/google-logo.svg +1 -1
  132. package/icons/lucide/graduation-cap.svg +1 -1
  133. package/icons/lucide/hammer.svg +1 -1
  134. package/icons/lucide/hand-heart.svg +1 -1
  135. package/icons/lucide/handshake.svg +1 -1
  136. package/icons/lucide/hard-drives.svg +1 -1
  137. package/icons/lucide/heart.svg +1 -1
  138. package/icons/lucide/house.svg +1 -1
  139. package/icons/lucide/image-square.svg +1 -1
  140. package/icons/lucide/image.svg +1 -1
  141. package/icons/lucide/info.svg +1 -1
  142. package/icons/lucide/keyboard.svg +1 -1
  143. package/icons/lucide/leaf.svg +1 -1
  144. package/icons/lucide/lifebuoy.svg +1 -1
  145. package/icons/lucide/lightbulb.svg +1 -1
  146. package/icons/lucide/link-break.svg +1 -1
  147. package/icons/lucide/link-simple.svg +1 -1
  148. package/icons/lucide/list-bullets.svg +1 -1
  149. package/icons/lucide/list-checks.svg +1 -1
  150. package/icons/lucide/list-numbers.svg +1 -1
  151. package/icons/lucide/list.svg +1 -1
  152. package/icons/lucide/lock-simple-open.svg +1 -1
  153. package/icons/lucide/lock-simple.svg +1 -1
  154. package/icons/lucide/magnifying-glass.svg +1 -1
  155. package/icons/lucide/map-pin.svg +1 -1
  156. package/icons/lucide/map-trifold.svg +1 -1
  157. package/icons/lucide/medal.svg +1 -1
  158. package/icons/lucide/megaphone.svg +1 -1
  159. package/icons/lucide/minus.svg +1 -1
  160. package/icons/lucide/moon.svg +1 -1
  161. package/icons/lucide/newspaper.svg +1 -1
  162. package/icons/lucide/pack.json +23 -23
  163. package/icons/lucide/paint-brush-broad.svg +1 -1
  164. package/icons/lucide/palette.svg +1 -1
  165. package/icons/lucide/paper-plane-tilt.svg +1 -1
  166. package/icons/lucide/pencil-simple.svg +1 -1
  167. package/icons/lucide/phone.svg +1 -1
  168. package/icons/lucide/play-fill.svg +1 -1
  169. package/icons/lucide/plus.svg +1 -1
  170. package/icons/lucide/prohibit.svg +1 -1
  171. package/icons/lucide/puzzle-piece.svg +1 -1
  172. package/icons/lucide/question.svg +1 -1
  173. package/icons/lucide/quotes.svg +1 -1
  174. package/icons/lucide/rows.svg +1 -1
  175. package/icons/lucide/ruler.svg +1 -1
  176. package/icons/lucide/scan.svg +1 -1
  177. package/icons/lucide/shapes.svg +1 -1
  178. package/icons/lucide/share-network.svg +1 -1
  179. package/icons/lucide/shield-check.svg +1 -1
  180. package/icons/lucide/sidebar-simple.svg +1 -1
  181. package/icons/lucide/sign-out.svg +1 -1
  182. package/icons/lucide/signpost.svg +1 -1
  183. package/icons/lucide/sliders-horizontal.svg +1 -1
  184. package/icons/lucide/smiley.svg +1 -1
  185. package/icons/lucide/sparkle.svg +1 -1
  186. package/icons/lucide/square-half-bottom.svg +1 -1
  187. package/icons/lucide/square.svg +1 -1
  188. package/icons/lucide/squares-four.svg +1 -1
  189. package/icons/lucide/sticker.svg +1 -1
  190. package/icons/lucide/storefront.svg +1 -1
  191. package/icons/lucide/sun.svg +1 -1
  192. package/icons/lucide/swatches.svg +1 -1
  193. package/icons/lucide/tag.svg +1 -1
  194. package/icons/lucide/text-aa.svg +1 -1
  195. package/icons/lucide/text-align-left.svg +1 -1
  196. package/icons/lucide/text-b.svg +1 -1
  197. package/icons/lucide/text-h-one.svg +1 -1
  198. package/icons/lucide/text-h-three.svg +1 -1
  199. package/icons/lucide/text-h-two.svg +1 -1
  200. package/icons/lucide/text-italic.svg +1 -1
  201. package/icons/lucide/text-t.svg +1 -1
  202. package/icons/lucide/ticket.svg +1 -1
  203. package/icons/lucide/toggle-right.svg +1 -1
  204. package/icons/lucide/train.svg +1 -1
  205. package/icons/lucide/trash.svg +1 -1
  206. package/icons/lucide/upload-simple.svg +1 -1
  207. package/icons/lucide/user-circle.svg +1 -1
  208. package/icons/lucide/user.svg +1 -1
  209. package/icons/lucide/users-three.svg +1 -1
  210. package/icons/lucide/users.svg +1 -1
  211. package/icons/lucide/video-camera.svg +1 -1
  212. package/icons/lucide/warning-circle.svg +1 -1
  213. package/icons/lucide/warning.svg +1 -1
  214. package/icons/lucide/wave-sine.svg +1 -1
  215. package/icons/lucide/wheelchair.svg +1 -1
  216. package/icons/lucide/wrench.svg +1 -1
  217. package/icons/lucide/x.svg +1 -1
  218. package/icons/material-symbols/LICENSE +201 -201
  219. package/icons/material-symbols/address-book.svg +1 -1
  220. package/icons/material-symbols/app-window.svg +1 -1
  221. package/icons/material-symbols/arrow-counter-clockwise.svg +1 -1
  222. package/icons/material-symbols/arrow-down.svg +1 -1
  223. package/icons/material-symbols/arrow-left.svg +1 -1
  224. package/icons/material-symbols/arrow-right.svg +1 -1
  225. package/icons/material-symbols/arrow-square-out.svg +1 -1
  226. package/icons/material-symbols/arrow-u-up-left.svg +1 -1
  227. package/icons/material-symbols/arrow-u-up-right.svg +1 -1
  228. package/icons/material-symbols/arrow-up-right.svg +1 -1
  229. package/icons/material-symbols/arrow-up.svg +1 -1
  230. package/icons/material-symbols/arrows-down-up.svg +1 -1
  231. package/icons/material-symbols/arrows-in-line-horizontal.svg +1 -1
  232. package/icons/material-symbols/arrows-out-line-horizontal.svg +1 -1
  233. package/icons/material-symbols/article.svg +1 -1
  234. package/icons/material-symbols/bank.svg +1 -1
  235. package/icons/material-symbols/bell.svg +1 -1
  236. package/icons/material-symbols/bicycle.svg +1 -1
  237. package/icons/material-symbols/binoculars.svg +1 -1
  238. package/icons/material-symbols/book-open-text.svg +1 -1
  239. package/icons/material-symbols/book-open.svg +1 -1
  240. package/icons/material-symbols/browser.svg +1 -1
  241. package/icons/material-symbols/buildings.svg +1 -1
  242. package/icons/material-symbols/bus.svg +1 -1
  243. package/icons/material-symbols/calendar-blank.svg +1 -1
  244. package/icons/material-symbols/calendar-check.svg +1 -1
  245. package/icons/material-symbols/car.svg +1 -1
  246. package/icons/material-symbols/cards.svg +1 -1
  247. package/icons/material-symbols/caret-down.svg +1 -1
  248. package/icons/material-symbols/caret-left.svg +1 -1
  249. package/icons/material-symbols/caret-right.svg +1 -1
  250. package/icons/material-symbols/caret-up.svg +1 -1
  251. package/icons/material-symbols/certificate.svg +1 -1
  252. package/icons/material-symbols/chart-line-up.svg +1 -1
  253. package/icons/material-symbols/chats.svg +1 -1
  254. package/icons/material-symbols/check-circle.svg +1 -1
  255. package/icons/material-symbols/check.svg +1 -1
  256. package/icons/material-symbols/circle-half.svg +1 -1
  257. package/icons/material-symbols/circle.svg +1 -1
  258. package/icons/material-symbols/clock-counter-clockwise.svg +1 -1
  259. package/icons/material-symbols/clock.svg +1 -1
  260. package/icons/material-symbols/code.svg +1 -1
  261. package/icons/material-symbols/coffee.svg +1 -1
  262. package/icons/material-symbols/columns.svg +1 -1
  263. package/icons/material-symbols/cookie.svg +1 -1
  264. package/icons/material-symbols/copy.svg +1 -1
  265. package/icons/material-symbols/credit-card.svg +1 -1
  266. package/icons/material-symbols/currency-circle-dollar.svg +1 -1
  267. package/icons/material-symbols/cursor-click.svg +1 -1
  268. package/icons/material-symbols/database.svg +1 -1
  269. package/icons/material-symbols/desktop.svg +1 -1
  270. package/icons/material-symbols/device-mobile.svg +1 -1
  271. package/icons/material-symbols/door-open.svg +1 -1
  272. package/icons/material-symbols/download-simple.svg +1 -1
  273. package/icons/material-symbols/envelope-simple.svg +1 -1
  274. package/icons/material-symbols/eye-slash.svg +1 -1
  275. package/icons/material-symbols/eye.svg +1 -1
  276. package/icons/material-symbols/file-pdf.svg +1 -1
  277. package/icons/material-symbols/file-text.svg +1 -1
  278. package/icons/material-symbols/file-video.svg +1 -1
  279. package/icons/material-symbols/file-zip.svg +1 -1
  280. package/icons/material-symbols/flower-lotus.svg +1 -1
  281. package/icons/material-symbols/folder-simple.svg +1 -1
  282. package/icons/material-symbols/funnel.svg +1 -1
  283. package/icons/material-symbols/gauge.svg +1 -1
  284. package/icons/material-symbols/gear.svg +1 -1
  285. package/icons/material-symbols/github-logo.svg +1 -1
  286. package/icons/material-symbols/globe.svg +1 -1
  287. package/icons/material-symbols/google-logo.svg +1 -1
  288. package/icons/material-symbols/graduation-cap.svg +1 -1
  289. package/icons/material-symbols/hammer.svg +1 -1
  290. package/icons/material-symbols/hand-heart.svg +1 -1
  291. package/icons/material-symbols/handshake.svg +1 -1
  292. package/icons/material-symbols/hard-drives.svg +1 -1
  293. package/icons/material-symbols/heart.svg +1 -1
  294. package/icons/material-symbols/house.svg +1 -1
  295. package/icons/material-symbols/image-square.svg +1 -1
  296. package/icons/material-symbols/image.svg +1 -1
  297. package/icons/material-symbols/info.svg +1 -1
  298. package/icons/material-symbols/keyboard.svg +1 -1
  299. package/icons/material-symbols/leaf.svg +1 -1
  300. package/icons/material-symbols/lifebuoy.svg +1 -1
  301. package/icons/material-symbols/lightbulb.svg +1 -1
  302. package/icons/material-symbols/link-break.svg +1 -1
  303. package/icons/material-symbols/link-simple.svg +1 -1
  304. package/icons/material-symbols/list-bullets.svg +1 -1
  305. package/icons/material-symbols/list-checks.svg +1 -1
  306. package/icons/material-symbols/list-numbers.svg +1 -1
  307. package/icons/material-symbols/list.svg +1 -1
  308. package/icons/material-symbols/lock-simple-open.svg +1 -1
  309. package/icons/material-symbols/lock-simple.svg +1 -1
  310. package/icons/material-symbols/magnifying-glass.svg +1 -1
  311. package/icons/material-symbols/map-pin.svg +1 -1
  312. package/icons/material-symbols/map-trifold.svg +1 -1
  313. package/icons/material-symbols/medal.svg +1 -1
  314. package/icons/material-symbols/megaphone.svg +1 -1
  315. package/icons/material-symbols/minus.svg +1 -1
  316. package/icons/material-symbols/moon.svg +1 -1
  317. package/icons/material-symbols/newspaper.svg +1 -1
  318. package/icons/material-symbols/pack.json +29 -29
  319. package/icons/material-symbols/paint-brush-broad.svg +1 -1
  320. package/icons/material-symbols/palette.svg +1 -1
  321. package/icons/material-symbols/paper-plane-tilt.svg +1 -1
  322. package/icons/material-symbols/pencil-simple.svg +1 -1
  323. package/icons/material-symbols/phone.svg +1 -1
  324. package/icons/material-symbols/play-fill.svg +1 -1
  325. package/icons/material-symbols/plus.svg +1 -1
  326. package/icons/material-symbols/prohibit.svg +1 -1
  327. package/icons/material-symbols/puzzle-piece.svg +1 -1
  328. package/icons/material-symbols/question.svg +1 -1
  329. package/icons/material-symbols/quotes.svg +1 -1
  330. package/icons/material-symbols/rows.svg +1 -1
  331. package/icons/material-symbols/ruler.svg +1 -1
  332. package/icons/material-symbols/scan.svg +1 -1
  333. package/icons/material-symbols/shapes.svg +1 -1
  334. package/icons/material-symbols/share-network.svg +1 -1
  335. package/icons/material-symbols/shield-check.svg +1 -1
  336. package/icons/material-symbols/sidebar-simple.svg +1 -1
  337. package/icons/material-symbols/sign-out.svg +1 -1
  338. package/icons/material-symbols/signpost.svg +1 -1
  339. package/icons/material-symbols/sliders-horizontal.svg +1 -1
  340. package/icons/material-symbols/smiley.svg +1 -1
  341. package/icons/material-symbols/sparkle.svg +1 -1
  342. package/icons/material-symbols/square-half-bottom.svg +1 -1
  343. package/icons/material-symbols/square.svg +1 -1
  344. package/icons/material-symbols/squares-four.svg +1 -1
  345. package/icons/material-symbols/sticker.svg +1 -1
  346. package/icons/material-symbols/storefront.svg +1 -1
  347. package/icons/material-symbols/sun.svg +1 -1
  348. package/icons/material-symbols/swatches.svg +1 -1
  349. package/icons/material-symbols/tag.svg +1 -1
  350. package/icons/material-symbols/text-aa.svg +1 -1
  351. package/icons/material-symbols/text-align-left.svg +1 -1
  352. package/icons/material-symbols/text-b.svg +1 -1
  353. package/icons/material-symbols/text-h-one.svg +1 -1
  354. package/icons/material-symbols/text-h-three.svg +1 -1
  355. package/icons/material-symbols/text-h-two.svg +1 -1
  356. package/icons/material-symbols/text-italic.svg +1 -1
  357. package/icons/material-symbols/text-t.svg +1 -1
  358. package/icons/material-symbols/ticket.svg +1 -1
  359. package/icons/material-symbols/toggle-right.svg +1 -1
  360. package/icons/material-symbols/train.svg +1 -1
  361. package/icons/material-symbols/trash.svg +1 -1
  362. package/icons/material-symbols/upload-simple.svg +1 -1
  363. package/icons/material-symbols/user-circle.svg +1 -1
  364. package/icons/material-symbols/user.svg +1 -1
  365. package/icons/material-symbols/users-three.svg +1 -1
  366. package/icons/material-symbols/users.svg +1 -1
  367. package/icons/material-symbols/video-camera.svg +1 -1
  368. package/icons/material-symbols/warning-circle.svg +1 -1
  369. package/icons/material-symbols/warning.svg +1 -1
  370. package/icons/material-symbols/wave-sine.svg +1 -1
  371. package/icons/material-symbols/wheelchair.svg +1 -1
  372. package/icons/material-symbols/wrench.svg +1 -1
  373. package/icons/material-symbols/x.svg +1 -1
  374. package/icons/phosphor/pack.json +8 -8
  375. package/lib/apps.mjs +142 -139
  376. package/lib/apps.test.d.mts +1 -0
  377. package/lib/apps.test.mjs +50 -0
  378. package/lib/blocks.mjs +90 -90
  379. package/lib/caseCollisions.d.mts +4 -0
  380. package/lib/caseCollisions.mjs +62 -0
  381. package/lib/caseCollisions.test.d.mts +1 -0
  382. package/lib/caseCollisions.test.mjs +74 -0
  383. package/lib/colors.ts +86 -86
  384. package/lib/contactBar.ts +18 -18
  385. package/lib/contracts.d.mts +15 -0
  386. package/lib/contracts.mjs +17 -0
  387. package/lib/cookieCategories.mjs +28 -28
  388. package/lib/crop.mjs +83 -83
  389. package/lib/csp.mjs +130 -130
  390. package/lib/cspSources.mjs +60 -60
  391. package/lib/dynamic-colors.ts +426 -426
  392. package/lib/git.mjs +64 -64
  393. package/lib/hooks.ts +51 -51
  394. package/lib/inline.ts +20 -20
  395. package/lib/license-texts/Apache-2.0.txt +190 -190
  396. package/lib/license-texts/BSD-2-Clause.txt +24 -24
  397. package/lib/license-texts/BSD-3-Clause.txt +28 -28
  398. package/lib/license-texts/ISC.txt +15 -15
  399. package/lib/license-texts/MIT.txt +21 -21
  400. package/lib/licenses.d.mts +1 -1
  401. package/lib/licenses.mjs +683 -683
  402. package/lib/markdown.ts +42 -42
  403. package/lib/motion-schemes.mjs +5 -5
  404. package/lib/motion.ts +131 -131
  405. package/lib/notice.mjs +34 -34
  406. package/lib/scheduled.mjs +37 -37
  407. package/lib/snackbar.ts +149 -149
  408. package/lib/status.mjs +18 -18
  409. package/lib/storeEntries.d.mts +18 -0
  410. package/lib/storeEntries.mjs +64 -0
  411. package/lib/storeEntries.test.d.mts +1 -0
  412. package/lib/storeEntries.test.mjs +71 -0
  413. package/lib/svg.mjs +231 -231
  414. package/lib/text-colors.mjs +43 -43
  415. package/lib/video-id.mjs +72 -72
  416. package/lib/video.mjs +91 -91
  417. package/package.json +136 -131
  418. package/pages/404.astro +10 -10
  419. package/pages/[...slug].astro +51 -51
  420. package/pages/_headers.txt +31 -31
  421. package/pages/blog/index.astro +10 -10
  422. package/pages/blog/kategori/[category].astro +18 -18
  423. package/pages/editor/code-images.json.js +25 -25
  424. package/pages/editor/index.astro +75 -75
  425. package/pages/editor/manifest.webmanifest.js +23 -23
  426. package/pages/editor/sw.js +33 -33
  427. package/pages/editor/sw.js.js +4 -4
  428. package/pages/editor/thumbnails.json.js +21 -21
  429. package/pages/editor/version.json.js +22 -22
  430. package/pages/headers.js +4 -4
  431. package/pages/index.astro +10 -10
  432. package/pages/ny.astro +6 -6
  433. package/pages/robots.txt.js +3 -3
  434. package/pages/rss.xml.js +20 -20
  435. package/scripts/app-screenshots.mjs +164 -164
  436. package/scripts/app-workers.mjs +6 -6
  437. package/scripts/bin.mjs +12 -12
  438. package/scripts/built-site.mjs +134 -99
  439. package/scripts/check-consent.mjs +113 -113
  440. package/scripts/check-content.mjs +151 -149
  441. package/scripts/check-demo.mjs +24 -24
  442. package/scripts/check-store.mjs +160 -0
  443. package/scripts/check-themes.mjs +45 -45
  444. package/scripts/check-worker.mjs +569 -569
  445. package/scripts/compare-html.mjs +81 -81
  446. package/scripts/declarations.mjs +10 -0
  447. package/scripts/declarations.test.mjs +32 -0
  448. package/scripts/demo-site.mjs +42 -42
  449. package/scripts/editor-icons.mjs +56 -56
  450. package/scripts/editor-roundtrip.mjs +134 -134
  451. package/scripts/editor-screens.mjs +101 -101
  452. package/scripts/git-env.mjs +9 -9
  453. package/scripts/icon-packs.mjs +151 -151
  454. package/scripts/link-counts.mjs +22 -22
  455. package/scripts/page-colors.mjs +42 -42
  456. package/scripts/releases.mjs +80 -80
  457. package/scripts/responsive-images.mjs +94 -94
  458. package/scripts/scheduled-list.mjs +15 -15
  459. package/scripts/theme-screenshots.mjs +88 -88
  460. package/scripts/types.mjs +17 -21
  461. package/scripts/video-thumbnails.mjs +89 -89
  462. package/scripts/worker-modules.mjs +34 -34
  463. package/site/appCookies.mjs +74 -74
  464. package/site/apps.ts +21 -21
  465. package/site/autolinks.mjs +200 -200
  466. package/site/blockScripts.ts +31 -31
  467. package/site/categories.ts +16 -16
  468. package/site/consent.ts +26 -26
  469. package/site/content.config.ts +84 -84
  470. package/site/content.ts +104 -104
  471. package/site/cookieList.ts +17 -17
  472. package/site/defineSite.d.mts +2 -14
  473. package/site/defineSite.mjs +131 -136
  474. package/site/directives/interact.mjs +31 -31
  475. package/site/editor-version.mjs +26 -26
  476. package/site/fill.ts +13 -13
  477. package/site/format.ts +11 -11
  478. package/site/home.ts +66 -66
  479. package/site/iconPacks.mjs +43 -43
  480. package/site/icons.mjs +605 -605
  481. package/site/images.mjs +157 -157
  482. package/site/motion.ts +13 -13
  483. package/site/noindex.mjs +21 -21
  484. package/site/pageColors.ts +110 -110
  485. package/site/popups.ts +98 -98
  486. package/site/schema.ts +189 -189
  487. package/site/sections.ts +3 -3
  488. package/site/seo.ts +28 -28
  489. package/site/site.ts +76 -76
  490. package/site/siteConfig.mjs +8 -8
  491. package/site/siteCsp.mjs +75 -75
  492. package/site/siteModules.mjs +27 -27
  493. package/site/standardPages.ts +59 -59
  494. package/site/storeTheme.d.mts +6 -0
  495. package/site/storeTheme.mjs +29 -0
  496. package/site/storeTheme.test.d.mts +1 -0
  497. package/site/storeTheme.test.mjs +53 -0
  498. package/site/testimonials.ts +48 -48
  499. package/site/text.ts +43 -43
  500. package/site/theme.mjs +483 -472
  501. package/site/tracking.client.ts +225 -225
  502. package/site/tracking.ts +9 -9
  503. package/src/ActionParts.tsx +205 -205
  504. package/src/Advanced.tsx +152 -152
  505. package/src/App.tsx +901 -904
  506. package/src/AppList.tsx +1362 -1345
  507. package/src/BlockDialog.tsx +360 -360
  508. package/src/BlockParts.tsx +652 -652
  509. package/src/BlockSettings.tsx +533 -533
  510. package/src/BrandForm.tsx +164 -164
  511. package/src/Colors.tsx +476 -476
  512. package/src/CommunicationParts.tsx +199 -199
  513. package/src/CompanyForm.tsx +209 -209
  514. package/src/Consents.tsx +175 -175
  515. package/src/ContainmentParts.tsx +185 -185
  516. package/src/Crop.tsx +152 -152
  517. package/src/DataForm.tsx +434 -434
  518. package/src/Deleted.tsx +177 -177
  519. package/src/EntryForm.tsx +740 -740
  520. package/src/FileView.tsx +30 -30
  521. package/src/FormFrame.tsx +237 -237
  522. package/src/Keywords.tsx +225 -225
  523. package/src/Library.tsx +1563 -1563
  524. package/src/Licenses.tsx +336 -336
  525. package/src/LinkSheet.tsx +138 -138
  526. package/src/MarkdownEditor.tsx +1075 -1075
  527. package/src/Media.tsx +677 -677
  528. package/src/NavigationParts.tsx +350 -350
  529. package/src/NavigationRestParts.tsx +247 -247
  530. package/src/Notifications.tsx +59 -59
  531. package/src/PagePicker.tsx +136 -136
  532. package/src/Parts.tsx +991 -991
  533. package/src/PartsShown.tsx +168 -168
  534. package/src/PickerParts.tsx +183 -183
  535. package/src/Redirects.tsx +450 -450
  536. package/src/Screen.tsx +184 -184
  537. package/src/SectionsField.tsx +65 -65
  538. package/src/SelectionParts.tsx +134 -134
  539. package/src/SeoScores.tsx +184 -184
  540. package/src/Sheet.tsx +35 -35
  541. package/src/ThemeStore.tsx +376 -376
  542. package/src/Tokens.tsx +346 -346
  543. package/src/Versions.tsx +214 -214
  544. package/src/addresses.ts +75 -75
  545. package/src/allIcons.ts +7 -7
  546. package/src/appFiles.ts +29 -29
  547. package/src/apps.ts +281 -281
  548. package/src/ask.tsx +123 -123
  549. package/src/blocks.ts +251 -251
  550. package/src/brand.ts +153 -153
  551. package/src/cache.ts +42 -42
  552. package/src/check.ts +285 -285
  553. package/src/checkSite.ts +256 -256
  554. package/src/{consents.ts → consentData.ts} +26 -26
  555. package/src/cookieList.ts +70 -70
  556. package/src/countries.ts +59 -59
  557. package/src/deploy.ts +155 -155
  558. package/src/editor.css +602 -602
  559. package/src/examples.ts +85 -85
  560. package/src/fields.tsx +942 -942
  561. package/src/frontmatter.mjs +42 -42
  562. package/src/github.ts +376 -376
  563. package/src/i18n/da-DK/advanced.ts +28 -28
  564. package/src/i18n/da-DK/app.ts +71 -71
  565. package/src/i18n/da-DK/apps.ts +90 -90
  566. package/src/i18n/da-DK/blockSettings.ts +38 -38
  567. package/src/i18n/da-DK/blocks.ts +408 -408
  568. package/src/i18n/da-DK/check.ts +25 -25
  569. package/src/i18n/da-DK/colors.ts +64 -64
  570. package/src/i18n/da-DK/common.ts +118 -118
  571. package/src/i18n/da-DK/company.ts +24 -24
  572. package/src/i18n/da-DK/consents.ts +23 -23
  573. package/src/i18n/da-DK/forms.ts +116 -116
  574. package/src/i18n/da-DK/history.ts +35 -35
  575. package/src/i18n/da-DK/index.ts +49 -49
  576. package/src/i18n/da-DK/keywords.ts +19 -19
  577. package/src/i18n/da-DK/library.ts +135 -135
  578. package/src/i18n/da-DK/licenses.ts +25 -25
  579. package/src/i18n/da-DK/media.ts +79 -79
  580. package/src/i18n/da-DK/parts.ts +696 -696
  581. package/src/i18n/da-DK/preview.ts +13 -13
  582. package/src/i18n/da-DK/redirects.ts +51 -51
  583. package/src/i18n/da-DK/seo.ts +20 -20
  584. package/src/i18n/da-DK/text.ts +35 -35
  585. package/src/i18n/da-DK/theme.ts +41 -41
  586. package/src/i18n/en-US/advanced.ts +32 -32
  587. package/src/i18n/en-US/app.ts +84 -84
  588. package/src/i18n/en-US/apps.ts +134 -134
  589. package/src/i18n/en-US/blockSettings.ts +48 -48
  590. package/src/i18n/en-US/blocks.ts +441 -441
  591. package/src/i18n/en-US/check.ts +31 -31
  592. package/src/i18n/en-US/colors.ts +82 -82
  593. package/src/i18n/en-US/common.ts +144 -144
  594. package/src/i18n/en-US/company.ts +25 -25
  595. package/src/i18n/en-US/consents.ts +25 -25
  596. package/src/i18n/en-US/forms.ts +145 -145
  597. package/src/i18n/en-US/history.ts +43 -43
  598. package/src/i18n/en-US/index.ts +51 -51
  599. package/src/i18n/en-US/keywords.ts +24 -24
  600. package/src/i18n/en-US/library.ts +176 -176
  601. package/src/i18n/en-US/licenses.ts +36 -36
  602. package/src/i18n/en-US/media.ts +80 -80
  603. package/src/i18n/en-US/parts.ts +718 -718
  604. package/src/i18n/en-US/preview.ts +15 -15
  605. package/src/i18n/en-US/redirects.ts +66 -66
  606. package/src/i18n/en-US/seo.ts +26 -26
  607. package/src/i18n/en-US/text.ts +41 -41
  608. package/src/i18n/en-US/theme.ts +41 -41
  609. package/src/i18n/index.ts +124 -124
  610. package/src/icon.tsx +160 -160
  611. package/src/iconPacks.ts +89 -89
  612. package/src/images.ts +163 -163
  613. package/src/{licenses.ts → licenseData.ts} +79 -79
  614. package/src/markdown.mjs +204 -204
  615. package/src/nav.ts +68 -68
  616. package/src/notFound.ts +28 -28
  617. package/src/{notifications.ts → notificationData.ts} +223 -223
  618. package/src/pagePreview.tsx +204 -204
  619. package/src/r2Caching.ts +55 -55
  620. package/src/{redirects.ts → redirectData.ts} +149 -149
  621. package/src/registry.tsx +188 -188
  622. package/src/schema.ts +417 -417
  623. package/src/sections.mjs +303 -303
  624. package/src/seo.ts +333 -333
  625. package/src/shared.ts +44 -44
  626. package/src/sidebar.ts +31 -31
  627. package/src/site.ts +317 -317
  628. package/src/standard/Block.astro +19 -19
  629. package/src/standard/BlockSite.astro +18 -18
  630. package/src/standard/accordion/index.tsx +47 -47
  631. package/src/standard/accordion/load.ts +23 -23
  632. package/src/standard/accordion/shared.ts +15 -15
  633. package/src/standard/accordion/view.ts +32 -32
  634. package/src/standard/buttons/fields.ts +98 -98
  635. package/src/standard/buttons/index.tsx +23 -23
  636. package/src/standard/buttons/load.ts +34 -34
  637. package/src/standard/buttons/shared.ts +12 -12
  638. package/src/standard/buttons/view.ts +30 -30
  639. package/src/standard/cards/index.tsx +71 -71
  640. package/src/standard/cards/load.ts +17 -17
  641. package/src/standard/cards/shared.ts +27 -27
  642. package/src/standard/cards/view.ts +29 -29
  643. package/src/standard/checklist/index.tsx +27 -27
  644. package/src/standard/checklist/load.ts +5 -5
  645. package/src/standard/checklist/view.ts +13 -13
  646. package/src/standard/cookies/index.tsx +17 -17
  647. package/src/standard/cookies/list.ts +56 -56
  648. package/src/standard/cookies/load.ts +11 -11
  649. package/src/standard/cookies/shared.ts +20 -20
  650. package/src/standard/cookies/view.ts +28 -28
  651. package/src/standard/faq/index.tsx +29 -29
  652. package/src/standard/faq/load.ts +14 -14
  653. package/src/standard/faq/view.ts +21 -21
  654. package/src/standard/head.ts +23 -23
  655. package/src/standard/hero/fields.ts +48 -48
  656. package/src/standard/hero/index.tsx +57 -57
  657. package/src/standard/hero/load.ts +23 -23
  658. package/src/standard/hero/view.ts +38 -38
  659. package/src/standard/links/index.tsx +41 -41
  660. package/src/standard/links/load.ts +17 -17
  661. package/src/standard/links/view.ts +25 -25
  662. package/src/standard/list/index.tsx +50 -50
  663. package/src/standard/list/load.ts +5 -5
  664. package/src/standard/list/view.ts +18 -18
  665. package/src/standard/load.ts +7 -7
  666. package/src/standard/notice/index.tsx +30 -30
  667. package/src/standard/notice/load.ts +16 -16
  668. package/src/standard/notice/view.ts +10 -10
  669. package/src/standard/points/index.tsx +42 -42
  670. package/src/standard/points/load.ts +5 -5
  671. package/src/standard/points/view.ts +12 -12
  672. package/src/standard/posts/index.tsx +132 -132
  673. package/src/standard/posts/load.ts +36 -36
  674. package/src/standard/posts/shared.ts +21 -21
  675. package/src/standard/posts/view.ts +63 -63
  676. package/src/standard/pricecards/index.tsx +57 -57
  677. package/src/standard/pricecards/load.ts +11 -11
  678. package/src/standard/pricecards/view.ts +50 -50
  679. package/src/standard/sharedTexts.ts +6 -6
  680. package/src/standard/site.ts +124 -124
  681. package/src/standard/siteLooks.ts +19 -19
  682. package/src/standard/sites.ts +13 -13
  683. package/src/standard/steps/index.tsx +28 -28
  684. package/src/standard/steps/load.ts +5 -5
  685. package/src/standard/steps/view.ts +11 -11
  686. package/src/standard/testimonials/index.tsx +87 -87
  687. package/src/standard/testimonials/list.ts +43 -43
  688. package/src/standard/testimonials/load.ts +58 -58
  689. package/src/standard/testimonials/shared.ts +13 -13
  690. package/src/standard/testimonials/view.ts +76 -76
  691. package/src/standard/themeBlocks.ts +13 -13
  692. package/src/standard/video/index.tsx +23 -23
  693. package/src/standard/video/load.ts +10 -10
  694. package/src/standard/video/view.ts +42 -42
  695. package/src/standard/view.tsx +105 -105
  696. package/src/standard/views.ts +37 -37
  697. package/src/store.ts +479 -499
  698. package/src/theme.ts +90 -90
  699. package/src/themeUi.ts +97 -97
  700. package/src/themes.ts +91 -91
  701. package/src/ui.tsx +3402 -3402
  702. package/src/virtual.d.ts +5 -5
  703. package/src/when.ts +22 -22
  704. package/starter/.githooks/pre-push +4 -4
  705. package/starter/.nvmrc +1 -1
  706. package/starter/.prettierignore +11 -11
  707. package/starter/.prettierrc.json +7 -7
  708. package/starter/README.md +27 -26
  709. package/starter/astro.config.mjs +5 -5
  710. package/starter/package.json +67 -67
  711. package/starter/public/_redirects +1 -1
  712. package/starter/public/favicon.svg +1 -1
  713. package/starter/public/logo.svg +1 -1
  714. package/starter/src/content/pages/blog.md +8 -8
  715. package/starter/src/content/pages/forside.md +9 -9
  716. package/starter/src/content/pages/kontakt.md +7 -7
  717. package/starter/src/content/pages/privatlivspolitik.md +9 -9
  718. package/starter/src/content/pages/siden-findes-ikke.md +7 -7
  719. package/starter/src/content.config.ts +2 -2
  720. package/starter/src/data/apps.json +1 -1
  721. package/starter/src/data/block-settings.json +3 -3
  722. package/starter/src/data/blocks.json +1 -1
  723. package/starter/src/data/booking.json +6 -6
  724. package/starter/src/data/colors.json +70 -70
  725. package/starter/src/data/contact.json +8 -8
  726. package/starter/src/data/cookies.json +21 -21
  727. package/starter/src/data/csp.json +1 -1
  728. package/starter/src/data/footer.json +15 -15
  729. package/starter/src/data/internal-links.json +4 -4
  730. package/starter/src/data/menu.json +4 -4
  731. package/starter/src/data/mobile-menu.json +4 -4
  732. package/starter/src/data/old-addresses.json +1 -1
  733. package/starter/src/data/redirects.json +1 -1
  734. package/starter/src/data/standard-pages.json +8 -8
  735. package/starter/src/data/theme.json +1 -1
  736. package/starter/src/env.d.ts +2 -2
  737. package/starter/src/site/config.ts +13 -13
  738. package/starter/src/site/worker.js +14 -14
  739. package/starter/tsconfig.json +17 -17
  740. package/starter/worker/apps.js +6 -6
  741. package/starter/wrangler.jsonc +39 -39
  742. package/theme/LICENSE +21 -21
  743. package/theme/blocks/ArrowLink.tsx +14 -14
  744. package/theme/blocks/BlockHead.tsx +26 -26
  745. package/theme/blocks/Panel.tsx +32 -32
  746. package/theme/blocks/Person.tsx +26 -26
  747. package/theme/blocks/accordion/PageRow.tsx +25 -25
  748. package/theme/blocks/accordion/View.tsx +17 -17
  749. package/theme/blocks/buttons/Buttons.tsx +28 -28
  750. package/theme/blocks/buttons/View.tsx +12 -12
  751. package/theme/blocks/cards/LinkCards.tsx +72 -72
  752. package/theme/blocks/cards/View.tsx +20 -20
  753. package/theme/blocks/checklist/Checks.tsx +15 -15
  754. package/theme/blocks/checklist/View.tsx +14 -14
  755. package/theme/blocks/cookies/View.tsx +36 -36
  756. package/theme/blocks/faq/Accordion.tsx +34 -34
  757. package/theme/blocks/faq/View.tsx +16 -16
  758. package/theme/blocks/faq/script.ts +56 -56
  759. package/theme/blocks/hero/View.tsx +44 -44
  760. package/theme/blocks/links/LinkGroups.tsx +24 -24
  761. package/theme/blocks/links/View.tsx +17 -17
  762. package/theme/blocks/list/Rows.tsx +24 -24
  763. package/theme/blocks/list/View.tsx +14 -14
  764. package/theme/blocks/notice/View.tsx +13 -13
  765. package/theme/blocks/points/PointList.tsx +34 -34
  766. package/theme/blocks/points/View.tsx +14 -14
  767. package/theme/blocks/posts/View.tsx +26 -26
  768. package/theme/blocks/pricecards/View.tsx +40 -40
  769. package/theme/blocks/steps/StepList.tsx +23 -23
  770. package/theme/blocks/steps/View.tsx +14 -14
  771. package/theme/blocks/testimonials/List.tsx +46 -46
  772. package/theme/blocks/testimonials/Slider.tsx +44 -44
  773. package/theme/blocks/testimonials/Testimonial.tsx +124 -124
  774. package/theme/blocks/testimonials/View.tsx +21 -21
  775. package/theme/blocks/testimonials/script.ts +52 -52
  776. package/theme/blocks/video/View.tsx +41 -41
  777. package/theme/components/ActionBar.astro +63 -63
  778. package/theme/components/AppSlot.astro +21 -21
  779. package/theme/components/ArrowLink.tsx +21 -21
  780. package/theme/components/BlogIndex.astro +48 -48
  781. package/theme/components/BlogPosts.astro +18 -18
  782. package/theme/components/BlogPosts.tsx +45 -45
  783. package/theme/components/BookButton.tsx +22 -22
  784. package/theme/components/Container.astro +11 -11
  785. package/theme/components/CookieConsent.astro +121 -121
  786. package/theme/components/EndBlock.astro +21 -21
  787. package/theme/components/FontPreload.astro +6 -6
  788. package/theme/components/Footer.astro +85 -85
  789. package/theme/components/Header.astro +186 -186
  790. package/theme/components/Icon.astro +16 -16
  791. package/theme/components/Img.astro +29 -29
  792. package/theme/components/Img.tsx +33 -33
  793. package/theme/components/Inline.astro +11 -11
  794. package/theme/components/Logo.astro +23 -23
  795. package/theme/components/LogoMark.astro +10 -10
  796. package/theme/components/Markdown.astro +17 -17
  797. package/theme/components/MobileMenu.tsx +224 -224
  798. package/theme/components/MobileNav.astro +33 -33
  799. package/theme/components/PageHeader.astro +22 -22
  800. package/theme/components/PageSection.astro +24 -24
  801. package/theme/components/PhoneButton.tsx +11 -11
  802. package/theme/components/Popup.astro +145 -145
  803. package/theme/components/PopupButton.tsx +24 -24
  804. package/theme/components/PopupView.tsx +48 -48
  805. package/theme/components/PostList.tsx +58 -58
  806. package/theme/components/PostMeta.tsx +17 -17
  807. package/theme/components/RichText.astro +28 -28
  808. package/theme/components/Section.astro +29 -29
  809. package/theme/components/SectionHeading.tsx +8 -8
  810. package/theme/components/TextSection.astro +16 -16
  811. package/theme/components/home/PageBlock.astro +19 -19
  812. package/theme/components/home/Text.astro +13 -13
  813. package/theme/components/loadPopup.ts +22 -22
  814. package/theme/components/loadPosts.ts +16 -16
  815. package/theme/components/posts.ts +15 -15
  816. package/theme/editor/looks.mjs +7 -7
  817. package/theme/editor/previews.tsx +56 -56
  818. package/theme/layouts/Base.astro +273 -273
  819. package/theme/layouts/PageLayout.astro +126 -126
  820. package/theme/layouts/PostLayout.astro +137 -137
  821. package/theme/scripts/motion.ts +29 -29
  822. package/theme/styles/base.css +320 -320
  823. package/theme/styles/blocks.css +1808 -1808
  824. package/theme/styles/components.css +206 -206
  825. package/theme/styles/global.css +1302 -1302
  826. package/theme/styles/ui.css +6544 -6544
  827. package/theme/templates/Blog.astro +38 -38
  828. package/theme/templates/Category.astro +19 -19
  829. package/theme/templates/Home.astro +36 -36
  830. package/theme/templates/New.astro +68 -68
  831. package/theme/templates/NotFound.astro +117 -117
  832. package/theme/theme.json +28 -28
  833. package/theme/ui/Badge.tsx +45 -45
  834. package/theme/ui/BottomSheet.tsx +148 -148
  835. package/theme/ui/Button.tsx +79 -79
  836. package/theme/ui/ButtonGroup.tsx +31 -31
  837. package/theme/ui/Card.tsx +45 -45
  838. package/theme/ui/Carousel.tsx +124 -124
  839. package/theme/ui/Checkbox.tsx +59 -59
  840. package/theme/ui/Chip.tsx +101 -101
  841. package/theme/ui/ChipSet.tsx +27 -27
  842. package/theme/ui/DatePicker.tsx +149 -149
  843. package/theme/ui/DatePickerContainer.tsx +316 -316
  844. package/theme/ui/Dialog.tsx +100 -100
  845. package/theme/ui/Divider.tsx +27 -27
  846. package/theme/ui/ExposedDropdownMenu.tsx +77 -77
  847. package/theme/ui/Fab.tsx +88 -88
  848. package/theme/ui/FabMenu.tsx +67 -67
  849. package/theme/ui/IconButton.tsx +78 -78
  850. package/theme/ui/List.tsx +287 -287
  851. package/theme/ui/LoadingIndicator.tsx +29 -29
  852. package/theme/ui/Menu.tsx +278 -278
  853. package/theme/ui/NavigationBar.tsx +62 -62
  854. package/theme/ui/NavigationDrawer.tsx +80 -80
  855. package/theme/ui/NavigationRail.tsx +154 -154
  856. package/theme/ui/ProgressIndicator.tsx +162 -162
  857. package/theme/ui/RadioButton.tsx +50 -50
  858. package/theme/ui/Search.tsx +129 -129
  859. package/theme/ui/SegmentedButton.tsx +49 -49
  860. package/theme/ui/SideSheet.tsx +54 -54
  861. package/theme/ui/Slider.tsx +155 -155
  862. package/theme/ui/Snackbar.tsx +67 -67
  863. package/theme/ui/SplitButton.tsx +67 -67
  864. package/theme/ui/Switch.tsx +60 -60
  865. package/theme/ui/Tabs.tsx +114 -114
  866. package/theme/ui/TextField.tsx +278 -278
  867. package/theme/ui/TimePicker.tsx +128 -128
  868. package/theme/ui/TimePickerContainer.tsx +234 -234
  869. package/theme/ui/Toolbar.tsx +67 -67
  870. package/theme/ui/Tooltip.tsx +58 -58
  871. package/theme/ui/TopAppBar.tsx +77 -77
  872. package/theme/ui/bottomSheet.script.ts +8 -8
  873. package/theme/ui/{bottomSheet.ts → bottomSheetControl.ts} +211 -211
  874. package/theme/ui/carousel.script.ts +28 -28
  875. package/theme/ui/carouselLayout.ts +229 -229
  876. package/theme/ui/checkbox.script.ts +8 -8
  877. package/theme/ui/datePicker.script.ts +302 -302
  878. package/theme/ui/dates.ts +185 -185
  879. package/theme/ui/{dialog.ts → dialogControl.ts} +48 -48
  880. package/theme/ui/dropdownMenu.script.ts +166 -166
  881. package/theme/ui/fabMenu.script.ts +57 -57
  882. package/theme/ui/navigationRail.script.ts +47 -47
  883. package/theme/ui/ripple.script.ts +159 -159
  884. package/theme/ui/search.script.ts +92 -92
  885. package/theme/ui/{sideSheet.ts → sideSheetControl.ts} +48 -48
  886. package/theme/ui/slider.script.ts +12 -12
  887. package/theme/ui/sliderUpdate.ts +52 -52
  888. package/theme/ui/snackbar.script.ts +16 -16
  889. package/theme/ui/splitButton.script.ts +63 -63
  890. package/theme/ui/tabs.script.ts +48 -48
  891. package/theme/ui/textField.script.ts +17 -17
  892. package/theme/ui/textFieldUpdate.ts +44 -44
  893. package/theme/ui/timePicker.script.ts +248 -248
  894. package/theme/ui/toolbar.script.ts +43 -43
  895. package/theme/ui/tooltip.script.ts +68 -68
  896. package/worker/consent.js +141 -141
  897. package/worker/editor-github.js +167 -167
  898. package/worker/editor-host.js +74 -74
  899. package/worker/files.js +401 -401
  900. package/worker/github.js +36 -36
  901. package/worker/index.js +188 -184
  902. package/worker/not-found.js +97 -97
  903. package/worker/oauth.js +95 -95
  904. package/worker/publish.js +52 -52
  905. package/worker/push.js +270 -270
  906. package/worker/r2-status.js +50 -50
  907. package/worker/session.js +58 -58
  908. package/worker/store.js +46 -0
@@ -1,652 +1,652 @@
1
- // "Dele" › "UI-komponenter" (#udseende/dele/ui), "Dele" › "Blokke" (#udseende/dele/blokke) and "Dele" › a list of kinds
2
- // ("Promovering", #udseende/dele/liste/<id>): how the site looks, every part in every version, to see and agree on it.
3
- // "UI-komponenter" has the theme's UI components (its buttons and icon buttons, text fields and checkboxes …,
4
- // packages/editor/theme/ui/, through @site/editor) in every kind, size and state; "Blokke" every block, the standard
5
- // ones (packages/editor/src/standard/), which every theme styles, and then the apps', each in its own group; a list of
6
- // kinds each of its kinds as the site draws an entry of it, the list's own (the pop-up, the bars) and the apps' (a
7
- // pop-up, once for each of its states), the kind a group. A block's versions are the
8
- // options of its choices side by side (a field with `segments`: the designs of "Kort"), the first choice's all, each
9
- // other's but the one a new block has (its default, else the empty one: the backgrounds of "Kort", with the first's empty
10
- // option; the width of "Banner", as wide as the text). All of it is drawn with the
11
- // made-up site of examples.ts, never the site's own, with the search, the order and the filter of "Editor"
12
- // (PartsShown.tsx). Nothing here is saved.
13
- import { useMemo } from 'react';
14
- import Screen from './Screen';
15
- import { Part, PartGroup, PartsShown } from './PartsShown';
16
- import { Preview } from './ui';
17
- import {
18
- SiteButton,
19
- SiteCard,
20
- SiteCheckbox,
21
- SiteChip,
22
- SiteIconButton,
23
- SiteList,
24
- SiteListItem,
25
- SiteTextField,
26
- buttonShapes,
27
- buttonSizes,
28
- cardKinds,
29
- chipKinds,
30
- chipSetLayouts,
31
- SiteChipSet,
32
- iconButtonWidths,
33
- } from './themeUi';
34
- import ContainmentParts from './ContainmentParts';
35
- import NavigationParts from './NavigationParts';
36
- import ActionParts from './ActionParts';
37
- import SelectionParts from './SelectionParts';
38
- import CommunicationParts from './CommunicationParts';
39
- import NavigationRestParts from './NavigationRestParts';
40
- import PickerParts from './PickerParts';
41
- import { exampleOf, type BlockData, type BlockProps, type SiteBlock } from './blocks';
42
- import { apps, preview, siteBlocks, standardTypes } from './registry';
43
- import { examplePicture, exampleData, kindExample } from './examples';
44
- import type { Field, FolderCollection, PreviewVariant } from './schema';
45
- import { buttonKinds, iconButtonKinds } from './standard/view';
46
- import { kindDraw } from './apps';
47
- import { collections } from './site';
48
- import { t } from './i18n';
49
- import { Svg } from './icon';
50
-
51
- const { screens } = t.parts;
52
- const back = { href: '#udseende/dele', label: t.common.parts.editorParts };
53
-
54
- // The fields filled in with the plain picture where they have none (a card's, a list's items').
55
- function pictured(fields: Field[], props: BlockProps): BlockProps {
56
- const filled = { ...props };
57
- for (const f of fields) {
58
- const v = filled[f.name];
59
- if (f.type === 'image' && !v) filled[f.name] = examplePicture;
60
- else if (f.type === 'object' && f.fields) filled[f.name] = pictured(f.fields, (v ?? {}) as BlockProps);
61
- else if (f.type === 'list' && f.fields && Array.isArray(v)) filled[f.name] = v.map((item) => pictured(f.fields!, item as BlockProps));
62
- }
63
- return filled;
64
- }
65
-
66
- // A block's versions: one for each option of its first choice side by side and for each other option of the others
67
- // than the one a new block has, else only itself.
68
- function versionsOf(block: SiteBlock): PreviewVariant[] {
69
- const [first, ...rest] = block.fields.filter((f) => f.type === 'select' && f.segments && !f.only);
70
- if (!first?.options) return [{ label: '', props: {} }];
71
- return [
72
- ...first.options.map((o) => ({ label: o.label, props: { [first.name]: o.value } })),
73
- ...rest.flatMap((c) =>
74
- (c.options ?? []).filter((o) => o.value !== String(c.default ?? '')).map((o) => ({ label: o.label, props: { [c.name]: o.value } })),
75
- ),
76
- ];
77
- }
78
-
79
- /** A block in each of its versions, filled in as an example, under its name (and the version's). */
80
- function BlockShown({ block, data }: { block: SiteBlock; data: BlockData }) {
81
- const example = exampleOf(block, data);
82
- return versionsOf(block).map((v) => (
83
- <Part key={v.label} name={v.label ? `${block.label} · ${v.label}` : block.label} use={block.hint}>
84
- <Preview>{preview(block.type, pictured(block.fields, { ...example, ...v.props }), data)}</Preview>
85
- </Part>
86
- ));
87
- }
88
-
89
- /** The theme's chips, as the site draws them: every kind, elevated on a picture, in every state (chosen, with an icon or
90
- * a picture, with the button that removes it, dragged, only shown) and disabled. */
91
- function ChipParts() {
92
- const row = 'flex flex-wrap items-center gap-3';
93
- const { input, filter, suggestion, assist } = screens.chipKinds;
94
- return (
95
- <Part name="Chip" use={screens.chip}>
96
- <Preview>
97
- <div className="space-y-4 p-4">
98
- <div className={row}>
99
- {chipKinds.map((k) => (
100
- <SiteChip key={k} kind={k} label={screens.chipKinds[k]} />
101
- ))}
102
- </div>
103
- <div className={`${row} rounded-xl bg-cover bg-center p-4`} style={{ backgroundImage: `url("${examplePicture}")` }}>
104
- <SiteChip elevated icon="calendar-blank" label={`${assist} · ${screens.elevated}`} />
105
- <SiteChip elevated kind="filter" label={`${filter} · ${screens.elevated}`} />
106
- <SiteChip elevated kind="filter" selected label={screens.selected} />
107
- <SiteChip elevated kind="suggestion" label={`${suggestion} · ${screens.elevated}`} />
108
- </div>
109
- <div className={row}>
110
- <SiteChip kind="filter" selected label={screens.selected} />
111
- <SiteChip kind="filter" label={filter} />
112
- <SiteChip kind="suggestion" selected label={`${suggestion} · ${screens.selected}`} />
113
- <SiteChip icon="calendar-blank" label={screens.withIcon} />
114
- <SiteChip kind="input" trailingIcon="x" label={input} />
115
- <SiteChip kind="input" avatar={examplePicture} removeLabel={screens.remove(screens.withAvatar)} label={screens.withAvatar} />
116
- <SiteChip kind="input" selected removeLabel={screens.remove(screens.selected)} label={screens.selected} />
117
- <SiteChip kind="input" dragged avatar={examplePicture} label={screens.dragged} />
118
- <SiteChip plain label={screens.plain} />
119
- </div>
120
- <div className={row}>
121
- {chipKinds.map((k) => (
122
- <SiteChip key={k} kind={k} disabled label={screens.disabled} />
123
- ))}
124
- <SiteChip kind="input" disabled removeLabel={screens.remove(screens.disabled)} label={screens.disabled} />
125
- <SiteChip elevated disabled label={`${screens.elevated} · ${screens.disabled}`} />
126
- <SiteChip href="" disabled label={screens.disabled} />
127
- </div>
128
- </div>
129
- </Preview>
130
- </Part>
131
- );
132
- }
133
-
134
- /** The theme's chip sets, as the site draws them: each layout, with more chips than there is room for on one line. */
135
- function ChipSetParts() {
136
- return (
137
- <Part name="ChipSet" use={screens.chipSet}>
138
- <Preview>
139
- <div className="max-w-sm space-y-4 p-4">
140
- {chipSetLayouts.map((layout) => (
141
- <SiteChipSet key={layout} layout={layout} label={screens.chipSetLayouts[layout]}>
142
- {[...chipKinds, ...chipKinds].map((k, i) => (
143
- <SiteChip key={i} kind="filter" selected={!i} label={`${screens.chipSetLayouts[layout]} ${i + 1}`} />
144
- ))}
145
- </SiteChipSet>
146
- ))}
147
- </div>
148
- </Preview>
149
- </Part>
150
- );
151
- }
152
-
153
- // The standard blocks (not HTML, which has no look of its own).
154
- const standardBlocks = siteBlocks.filter((b) => standardTypes.has(b.type));
155
-
156
- // The kinds a toggle button can be (Material: never a text button).
157
- const toggleKinds = buttonKinds.filter((k) => k !== 'text');
158
-
159
- /** The theme's buttons and icon buttons, as the site draws them: every kind, the five sizes, both shapes, each kind
160
- * that can be a toggle off and on in both shapes, the icon buttons' widths, with an icon, and disabled. */
161
- function ButtonParts() {
162
- const row = 'flex flex-wrap items-center gap-3';
163
- const kinds = t.blocks.buttons.kinds;
164
- return (
165
- <>
166
- <Part name="Button" use={screens.button}>
167
- <Preview>
168
- <div className="space-y-4 p-4">
169
- <div className={row}>
170
- {buttonKinds.map((k) => (
171
- <SiteButton key={k} kind={k}>
172
- {kinds[k]}
173
- </SiteButton>
174
- ))}
175
- </div>
176
- <div className={row}>
177
- {buttonSizes.map((size) => (
178
- <SiteButton key={size} size={size}>
179
- {screens.sizes[size]}
180
- </SiteButton>
181
- ))}
182
- </div>
183
- <div className={row}>
184
- {buttonSizes.map((size) => (
185
- <SiteButton key={size} size={size} shape="square" kind="tonal">
186
- {screens.sizes[size]}
187
- </SiteButton>
188
- ))}
189
- </div>
190
- {buttonShapes.map((shape) => (
191
- <div key={shape} className={row} role="group" aria-label={screens.shapes[shape]}>
192
- {toggleKinds.map((k) =>
193
- ([false, true] as const).map((on) => (
194
- <SiteButton key={`${k}-${on}`} kind={k} shape={shape} selected={on} icon="heart">
195
- {on ? screens.toggle.on : screens.toggle.off}
196
- </SiteButton>
197
- )),
198
- )}
199
- </div>
200
- ))}
201
- <div className={row}>
202
- <SiteButton icon="phone">{screens.withIcon}</SiteButton>
203
- <SiteButton kind="outlined" trailingIcon="arrow-right">
204
- {screens.withIcon}
205
- </SiteButton>
206
- {buttonKinds.map((k) => (
207
- <SiteButton key={k} kind={k} disabled>
208
- {screens.disabled}
209
- </SiteButton>
210
- ))}
211
- <SiteButton selected disabled>
212
- {screens.disabled}
213
- </SiteButton>
214
- </div>
215
- </div>
216
- </Preview>
217
- </Part>
218
- <Part name="IconButton" use={screens.iconButton}>
219
- <Preview>
220
- <div className="space-y-4 p-4">
221
- <div className={row}>
222
- {iconButtonKinds.map((k) => (
223
- <SiteIconButton key={k} kind={k} icon="x" label={screens.iconKinds[k]} title={screens.iconKinds[k]} />
224
- ))}
225
- </div>
226
- <div className={row}>
227
- {buttonSizes.map((size) => (
228
- <SiteIconButton key={size} kind="filled" size={size} icon="phone" label={screens.sizes[size]} title={screens.sizes[size]} />
229
- ))}
230
- </div>
231
- <div className={row}>
232
- {buttonSizes.map((size) => (
233
- <SiteIconButton
234
- key={size}
235
- kind="tonal"
236
- size={size}
237
- shape="square"
238
- icon="phone"
239
- label={`${screens.sizes[size]}, ${screens.shapes.square}`}
240
- title={`${screens.sizes[size]}, ${screens.shapes.square}`}
241
- />
242
- ))}
243
- </div>
244
- <div className={row}>
245
- {(['small', 'medium'] as const).flatMap((size) =>
246
- iconButtonWidths.map((width) => (
247
- <SiteIconButton
248
- key={`${size}-${width}`}
249
- kind="outlined"
250
- size={size}
251
- width={width}
252
- icon="phone"
253
- label={`${screens.sizes[size]}, ${screens.widths[width]}`}
254
- title={`${screens.sizes[size]}, ${screens.widths[width]}`}
255
- />
256
- )),
257
- )}
258
- </div>
259
- {buttonShapes.map((shape) => (
260
- <div key={shape} className={row} role="group" aria-label={screens.shapes[shape]}>
261
- {iconButtonKinds.map((k) =>
262
- ([false, true] as const).map((on) => (
263
- <SiteIconButton
264
- key={`${k}-${on}`}
265
- kind={k}
266
- shape={shape}
267
- selected={on}
268
- icon="heart"
269
- label={`${screens.iconKinds[k]}, ${on ? screens.toggle.on : screens.toggle.off}`}
270
- title={`${screens.iconKinds[k]}, ${on ? screens.toggle.on : screens.toggle.off}`}
271
- />
272
- )),
273
- )}
274
- </div>
275
- ))}
276
- <div className={row}>
277
- {iconButtonKinds.map((k) => (
278
- <SiteIconButton key={k} kind={k} icon="phone" label={screens.disabled} disabled />
279
- ))}
280
- <SiteIconButton kind="filled" icon="phone" label={screens.disabled} selected disabled />
281
- </div>
282
- </div>
283
- </Preview>
284
- </Part>
285
- </>
286
- );
287
- }
288
-
289
- /** The theme's form controls, as the site draws them: each kind of text field empty, filled in, with a line under it,
290
- * with an error, with only a placeholder and disabled, with an icon before it, a search field with its clear button, a
291
- * prefix and a suffix, the error's icon, a password with its button, a counter, read-only, and several lines (growing,
292
- * and three rows); and a checkbox empty, ticked, with a line, disabled, indeterminate and wrong. */
293
- function FieldParts() {
294
- const fields = 'grid gap-6 sm:grid-cols-2';
295
- return (
296
- <>
297
- <Part name="TextField" use={screens.textField}>
298
- <Preview>
299
- <div className="space-y-6 p-4">
300
- {(['outlined', 'filled'] as const).map((kind) => (
301
- <div key={kind} className={fields} aria-label={screens.fieldKinds[kind]} role="group">
302
- <SiteTextField kind={kind} label={screens.fieldLabel} type="email" />
303
- <SiteTextField kind={kind} label={screens.fieldLabel} type="email" defaultValue={screens.fieldValue} />
304
- <SiteTextField kind={kind} label={screens.fieldLabel} type="email" supporting={screens.fieldSupporting} />
305
- <SiteTextField kind={kind} label={screens.fieldLabel} type="email" defaultValue="navn@" error={screens.fieldError} />
306
- <SiteTextField kind={kind} label={screens.fieldLabel} hideLabel type="email" placeholder={screens.fieldPlaceholder} />
307
- <SiteTextField kind={kind} label={screens.fieldLabel} type="email" disabled />
308
- <SiteTextField kind={kind} label={screens.fieldLabel} type="email" leadingIcon="envelope-simple" />
309
- <SiteTextField
310
- kind={kind}
311
- label={screens.fieldSearch}
312
- hideLabel
313
- type="search"
314
- placeholder={screens.fieldSearch}
315
- leadingIcon="magnifying-glass"
316
- clearLabel={screens.fieldClear}
317
- defaultValue={screens.fieldNote}
318
- />
319
- <SiteTextField kind={kind} label={screens.fieldPhone} type="tel" prefix={screens.fieldPrefix} defaultValue="12 34 56 78" />
320
- <SiteTextField kind={kind} label={screens.fieldPrice} inputMode="numeric" suffix={screens.fieldSuffix} defaultValue="450" />
321
- <SiteTextField
322
- kind={kind}
323
- label={screens.fieldLabel}
324
- type="email"
325
- defaultValue="navn@"
326
- error={screens.fieldError}
327
- leadingIcon="envelope-simple"
328
- errorIcon
329
- />
330
- <SiteTextField
331
- kind={kind}
332
- label={screens.fieldPassword}
333
- type="password"
334
- defaultValue={screens.fieldPasswordValue}
335
- passwordLabel={screens.fieldShowPassword}
336
- />
337
- <SiteTextField
338
- kind={kind}
339
- label={screens.fieldName}
340
- supporting={screens.fieldNameSupporting}
341
- counter
342
- maxLength={30}
343
- defaultValue={screens.fieldValue}
344
- />
345
- <SiteTextField kind={kind} label={screens.fieldReadOnly} readOnly defaultValue={screens.fieldReadOnlyValue} />
346
- <SiteTextField kind={kind} label={screens.fieldMessage} multiline defaultValue={screens.fieldMessageValue} />
347
- <SiteTextField kind={kind} label={screens.fieldNote} rows={3} counter maxLength={200} />
348
- </div>
349
- ))}
350
- </div>
351
- </Preview>
352
- </Part>
353
- <Part name="Checkbox" use={screens.checkbox}>
354
- <Preview>
355
- <div className={`${fields} p-4`}>
356
- <SiteCheckbox label={screens.checkboxLabel} />
357
- <SiteCheckbox label={screens.checkboxLabel} checked />
358
- <SiteCheckbox label={screens.checkboxLabel} supporting={screens.checkboxSupporting} />
359
- <SiteCheckbox label={screens.checkboxLabel} supporting={screens.checkboxSupporting} checked disabled />
360
- <SiteCheckbox label={screens.checkboxParent} supporting={screens.checkboxSupporting} indeterminate />
361
- <SiteCheckbox label={screens.checkboxParent} indeterminate disabled />
362
- <SiteCheckbox label={screens.checkboxLabel} error={screens.checkboxError} />
363
- <SiteCheckbox label={screens.checkboxLabel} error checked />
364
- </div>
365
- </Preview>
366
- </Part>
367
- </>
368
- );
369
- }
370
-
371
- /** The theme's cards in each kind, one a link, and lists: one line, a link and an icon with a text under it; one, two
372
- * and three lines; each leading kind; the choices; selected and disabled; each kind of dividers; and segmented. */
373
- function CardParts() {
374
- const say = screens.cardsAndLists;
375
- const [one, link, withIcon] = say.items;
376
- const lists = say.lists;
377
- const [icon, avatar, avatarPicture, image, video] = lists.headlines;
378
- const [checkbox, radio, switchItem, after] = lists.choices;
379
- return (
380
- <>
381
- <Part name="Card" use={say.card}>
382
- <Preview>
383
- <div className="grid gap-4 p-4 sm:grid-cols-2">
384
- {cardKinds.map((k) => (
385
- <SiteCard key={k} kind={k}>
386
- <p className="font-medium">{say.kinds[k]}</p>
387
- <p className="mt-1 text-muted">{say.text}</p>
388
- </SiteCard>
389
- ))}
390
- <SiteCard href="">
391
- <p className="font-medium">{say.link}</p>
392
- <p className="mt-1 text-muted">{say.text}</p>
393
- </SiteCard>
394
- {cardKinds.map((k) => (
395
- <SiteCard key={k} kind={k} dragged>
396
- <p className="font-medium">{`${say.kinds[k]} · ${screens.dragged}`}</p>
397
- <p className="mt-1 text-muted">{say.text}</p>
398
- </SiteCard>
399
- ))}
400
- </div>
401
- </Preview>
402
- </Part>
403
- <Part name="List" use={say.list}>
404
- <Preview>
405
- <div className="grid items-start gap-4 p-4 lg:grid-cols-2">
406
- <SiteCard>
407
- <SiteList>
408
- <SiteListItem headline={one} />
409
- <SiteListItem href="" headline={link} trailing={<Svg name="arrow-right" size={18} />} />
410
- <SiteListItem
411
- href=""
412
- leading={<Svg name="phone" size={24} />}
413
- headline={withIcon}
414
- supporting={say.supporting}
415
- trailing={<Svg name="caret-right" size={20} />}
416
- />
417
- </SiteList>
418
- </SiteCard>
419
- <SiteCard>
420
- <SiteList aria-label={lists.lines}>
421
- <SiteListItem href="" headline={one} trailingSupporting={lists.trailing} />
422
- <SiteListItem href="" headline={one} supporting={say.supporting} trailingIcon="caret-right" />
423
- <SiteListItem href="" overline={lists.overline} headline={one} supporting={say.supporting} trailingIcon="caret-right" />
424
- <SiteListItem
425
- href=""
426
- lines={3}
427
- leadingIcon="calendar-blank"
428
- headline={one}
429
- supporting={lists.long}
430
- trailingSupporting={lists.trailing}
431
- />
432
- </SiteList>
433
- </SiteCard>
434
- <SiteCard>
435
- <SiteList dividers="inset" aria-label={lists.leading}>
436
- <SiteListItem href="" leadingIcon="phone" headline={icon} supporting={say.supporting} trailingIcon="caret-right" />
437
- <SiteListItem
438
- href=""
439
- leadingAvatar={lists.letter}
440
- headline={avatar}
441
- supporting={say.supporting}
442
- trailingSupporting={lists.trailing}
443
- />
444
- <SiteListItem href="" leadingAvatar={{ src: examplePicture }} headline={avatarPicture} supporting={say.supporting} />
445
- <SiteListItem href="" leadingImage={{ src: examplePicture }} headline={image} supporting={say.supporting} />
446
- <SiteListItem href="" leadingVideo={{ src: examplePicture }} lines={3} headline={video} supporting={lists.long} />
447
- </SiteList>
448
- </SiteCard>
449
- <SiteCard>
450
- <SiteList aria-label={lists.controls}>
451
- <SiteListItem control={{ type: 'checkbox', checked: true }} headline={checkbox} supporting={say.supporting} />
452
- <SiteListItem control={{ type: 'radio-button', name: 'parts-list-radio', checked: true }} headline={radio} />
453
- <SiteListItem control={{ type: 'radio-button', name: 'parts-list-radio' }} headline={radio} />
454
- <SiteListItem control={{ type: 'switch', checked: true, icons: 'selected' }} leadingIcon="moon" headline={switchItem} />
455
- <SiteListItem control={{ type: 'checkbox', at: 'trailing' }} leadingAvatar={lists.letter} headline={after} />
456
- </SiteList>
457
- </SiteCard>
458
- <SiteCard>
459
- <SiteList aria-label={lists.states}>
460
- <SiteListItem href="" selected leadingIcon="house" headline={lists.selected} supporting={say.supporting} />
461
- <SiteListItem href="" disabled leadingIcon="house" headline={lists.disabled} supporting={say.supporting} />
462
- <SiteListItem control={{ type: 'switch' }} disabled headline={lists.disabled} />
463
- </SiteList>
464
- </SiteCard>
465
- <SiteCard>
466
- <SiteList aria-label={lists.more}>
467
- <SiteListItem
468
- onClick={() => {}}
469
- leadingIcon="pencil-simple"
470
- headline={lists.tapped}
471
- supporting={say.supporting}
472
- trailingIcon="caret-right"
473
- />
474
- <SiteListItem
475
- href=""
476
- headline={lists.withActions}
477
- supporting={lists.long}
478
- truncate
479
- actions={<SiteIconButton icon="trash" label={lists.remove} />}
480
- />
481
- <SiteListItem href="" headline={lists.address} supporting={lists.sendsTo} columns />
482
- </SiteList>
483
- </SiteCard>
484
- {(['middle-inset', 'none'] as const).map((dividers) => (
485
- <SiteCard key={dividers}>
486
- <SiteList dividers={dividers} aria-label={lists.dividers[dividers]}>
487
- {[icon, avatar, image].map((h) => (
488
- <SiteListItem
489
- key={h}
490
- href=""
491
- leadingIcon="phone"
492
- headline={`${lists.dividers[dividers]} · ${h}`}
493
- trailingIcon="caret-right"
494
- />
495
- ))}
496
- </SiteList>
497
- </SiteCard>
498
- ))}
499
- <SiteList kind="segmented" aria-label={lists.segmented}>
500
- <SiteListItem href="" leadingIcon="phone" headline={lists.segmented} supporting={say.supporting} trailingIcon="caret-right" />
501
- <SiteListItem
502
- href=""
503
- selected
504
- leadingIcon="envelope-simple"
505
- headline={lists.selected}
506
- supporting={say.supporting}
507
- trailingIcon="caret-right"
508
- />
509
- <SiteListItem control={{ type: 'checkbox', checked: true }} headline={checkbox} />
510
- <SiteListItem control={{ type: 'switch' }} leadingIcon="moon" headline={switchItem} />
511
- <SiteListItem href="" disabled leadingIcon="map-pin" headline={lists.disabled} />
512
- </SiteList>
513
- </div>
514
- </Preview>
515
- </Part>
516
- </>
517
- );
518
- }
519
-
520
- /** "Dele" › "UI-komponenter" (#udseende/dele/ui): the theme's UI components in every kind, size and state. */
521
- export function ComponentParts() {
522
- const groups = [
523
- { id: 'ui', title: screens.ui },
524
- { id: 'fields', title: screens.fields },
525
- { id: 'chips', title: screens.chips },
526
- { id: 'containment', title: screens.containment.title },
527
- { id: 'cards', title: screens.cardsAndLists.title },
528
- { id: 'navigation', title: screens.navigation.title },
529
- { id: 'actions', title: screens.actions.title },
530
- { id: 'selection', title: screens.selection.title },
531
- { id: 'communication', title: screens.communication.title },
532
- { id: 'navigationRest', title: screens.navigationRest.title },
533
- { id: 'pickers', title: screens.pickers.title },
534
- ];
535
- return (
536
- <Screen title={screens.components} back={back}>
537
- <div className="space-y-10">
538
- <p className="text-muted">{screens.componentsIntro}</p>
539
- <PartsShown groups={groups} keep="parts-components" search={screens.search} none={screens.none}>
540
- <PartGroup group="ui">
541
- <ButtonParts />
542
- </PartGroup>
543
- <PartGroup group="fields">
544
- <FieldParts />
545
- </PartGroup>
546
- <PartGroup group="chips">
547
- <ChipParts />
548
- <ChipSetParts />
549
- </PartGroup>
550
- <PartGroup group="containment">
551
- <ContainmentParts />
552
- </PartGroup>
553
- <PartGroup group="cards">
554
- <CardParts />
555
- </PartGroup>
556
- <PartGroup group="navigation">
557
- <NavigationParts />
558
- </PartGroup>
559
- <PartGroup group="actions">
560
- <ActionParts />
561
- </PartGroup>
562
- <PartGroup group="selection">
563
- <SelectionParts />
564
- </PartGroup>
565
- <PartGroup group="communication">
566
- <CommunicationParts />
567
- </PartGroup>
568
- <PartGroup group="navigationRest">
569
- <NavigationRestParts />
570
- </PartGroup>
571
- <PartGroup group="pickers">
572
- <PickerParts />
573
- </PartGroup>
574
- </PartsShown>
575
- </div>
576
- </Screen>
577
- );
578
- }
579
-
580
- /** "Dele" › "Blokke" (#udseende/dele/blokke): every block, the standard ones and then the apps', each a group of its
581
- * own, in all its versions. */
582
- export function BlocksParts() {
583
- const data = useMemo(exampleData, []);
584
- const blocks = [...standardBlocks, ...apps.flatMap((app) => siteBlocks.filter((b) => b.app === app.id))];
585
- return (
586
- <Screen title={screens.blocks} back={back}>
587
- <div className="space-y-10">
588
- <p className="text-muted">{screens.blocksIntro}</p>
589
- <PartsShown
590
- groups={blocks.map((b) => ({ id: b.type, title: b.label }))}
591
- keep="parts-blocks"
592
- search={screens.search}
593
- none={screens.none}
594
- >
595
- {blocks.map((b) => (
596
- <PartGroup key={b.type} group={b.type}>
597
- <BlockShown block={b} data={data} />
598
- </PartGroup>
599
- ))}
600
- </PartsShown>
601
- </div>
602
- </Screen>
603
- );
604
- }
605
-
606
- /** The lists of kinds ("Promovering"), each a screen of "Dele". */
607
- export const kindLists = () => collections.filter((c): c is FolderCollection => c.kind === 'folder' && !!c.kinds && !!c.fields?.length);
608
-
609
- /** "Dele" › a list of kinds ("Promovering", #udseende/dele/liste/<id>): each of its kinds as the site draws it, its own
610
- * (FolderCollection.draws: the pop-up, the bars) and the apps' (AppKind: Mailchimp's signup, once for each of its
611
- * states), each a group of its own, as a new one of the kind with the made-up texts (kindExample). */
612
- export function KindParts({ id }: { id: string }) {
613
- const data = useMemo(exampleData, []);
614
- const list = kindLists().find((c) => c.id === id);
615
- const kindField = list?.fields.find((f) => f.name === list.kinds);
616
- if (!list || !kindField) return null;
617
- const own = (kindField.options ?? []).flatMap((o) => {
618
- const draw = list.draws?.[o.value];
619
- return draw ? [{ id: o.value, label: o.label, hint: o.hint, variants: [{ label: '', props: {} }], draw }] : [];
620
- });
621
- const added = apps.flatMap((app) => {
622
- const kind = app.kinds?.[list.id];
623
- const draw = kind && kindDraw(kind, list);
624
- return kind && draw
625
- ? [{ id: app.id, label: kind.label, hint: kind.hint, variants: kind.variants ?? [{ label: '', props: {} }], draw }]
626
- : [];
627
- });
628
- const kinds = [...own, ...added];
629
- return (
630
- <Screen title={list.label} back={back}>
631
- <div className="space-y-10">
632
- <p className="text-muted">{screens.kindsIntro(list.singular)}</p>
633
- <PartsShown
634
- groups={kinds.map((k) => ({ id: k.id, title: k.label }))}
635
- keep={`parts-list-${list.id}`}
636
- search={screens.search}
637
- none={screens.none}
638
- >
639
- {kinds.map((k) => (
640
- <PartGroup key={k.id} group={k.id}>
641
- {k.variants.map((v) => (
642
- <Part key={v.label} name={v.label ? `${k.label} · ${v.label}` : k.label} use={k.hint}>
643
- <Preview>{k.draw({ ...kindExample(list, k.id), ...v.props }, data)}</Preview>
644
- </Part>
645
- ))}
646
- </PartGroup>
647
- ))}
648
- </PartsShown>
649
- </div>
650
- </Screen>
651
- );
652
- }
1
+ // "Dele" › "UI-komponenter" (#udseende/dele/ui), "Dele" › "Blokke" (#udseende/dele/blokke) and "Dele" › a list of kinds
2
+ // ("Promovering", #udseende/dele/liste/<id>): how the site looks, every part in every version, to see and agree on it.
3
+ // "UI-komponenter" has the theme's UI components (its buttons and icon buttons, text fields and checkboxes …,
4
+ // packages/editor/theme/ui/, through @site/editor) in every kind, size and state; "Blokke" every block, the standard
5
+ // ones (packages/editor/src/standard/), which every theme styles, and then the apps', each in its own group; a list of
6
+ // kinds each of its kinds as the site draws an entry of it, the list's own (the pop-up, the bars) and the apps' (a
7
+ // pop-up, once for each of its states), the kind a group. A block's versions are the
8
+ // options of its choices side by side (a field with `segments`: the designs of "Kort"), the first choice's all, each
9
+ // other's but the one a new block has (its default, else the empty one: the backgrounds of "Kort", with the first's empty
10
+ // option; the width of "Banner", as wide as the text). All of it is drawn with the
11
+ // made-up site of examples.ts, never the site's own, with the search, the order and the filter of "Editor"
12
+ // (PartsShown.tsx). Nothing here is saved.
13
+ import { useMemo } from 'react';
14
+ import Screen from './Screen';
15
+ import { Part, PartGroup, PartsShown } from './PartsShown';
16
+ import { Preview } from './ui';
17
+ import {
18
+ SiteButton,
19
+ SiteCard,
20
+ SiteCheckbox,
21
+ SiteChip,
22
+ SiteIconButton,
23
+ SiteList,
24
+ SiteListItem,
25
+ SiteTextField,
26
+ buttonShapes,
27
+ buttonSizes,
28
+ cardKinds,
29
+ chipKinds,
30
+ chipSetLayouts,
31
+ SiteChipSet,
32
+ iconButtonWidths,
33
+ } from './themeUi';
34
+ import ContainmentParts from './ContainmentParts';
35
+ import NavigationParts from './NavigationParts';
36
+ import ActionParts from './ActionParts';
37
+ import SelectionParts from './SelectionParts';
38
+ import CommunicationParts from './CommunicationParts';
39
+ import NavigationRestParts from './NavigationRestParts';
40
+ import PickerParts from './PickerParts';
41
+ import { exampleOf, type BlockData, type BlockProps, type SiteBlock } from './blocks';
42
+ import { apps, preview, siteBlocks, standardTypes } from './registry';
43
+ import { examplePicture, exampleData, kindExample } from './examples';
44
+ import type { Field, FolderCollection, PreviewVariant } from './schema';
45
+ import { buttonKinds, iconButtonKinds } from './standard/view';
46
+ import { kindDraw } from './apps';
47
+ import { collections } from './site';
48
+ import { t } from './i18n';
49
+ import { Svg } from './icon';
50
+
51
+ const { screens } = t.parts;
52
+ const back = { href: '#udseende/dele', label: t.common.parts.editorParts };
53
+
54
+ // The fields filled in with the plain picture where they have none (a card's, a list's items').
55
+ function pictured(fields: Field[], props: BlockProps): BlockProps {
56
+ const filled = { ...props };
57
+ for (const f of fields) {
58
+ const v = filled[f.name];
59
+ if (f.type === 'image' && !v) filled[f.name] = examplePicture;
60
+ else if (f.type === 'object' && f.fields) filled[f.name] = pictured(f.fields, (v ?? {}) as BlockProps);
61
+ else if (f.type === 'list' && f.fields && Array.isArray(v)) filled[f.name] = v.map((item) => pictured(f.fields!, item as BlockProps));
62
+ }
63
+ return filled;
64
+ }
65
+
66
+ // A block's versions: one for each option of its first choice side by side and for each other option of the others
67
+ // than the one a new block has, else only itself.
68
+ function versionsOf(block: SiteBlock): PreviewVariant[] {
69
+ const [first, ...rest] = block.fields.filter((f) => f.type === 'select' && f.segments && !f.only);
70
+ if (!first?.options) return [{ label: '', props: {} }];
71
+ return [
72
+ ...first.options.map((o) => ({ label: o.label, props: { [first.name]: o.value } })),
73
+ ...rest.flatMap((c) =>
74
+ (c.options ?? []).filter((o) => o.value !== String(c.default ?? '')).map((o) => ({ label: o.label, props: { [c.name]: o.value } })),
75
+ ),
76
+ ];
77
+ }
78
+
79
+ /** A block in each of its versions, filled in as an example, under its name (and the version's). */
80
+ function BlockShown({ block, data }: { block: SiteBlock; data: BlockData }) {
81
+ const example = exampleOf(block, data);
82
+ return versionsOf(block).map((v) => (
83
+ <Part key={v.label} name={v.label ? `${block.label} · ${v.label}` : block.label} use={block.hint}>
84
+ <Preview>{preview(block.type, pictured(block.fields, { ...example, ...v.props }), data)}</Preview>
85
+ </Part>
86
+ ));
87
+ }
88
+
89
+ /** The theme's chips, as the site draws them: every kind, elevated on a picture, in every state (chosen, with an icon or
90
+ * a picture, with the button that removes it, dragged, only shown) and disabled. */
91
+ function ChipParts() {
92
+ const row = 'flex flex-wrap items-center gap-3';
93
+ const { input, filter, suggestion, assist } = screens.chipKinds;
94
+ return (
95
+ <Part name="Chip" use={screens.chip}>
96
+ <Preview>
97
+ <div className="space-y-4 p-4">
98
+ <div className={row}>
99
+ {chipKinds.map((k) => (
100
+ <SiteChip key={k} kind={k} label={screens.chipKinds[k]} />
101
+ ))}
102
+ </div>
103
+ <div className={`${row} rounded-xl bg-cover bg-center p-4`} style={{ backgroundImage: `url("${examplePicture}")` }}>
104
+ <SiteChip elevated icon="calendar-blank" label={`${assist} · ${screens.elevated}`} />
105
+ <SiteChip elevated kind="filter" label={`${filter} · ${screens.elevated}`} />
106
+ <SiteChip elevated kind="filter" selected label={screens.selected} />
107
+ <SiteChip elevated kind="suggestion" label={`${suggestion} · ${screens.elevated}`} />
108
+ </div>
109
+ <div className={row}>
110
+ <SiteChip kind="filter" selected label={screens.selected} />
111
+ <SiteChip kind="filter" label={filter} />
112
+ <SiteChip kind="suggestion" selected label={`${suggestion} · ${screens.selected}`} />
113
+ <SiteChip icon="calendar-blank" label={screens.withIcon} />
114
+ <SiteChip kind="input" trailingIcon="x" label={input} />
115
+ <SiteChip kind="input" avatar={examplePicture} removeLabel={screens.remove(screens.withAvatar)} label={screens.withAvatar} />
116
+ <SiteChip kind="input" selected removeLabel={screens.remove(screens.selected)} label={screens.selected} />
117
+ <SiteChip kind="input" dragged avatar={examplePicture} label={screens.dragged} />
118
+ <SiteChip plain label={screens.plain} />
119
+ </div>
120
+ <div className={row}>
121
+ {chipKinds.map((k) => (
122
+ <SiteChip key={k} kind={k} disabled label={screens.disabled} />
123
+ ))}
124
+ <SiteChip kind="input" disabled removeLabel={screens.remove(screens.disabled)} label={screens.disabled} />
125
+ <SiteChip elevated disabled label={`${screens.elevated} · ${screens.disabled}`} />
126
+ <SiteChip href="" disabled label={screens.disabled} />
127
+ </div>
128
+ </div>
129
+ </Preview>
130
+ </Part>
131
+ );
132
+ }
133
+
134
+ /** The theme's chip sets, as the site draws them: each layout, with more chips than there is room for on one line. */
135
+ function ChipSetParts() {
136
+ return (
137
+ <Part name="ChipSet" use={screens.chipSet}>
138
+ <Preview>
139
+ <div className="max-w-sm space-y-4 p-4">
140
+ {chipSetLayouts.map((layout) => (
141
+ <SiteChipSet key={layout} layout={layout} label={screens.chipSetLayouts[layout]}>
142
+ {[...chipKinds, ...chipKinds].map((k, i) => (
143
+ <SiteChip key={i} kind="filter" selected={!i} label={`${screens.chipSetLayouts[layout]} ${i + 1}`} />
144
+ ))}
145
+ </SiteChipSet>
146
+ ))}
147
+ </div>
148
+ </Preview>
149
+ </Part>
150
+ );
151
+ }
152
+
153
+ // The standard blocks (not HTML, which has no look of its own).
154
+ const standardBlocks = siteBlocks.filter((b) => standardTypes.has(b.type));
155
+
156
+ // The kinds a toggle button can be (Material: never a text button).
157
+ const toggleKinds = buttonKinds.filter((k) => k !== 'text');
158
+
159
+ /** The theme's buttons and icon buttons, as the site draws them: every kind, the five sizes, both shapes, each kind
160
+ * that can be a toggle off and on in both shapes, the icon buttons' widths, with an icon, and disabled. */
161
+ function ButtonParts() {
162
+ const row = 'flex flex-wrap items-center gap-3';
163
+ const kinds = t.blocks.buttons.kinds;
164
+ return (
165
+ <>
166
+ <Part name="Button" use={screens.button}>
167
+ <Preview>
168
+ <div className="space-y-4 p-4">
169
+ <div className={row}>
170
+ {buttonKinds.map((k) => (
171
+ <SiteButton key={k} kind={k}>
172
+ {kinds[k]}
173
+ </SiteButton>
174
+ ))}
175
+ </div>
176
+ <div className={row}>
177
+ {buttonSizes.map((size) => (
178
+ <SiteButton key={size} size={size}>
179
+ {screens.sizes[size]}
180
+ </SiteButton>
181
+ ))}
182
+ </div>
183
+ <div className={row}>
184
+ {buttonSizes.map((size) => (
185
+ <SiteButton key={size} size={size} shape="square" kind="tonal">
186
+ {screens.sizes[size]}
187
+ </SiteButton>
188
+ ))}
189
+ </div>
190
+ {buttonShapes.map((shape) => (
191
+ <div key={shape} className={row} role="group" aria-label={screens.shapes[shape]}>
192
+ {toggleKinds.map((k) =>
193
+ ([false, true] as const).map((on) => (
194
+ <SiteButton key={`${k}-${on}`} kind={k} shape={shape} selected={on} icon="heart">
195
+ {on ? screens.toggle.on : screens.toggle.off}
196
+ </SiteButton>
197
+ )),
198
+ )}
199
+ </div>
200
+ ))}
201
+ <div className={row}>
202
+ <SiteButton icon="phone">{screens.withIcon}</SiteButton>
203
+ <SiteButton kind="outlined" trailingIcon="arrow-right">
204
+ {screens.withIcon}
205
+ </SiteButton>
206
+ {buttonKinds.map((k) => (
207
+ <SiteButton key={k} kind={k} disabled>
208
+ {screens.disabled}
209
+ </SiteButton>
210
+ ))}
211
+ <SiteButton selected disabled>
212
+ {screens.disabled}
213
+ </SiteButton>
214
+ </div>
215
+ </div>
216
+ </Preview>
217
+ </Part>
218
+ <Part name="IconButton" use={screens.iconButton}>
219
+ <Preview>
220
+ <div className="space-y-4 p-4">
221
+ <div className={row}>
222
+ {iconButtonKinds.map((k) => (
223
+ <SiteIconButton key={k} kind={k} icon="x" label={screens.iconKinds[k]} title={screens.iconKinds[k]} />
224
+ ))}
225
+ </div>
226
+ <div className={row}>
227
+ {buttonSizes.map((size) => (
228
+ <SiteIconButton key={size} kind="filled" size={size} icon="phone" label={screens.sizes[size]} title={screens.sizes[size]} />
229
+ ))}
230
+ </div>
231
+ <div className={row}>
232
+ {buttonSizes.map((size) => (
233
+ <SiteIconButton
234
+ key={size}
235
+ kind="tonal"
236
+ size={size}
237
+ shape="square"
238
+ icon="phone"
239
+ label={`${screens.sizes[size]}, ${screens.shapes.square}`}
240
+ title={`${screens.sizes[size]}, ${screens.shapes.square}`}
241
+ />
242
+ ))}
243
+ </div>
244
+ <div className={row}>
245
+ {(['small', 'medium'] as const).flatMap((size) =>
246
+ iconButtonWidths.map((width) => (
247
+ <SiteIconButton
248
+ key={`${size}-${width}`}
249
+ kind="outlined"
250
+ size={size}
251
+ width={width}
252
+ icon="phone"
253
+ label={`${screens.sizes[size]}, ${screens.widths[width]}`}
254
+ title={`${screens.sizes[size]}, ${screens.widths[width]}`}
255
+ />
256
+ )),
257
+ )}
258
+ </div>
259
+ {buttonShapes.map((shape) => (
260
+ <div key={shape} className={row} role="group" aria-label={screens.shapes[shape]}>
261
+ {iconButtonKinds.map((k) =>
262
+ ([false, true] as const).map((on) => (
263
+ <SiteIconButton
264
+ key={`${k}-${on}`}
265
+ kind={k}
266
+ shape={shape}
267
+ selected={on}
268
+ icon="heart"
269
+ label={`${screens.iconKinds[k]}, ${on ? screens.toggle.on : screens.toggle.off}`}
270
+ title={`${screens.iconKinds[k]}, ${on ? screens.toggle.on : screens.toggle.off}`}
271
+ />
272
+ )),
273
+ )}
274
+ </div>
275
+ ))}
276
+ <div className={row}>
277
+ {iconButtonKinds.map((k) => (
278
+ <SiteIconButton key={k} kind={k} icon="phone" label={screens.disabled} disabled />
279
+ ))}
280
+ <SiteIconButton kind="filled" icon="phone" label={screens.disabled} selected disabled />
281
+ </div>
282
+ </div>
283
+ </Preview>
284
+ </Part>
285
+ </>
286
+ );
287
+ }
288
+
289
+ /** The theme's form controls, as the site draws them: each kind of text field empty, filled in, with a line under it,
290
+ * with an error, with only a placeholder and disabled, with an icon before it, a search field with its clear button, a
291
+ * prefix and a suffix, the error's icon, a password with its button, a counter, read-only, and several lines (growing,
292
+ * and three rows); and a checkbox empty, ticked, with a line, disabled, indeterminate and wrong. */
293
+ function FieldParts() {
294
+ const fields = 'grid gap-6 sm:grid-cols-2';
295
+ return (
296
+ <>
297
+ <Part name="TextField" use={screens.textField}>
298
+ <Preview>
299
+ <div className="space-y-6 p-4">
300
+ {(['outlined', 'filled'] as const).map((kind) => (
301
+ <div key={kind} className={fields} aria-label={screens.fieldKinds[kind]} role="group">
302
+ <SiteTextField kind={kind} label={screens.fieldLabel} type="email" />
303
+ <SiteTextField kind={kind} label={screens.fieldLabel} type="email" defaultValue={screens.fieldValue} />
304
+ <SiteTextField kind={kind} label={screens.fieldLabel} type="email" supporting={screens.fieldSupporting} />
305
+ <SiteTextField kind={kind} label={screens.fieldLabel} type="email" defaultValue="navn@" error={screens.fieldError} />
306
+ <SiteTextField kind={kind} label={screens.fieldLabel} hideLabel type="email" placeholder={screens.fieldPlaceholder} />
307
+ <SiteTextField kind={kind} label={screens.fieldLabel} type="email" disabled />
308
+ <SiteTextField kind={kind} label={screens.fieldLabel} type="email" leadingIcon="envelope-simple" />
309
+ <SiteTextField
310
+ kind={kind}
311
+ label={screens.fieldSearch}
312
+ hideLabel
313
+ type="search"
314
+ placeholder={screens.fieldSearch}
315
+ leadingIcon="magnifying-glass"
316
+ clearLabel={screens.fieldClear}
317
+ defaultValue={screens.fieldNote}
318
+ />
319
+ <SiteTextField kind={kind} label={screens.fieldPhone} type="tel" prefix={screens.fieldPrefix} defaultValue="12 34 56 78" />
320
+ <SiteTextField kind={kind} label={screens.fieldPrice} inputMode="numeric" suffix={screens.fieldSuffix} defaultValue="450" />
321
+ <SiteTextField
322
+ kind={kind}
323
+ label={screens.fieldLabel}
324
+ type="email"
325
+ defaultValue="navn@"
326
+ error={screens.fieldError}
327
+ leadingIcon="envelope-simple"
328
+ errorIcon
329
+ />
330
+ <SiteTextField
331
+ kind={kind}
332
+ label={screens.fieldPassword}
333
+ type="password"
334
+ defaultValue={screens.fieldPasswordValue}
335
+ passwordLabel={screens.fieldShowPassword}
336
+ />
337
+ <SiteTextField
338
+ kind={kind}
339
+ label={screens.fieldName}
340
+ supporting={screens.fieldNameSupporting}
341
+ counter
342
+ maxLength={30}
343
+ defaultValue={screens.fieldValue}
344
+ />
345
+ <SiteTextField kind={kind} label={screens.fieldReadOnly} readOnly defaultValue={screens.fieldReadOnlyValue} />
346
+ <SiteTextField kind={kind} label={screens.fieldMessage} multiline defaultValue={screens.fieldMessageValue} />
347
+ <SiteTextField kind={kind} label={screens.fieldNote} rows={3} counter maxLength={200} />
348
+ </div>
349
+ ))}
350
+ </div>
351
+ </Preview>
352
+ </Part>
353
+ <Part name="Checkbox" use={screens.checkbox}>
354
+ <Preview>
355
+ <div className={`${fields} p-4`}>
356
+ <SiteCheckbox label={screens.checkboxLabel} />
357
+ <SiteCheckbox label={screens.checkboxLabel} checked />
358
+ <SiteCheckbox label={screens.checkboxLabel} supporting={screens.checkboxSupporting} />
359
+ <SiteCheckbox label={screens.checkboxLabel} supporting={screens.checkboxSupporting} checked disabled />
360
+ <SiteCheckbox label={screens.checkboxParent} supporting={screens.checkboxSupporting} indeterminate />
361
+ <SiteCheckbox label={screens.checkboxParent} indeterminate disabled />
362
+ <SiteCheckbox label={screens.checkboxLabel} error={screens.checkboxError} />
363
+ <SiteCheckbox label={screens.checkboxLabel} error checked />
364
+ </div>
365
+ </Preview>
366
+ </Part>
367
+ </>
368
+ );
369
+ }
370
+
371
+ /** The theme's cards in each kind, one a link, and lists: one line, a link and an icon with a text under it; one, two
372
+ * and three lines; each leading kind; the choices; selected and disabled; each kind of dividers; and segmented. */
373
+ function CardParts() {
374
+ const say = screens.cardsAndLists;
375
+ const [one, link, withIcon] = say.items;
376
+ const lists = say.lists;
377
+ const [icon, avatar, avatarPicture, image, video] = lists.headlines;
378
+ const [checkbox, radio, switchItem, after] = lists.choices;
379
+ return (
380
+ <>
381
+ <Part name="Card" use={say.card}>
382
+ <Preview>
383
+ <div className="grid gap-4 p-4 sm:grid-cols-2">
384
+ {cardKinds.map((k) => (
385
+ <SiteCard key={k} kind={k}>
386
+ <p className="font-medium">{say.kinds[k]}</p>
387
+ <p className="mt-1 text-muted">{say.text}</p>
388
+ </SiteCard>
389
+ ))}
390
+ <SiteCard href="">
391
+ <p className="font-medium">{say.link}</p>
392
+ <p className="mt-1 text-muted">{say.text}</p>
393
+ </SiteCard>
394
+ {cardKinds.map((k) => (
395
+ <SiteCard key={k} kind={k} dragged>
396
+ <p className="font-medium">{`${say.kinds[k]} · ${screens.dragged}`}</p>
397
+ <p className="mt-1 text-muted">{say.text}</p>
398
+ </SiteCard>
399
+ ))}
400
+ </div>
401
+ </Preview>
402
+ </Part>
403
+ <Part name="List" use={say.list}>
404
+ <Preview>
405
+ <div className="grid items-start gap-4 p-4 lg:grid-cols-2">
406
+ <SiteCard>
407
+ <SiteList>
408
+ <SiteListItem headline={one} />
409
+ <SiteListItem href="" headline={link} trailing={<Svg name="arrow-right" size={18} />} />
410
+ <SiteListItem
411
+ href=""
412
+ leading={<Svg name="phone" size={24} />}
413
+ headline={withIcon}
414
+ supporting={say.supporting}
415
+ trailing={<Svg name="caret-right" size={20} />}
416
+ />
417
+ </SiteList>
418
+ </SiteCard>
419
+ <SiteCard>
420
+ <SiteList aria-label={lists.lines}>
421
+ <SiteListItem href="" headline={one} trailingSupporting={lists.trailing} />
422
+ <SiteListItem href="" headline={one} supporting={say.supporting} trailingIcon="caret-right" />
423
+ <SiteListItem href="" overline={lists.overline} headline={one} supporting={say.supporting} trailingIcon="caret-right" />
424
+ <SiteListItem
425
+ href=""
426
+ lines={3}
427
+ leadingIcon="calendar-blank"
428
+ headline={one}
429
+ supporting={lists.long}
430
+ trailingSupporting={lists.trailing}
431
+ />
432
+ </SiteList>
433
+ </SiteCard>
434
+ <SiteCard>
435
+ <SiteList dividers="inset" aria-label={lists.leading}>
436
+ <SiteListItem href="" leadingIcon="phone" headline={icon} supporting={say.supporting} trailingIcon="caret-right" />
437
+ <SiteListItem
438
+ href=""
439
+ leadingAvatar={lists.letter}
440
+ headline={avatar}
441
+ supporting={say.supporting}
442
+ trailingSupporting={lists.trailing}
443
+ />
444
+ <SiteListItem href="" leadingAvatar={{ src: examplePicture }} headline={avatarPicture} supporting={say.supporting} />
445
+ <SiteListItem href="" leadingImage={{ src: examplePicture }} headline={image} supporting={say.supporting} />
446
+ <SiteListItem href="" leadingVideo={{ src: examplePicture }} lines={3} headline={video} supporting={lists.long} />
447
+ </SiteList>
448
+ </SiteCard>
449
+ <SiteCard>
450
+ <SiteList aria-label={lists.controls}>
451
+ <SiteListItem control={{ type: 'checkbox', checked: true }} headline={checkbox} supporting={say.supporting} />
452
+ <SiteListItem control={{ type: 'radio-button', name: 'parts-list-radio', checked: true }} headline={radio} />
453
+ <SiteListItem control={{ type: 'radio-button', name: 'parts-list-radio' }} headline={radio} />
454
+ <SiteListItem control={{ type: 'switch', checked: true, icons: 'selected' }} leadingIcon="moon" headline={switchItem} />
455
+ <SiteListItem control={{ type: 'checkbox', at: 'trailing' }} leadingAvatar={lists.letter} headline={after} />
456
+ </SiteList>
457
+ </SiteCard>
458
+ <SiteCard>
459
+ <SiteList aria-label={lists.states}>
460
+ <SiteListItem href="" selected leadingIcon="house" headline={lists.selected} supporting={say.supporting} />
461
+ <SiteListItem href="" disabled leadingIcon="house" headline={lists.disabled} supporting={say.supporting} />
462
+ <SiteListItem control={{ type: 'switch' }} disabled headline={lists.disabled} />
463
+ </SiteList>
464
+ </SiteCard>
465
+ <SiteCard>
466
+ <SiteList aria-label={lists.more}>
467
+ <SiteListItem
468
+ onClick={() => {}}
469
+ leadingIcon="pencil-simple"
470
+ headline={lists.tapped}
471
+ supporting={say.supporting}
472
+ trailingIcon="caret-right"
473
+ />
474
+ <SiteListItem
475
+ href=""
476
+ headline={lists.withActions}
477
+ supporting={lists.long}
478
+ truncate
479
+ actions={<SiteIconButton icon="trash" label={lists.remove} />}
480
+ />
481
+ <SiteListItem href="" headline={lists.address} supporting={lists.sendsTo} columns />
482
+ </SiteList>
483
+ </SiteCard>
484
+ {(['middle-inset', 'none'] as const).map((dividers) => (
485
+ <SiteCard key={dividers}>
486
+ <SiteList dividers={dividers} aria-label={lists.dividers[dividers]}>
487
+ {[icon, avatar, image].map((h) => (
488
+ <SiteListItem
489
+ key={h}
490
+ href=""
491
+ leadingIcon="phone"
492
+ headline={`${lists.dividers[dividers]} · ${h}`}
493
+ trailingIcon="caret-right"
494
+ />
495
+ ))}
496
+ </SiteList>
497
+ </SiteCard>
498
+ ))}
499
+ <SiteList kind="segmented" aria-label={lists.segmented}>
500
+ <SiteListItem href="" leadingIcon="phone" headline={lists.segmented} supporting={say.supporting} trailingIcon="caret-right" />
501
+ <SiteListItem
502
+ href=""
503
+ selected
504
+ leadingIcon="envelope-simple"
505
+ headline={lists.selected}
506
+ supporting={say.supporting}
507
+ trailingIcon="caret-right"
508
+ />
509
+ <SiteListItem control={{ type: 'checkbox', checked: true }} headline={checkbox} />
510
+ <SiteListItem control={{ type: 'switch' }} leadingIcon="moon" headline={switchItem} />
511
+ <SiteListItem href="" disabled leadingIcon="map-pin" headline={lists.disabled} />
512
+ </SiteList>
513
+ </div>
514
+ </Preview>
515
+ </Part>
516
+ </>
517
+ );
518
+ }
519
+
520
+ /** "Dele" › "UI-komponenter" (#udseende/dele/ui): the theme's UI components in every kind, size and state. */
521
+ export function ComponentParts() {
522
+ const groups = [
523
+ { id: 'ui', title: screens.ui },
524
+ { id: 'fields', title: screens.fields },
525
+ { id: 'chips', title: screens.chips },
526
+ { id: 'containment', title: screens.containment.title },
527
+ { id: 'cards', title: screens.cardsAndLists.title },
528
+ { id: 'navigation', title: screens.navigation.title },
529
+ { id: 'actions', title: screens.actions.title },
530
+ { id: 'selection', title: screens.selection.title },
531
+ { id: 'communication', title: screens.communication.title },
532
+ { id: 'navigationRest', title: screens.navigationRest.title },
533
+ { id: 'pickers', title: screens.pickers.title },
534
+ ];
535
+ return (
536
+ <Screen title={screens.components} back={back}>
537
+ <div className="space-y-10">
538
+ <p className="text-muted">{screens.componentsIntro}</p>
539
+ <PartsShown groups={groups} keep="parts-components" search={screens.search} none={screens.none}>
540
+ <PartGroup group="ui">
541
+ <ButtonParts />
542
+ </PartGroup>
543
+ <PartGroup group="fields">
544
+ <FieldParts />
545
+ </PartGroup>
546
+ <PartGroup group="chips">
547
+ <ChipParts />
548
+ <ChipSetParts />
549
+ </PartGroup>
550
+ <PartGroup group="containment">
551
+ <ContainmentParts />
552
+ </PartGroup>
553
+ <PartGroup group="cards">
554
+ <CardParts />
555
+ </PartGroup>
556
+ <PartGroup group="navigation">
557
+ <NavigationParts />
558
+ </PartGroup>
559
+ <PartGroup group="actions">
560
+ <ActionParts />
561
+ </PartGroup>
562
+ <PartGroup group="selection">
563
+ <SelectionParts />
564
+ </PartGroup>
565
+ <PartGroup group="communication">
566
+ <CommunicationParts />
567
+ </PartGroup>
568
+ <PartGroup group="navigationRest">
569
+ <NavigationRestParts />
570
+ </PartGroup>
571
+ <PartGroup group="pickers">
572
+ <PickerParts />
573
+ </PartGroup>
574
+ </PartsShown>
575
+ </div>
576
+ </Screen>
577
+ );
578
+ }
579
+
580
+ /** "Dele" › "Blokke" (#udseende/dele/blokke): every block, the standard ones and then the apps', each a group of its
581
+ * own, in all its versions. */
582
+ export function BlocksParts() {
583
+ const data = useMemo(exampleData, []);
584
+ const blocks = [...standardBlocks, ...apps.flatMap((app) => siteBlocks.filter((b) => b.app === app.id))];
585
+ return (
586
+ <Screen title={screens.blocks} back={back}>
587
+ <div className="space-y-10">
588
+ <p className="text-muted">{screens.blocksIntro}</p>
589
+ <PartsShown
590
+ groups={blocks.map((b) => ({ id: b.type, title: b.label }))}
591
+ keep="parts-blocks"
592
+ search={screens.search}
593
+ none={screens.none}
594
+ >
595
+ {blocks.map((b) => (
596
+ <PartGroup key={b.type} group={b.type}>
597
+ <BlockShown block={b} data={data} />
598
+ </PartGroup>
599
+ ))}
600
+ </PartsShown>
601
+ </div>
602
+ </Screen>
603
+ );
604
+ }
605
+
606
+ /** The lists of kinds ("Promovering"), each a screen of "Dele". */
607
+ export const kindLists = () => collections.filter((c): c is FolderCollection => c.kind === 'folder' && !!c.kinds && !!c.fields?.length);
608
+
609
+ /** "Dele" › a list of kinds ("Promovering", #udseende/dele/liste/<id>): each of its kinds as the site draws it, its own
610
+ * (FolderCollection.draws: the pop-up, the bars) and the apps' (AppKind: Mailchimp's signup, once for each of its
611
+ * states), each a group of its own, as a new one of the kind with the made-up texts (kindExample). */
612
+ export function KindParts({ id }: { id: string }) {
613
+ const data = useMemo(exampleData, []);
614
+ const list = kindLists().find((c) => c.id === id);
615
+ const kindField = list?.fields.find((f) => f.name === list.kinds);
616
+ if (!list || !kindField) return null;
617
+ const own = (kindField.options ?? []).flatMap((o) => {
618
+ const draw = list.draws?.[o.value];
619
+ return draw ? [{ id: o.value, label: o.label, hint: o.hint, variants: [{ label: '', props: {} }], draw }] : [];
620
+ });
621
+ const added = apps.flatMap((app) => {
622
+ const kind = app.kinds?.[list.id];
623
+ const draw = kind && kindDraw(kind, list);
624
+ return kind && draw
625
+ ? [{ id: app.id, label: kind.label, hint: kind.hint, variants: kind.variants ?? [{ label: '', props: {} }], draw }]
626
+ : [];
627
+ });
628
+ const kinds = [...own, ...added];
629
+ return (
630
+ <Screen title={list.label} back={back}>
631
+ <div className="space-y-10">
632
+ <p className="text-muted">{screens.kindsIntro(list.singular)}</p>
633
+ <PartsShown
634
+ groups={kinds.map((k) => ({ id: k.id, title: k.label }))}
635
+ keep={`parts-list-${list.id}`}
636
+ search={screens.search}
637
+ none={screens.none}
638
+ >
639
+ {kinds.map((k) => (
640
+ <PartGroup key={k.id} group={k.id}>
641
+ {k.variants.map((v) => (
642
+ <Part key={v.label} name={v.label ? `${k.label} · ${v.label}` : k.label} use={k.hint}>
643
+ <Preview>{k.draw({ ...kindExample(list, k.id), ...v.props }, data)}</Preview>
644
+ </Part>
645
+ ))}
646
+ </PartGroup>
647
+ ))}
648
+ </PartsShown>
649
+ </div>
650
+ </Screen>
651
+ );
652
+ }