acinguiux-preact-components 0.0.1

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 (313) hide show
  1. package/package.json +56 -0
  2. package/src/content/themes/theme-acinguiux-amg/theme-acinguiux-amg.css +23 -0
  3. package/src/content/themes/theme-acinguiux-cafe/theme-acinguiux-cafe.css +47 -0
  4. package/src/content/themes/theme-acinguiux-energy/theme-acinguiux-energy.css +45 -0
  5. package/src/content/themes/theme-acinguiux-livewire/theme-acinguiux-livewire.css +22 -0
  6. package/src/content/themes/theme-acinguiux-livewire-italy/theme-acinguiux-livewire-italy.css +22 -0
  7. package/src/content/themes/theme-acinguiux-recharge/theme-acinguiux-recharge.css +49 -0
  8. package/src/content/themes/theme-allon/theme-allon.css +25 -0
  9. package/src/content/themes/theme-atlas/theme-atlas.css +31 -0
  10. package/src/content/themes/theme-aurvana/resources/favicon/apple-touch-icon.png +0 -0
  11. package/src/content/themes/theme-aurvana/resources/favicon/favico.ico +0 -0
  12. package/src/content/themes/theme-aurvana/resources/favicon/favicon-96x96.png +0 -0
  13. package/src/content/themes/theme-aurvana/resources/favicon/favicon.ico +0 -0
  14. package/src/content/themes/theme-aurvana/resources/favicon/favicon.png +0 -0
  15. package/src/content/themes/theme-aurvana/resources/favicon/favicon.svg +13 -0
  16. package/src/content/themes/theme-aurvana/resources/favicon/google-touch-icon.png +0 -0
  17. package/src/content/themes/theme-aurvana/resources/favicon/manifest.json +14 -0
  18. package/src/content/themes/theme-aurvana/resources/favicon/site.webmanifest +21 -0
  19. package/src/content/themes/theme-aurvana/resources/favicon/web-app-manifest-192x192.png +0 -0
  20. package/src/content/themes/theme-aurvana/resources/favicon/web-app-manifest-512x512.png +0 -0
  21. package/src/content/themes/theme-aurvana/theme-aurvana.css +49 -0
  22. package/src/content/themes/theme-base/theme-base.css +49 -0
  23. package/src/content/themes/theme-base2/resources/favicon/android-chrome-192x192.png +0 -0
  24. package/src/content/themes/theme-base2/resources/favicon/android-chrome-512x512.png +0 -0
  25. package/src/content/themes/theme-base2/resources/favicon/apple-touch-icon.png +0 -0
  26. package/src/content/themes/theme-base2/resources/favicon/favico.ico +0 -0
  27. package/src/content/themes/theme-base2/resources/favicon/favicon-16x16.png +0 -0
  28. package/src/content/themes/theme-base2/resources/favicon/favicon-32x32.png +0 -0
  29. package/src/content/themes/theme-base2/resources/favicon/favicon-96x96.png +0 -0
  30. package/src/content/themes/theme-base2/resources/favicon/favicon.ico +0 -0
  31. package/src/content/themes/theme-base2/resources/favicon/favicon.png +0 -0
  32. package/src/content/themes/theme-base2/resources/favicon/favicon.svg +9 -0
  33. package/src/content/themes/theme-base2/resources/favicon/google-touch-icon.png +0 -0
  34. package/src/content/themes/theme-base2/resources/favicon/manifest.json +14 -0
  35. package/src/content/themes/theme-base2/resources/favicon/site.webmanifest +1 -0
  36. package/src/content/themes/theme-base2/resources/favicon/web-app-manifest-192x192.png +0 -0
  37. package/src/content/themes/theme-base2/resources/favicon/web-app-manifest-512x512.png +0 -0
  38. package/src/content/themes/theme-base2/resources/fonts/acinguiux-typeface-la-heavy-221208.woff2 +0 -0
  39. package/src/content/themes/theme-base2/theme-base2.css +47 -0
  40. package/src/content/themes/theme-eco-marathon/theme-eco-marathon.css +22 -0
  41. package/src/content/themes/theme-energy-transition-campus-amsterdam/theme-energy-transition-campus-amsterdam.css +26 -0
  42. package/src/content/themes/theme-evpass/theme-evpass.css +46 -0
  43. package/src/content/themes/theme-nam-2025/resources/favicon/apple-touch-icon.png +0 -0
  44. package/src/content/themes/theme-nam-2025/resources/favicon/favico.ico +0 -0
  45. package/src/content/themes/theme-nam-2025/resources/favicon/favicon-96x96.png +0 -0
  46. package/src/content/themes/theme-nam-2025/resources/favicon/favicon.ico +0 -0
  47. package/src/content/themes/theme-nam-2025/resources/favicon/favicon.png +0 -0
  48. package/src/content/themes/theme-nam-2025/resources/favicon/favicon.svg +9 -0
  49. package/src/content/themes/theme-nam-2025/resources/favicon/google-touch-icon.png +0 -0
  50. package/src/content/themes/theme-nam-2025/resources/favicon/manifest.json +14 -0
  51. package/src/content/themes/theme-nam-2025/resources/favicon/site.webmanifest +21 -0
  52. package/src/content/themes/theme-nam-2025/resources/favicon/web-app-manifest-192x192.png +0 -0
  53. package/src/content/themes/theme-nam-2025/resources/favicon/web-app-manifest-512x512.png +0 -0
  54. package/src/content/themes/theme-nam-2025/theme-nam-2025.css +47 -0
  55. package/src/content/themes/theme-pennzoil/theme-pennzoil.css +36 -0
  56. package/src/content/themes/theme-quaker-state/theme-quaker-state.css +63 -0
  57. package/src/content/themes/theme-tafawoq/theme-tafawoq.css +26 -0
  58. package/src/content/themes/theme-vegetable/resources/favicon/apple-touch-icon.png +0 -0
  59. package/src/content/themes/theme-vegetable/resources/favicon/favico.ico +0 -0
  60. package/src/content/themes/theme-vegetable/resources/favicon/favicon-96x96.png +0 -0
  61. package/src/content/themes/theme-vegetable/resources/favicon/favicon.ico +0 -0
  62. package/src/content/themes/theme-vegetable/resources/favicon/favicon.png +0 -0
  63. package/src/content/themes/theme-vegetable/resources/favicon/favicon.svg +13 -0
  64. package/src/content/themes/theme-vegetable/resources/favicon/google-touch-icon.png +0 -0
  65. package/src/content/themes/theme-vegetable/resources/favicon/manifest.json +14 -0
  66. package/src/content/themes/theme-vegetable/resources/favicon/site.webmanifest +21 -0
  67. package/src/content/themes/theme-vegetable/resources/favicon/web-app-manifest-192x192.png +0 -0
  68. package/src/content/themes/theme-vegetable/resources/favicon/web-app-manifest-512x512.png +0 -0
  69. package/src/content/themes/theme-vegetable/theme-vegetable.css +49 -0
  70. package/src/content/themes/theme-zeolyst/resources/fonts/type-ar-medium.woff2 +0 -0
  71. package/src/content/themes/theme-zeolyst/theme-zeolyst.css +29 -0
  72. package/src/main/atoms/audio.js +16 -0
  73. package/src/main/atoms/box.js +5 -0
  74. package/src/main/atoms/button.js +40 -0
  75. package/src/main/atoms/card.js +22 -0
  76. package/src/main/atoms/form.js +30 -0
  77. package/src/main/atoms/heading.js +17 -0
  78. package/src/main/atoms/icon.js +24 -0
  79. package/src/main/atoms/img.js +131 -0
  80. package/src/main/atoms/input.js +55 -0
  81. package/src/main/atoms/link-text.js +21 -0
  82. package/src/main/atoms/link.js +60 -0
  83. package/src/main/atoms/list.js +12 -0
  84. package/src/main/atoms/logo.js +9 -0
  85. package/src/main/atoms/menu.js +10 -0
  86. package/src/main/atoms/message.js +5 -0
  87. package/src/main/atoms/nav-link.js +49 -0
  88. package/src/main/atoms/popup.js +47 -0
  89. package/src/main/atoms/rich-text.js +128 -0
  90. package/src/main/atoms/scroller.js +224 -0
  91. package/src/main/atoms/svg.js +65 -0
  92. package/src/main/atoms/table.js +32 -0
  93. package/src/main/atoms/textarea.js +10 -0
  94. package/src/main/atoms/time.js +12 -0
  95. package/src/main/atoms/video.js +100 -0
  96. package/src/main/export-main.js +12 -0
  97. package/src/main/export-matter.js +86 -0
  98. package/src/main/export-preact-hooks.js +1 -0
  99. package/src/main/export-preact.js +1 -0
  100. package/src/main/index.js +13 -0
  101. package/src/main/molecules/asset.js +23 -0
  102. package/src/main/molecules/glossary.js +44 -0
  103. package/src/main/molecules/links.js +23 -0
  104. package/src/main/molecules/promo-text.js +27 -0
  105. package/src/main/molecules/tags.js +15 -0
  106. package/src/main/molecules/tree.js +51 -0
  107. package/src/main/organisms/accordion-item.js +106 -0
  108. package/src/main/organisms/author.js +29 -0
  109. package/src/main/organisms/breadcrumb.js +69 -0
  110. package/src/main/organisms/call-to-action.js +24 -0
  111. package/src/main/organisms/carousel.js +178 -0
  112. package/src/main/organisms/cart-item.js +156 -0
  113. package/src/main/organisms/cart.js +162 -0
  114. package/src/main/organisms/contact-form.js +141 -0
  115. package/src/main/organisms/container/ab-test.js +47 -0
  116. package/src/main/organisms/container/default.js +6 -0
  117. package/src/main/organisms/container/filtered-section.js +293 -0
  118. package/src/main/organisms/container/footer.js +12 -0
  119. package/src/main/organisms/container/grid.js +44 -0
  120. package/src/main/organisms/container/header.js +13 -0
  121. package/src/main/organisms/container/list.js +7 -0
  122. package/src/main/organisms/container/main.js +6 -0
  123. package/src/main/organisms/container/raw.js +7 -0
  124. package/src/main/organisms/container/section.js +28 -0
  125. package/src/main/organisms/container.js +29 -0
  126. package/src/main/organisms/content-owner.js +15 -0
  127. package/src/main/organisms/date-entry.js +56 -0
  128. package/src/main/organisms/external-search.js +73 -0
  129. package/src/main/organisms/filtered-item.js +163 -0
  130. package/src/main/organisms/footer-item.js +17 -0
  131. package/src/main/organisms/image-gallery.js +164 -0
  132. package/src/main/organisms/last-modified.js +20 -0
  133. package/src/main/organisms/legal-footer.js +16 -0
  134. package/src/main/organisms/list-item.js +48 -0
  135. package/src/main/organisms/metadata.js +11 -0
  136. package/src/main/organisms/navigation.js +232 -0
  137. package/src/main/organisms/notification.js +87 -0
  138. package/src/main/organisms/order-tracker.js +203 -0
  139. package/src/main/organisms/page-header-banner.js +26 -0
  140. package/src/main/organisms/page-header.js +33 -0
  141. package/src/main/organisms/page-tags.js +14 -0
  142. package/src/main/organisms/page.js +260 -0
  143. package/src/main/organisms/press-release.js +24 -0
  144. package/src/main/organisms/product-admin.js +204 -0
  145. package/src/main/organisms/promo-banner.js +28 -0
  146. package/src/main/organisms/promo-bottom.js +23 -0
  147. package/src/main/organisms/promo-button.js +8 -0
  148. package/src/main/organisms/promo-card-cover.js +35 -0
  149. package/src/main/organisms/promo-card.js +33 -0
  150. package/src/main/organisms/promo-full.js +20 -0
  151. package/src/main/organisms/promo-image.js +22 -0
  152. package/src/main/organisms/promo-lure.js +22 -0
  153. package/src/main/organisms/promo-product-card.js +187 -0
  154. package/src/main/organisms/promo-product-full.js +293 -0
  155. package/src/main/organisms/promo-simple.js +23 -0
  156. package/src/main/organisms/quote.js +21 -0
  157. package/src/main/organisms/search-form.js +42 -0
  158. package/src/main/organisms/search-nav.js +66 -0
  159. package/src/main/organisms/search-result.js +53 -0
  160. package/src/main/organisms/slider.js +26 -0
  161. package/src/main/organisms/standalone-asset.js +22 -0
  162. package/src/main/organisms/tabs.js +277 -0
  163. package/src/main/organisms/topbar.js +83 -0
  164. package/src/main/organisms/web-component.js +53 -0
  165. package/src/main/routing/annotation.js +9 -0
  166. package/src/main/routing/component.js +138 -0
  167. package/src/main/routing/empty.js +5 -0
  168. package/src/main/routing/error-handler.js +64 -0
  169. package/src/main/routing/placeholder-image.svg +5 -0
  170. package/src/main/routing/router.js +219 -0
  171. package/src/main/shared/analytics.js +677 -0
  172. package/src/main/shared/bubble-event.js +11 -0
  173. package/src/main/shared/custom-element.js +21 -0
  174. package/src/main/shared/deep-selector.js +28 -0
  175. package/src/main/shared/disable-transparency.js +10 -0
  176. package/src/main/shared/format-time.js +8 -0
  177. package/src/main/shared/get-id.js +5 -0
  178. package/src/main/shared/get-meta.js +3 -0
  179. package/src/main/shared/get-size-class.js +3 -0
  180. package/src/main/shared/get-size.js +11 -0
  181. package/src/main/shared/h.js +88 -0
  182. package/src/main/shared/hash-jump.js +33 -0
  183. package/src/main/shared/icons/arrow-back.svg +1 -0
  184. package/src/main/shared/icons/arrow-down.svg +1 -0
  185. package/src/main/shared/icons/arrow-next.svg +1 -0
  186. package/src/main/shared/icons/arrow-tail-right.svg +1 -0
  187. package/src/main/shared/icons/arrow-tail-up.svg +1 -0
  188. package/src/main/shared/icons/arrow-up.svg +1 -0
  189. package/src/main/shared/icons/asset-download.svg +1 -0
  190. package/src/main/shared/icons/logo.svg +5 -0
  191. package/src/main/shared/icons/low-carbon-placeholder.svg +9 -0
  192. package/src/main/shared/icons/media-pause.svg +1 -0
  193. package/src/main/shared/icons/media-play.svg +1 -0
  194. package/src/main/shared/icons/navigation-burger.svg +1 -0
  195. package/src/main/shared/icons/navigation-close.svg +1 -0
  196. package/src/main/shared/icons/navigation-link.svg +1 -0
  197. package/src/main/shared/icons/navigation-refresh.svg +1 -0
  198. package/src/main/shared/icons/navigation-search.svg +1 -0
  199. package/src/main/shared/icons/navigation-share.svg +1 -0
  200. package/src/main/shared/icons/toggle-newwindow.svg +1 -0
  201. package/src/main/shared/icons.js +18 -0
  202. package/src/main/shared/id-from-string.js +5 -0
  203. package/src/main/shared/mark-selection.js +19 -0
  204. package/src/main/shared/register.js +26 -0
  205. package/src/main/shared/renderer.js +43 -0
  206. package/src/main/shared/simple-consent-api.js +70 -0
  207. package/src/main/shared/split-links.js +11 -0
  208. package/src/main/shared/t.js +60 -0
  209. package/src/main/shared/twind.js +837 -0
  210. package/src/main/shared/update-head.js +34 -0
  211. package/src/main/shared/update-scrollbar-width.js +30 -0
  212. package/src/main/shared/use-link.js +151 -0
  213. package/src/main/shared/use-persistent-state.js +42 -0
  214. package/src/main/shared/wait-for-dom-ready.js +6 -0
  215. package/src/main/shared/wcm-mode.js +4 -0
  216. package/src/wcs/components/acinguiux-preact-doc/acinguiux-preact-doc.js +207 -0
  217. package/src/wcs/components/admin-dashboard/admin-dashboard.js +487 -0
  218. package/src/wcs/components/admin-login/admin-login.js +91 -0
  219. package/src/wcs/components/bazaar-voice/bazaar-voice.js +56 -0
  220. package/src/wcs/components/chatbot-koreai/chatbot-koreai.js +176 -0
  221. package/src/wcs/components/chatbot-koreai/koreai-transport.js +217 -0
  222. package/src/wcs/components/chatbot-ms/chatbot-ms.js +210 -0
  223. package/src/wcs/components/chatbot-test/chatbot-test.js +44 -0
  224. package/src/wcs/components/comparison-chart/comparison-chart.js +111 -0
  225. package/src/wcs/components/consent-banner/consent-banner.js +248 -0
  226. package/src/wcs/components/consent-banner/icons/ccpa.svg +6 -0
  227. package/src/wcs/components/consent-banner/icons/info.svg +1 -0
  228. package/src/wcs/components/consent-banner/provider-onetrust.js +131 -0
  229. package/src/wcs/components/decision-tree/arrow-back.svg +3 -0
  230. package/src/wcs/components/decision-tree/badges.js +37 -0
  231. package/src/wcs/components/decision-tree/decision-tree.js +162 -0
  232. package/src/wcs/components/dynamic-contact-details/dynamic-contact-details.js +111 -0
  233. package/src/wcs/components/example-accordion/example-accordion.js +10 -0
  234. package/src/wcs/components/example-asset/example-asset.js +12 -0
  235. package/src/wcs/components/example-form/example-form.js +59 -0
  236. package/src/wcs/components/example-nested/example-nested.js +10 -0
  237. package/src/wcs/components/example-routing/example-routing.js +51 -0
  238. package/src/wcs/components/example-rtl/example-rtl.js +28 -0
  239. package/src/wcs/components/example-tabs/example-tabs.js +12 -0
  240. package/src/wcs/components/example-web-component/example-web-component.js +34 -0
  241. package/src/wcs/components/floating-button/floating-button.js +17 -0
  242. package/src/wcs/components/formstack-form/fields/address.js +38 -0
  243. package/src/wcs/components/formstack-form/fields/checkbox.js +42 -0
  244. package/src/wcs/components/formstack-form/fields/date.js +22 -0
  245. package/src/wcs/components/formstack-form/fields/description.js +8 -0
  246. package/src/wcs/components/formstack-form/fields/input.js +8 -0
  247. package/src/wcs/components/formstack-form/fields/name.js +39 -0
  248. package/src/wcs/components/formstack-form/fields/radio.js +24 -0
  249. package/src/wcs/components/formstack-form/fields/rating.js +53 -0
  250. package/src/wcs/components/formstack-form/fields/section.js +8 -0
  251. package/src/wcs/components/formstack-form/fields/select.js +10 -0
  252. package/src/wcs/components/formstack-form/fields/textarea.js +8 -0
  253. package/src/wcs/components/formstack-form/fields/wrapper.js +11 -0
  254. package/src/wcs/components/formstack-form/formstack-form.js +280 -0
  255. package/src/wcs/components/fuel-prices/fuel-prices.js +45 -0
  256. package/src/wcs/components/furniture-overview/furniture-overview.js +115 -0
  257. package/src/wcs/components/gauge-value/gauge-value.js +65 -0
  258. package/src/wcs/components/help-centre/api.js +150 -0
  259. package/src/wcs/components/help-centre/help-centre.js +400 -0
  260. package/src/wcs/components/help-centre/icon-search.svg +1 -0
  261. package/src/wcs/components/image-gen/admin-panel.js +248 -0
  262. package/src/wcs/components/image-gen/image-gen.js +385 -0
  263. package/src/wcs/components/image-gen/labels.js +37 -0
  264. package/src/wcs/components/image-gen/use-api.js +392 -0
  265. package/src/wcs/components/inspired-gallery/inspired-gallery.js +118 -0
  266. package/src/wcs/components/launch-container/launch-container.js +95 -0
  267. package/src/wcs/components/launch-container/ledger.js +140 -0
  268. package/src/wcs/components/lng-map/lng-map.js +44 -0
  269. package/src/wcs/components/mouseflow-analytics/mouseflow-analytics.js +39 -0
  270. package/src/wcs/components/msds-search/msds-search.js +127 -0
  271. package/src/wcs/components/msds-search/navigation-search.svg +3 -0
  272. package/src/wcs/components/product-catalogue/icon-back.svg +3 -0
  273. package/src/wcs/components/product-catalogue/icon-cart.svg +3 -0
  274. package/src/wcs/components/product-catalogue/icon-close.svg +3 -0
  275. package/src/wcs/components/product-catalogue/product-catalogue.js +215 -0
  276. package/src/wcs/components/product-links/icon-cart.svg +3 -0
  277. package/src/wcs/components/product-links/product-links.js +43 -0
  278. package/src/wcs/components/rio-iframe/rio-iframe.js +137 -0
  279. package/src/wcs/components/salsify-products/filter-tools.js +60 -0
  280. package/src/wcs/components/salsify-products/icon-cart.svg +3 -0
  281. package/src/wcs/components/salsify-products/process-products.js +53 -0
  282. package/src/wcs/components/salsify-products/route-tools.js +54 -0
  283. package/src/wcs/components/salsify-products/salsify-products.js +281 -0
  284. package/src/wcs/components/shout-out/shout-out.js +51 -0
  285. package/src/wcs/components/simple-chart/simple-chart.js +53 -0
  286. package/src/wcs/components/single-stat/single-stat.js +85 -0
  287. package/src/wcs/components/site-feedback/site-feedback.js +56 -0
  288. package/src/wcs/components/skds-search/navigation-search.svg +3 -0
  289. package/src/wcs/components/skds-search/skds-search.js +103 -0
  290. package/src/wcs/components/smart-banner/smart-banner.js +104 -0
  291. package/src/wcs/components/standalone-table/arrow-up-down.svg +3 -0
  292. package/src/wcs/components/standalone-table/arrow-up.svg +3 -0
  293. package/src/wcs/components/standalone-table/standalone-table.js +440 -0
  294. package/src/wcs/components/station-locator/station-locator.js +49 -0
  295. package/src/wcs/components/store-badges/badges.js +60 -0
  296. package/src/wcs/components/store-badges/store-badges.js +93 -0
  297. package/src/wcs/components/topbar-button/person.svg +1 -0
  298. package/src/wcs/components/topbar-button/topbar-button.js +22 -0
  299. package/src/wcs/components/universal-gallery/universal-gallery.js +308 -0
  300. package/src/wcs/components/zendesk-chat/zendesk-chat.js +133 -0
  301. package/src/wcs/shared/chat-bot/README.md +61 -0
  302. package/src/wcs/shared/chat-bot/chat-bot.js +216 -0
  303. package/src/wcs/shared/chat-bot/resources/arrow-next.svg +1 -0
  304. package/src/wcs/shared/chat-bot/resources/navigation-close.svg +1 -0
  305. package/src/wcs/shared/chat-bot/resources/person.svg +1 -0
  306. package/src/wcs/shared/chat-bot/resources/upload.svg +1 -0
  307. package/src/wcs/shared/filtered-data/README.md +52 -0
  308. package/src/wcs/shared/filtered-data/fetch-data.js +33 -0
  309. package/src/wcs/shared/filtered-data/filtered-data.js +337 -0
  310. package/src/wcs/shared/promo-with-popup/icon-close.svg +3 -0
  311. package/src/wcs/shared/promo-with-popup/icon-next.svg +3 -0
  312. package/src/wcs/shared/promo-with-popup/icon-prev.svg +3 -0
  313. package/src/wcs/shared/promo-with-popup/promo-with-popup.js +93 -0
@@ -0,0 +1,44 @@
1
+ import h from '#acinguiux-preact/main/shared/h.js'
2
+
3
+ const COLUMNS = 12
4
+
5
+ function getTabletColspan (desktopColspan) {
6
+ // Preserve full width on table only if desktop width is 10 columns or more.
7
+ return desktopColspan < 10 ? 1 : 2
8
+ }
9
+
10
+ function getMobileColspan (colspan, mobileCols) {
11
+ if (!mobileCols) return 1
12
+ return 1
13
+ }
14
+
15
+ export function Grid ({ _tag, _wrap, _parentColspan = COLUMNS, _mobileCols, _list, _gap, children, ...props }) {
16
+ const wrappedChildren = []
17
+ for (const [ii, child] of children.entries()) {
18
+ const wrap = _wrap?.[ii] ?? {}
19
+ const colstart = Math.min(_parentColspan, wrap.colstart ?? 0)
20
+ const colspan = Math.min(_parentColspan, wrap.colspan ?? COLUMNS)
21
+
22
+ let colstartClass = colstart ? `lg:col-start-${colstart}` : ''
23
+ if (colstart === 1) {
24
+ colstartClass += ' md:col-start-1'
25
+ }
26
+
27
+ const mobileColSpan = getMobileColspan(colspan, _mobileCols)
28
+
29
+ wrappedChildren.push(h('div', {
30
+ className: `lg:col-span-${colspan ?? COLUMNS} md:col-span-${getTabletColspan(colspan)} sm:col-span-${mobileColSpan} ${colstartClass}`,
31
+ ..._list && { role: 'listitem' },
32
+ children: child
33
+ }))
34
+ }
35
+
36
+ const mobileGridCols = _mobileCols || 1
37
+ const gapClass = _gap ? (_mobileCols ? 'sm:gap-2 lg:gap-5' : 'gap-5') : ''
38
+ return h(_tag || 'div', {
39
+ ..._list && { role: 'list' },
40
+ ...props,
41
+ children: wrappedChildren,
42
+ className: `grid lg:grid-cols-${_parentColspan} md:grid-cols-${getTabletColspan(_parentColspan)} sm:grid-cols-${mobileGridCols} ${gapClass}`
43
+ })
44
+ }
@@ -0,0 +1,13 @@
1
+ import h from '#acinguiux-preact/main/shared/h.js'
2
+ import { Grid } from './grid.js'
3
+
4
+ export function Header (props) {
5
+ return h('div', {
6
+ ...props,
7
+ className: 'text-txa bg-bga',
8
+ children: h(Grid, {
9
+ ...props,
10
+ _tag: 'header'
11
+ })
12
+ })
13
+ }
@@ -0,0 +1,7 @@
1
+ import h from '#acinguiux-preact/main/shared/h.js'
2
+ import { Grid } from './grid.js'
3
+
4
+ // Add list markup.
5
+ export function List (props) {
6
+ return h(Grid, { ...props, _color: undefined, _gap: true, _list: true })
7
+ }
@@ -0,0 +1,6 @@
1
+ import h from '#acinguiux-preact/main/shared/h.js'
2
+ import { Grid } from './grid.js'
3
+
4
+ export function Main (props) {
5
+ return h(Grid, { ...props, _tag: 'main', id: 'main' })
6
+ }
@@ -0,0 +1,7 @@
1
+ import h from '#acinguiux-preact/main/shared/h.js'
2
+ import { Grid } from './grid.js'
3
+
4
+ // Raw grid without gap.
5
+ export function Raw (props) {
6
+ return h(Grid, { ...props, _color: undefined })
7
+ }
@@ -0,0 +1,28 @@
1
+ import { Asset } from '#acinguiux-preact/main/molecules/asset.js'
2
+ import { PromoText } from '#acinguiux-preact/main/molecules/promo-text.js'
3
+ import h from '#acinguiux-preact/main/shared/h.js'
4
+ import { Grid } from './grid.js'
5
+
6
+ export function Section (props) {
7
+ const { _model } = props
8
+
9
+ return h('div', {
10
+ ...props,
11
+ className: 'text-txa bg-bga grid grid-cols-1',
12
+ // The first section should not have a top padding. That's where the Breadcrumb sits.
13
+ _style: id => `
14
+ :first-child > ${id} > div {
15
+ padding-top: 0;
16
+ }
17
+ `,
18
+ children: [
19
+ _model?.image?.src && h('div', { className: 'row-start-1 col-start-1 col-span-12' },
20
+ h(Asset, { _model, _tall: true, role: 'presentation' })
21
+ ),
22
+ h('div', { className: 'relative max-w-page m-auto w-full row-start-1 col-start-1 px-3 py-12 space-y-5' },
23
+ h(PromoText, { _model, _level: 2, _align: 'center' }),
24
+ h(Grid, { ...props, _tag: 'section', _gap: true })
25
+ )
26
+ ]
27
+ })
28
+ }
@@ -0,0 +1,29 @@
1
+ import h from '../shared/h.js'
2
+ import { ABTest } from './container/ab-test.js'
3
+ import { Default } from './container/default.js'
4
+ import { FilteredSection, SearchableSection } from './container/filtered-section.js'
5
+ import { Footer } from './container/footer.js'
6
+ import { Header } from './container/header.js'
7
+ import { List } from './container/list.js'
8
+ import { Main } from './container/main.js'
9
+ import { Raw } from './container/raw.js'
10
+ import { Section } from './container/section.js'
11
+
12
+ export function Container ({ _variant, _wrap, ...props }) {
13
+ const variants = {
14
+ // Framework
15
+ header: Header,
16
+ footer: Footer,
17
+ main: Main,
18
+ section: Section,
19
+ filtered: FilteredSection,
20
+ searchable: SearchableSection,
21
+
22
+ // Content
23
+ raw: Raw,
24
+ list: List,
25
+ abtest: ABTest
26
+ }
27
+
28
+ return h(variants[_variant] || Default, { ...props, _wrap })
29
+ }
@@ -0,0 +1,15 @@
1
+ import h from '../shared/h.js'
2
+ import { isPublish } from '../shared/wcm-mode.js'
3
+
4
+ export function ContentOwner ({ _model, ...props }) {
5
+ const { title } = _model
6
+
7
+ if (isPublish) {
8
+ return null
9
+ }
10
+
11
+ return h('div', { ...props, className: 'pal-system-solid bg-bga text-txa px-6 py-4 text-sm' },
12
+ h('span', { className: 'font-bold' }, 'Owner: '),
13
+ title
14
+ )
15
+ }
@@ -0,0 +1,56 @@
1
+ import { Box } from '../atoms/box.js'
2
+ import { Time } from '../atoms/time.js'
3
+ import { PromoText } from '../molecules/promo-text.js'
4
+ import { ValidationError } from '../routing/error-handler.js'
5
+ import h from '../shared/h.js'
6
+
7
+ export function DateEntry ({ _model, _variant, ...props }) {
8
+ const { date, title } = _model
9
+ if (!date || !title) {
10
+ throw new ValidationError()
11
+ }
12
+
13
+ return h('div', { ...props, className: 'bg-bga text-txa border-txa/20 flex rounded-2xl' },
14
+ h(Box, {
15
+ className: 'relative grow-0 shrink-0 w-36 p-6',
16
+ children: h(Time, { _time: date }),
17
+ _style: id => {
18
+ const styles = []
19
+ // Vertical linke
20
+ styles.push(`
21
+ ${id}::before {
22
+ content: '';
23
+ box-sizing: border-box;
24
+ position: absolute;
25
+ width: 1px;
26
+ height: calc(100% + 20px); /* Extend by the gap size. */
27
+ border-right: 1px dashed hsl(var(--color-txa));
28
+ top: 0px;
29
+ right: 0px;
30
+ }`)
31
+
32
+ // Timeline dot.
33
+ _variant === 'timeline' && styles.push(`
34
+ ${id}::after {
35
+ content: '';
36
+ box-sizing: border-box;
37
+ position: absolute;
38
+ width: 17px;
39
+ height: 17px;
40
+ border: 3px solid hsl(var(--color-bga));
41
+ background-color: hsl(var(--color-txa));
42
+ box-shadow: 0 0 0 1px hsl(var(--color-txa));
43
+ border-radius: 100%;
44
+ top: 27px;
45
+ right: -8px;
46
+ }`)
47
+
48
+ return styles.join('')
49
+ }
50
+ }),
51
+ h('div', {
52
+ className: 'grow',
53
+ children: h(PromoText, { _model: { ..._model, date: null } })
54
+ })
55
+ )
56
+ }
@@ -0,0 +1,73 @@
1
+ import { useState } from 'preact/hooks'
2
+ import { Box } from '../atoms/box.js'
3
+ import { Button } from '../atoms/button.js'
4
+ import { Heading } from '../atoms/heading.js'
5
+ import { Input } from '../atoms/input.js'
6
+ import { RichText } from '../atoms/rich-text.js'
7
+ import { Asset } from '../molecules/asset.js'
8
+ import disableTransparency from '../shared/disable-transparency.js'
9
+ import h from '../shared/h.js'
10
+ import { NAVIGATION_SEARCH } from '../shared/icons.js'
11
+ import t from '../shared/t.js'
12
+ import { ValidationError } from '../routing/error-handler.js'
13
+
14
+ export function ExternalSearch ({ _model, _color, ...props }) {
15
+ const { image, links, title, text } = _model
16
+ if (!text || !title || links.length === 0) {
17
+ throw new ValidationError()
18
+ }
19
+
20
+ const [value, setValue] = useState('')
21
+ const firstLink = links[0]
22
+ const hasAsset = image.src
23
+
24
+ const inputProps = {
25
+ type: 'search',
26
+ placeholder: firstLink.name,
27
+ title: t('Enter your search term'),
28
+ onInput: event => setValue(event.target.value),
29
+ value
30
+ }
31
+
32
+ const buttonProps = {
33
+ _textless: true,
34
+ _model: {
35
+ name: t('Submit'),
36
+ icon: NAVIGATION_SEARCH
37
+ },
38
+ type: 'submit',
39
+ onClick: event => {
40
+ event.preventDefault()
41
+ const url = firstLink.value + encodeURIComponent(value)
42
+ globalThis.location.href = url
43
+ }
44
+ }
45
+
46
+ const form = h('form', {
47
+ action: firstLink.value,
48
+ className: `lg:rounded-xl bg-bga text-txa ${disableTransparency(_color)}`,
49
+ children: h(Box,
50
+ h(Heading, { _level: 3 }, title),
51
+ h(RichText, text),
52
+ h('div', { className: 'flex space-x-5' },
53
+ h('div', { className: 'grow' },
54
+ h(Input, inputProps)
55
+ ),
56
+ h('div', { className: 'shrink' },
57
+ h(Button, buttonProps)
58
+ )
59
+ )
60
+ )
61
+ })
62
+
63
+ if (!hasAsset) {
64
+ return h('div', { ...props, className: 'rounded-2xl overflow-hidden w-full' }, form)
65
+ }
66
+
67
+ return h('div', { ...props, className: 'relative overflow-hidden rounded-2xl' },
68
+ h(Asset, { _model, role: 'presentation' }),
69
+ h('div', { className: 'lg:absolute lg:top-6 lg:start-0 lg:end-0 lg:grid lg:grid-cols-12 gap-x-5' },
70
+ h('div', { className: 'lg:col-start-2 lg:col-span-10' }, form)
71
+ )
72
+ )
73
+ }
@@ -0,0 +1,163 @@
1
+ import { useState } from 'preact/hooks'
2
+ import { Button } from '../atoms/button.js'
3
+ import { Card } from '../atoms/card.js'
4
+ import { Heading } from '../atoms/heading.js'
5
+ import { Popup } from '../atoms/popup.js'
6
+ import { RichText } from '../atoms/rich-text.js'
7
+ import { Time } from '../atoms/time.js'
8
+ import { Asset } from '../molecules/asset.js'
9
+ import { Links } from '../molecules/links.js'
10
+ import { PromoText } from '../molecules/promo-text.js'
11
+ import { ValidationError } from '../routing/error-handler.js'
12
+ import h from '../shared/h.js'
13
+ import { NAVIGATION_CLOSE } from '../shared/icons.js'
14
+ import t from '../shared/t.js'
15
+ import { Fragment } from 'preact'
16
+
17
+ export function FilteredItem ({ _model, _variant, ...props }) {
18
+ if (!_model.title) {
19
+ throw new ValidationError()
20
+ }
21
+
22
+ const Component = { tags: WithTags, popup: WithPopup, links: WithLinks }[_variant] || Default
23
+ return Component({ _model, ...props })
24
+ }
25
+
26
+ function Default ({ _model, ...props }) {
27
+ return h('div', { ...props, className: 'h-full' },
28
+ h(CardWrapper, { _model },
29
+ h(BasicContent, { _model: { ..._model, links: [], tags: [] } },
30
+ h(Labels, { _model })
31
+ )
32
+ )
33
+ )
34
+ }
35
+
36
+ function WithTags ({ _model, ...props }) {
37
+ const tags = _model.tags.map(tag => ({ name: tag.value }))
38
+ return h('div', { ...props, className: 'h-full' },
39
+ h(CardWrapper, { _model },
40
+ h(BasicContent, { _model: { ..._model, links: [], tags } })
41
+ )
42
+ )
43
+ }
44
+
45
+ function WithLinks ({ _model, ...props }) {
46
+ return h('div', { ...props, className: 'h-full' },
47
+ h(StaticCard, { _model },
48
+ h(BasicContent, { _model: { ..._model, tags: [] } },
49
+ h(Labels, { _model })
50
+ )
51
+ )
52
+ )
53
+ }
54
+
55
+ function WithPopup ({ _model, ...props }) {
56
+ const [showPopup, setShowPopup] = useState(false)
57
+
58
+ return h('div', { ...props, className: 'h-full' },
59
+ h(Card, {
60
+ _model: { value: '#' },
61
+ role: 'button',
62
+ onClick (event) {
63
+ setShowPopup(true)
64
+ event.preventDefault()
65
+ },
66
+ children: h(BasicContent, { _model: { ..._model, text: null, links: [], tags: [] } },
67
+ h(Labels, { _model })
68
+ )
69
+ }),
70
+ h(Popup, {
71
+ _color: props._color,
72
+ _layout: 'toast',
73
+ _show: showPopup,
74
+ onKeyDown (event) {
75
+ if (event.key === 'Escape') {
76
+ setShowPopup(false)
77
+ event.preventDefault()
78
+ }
79
+ },
80
+ children: h('div', { className: 'grid gap-5 grid-cols-2 sm:grid-cols-1' },
81
+ _model.asset?.src && h('div', { className: 'space-y-5 sm:hidden' },
82
+ h('div', { className: 'rounded-xl overflow-hidden' },
83
+ h(Asset, { _model })
84
+ ),
85
+ h('div',
86
+ h(Labels, { _model })
87
+ )
88
+ ),
89
+ h('div', { className: 'space-y-5' },
90
+ h('div', { className: 'flex gap-2' },
91
+ h('div', { className: 'grow' },
92
+ h(Heading, { _level: 3 }, _model.title),
93
+ _model.date && h(Time, { _time: _model.date })
94
+ ),
95
+ h('div', { className: 'shrink-0' },
96
+ h(Button, {
97
+ _variant: 'plain',
98
+ _textless: true,
99
+ _size: 'xs',
100
+ _model: {
101
+ icon: NAVIGATION_CLOSE,
102
+ name: t('Close')
103
+ },
104
+ onClick: () => setShowPopup(false)
105
+ })
106
+ )
107
+ ),
108
+ _model.asset?.src && h('div', { className: 'rounded-xl overflow-hidden lg:hidden md:hidden' },
109
+ h(Asset, { _model })
110
+ ),
111
+ h(RichText, _model.text),
112
+ h(Links, { _model })
113
+ )
114
+ )
115
+ })
116
+ )
117
+ }
118
+
119
+ function BasicContent ({ _model, children }) {
120
+ return h('div', { className: 'flex flex-col h-full' },
121
+ Boolean(_model.asset.src) && h(Asset, { _model }),
122
+ h(PromoText, { _model }),
123
+ children
124
+ )
125
+ }
126
+
127
+ function Labels ({ _model }) {
128
+ const { tags } = _model
129
+ if (!tags || tags.length === 0) {
130
+ return null
131
+ }
132
+
133
+ const labels = {}
134
+ for (const tag of tags) {
135
+ labels[tag.name] ||= []
136
+ labels[tag.name].push(tag.value)
137
+ }
138
+
139
+ const labelEntries = Object.entries(labels)
140
+
141
+ return h(Fragment,
142
+ h('div', { className: 'grow' }), // Pushes labels to the bottom.
143
+ h('div', { className: 'px-6 pb-6' },
144
+ h('hr', { className: 'mb-2 w-6 h-1 bg-bgb' }),
145
+ h('div', { className: 'space-y-1' }, labelEntries.map(([name, values]) =>
146
+ h('dl', { className: 'col-span-1 text-sm flex gap-2' },
147
+ h('dt', { className: 'font-bold basis-24 grow-0 shrink-0' }, `${name}`),
148
+ h('dd', values.join(', '))
149
+ )
150
+ ))
151
+ )
152
+ )
153
+ }
154
+
155
+ function StaticCard ({ _color, ...props }) {
156
+ return h('div', { ...props, _color, className: 'bg-bga text-txa h-full rounded-2xl overflow-hidden flex flex-col' })
157
+ }
158
+
159
+ function CardWrapper ({ _model, children }) {
160
+ const linkModel = { name: _model.title, value: _model.links[0]?.value }
161
+ const hasLink = Boolean(_model.links[0]?.value)
162
+ return h(hasLink ? Card : StaticCard, { _model: linkModel, children })
163
+ }
@@ -0,0 +1,17 @@
1
+ import { Box } from '../atoms/box.js'
2
+ import { Heading } from '../atoms/heading.js'
3
+ import { Links } from '../molecules/links.js'
4
+ import { ValidationError } from '../routing/error-handler.js'
5
+ import h from '../shared/h.js'
6
+
7
+ export function FooterItem ({ _model, ...props }) {
8
+ const { title, links } = _model
9
+ if (!title || links.length === 0) {
10
+ throw new ValidationError()
11
+ }
12
+
13
+ return h(Box, { ...props, className: 'text-sm' },
14
+ h(Heading, { _level: 2, _size: 3 }, title),
15
+ h(Links, { _model, _variant: 'simple' })
16
+ )
17
+ }
@@ -0,0 +1,164 @@
1
+ import { useEffect, useRef, useState } from 'preact/hooks'
2
+ import { Button } from '../atoms/button.js'
3
+ import { Popup } from '../atoms/popup.js'
4
+ import { Scroller } from '../atoms/scroller.js'
5
+ import { Asset } from '../molecules/asset.js'
6
+ import h from '../shared/h.js'
7
+ import { NAVIGATION_CLOSE } from '../shared/icons.js'
8
+ import t from '../shared/t.js'
9
+
10
+ // -----------------------------------------------------------------------------
11
+ // Main component
12
+ // -----------------------------------------------------------------------------
13
+
14
+ export function ImageGallery ({ _model, _color, children, ...props }) {
15
+ const [state, setState] = useState({
16
+ index: null,
17
+ showList: false,
18
+ title: _model.title,
19
+ color: _color
20
+ })
21
+
22
+ return h('div', { ...props, className: undefined },
23
+ h(GalleryOverview, { state, setState, children }),
24
+ h(GalleryList, { state, setState, children }),
25
+ h(GalleryDetails, { state, setState, children })
26
+ )
27
+ }
28
+
29
+ // -----------------------------------------------------------------------------
30
+ // Helpers
31
+ // -----------------------------------------------------------------------------
32
+
33
+ function GalleryPopup ({ show, title, children, onHide, popupRef }) {
34
+ return h(Popup, {
35
+ ref: popupRef,
36
+ _layout: 'full',
37
+ 'aria-label': title,
38
+ _show: show,
39
+ onKeyDown (event) {
40
+ if (event.key === 'Escape') {
41
+ event.preventDefault()
42
+ onHide()
43
+ }
44
+ },
45
+ children: h('div', { className: 'flex flex-col gap-5 h-full' },
46
+ h('div', {
47
+ className: 'flex justify-end',
48
+ children: h(Button, {
49
+ onClick: onHide,
50
+ _textless: true,
51
+ _model: {
52
+ name: t('Close'), icon: NAVIGATION_CLOSE
53
+ }
54
+ })
55
+ }),
56
+ h('div', { className: 'grow' }, children)
57
+ )
58
+ })
59
+ }
60
+
61
+ function ThumbnailContainer ({ onClick, className, children }) {
62
+ return h('div', {
63
+ className: `cursor-pointer clickable transition rounded-2xl overflow-hidden relative animate-fade ${className ?? ''}`,
64
+ _style: id => `${id}:hover { transform: scale(1.02); }`,
65
+ role: 'button',
66
+ tabindex: 0,
67
+ onClick,
68
+ onKeyDown (event) {
69
+ if (event.key === 'Enter') {
70
+ event.preventDefault()
71
+ onClick()
72
+ }
73
+ },
74
+ children
75
+ })
76
+ }
77
+
78
+ // -----------------------------------------------------------------------------
79
+ // Views
80
+ // -----------------------------------------------------------------------------
81
+
82
+ function GalleryOverview ({ state, setState, children }) {
83
+ const maxSlides = 5
84
+ const lastSlide = maxSlides - 1
85
+ const tiles = { sm: 1, md: 2, lg: 4 }
86
+
87
+ // Discard all children that have no image source.
88
+ const validChildren = children?.filter(child => child?.props?._model?.image?.src)
89
+
90
+ return validChildren.length > 0 && h('div', { role: 'list', className: 'grid gap-5 grid-cols-4 grid-rows-2' },
91
+ ...validChildren.slice(0, maxSlides).map((child, index) => {
92
+ const hasMore = index === lastSlide && validChildren.length > maxSlides
93
+ const span = index === 0 ? tiles.md : tiles.sm
94
+ const smallSpan = index === 0 ? tiles.lg : tiles.sm
95
+
96
+ const onClick = hasMore
97
+ ? () => setState({ ...state, showList: true, index: null })
98
+ : () => setState({ ...state, index })
99
+
100
+ return h('div', {
101
+ 'data-index': index,
102
+ role: 'listitem',
103
+ className: `lg:row-span-${span} lg:col-span-${span} md:row-span-${span} md:col-span-${span} sm:col-span-${smallSpan} cursor-pointer aspect-square`,
104
+ children: h(ThumbnailContainer, { onClick, className: 'aspect-square' },
105
+ h(Asset, { ...child.props, _tall: true }),
106
+ hasMore && h('div', {
107
+ className: 'absolute top-0 start-0 end-0 bottom-0 flex items-center justify-center pal-transparent text-txa',
108
+ children: h('div', { className: 'font-custom text-3xl' }, `+${validChildren.length - maxSlides}`)
109
+ })
110
+ )
111
+ })
112
+ })
113
+ )
114
+ }
115
+
116
+ function GalleryList ({ state, setState, children }) {
117
+ const ref = useRef(null)
118
+
119
+ // Bring back the focus when detail view closes.
120
+ useEffect(() => {
121
+ state.index === null && ref.current?.base?.focus?.()
122
+ }, [state.index])
123
+
124
+ return h(GalleryPopup, {
125
+ popupRef: ref,
126
+ show: state.showList,
127
+ title: state.title,
128
+ onHide: () => setState({ ...state, showList: false }),
129
+ children: h('div', {
130
+ className: 'lg:columns-4 md:columns-3 sm:columns-2 gap-x-5 space-y-5',
131
+ children: children.map((child, index) => [
132
+ h(ThumbnailContainer, {
133
+ role: 'listitem',
134
+ onClick: () => setState({ ...state, index }),
135
+ children: h(Asset, { ...child.props })
136
+ }),
137
+ h('div', { className: 'hidden' }) // Hack for last item hover flicker.
138
+ ])
139
+ })
140
+ })
141
+ }
142
+
143
+ function GalleryDetails ({ state, setState, children }) {
144
+ return h(GalleryPopup, {
145
+ show: state.index !== null,
146
+ title: state.title,
147
+ onHide: () => setState({ ...state, index: null }),
148
+ children: h('div', { className: 'h-full' },
149
+ h(Scroller, { _tall: true, _count: [1, 1, 1], _index: state.index }, children.map((child, index) =>
150
+ h('figure', { className: 'flex flex-col gap-5 outline-none', tabindex: 0 },
151
+ h('picture', { className: 'grow relative h-full' },
152
+ h('span', { className: 'absolute start-0 end-0 top-0 bottom-0' },
153
+ h(Asset, { _model: child.props._model, _tall: true, _fit: 'contain' })
154
+ )
155
+ ),
156
+ h('figcaption', { className: 'shrink flex gap-x-5' },
157
+ h('span', { className: 'font-bold whitespace-nowrap' }, `${index + 1} / ${children.length}`),
158
+ h('span', { className: '' }, child.props._model.image?.caption)
159
+ )
160
+ )
161
+ ))
162
+ )
163
+ })
164
+ }
@@ -0,0 +1,20 @@
1
+ import { PromoText } from '../molecules/promo-text.js'
2
+ import h from '../shared/h.js'
3
+
4
+ export function LastModified ({ _model, ...props }) {
5
+ const { title } = _model
6
+ const locale = document.documentElement.lang || navigator.language
7
+ const dateModified = document.head.querySelector('meta[itemprop="dateModified"]')?.getAttribute('content')
8
+
9
+ if (dateModified) {
10
+ const formattedDate = new Date(dateModified).toLocaleDateString(locale, {
11
+ year: 'numeric',
12
+ month: 'short',
13
+ day: 'numeric'
14
+ })
15
+
16
+ return h(PromoText, { _model: { text: title ? `${title} ${formattedDate}` : formattedDate }, ...props })
17
+ } else {
18
+ return null
19
+ }
20
+ }
@@ -0,0 +1,16 @@
1
+ import { Link } from '../atoms/link.js'
2
+ import { ValidationError } from '../routing/error-handler.js'
3
+ import h from '../shared/h.js'
4
+
5
+ export function LegalFooter ({ _model, ...props }) {
6
+ const { links } = _model
7
+ if (links.length === 0) {
8
+ throw new ValidationError()
9
+ }
10
+
11
+ return h('div', { ...props, className: 'p-6 text-sm flex flex-wrap gap-5', role: 'list' }, links.map(link =>
12
+ h('div', { role: 'listitem', className: 'flex items-center' },
13
+ h(Link, { _variant: 'simple', _model: link, className: 'text-sm' })
14
+ )
15
+ ))
16
+ }