@iqual/nuxt-icms 1.6.1 → 1.6.2-rc.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 (260) hide show
  1. package/README.md +86 -0
  2. package/__tests__/anchors.spec.ts +43 -0
  3. package/__tests__/contract/blokkliComponents.spec.ts +59 -0
  4. package/__tests__/contract/componentFragments.spec.ts +24 -0
  5. package/__tests__/contract/languages.spec.ts +63 -0
  6. package/__tests__/contract/project.ts +144 -0
  7. package/__tests__/hreflang.spec.ts +39 -0
  8. package/{tests → __tests__}/pages.spec.ts +14 -5
  9. package/app.config.ts +15 -0
  10. package/app.vue +3 -21
  11. package/assets/css/backend.css +56 -0
  12. package/assets/css/base/base.css +2 -2
  13. package/assets/css/base/typography.css +2 -2
  14. package/assets/css/ckeditor.css +3 -4
  15. package/assets/css/components/decorations.css +1 -1
  16. package/assets/css/components/editor.css +1 -1
  17. package/assets/css/components/grid-container.css +19 -19
  18. package/assets/css/fe-fixes.css +6 -12
  19. package/assets/css/theme/colors/color-primary.css +33 -11
  20. package/assets/css/theme/colors/color-secondary.css +33 -11
  21. package/assets/css/utilities/utilities.css +1 -1
  22. package/assets/symbols/anchor.svg +3 -0
  23. package/blokkli.editAdapter.ts +56 -0
  24. package/bundles.ts +6 -6
  25. package/cache/__tests__/pageCache.spec.ts +540 -0
  26. package/cache/cacheTagRegistry.ts +124 -0
  27. package/cache/enabledForRequest.ts +21 -0
  28. package/cache/multiCache.serverOptions.ts +58 -0
  29. package/cache/pageCache.ts +360 -0
  30. package/components/Blokkli/Anchor/icon.svg +3 -0
  31. package/components/Blokkli/Anchor/index.vue +13 -0
  32. package/components/Blokkli/AnchorNavigation/icon.svg +8 -0
  33. package/components/Blokkli/AnchorNavigation/index.vue +9 -0
  34. package/components/Blokkli/Card/Element/index.vue +0 -1
  35. package/components/Blokkli/Collapsible/Element/index.vue +5 -0
  36. package/components/Blokkli/FAQ/Element/index.vue +0 -1
  37. package/components/Blokkli/Fragment/Separator/icon.svg +4 -0
  38. package/components/Blokkli/Fragment/Separator/index.vue +87 -0
  39. package/components/Blokkli/Gallery/index.vue +1 -3
  40. package/components/Blokkli/IconText/Element/index.vue +0 -1
  41. package/components/Blokkli/Introduction/index.vue +0 -1
  42. package/components/Blokkli/Listing/icon.svg +9 -0
  43. package/components/Blokkli/Listing/index.vue +24 -0
  44. package/components/Blokkli/Logo/Element/index.vue +0 -1
  45. package/components/Blokkli/Table/index.vue +0 -1
  46. package/components/Blokkli/Team/Element/index.vue +0 -1
  47. package/components/Blokkli/Team/Layout/index.vue +0 -1
  48. package/components/Blokkli/Testimonial/Element/index.vue +0 -1
  49. package/components/Blokkli/Text/index.vue +0 -1
  50. package/components/DesignSystem/Atoms/Button.vue +3 -0
  51. package/components/DesignSystem/Atoms/GridRow.vue +3 -1
  52. package/components/DesignSystem/Molecules/ButtonGroup.vue +5 -4
  53. package/components/DesignSystem/Molecules/IconText.vue +6 -6
  54. package/components/DesignSystem/Molecules/MediaLightbox.vue +8 -8
  55. package/components/DesignSystem/Molecules/MediaSlider.vue +9 -11
  56. package/components/DesignSystem/Molecules/Partnership.vue +7 -4
  57. package/components/DesignSystem/Molecules/Table.vue +35 -19
  58. package/components/DesignSystem/Molecules/TitleComposition.vue +46 -15
  59. package/components/DesignSystem/Molecules/iFrame.vue +2 -2
  60. package/components/DesignSystem/Organisms/CallToAction.vue +8 -7
  61. package/components/DesignSystem/Organisms/CallToActionFeature.vue +8 -7
  62. package/components/DesignSystem/Organisms/CallToActionFullwidth.vue +9 -8
  63. package/components/DesignSystem/Organisms/ContentBlock.vue +26 -16
  64. package/components/DesignSystem/Organisms/FacetedListing.vue +38 -17
  65. package/components/DesignSystem/Organisms/FactCard.vue +6 -7
  66. package/components/DesignSystem/Organisms/FeatureCard.vue +14 -14
  67. package/components/DesignSystem/Organisms/FlipTeaser.vue +19 -19
  68. package/components/DesignSystem/Organisms/HeaderHero.vue +11 -11
  69. package/components/DesignSystem/Organisms/HeaderTextImage.vue +10 -10
  70. package/components/DesignSystem/Organisms/LinkList.vue +20 -12
  71. package/components/DesignSystem/Organisms/LogoElement.vue +7 -4
  72. package/components/DesignSystem/Organisms/Map.vue +1 -1
  73. package/components/DesignSystem/Organisms/SearchResults.vue +15 -6
  74. package/components/DesignSystem/Organisms/SpotlightCard.vue +18 -18
  75. package/components/DesignSystem/Organisms/TeamElement.vue +19 -18
  76. package/components/DesignSystem/Organisms/TeaserCard.vue +16 -17
  77. package/components/DesignSystem/Organisms/TeaserSimple.vue +4 -31
  78. package/components/DesignSystem/Organisms/Testimonial.vue +13 -13
  79. package/components/DesignSystem/Organisms/TextCard.vue +10 -10
  80. package/components/DesignSystem/Organisms/TimelineElement.vue +20 -19
  81. package/components/DesignSystem/Organisms/TwoColumnTextElement.vue +5 -5
  82. package/components/DesignSystem/README.md +59 -40
  83. package/components/Drupal/Breadcrumb/index.vue +25 -12
  84. package/components/Drupal/Messages/index.vue +9 -4
  85. package/components/Drupal/Webform/index.vue +271 -51
  86. package/components/Drupal/Webform/mutation.graphql +17 -1
  87. package/components/Form/HiddenInput.vue +1 -4
  88. package/components/Form/SelectInput.vue +1 -1
  89. package/components/Form/SubmitButton.vue +2 -2
  90. package/components/Form/TextAreaInput.vue +3 -3
  91. package/components/Form/TextEmailInput.vue +1 -1
  92. package/components/Form/TextInput.vue +1 -1
  93. package/components/Form/TextPhoneInput.vue +1 -1
  94. package/components/Form/WebformMarkup.vue +1 -1
  95. package/components/Form/composables/useFormDefaultValue.ts +9 -13
  96. package/components/Form/composables/useFormElement.ts +5 -3
  97. package/components/Form/utils/types.ts +3 -3
  98. package/components/Media/Image/fragment.graphql +4 -0
  99. package/components/Media/Image/index.vue +27 -17
  100. package/components/Media/RemoteVideo/index.vue +3 -3
  101. package/components/Media/Video/index.vue +1 -1
  102. package/components/Node/Icms/Page/SearchResult/fragment.graphql +1 -1
  103. package/components/Node/Icms/Page/SearchResult/index.vue +2 -2
  104. package/components/Node/Icms/Page/Teaser/index.vue +1 -1
  105. package/components/Node/Icms/Page/index.vue +8 -2
  106. package/components/Paragraph/Anchor/fragment.graphql +4 -0
  107. package/components/Paragraph/Anchor/index.vue +48 -0
  108. package/components/Paragraph/AnchorNavigation/fragment.graphql +3 -0
  109. package/components/Paragraph/AnchorNavigation/index.vue +154 -0
  110. package/components/Paragraph/BlokkliFragment/fragment.graphql +5 -0
  111. package/components/Paragraph/Button/Element/fragment.graphql +1 -1
  112. package/components/Paragraph/Button/Element/index.vue +13 -8
  113. package/components/Paragraph/Card/Element/index.vue +1 -1
  114. package/components/Paragraph/Card/Layout/index.vue +9 -9
  115. package/components/Paragraph/Collapsible/Element/index.vue +2 -2
  116. package/components/Paragraph/Collapsible/Layout/index.vue +19 -18
  117. package/components/Paragraph/Contact/index.vue +17 -17
  118. package/components/Paragraph/Downloads/fragment.graphql +1 -1
  119. package/components/Paragraph/Downloads/index.vue +13 -13
  120. package/components/Paragraph/FAQ/Element/index.vue +4 -3
  121. package/components/Paragraph/FAQ/Layout/index.vue +42 -21
  122. package/components/Paragraph/FromLibrary/fragment.graphql +17 -0
  123. package/components/Paragraph/Gallery/index.vue +14 -14
  124. package/components/Paragraph/HeroImage/index.vue +26 -19
  125. package/components/Paragraph/IconText/Element/index.vue +4 -4
  126. package/components/Paragraph/IconText/Layout/index.vue +12 -12
  127. package/components/Paragraph/Introduction/index.vue +17 -17
  128. package/components/Paragraph/LinkLists/Element/fragment.graphql +1 -1
  129. package/components/Paragraph/LinkLists/Element/index.vue +5 -5
  130. package/components/Paragraph/LinkLists/Layout/index.vue +9 -9
  131. package/components/Paragraph/Listing/fragment.graphql +14 -0
  132. package/components/Paragraph/Listing/index.vue +91 -0
  133. package/components/Paragraph/Logo/Element/fragment.graphql +1 -1
  134. package/components/Paragraph/Logo/Element/index.vue +7 -4
  135. package/components/Paragraph/Media/index.vue +23 -21
  136. package/components/Paragraph/Partnerships/Element/fragment.graphql +1 -1
  137. package/components/Paragraph/Partnerships/Element/index.vue +10 -7
  138. package/components/Paragraph/Partnerships/Layout/index.vue +13 -13
  139. package/components/Paragraph/SingleTestimonial/index.vue +13 -13
  140. package/components/Paragraph/Table/index.vue +12 -12
  141. package/components/Paragraph/Team/Element/index.vue +16 -14
  142. package/components/Paragraph/Team/Layout/index.vue +9 -9
  143. package/components/Paragraph/Teasers/index.vue +14 -17
  144. package/components/Paragraph/Testimonial/Element/index.vue +19 -18
  145. package/components/Paragraph/Testimonial/Layout/index.vue +24 -18
  146. package/components/Paragraph/Text/fragment.graphql +1 -1
  147. package/components/Paragraph/Text/index.vue +8 -8
  148. package/components/Paragraph/TextMedia/index.vue +22 -22
  149. package/components/Paragraph/Timeline/Element/index.vue +19 -19
  150. package/components/Paragraph/Timeline/Layout/index.vue +51 -20
  151. package/components/Paragraph/TwoColumnText/Element/index.vue +13 -13
  152. package/components/Paragraph/TwoColumnText/Layout/index.vue +1 -1
  153. package/components/Paragraph/iFrame/index.vue +8 -8
  154. package/components/Search/Facets/FacetDropdownUI.vue +25 -31
  155. package/components/Search/Facets/FacetedSearchUI.vue +72 -48
  156. package/components/Search/Facets/fragment.graphql +20 -15
  157. package/components/Section/Footer/index.vue +55 -32
  158. package/components/Section/Header/Buttons.vue +4 -5
  159. package/components/Section/Header/DesktopMainMenu.vue +5 -4
  160. package/components/Section/Header/DesktopMainMenuDropdown.vue +5 -5
  161. package/components/Section/Header/LanguageDropdown.vue +2 -3
  162. package/components/Section/Header/Logo.vue +3 -3
  163. package/components/Section/Header/MainButtons.vue +4 -5
  164. package/components/Section/Header/MetaButtons.vue +5 -6
  165. package/components/Section/Header/MetaMenu.vue +1 -1
  166. package/components/Section/Header/MobileMainMenu.vue +1 -1
  167. package/components/Section/Header/MobileMainMenuItem.vue +2 -2
  168. package/components/Section/Header/index.vue +6 -13
  169. package/composables/__tests__/useImageSources.spec.ts +91 -0
  170. package/composables/breadcrumb.ts +12 -7
  171. package/composables/useAccordionScroll.ts +12 -4
  172. package/composables/useAllowedFragments.ts +14 -0
  173. package/composables/useAnchors.ts +48 -0
  174. package/composables/useChildTitleWeight.ts +1 -1
  175. package/composables/useCurrentLangcodeEnum.ts +1 -1
  176. package/composables/useCurrentNodeId.ts +8 -0
  177. package/composables/useDrupalUrl.ts +15 -0
  178. package/composables/useEnrichFacetLabels.ts +8 -6
  179. package/composables/useEntityRegistry.ts +3 -3
  180. package/composables/useGlobalConfig.ts +1 -2
  181. package/composables/useGraphqlCacheability.ts +12 -1
  182. package/composables/useHreflangLinks.ts +54 -0
  183. package/composables/useImageSources.ts +70 -28
  184. package/composables/useInitData.ts +1 -2
  185. package/composables/useIsHomepage.ts +1 -1
  186. package/composables/useLinkUrl.ts +30 -0
  187. package/composables/useMediaLightbox.ts +62 -50
  188. package/composables/useMenu.ts +1 -3
  189. package/composables/useMessageBus.ts +14 -7
  190. package/composables/useMobileMenuOverlayBus.ts +1 -1
  191. package/composables/useNavigationOffset.ts +49 -6
  192. package/composables/usePageCache.ts +33 -0
  193. package/composables/useSiteShell.ts +11 -0
  194. package/composables/useTheme.ts +17 -13
  195. package/config/__tests__/stubs/nuxt-multi-cache-config.ts +2 -0
  196. package/config/blokkli.ts +7 -13
  197. package/config/easyTexts.ts +1 -1
  198. package/config/graphqlMiddleware.ts +11 -4
  199. package/config/index.ts +5 -2
  200. package/config/languageNegotiation.ts +1 -1
  201. package/config/multiCache.ts +6 -1
  202. package/config/postcss-drupal/postcss.config.cjs +2 -2
  203. package/config/runtimeConfig.ts +7 -2
  204. package/config/svgIconSprite.ts +1 -2
  205. package/config/vuepal.ts +16 -18
  206. package/error.vue +1 -22
  207. package/layouts/default.vue +2 -6
  208. package/layouts/error.vue +7 -15
  209. package/modules/blokkliFragments.ts +76 -0
  210. package/modules/dynamicEntityComponentResolver.ts +47 -47
  211. package/modules/dynamicParagraphResolver.ts +43 -8
  212. package/modules/pageCache.ts +106 -0
  213. package/nuxt.config.ts +62 -33
  214. package/package.json +20 -19
  215. package/pages/[...slug]/index.vue +25 -4
  216. package/pages/index.vue +3 -3
  217. package/pages/node/[nid]/index.vue +2 -3
  218. package/patches/@blokkli+editor+2.0.0-alpha.13.patch +15 -1
  219. package/plugins/currentNode.ts +17 -0
  220. package/plugins/graphqlMiddleware.ts +10 -2
  221. package/plugins/initData.ts +15 -7
  222. package/plugins/registerNodeIcmsPageComponents.ts +6 -2
  223. package/plugins/siteShell.client.ts +94 -0
  224. package/queries/facetTermLabels.graphql +1 -5
  225. package/queries/fragment.linkUrl.graphql +12 -0
  226. package/queries/query.contentSearch.graphql +17 -2
  227. package/queries/query.initData.graphql +1 -1
  228. package/scripts/create-shade.ts +13 -4
  229. package/scripts/update-icms.ts +3 -1
  230. package/server/__tests__/graphqlMiddleware.serverOptions.spec.ts +2 -2
  231. package/server/__tests__/turnstile.spec.ts +119 -0
  232. package/server/api/icms/blokkli/last-changed.get.ts +24 -0
  233. package/server/api/icon/[...params].ts +3 -9
  234. package/server/graphqlMiddleware.serverOptions.ts +9 -8
  235. package/server/helpers/index.ts +0 -1
  236. package/server/middleware/turnstile.ts +51 -0
  237. package/server/plugins/frameAncestors.ts +20 -0
  238. package/server/plugins/pageCache.ts +59 -0
  239. package/server/utils/__tests__/accessDeniedHandover.spec.ts +49 -0
  240. package/server/utils/__tests__/backendRequestHeaders.spec.ts +115 -0
  241. package/server/utils/accessDeniedHandover.ts +48 -0
  242. package/server/utils/backendRequestHeaders.ts +51 -0
  243. package/server/utils/cacheability.ts +4 -4
  244. package/shared/__tests__/blokkliState.spec.ts +54 -0
  245. package/shared/__tests__/csp.spec.ts +53 -0
  246. package/shared/__tests__/drupalUrl.spec.ts +50 -0
  247. package/shared/blokkliState.ts +40 -0
  248. package/shared/csp.ts +47 -0
  249. package/shared/drupalUrl.ts +30 -0
  250. package/tailwind.config.ts +0 -5
  251. package/types/breadcrumb.ts +22 -0
  252. package/types/global.ts +15 -14
  253. package/types/langcode.ts +16 -0
  254. package/types/layerConfig.ts +84 -0
  255. package/utils/pageCache.ts +95 -0
  256. package/utils/turnstile.ts +35 -0
  257. package/composables/useWebformEnrichment.ts +0 -68
  258. package/server/__tests__/graphqlMiddleware.ts +0 -41
  259. package/server/multiCache.serverOptions.ts +0 -32
  260. package/vitest.config.mts +0 -28
@@ -30,12 +30,12 @@
30
30
  >
31
31
  <DesignSystemOrganismsContentBlock
32
32
  :pretitle="pretitle"
33
- :pretitleClass="themedClass('pretitleClass')"
33
+ :pretitle-class="themedClass('pretitleClass')"
34
34
  :title="title"
35
- :titleClass="themedClass('titleClass', 'mb-0')"
36
- :titleWeight="titleWeight"
37
- :titleStyle="titleStyle"
38
- :colorScheme="colorScheme"
35
+ :title-class="themedClass('titleClass', 'mb-0')"
36
+ :title-weight="titleWeight"
37
+ :title-style="titleStyle"
38
+ :color-scheme="colorScheme"
39
39
  />
40
40
  </div>
41
41
  <div
@@ -51,8 +51,8 @@
51
51
  >
52
52
  <DesignSystemOrganismsContentBlock
53
53
  :text="text"
54
- :textClass="themedClass('textClass')"
55
- :colorScheme="colorScheme"
54
+ :text-class="themedClass('textClass')"
55
+ :color-scheme="colorScheme"
56
56
  />
57
57
  </div>
58
58
  </DesignSystemAtomsGridRow>
@@ -79,12 +79,12 @@
79
79
  :load-more-text="$texts('listing.load_more', 'Load more')"
80
80
  :color-scheme="colorScheme"
81
81
  :debug="false"
82
- :alignHorizontalFull="alignHorizontalFull"
83
- @results-updated="onResultsUpdated"
82
+ :align-horizontal-full="alignHorizontalFull"
84
83
  :conjunction="conjunction"
84
+ @results-updated="onResultsUpdated"
85
85
  >
86
86
  <template #results="{ results }">
87
- <slot name="preResults" :results="results"></slot>
87
+ <slot name="preResults" :results="results" />
88
88
  <div
89
89
  v-if="!slider"
90
90
  :class="
@@ -95,19 +95,19 @@
95
95
  "
96
96
  >
97
97
  <component
98
- v-for="teaser in results?.results"
99
98
  :is="teaserComponent(teaser?.bundle)"
99
+ v-for="(teaser, teaserIndex) in results?.results"
100
+ :key="`${teaser?.bundle}-${teaserIndex}`"
100
101
  v-bind="teaser"
101
102
  />
102
103
  </div>
103
104
  <div v-else class="relative mt-10">
104
105
  <UCarousel
105
- v-model="carouselIndex"
106
106
  :items="results?.results || []"
107
107
  :arrows="(results?.results?.length || 0) > sliderColumns"
108
108
  :watch-drag="(results?.results?.length || 0) > sliderColumns"
109
- nextIcon="i-lucide-chevron-right"
110
- prevIcon="i-lucide-chevron-left"
109
+ next-icon="i-lucide-chevron-right"
110
+ prev-icon="i-lucide-chevron-left"
111
111
  :ui="{
112
112
  viewport: themedClass('carouselViewport'),
113
113
  item: sliderItemClass,
@@ -166,6 +166,15 @@ const props = withDefaults(
166
166
  prefilter?: Record<string, Array<{ id?: string; name?: string } | null>>
167
167
  availableFacets?: string[]
168
168
  contentTypeFilter?: string[]
169
+ /**
170
+ * Whether to exclude the node the listing sits on from its own results.
171
+ *
172
+ * Only meaningful for indexes whose datasource is nodes: the condition
173
+ * filters on `nid`, and search_api rejects a query naming a field the
174
+ * index does not have. Listings over another entity type — the event
175
+ * bundle indexes occurrence paragraphs — must switch it off.
176
+ */
177
+ excludeCurrentNode?: boolean
169
178
  additionalFilters?: Array<{ field: string; value: any; operator?: string }>
170
179
  containerClass?: string
171
180
  firstRowClass?: string
@@ -187,8 +196,11 @@ const props = withDefaults(
187
196
  }>(),
188
197
  {
189
198
  availableFacets: () => ['topics'],
199
+ excludeCurrentNode: true,
190
200
  index: 'content_search',
191
201
  debug: false,
202
+ prefilter: () => ({}),
203
+ sliderColumns: 1,
192
204
  },
193
205
  )
194
206
 
@@ -199,7 +211,7 @@ const { $texts } = useNuxtApp()
199
211
  const hasResults = ref(true)
200
212
 
201
213
  // Handle results updates from SearchFacetsFacetedSearchUI
202
- const onResultsUpdated = (hasResultsValue: boolean, count: number) => {
214
+ const onResultsUpdated = (hasResultsValue: boolean, _count: number) => {
203
215
  hasResults.value = hasResultsValue
204
216
  }
205
217
 
@@ -230,6 +242,8 @@ const listingType = computed(() => {
230
242
  return 'all' // default fallback
231
243
  })
232
244
 
245
+ const currentNodeId = useCurrentNodeId()
246
+
233
247
  // Configuration for the faceted search
234
248
  const baseFilter = computed(() => {
235
249
  const conditions: any[] = []
@@ -239,6 +253,15 @@ const baseFilter = computed(() => {
239
253
  conditions.push({ field: 'type', value: props?.contentTypeFilter })
240
254
  }
241
255
 
256
+ // Exclude the node the listing is placed on from its own results
257
+ if (props.excludeCurrentNode && currentNodeId.value) {
258
+ conditions.push({
259
+ field: 'nid',
260
+ value: [currentNodeId.value],
261
+ operator: 'NOT_EQUAL',
262
+ })
263
+ }
264
+
242
265
  // Add custom field conditions
243
266
  if (props?.additionalFilters && props.additionalFilters.length > 0) {
244
267
  conditions.push(...props.additionalFilters)
@@ -273,8 +296,6 @@ const teaserComponent = (bundle?: string) => {
273
296
  return null
274
297
  }
275
298
 
276
- const carouselIndex = ref(0)
277
-
278
299
  const viewport = useViewport()
279
300
 
280
301
  const sliderItemClass = computed(() => {
@@ -3,13 +3,13 @@
3
3
  <div :class="card({ colorScheme })">
4
4
  <slot name="content">
5
5
  <DesignSystemOrganismsContentBlock
6
- :containerClass="'flex h-full flex-col justify-between'"
6
+ :container-class="'flex h-full flex-col justify-between'"
7
7
  :title="title"
8
- :titleWeight="titleWeight"
9
- :titleStyle="'heading-2'"
10
- :titleClass="themedClass('titleClass', 'mb-6 font-bold')"
8
+ :title-weight="titleWeight"
9
+ :title-style="'heading-2'"
10
+ :title-class="themedClass('titleClass', 'mb-6 font-bold')"
11
11
  :text="text"
12
- :textClass="
12
+ :text-class="
13
13
  themedClass(
14
14
  'textClass',
15
15
  'text-sm mt-auto [&>p:last-of-type]:mb-0 opacity-60',
@@ -17,14 +17,13 @@
17
17
  "
18
18
  />
19
19
  </slot>
20
- <slot name="links"></slot>
20
+ <slot name="links" />
21
21
  </div>
22
22
  </div>
23
23
  </template>
24
24
 
25
25
  <script lang="ts" setup>
26
26
  import type { ColorScheme } from '@iqual/nuxt-icms/types/global'
27
- import type { MediaFragment } from '#graphql-operations'
28
27
  import { tv } from 'tailwind-variants'
29
28
 
30
29
  const themedClass = useTheme('DesignSystemOrganismsFactCard')
@@ -11,11 +11,11 @@
11
11
  <Media
12
12
  v-if="image"
13
13
  :media="image"
14
- imageAspectRatios="16/9"
15
- imageSizes="xs:100vw sm:100vw md:50vw lg:50vw"
16
- :mediaClass="themedClass('mediaClass')"
17
- :figcaptionClass="themedClass('figcaptionClass')"
18
- :elementClass="themedClass('elementClass')"
14
+ image-aspect-ratios="16/9"
15
+ image-sizes="xs:100vw sm:100vw md:50vw lg:50vw"
16
+ :media-class="themedClass('mediaClass')"
17
+ :figcaption-class="themedClass('figcaptionClass')"
18
+ :element-class="themedClass('elementClass')"
19
19
  />
20
20
  <div v-if="icon" :class="cardIconWrapper({ colorScheme })">
21
21
  <Media :media="icon" />
@@ -38,23 +38,23 @@
38
38
  <slot name="content">
39
39
  <DesignSystemOrganismsContentBlock
40
40
  :pretitle="pretitle"
41
- :pretitleClass="
41
+ :pretitle-class="
42
42
  themedClass(
43
43
  'pretitleClass',
44
44
  'text-center @xl:text-left [&>p:last-of-type]:mb-0 text-base lg:text-base font-medium',
45
45
  )
46
46
  "
47
47
  :title="title"
48
- :titleWeight="titleWeight"
49
- :titleStyle="'heading-5'"
50
- :titleClass="
48
+ :title-weight="titleWeight"
49
+ :title-style="'heading-5'"
50
+ :title-class="
51
51
  themedClass(
52
52
  'titleClass',
53
53
  'mb-2 text-center @xl:text-left font-semibold',
54
54
  )
55
55
  "
56
56
  :text="text"
57
- :textClass="
57
+ :text-class="
58
58
  themedClass(
59
59
  'textClass',
60
60
  'text-center @xl:text-left [&>p:last-of-type]:mb-0',
@@ -78,10 +78,10 @@
78
78
  :title="$texts('teaser_card.link_label', 'Read more')"
79
79
  :link="link?.path"
80
80
  :target-blank="false"
81
- :buttonStyle="'focus'"
82
- :colorScheme="colorScheme"
83
- :buttonClass="themedClass('buttonClass')"
84
- :labelClass="themedClass('labelClass')"
81
+ :button-style="'focus'"
82
+ :color-scheme="colorScheme"
83
+ :button-class="themedClass('buttonClass')"
84
+ :label-class="themedClass('labelClass')"
85
85
  />
86
86
  </div>
87
87
  </slot>
@@ -10,11 +10,11 @@
10
10
  <Media
11
11
  v-if="image"
12
12
  :media="image"
13
- imageSizes="xs:100vw sm:100vw md:50vw lg:320px"
14
- imageAspectRatios="1/1"
15
- :mediaClass="themedClass('mediaClass', 'w-full')"
16
- :figcaptionClass="themedClass('figcaptionClass')"
17
- :elementClass="themedClass('elementClass')"
13
+ image-sizes="xs:100vw sm:100vw md:50vw lg:320px"
14
+ image-aspect-ratios="1/1"
15
+ :media-class="themedClass('mediaClass', 'w-full')"
16
+ :figcaption-class="themedClass('figcaptionClass')"
17
+ :element-class="themedClass('elementClass')"
18
18
  />
19
19
  <!-- Opaque Overlay -->
20
20
  <div :class="opaqueOverlay({ colorScheme })" />
@@ -33,7 +33,7 @@
33
33
  <div v-if="icon" :class="cardIconWrapper({ colorScheme })">
34
34
  <Media
35
35
  :media="icon"
36
- :mediaClass="
36
+ :media-class="
37
37
  themedClass(
38
38
  'iconMediaClass',
39
39
  'w-full h-full object-scale-down object-center',
@@ -42,11 +42,11 @@
42
42
  />
43
43
  </div>
44
44
  <DesignSystemOrganismsContentBlock
45
- containerClass="mt-auto"
45
+ container-class="mt-auto"
46
46
  :title="title"
47
- :titleWeight="titleWeight"
48
- :titleStyle="'heading-5'"
49
- :titleClass="themedClass('titleClass', 'font-semibold mb-0')"
47
+ :title-weight="titleWeight"
48
+ :title-style="'heading-5'"
49
+ :title-class="themedClass('titleClass', 'font-semibold mb-0')"
50
50
  />
51
51
  </div>
52
52
 
@@ -65,30 +65,30 @@
65
65
  <div>
66
66
  <DesignSystemOrganismsContentBlock
67
67
  :pretitle="pretitle"
68
- :pretitleClass="
68
+ :pretitle-class="
69
69
  themedClass(
70
70
  'overlayPretitleClass',
71
71
  'text-gray-300 font-medium text-base lg:text-base mb-2',
72
72
  )
73
73
  "
74
74
  :title="title"
75
- :titleStyle="'heading-5'"
76
- :titleWeight="titleWeight"
77
- :titleClass="themedClass('overlayTitleClass', 'mb-2')"
75
+ :title-style="'heading-5'"
76
+ :title-weight="titleWeight"
77
+ :title-class="themedClass('overlayTitleClass', 'mb-2')"
78
78
  :subtitle="subtitle"
79
- :subtitleClass="themedClass('overlaySubtitleClass')"
79
+ :subtitle-class="themedClass('overlaySubtitleClass')"
80
80
  :text="text"
81
- :textClass="
81
+ :text-class="
82
82
  themedClass(
83
83
  'overlayTextClass',
84
84
  'text-sm line-clamp-3 [&>p:last-of-type]:mb-0',
85
85
  )
86
86
  "
87
- :colorScheme="colorScheme"
87
+ :color-scheme="colorScheme"
88
88
  />
89
89
  </div>
90
90
 
91
- <slot name="links"></slot>
91
+ <slot name="links" />
92
92
  </div>
93
93
  </slot>
94
94
 
@@ -113,7 +113,7 @@ import cn from '@iqual/nuxt-icms/composables/useCn'
113
113
 
114
114
  const themedClass = useTheme('DesignSystemOrganismsFlipTeaser')
115
115
 
116
- const props = defineProps<{
116
+ defineProps<{
117
117
  image?: MediaFragment
118
118
  icon?: MediaFragment
119
119
  pretitle?: string
@@ -13,13 +13,13 @@
13
13
  <Media
14
14
  v-if="image"
15
15
  :media="image"
16
- imageSizes="xs:100vw sm:100vw md:100vw lg:100vw"
17
- imageAspectRatios="xs:1/1 sm:1/1 md:16/9 lg:16/9"
18
- :mediaClass="
16
+ image-sizes="xs:100vw sm:100vw md:100vw lg:100vw"
17
+ image-aspect-ratios="xs:1/1 sm:1/1 md:16/9 lg:16/9"
18
+ :media-class="
19
19
  themedClass('mediaClass', 'header-grid-item max-h-[1080px] h-full')
20
20
  "
21
- :figcaptionClass="themedClass('figcaptionClass')"
22
- :elementClass="
21
+ :figcaption-class="themedClass('figcaptionClass')"
22
+ :element-class="
23
23
  themedClass('elementClass', 'size-full object-cover object-center')
24
24
  "
25
25
  />
@@ -33,7 +33,7 @@
33
33
  'header-grid-item z-10 w-full self-stretch bg-black opacity-50',
34
34
  )
35
35
  "
36
- ></div>
36
+ />
37
37
 
38
38
  <!-- Content row -->
39
39
  <DesignSystemAtomsGridRow
@@ -42,11 +42,11 @@
42
42
  <div :class="themedClass('columnClass', 'col-span-12')">
43
43
  <DesignSystemOrganismsContentBlock
44
44
  :pretitle="pretitle"
45
- :pretitleClass="themedClass('pretitleClass')"
45
+ :pretitle-class="themedClass('pretitleClass')"
46
46
  :title="title"
47
- :titleClass="themedClass('titleClass', 'mb-0')"
48
- titleWeight="h1"
49
- colorScheme="dark"
47
+ :title-class="themedClass('titleClass', 'mb-0')"
48
+ title-weight="h1"
49
+ color-scheme="dark"
50
50
  />
51
51
 
52
52
  <slot name="subtitle">
@@ -109,7 +109,7 @@
109
109
  </template>
110
110
 
111
111
  <script lang="ts" setup>
112
- import { type MediaFragment } from '#graphql-operations'
112
+ import type { MediaFragment } from '#graphql-operations'
113
113
 
114
114
  defineProps<{
115
115
  title?: string
@@ -12,13 +12,13 @@
12
12
  <slot name="content">
13
13
  <DesignSystemOrganismsContentBlock
14
14
  :title="title"
15
- titleWeight="p"
16
- :titleClass="themedClass('titleClass', 'text-h1 mb-4')"
15
+ title-weight="p"
16
+ :title-class="themedClass('titleClass', 'text-h1 mb-4')"
17
17
  :text="description"
18
- :textClass="themedClass('textClass', 'text-h6')"
18
+ :text-class="themedClass('textClass', 'text-h6')"
19
19
  />
20
20
  </slot>
21
- <slot name="extra"></slot>
21
+ <slot name="extra" />
22
22
  </div>
23
23
 
24
24
  <div
@@ -32,11 +32,11 @@
32
32
  <Media
33
33
  v-if="image"
34
34
  :media="image"
35
- imageSizes="xs:100vw sm:100vw md:800px lg:800px"
36
- :mediaClass="themedClass('mediaClass')"
37
- :figcaptionClass="themedClass('figcaptionClass')"
38
- :elementClass="themedClass('elementClass', 'rounded-lg')"
39
- imageAspectRatios="4/3"
35
+ image-sizes="xs:100vw sm:100vw md:800px lg:800px"
36
+ :media-class="themedClass('mediaClass')"
37
+ :figcaption-class="themedClass('figcaptionClass')"
38
+ :element-class="themedClass('elementClass', 'rounded-lg')"
39
+ image-aspect-ratios="4/3"
40
40
  />
41
41
  </div>
42
42
  </DesignSystemAtomsGridRow>
@@ -44,7 +44,7 @@
44
44
  </template>
45
45
 
46
46
  <script lang="ts" setup>
47
- import { type MediaFragment } from '#graphql-operations'
47
+ import type { MediaFragment } from '#graphql-operations'
48
48
 
49
49
  defineProps<{
50
50
  title?: string
@@ -2,19 +2,21 @@
2
2
  <div :class="linkList({ colorScheme, teaserStyle })">
3
3
  <DesignSystemOrganismsContentBlock
4
4
  :title="title"
5
- :titleWeight="titleWeight"
6
- :titleStyle="'heading-5'"
7
- :titleClass="themedClass('titleClass', 'mb-0 font-semibold')"
5
+ :title-weight="titleWeight"
6
+ :title-style="'heading-5'"
7
+ :title-class="themedClass('titleClass', 'mb-0 font-semibold')"
8
8
  />
9
9
 
10
10
  <ul :class="themedClass('listClass', 'flex flex-col gap-2')">
11
11
  <li
12
- v-for="link in links"
13
- :key="link?.uri?.path + '-' + link?.title"
12
+ v-for="link in resolvedLinks"
13
+ :key="link.url + '-' + link.title"
14
14
  :class="themedClass('listItemClass')"
15
15
  >
16
16
  <NuxtLink
17
- :to="link?.uri?.path"
17
+ :to="link.url"
18
+ :external="link.isFile"
19
+ :target="link.isFile ? '_blank' : undefined"
18
20
  :class="linkLabel({ colorScheme, teaserStyle })"
19
21
  >
20
22
  <div :class="bulletPointContainer({ colorScheme, teaserStyle })">
@@ -29,9 +31,9 @@
29
31
  </ul>
30
32
 
31
33
  <DesignSystemOrganismsContentBlock
32
- containerClass="mt-auto"
34
+ container-class="mt-auto"
33
35
  :text="text"
34
- :textClass="
36
+ :text-class="
35
37
  themedClass(
36
38
  'textClass',
37
39
  'mt-6 text-xs [&>p:last-of-type]:mb-0 opacity-75',
@@ -43,24 +45,30 @@
43
45
 
44
46
  <script lang="ts" setup>
45
47
  import type { ColorScheme, TeaserStyle } from '@iqual/nuxt-icms/types/global'
48
+ import type { LinkFieldUri } from '@iqual/nuxt-icms/composables/useLinkUrl'
46
49
  import { tv } from 'tailwind-variants'
47
50
 
48
51
  const themedClass = useTheme('DesignSystemOrganismsLinkList')
49
52
 
50
- defineProps<{
53
+ const props = defineProps<{
51
54
  title?: string
52
55
  titleWeight?: string
53
56
  text?: string
54
57
  links?: ({
55
58
  title?: string
56
- uri?: {
57
- path?: string
58
- }
59
+ uri?: LinkFieldUri
59
60
  } | null)[]
60
61
  colorScheme?: ColorScheme
61
62
  teaserStyle?: TeaserStyle
62
63
  }>()
63
64
 
65
+ const resolvedLinks = computed(() =>
66
+ (props.links ?? []).map((link) => ({
67
+ title: link?.title,
68
+ ...resolveLinkUrl(link?.uri),
69
+ })),
70
+ )
71
+
64
72
  const linkList = tv({
65
73
  base: themedClass('linkListBase', 'flex flex-col gap-8 p-8'),
66
74
  variants: {
@@ -2,16 +2,17 @@
2
2
  <NuxtLink
3
3
  :to="link"
4
4
  :title="title"
5
+ :external="external"
5
6
  :target="targetBlank ? '_blank' : '_self'"
6
7
  :class="logoElement({ colorScheme })"
7
8
  >
8
9
  <Media
9
10
  v-if="logo"
10
11
  :media="logo"
11
- imageSizes="xs:200px"
12
- :mediaClass="themedClass('mediaClass', 'w-full h-full')"
13
- :figcaptionClass="themedClass('figcaptionClass')"
14
- :elementClass="
12
+ image-sizes="xs:200px"
13
+ :media-class="themedClass('mediaClass', 'w-full h-full')"
14
+ :figcaption-class="themedClass('figcaptionClass')"
15
+ :element-class="
15
16
  themedClass('elementClass', 'w-full h-full object-scale-down')
16
17
  "
17
18
  />
@@ -29,6 +30,8 @@ defineProps<{
29
30
  logo?: MediaFragment
30
31
  link?: string
31
32
  title?: string
33
+ /** Force a native browser navigation (bypasses the Vue router), e.g. for file downloads. */
34
+ external?: boolean
32
35
  targetBlank?: boolean
33
36
  colorScheme?: ColorScheme
34
37
  mediaClass?: string
@@ -24,7 +24,7 @@
24
24
  >
25
25
  <mgl-popup>
26
26
  <h6>{{ location.label }}</h6>
27
- <div v-html="location.description"></div>
27
+ <div v-html="location.description" />
28
28
  </mgl-popup>
29
29
  </mgl-marker>
30
30
  </MglMap>
@@ -13,22 +13,31 @@
13
13
  </span>
14
14
  </p>
15
15
  <component
16
- v-for="teaser in results?.results"
17
16
  :is="teaserComponent(teaser?.bundle!)"
17
+ v-for="(teaser, index) in results?.results"
18
+ :key="`${teaser?.bundle}-${index}`"
18
19
  v-bind="teaser"
19
20
  />
20
21
  </div>
21
22
  </template>
22
23
 
23
24
  <script setup lang="ts">
24
- import type { ContentSearchQuery } from '#graphql-operations'
25
+ import type { LayoutOverviewResultsSearchQuery } from '#graphql-operations'
25
26
 
26
- type GroupedSearchResults = NonNullable<
27
- NonNullable<ContentSearchQuery['searchApiQuery']>['facets']
28
- >[number]
27
+ /**
28
+ * One display group as passed by FacetedSearchUI: either a facet group, which
29
+ * adds a label and a count, or the ungrouped result list.
30
+ */
31
+ type SearchResultGroup = {
32
+ label?: string
33
+ count?: number
34
+ results: NonNullable<
35
+ LayoutOverviewResultsSearchQuery['searchApiQuery']
36
+ >['results']
37
+ }
29
38
 
30
39
  defineProps<{
31
- results: GroupedSearchResults
40
+ results: SearchResultGroup
32
41
  }>()
33
42
 
34
43
  const themedClass = useTheme('DesignSystemOrganismsSearchResults')
@@ -11,15 +11,15 @@
11
11
  <Media
12
12
  v-if="image"
13
13
  :media="image"
14
- imageAspectRatios="3/4"
15
- imageSizes="xs:100vw sm:100vw md:50vw lg:33vw"
16
- :mediaClass="themedClass('mediaClass')"
17
- :figcaptionClass="themedClass('figcaptionClass')"
18
- :elementClass="themedClass('elementClass')"
14
+ image-aspect-ratios="3/4"
15
+ image-sizes="xs:100vw sm:100vw md:50vw lg:33vw"
16
+ :media-class="themedClass('mediaClass')"
17
+ :figcaption-class="themedClass('figcaptionClass')"
18
+ :element-class="themedClass('elementClass')"
19
19
  />
20
20
  </div>
21
21
 
22
- <div v-if="image" :class="overlay({ colorScheme })"></div>
22
+ <div v-if="image" :class="overlay({ colorScheme })" />
23
23
 
24
24
  <div
25
25
  :class="
@@ -32,7 +32,7 @@
32
32
  <div v-if="icon" :class="cardIconWrapper({ colorScheme })">
33
33
  <Media
34
34
  :media="icon"
35
- :mediaClass="
35
+ :media-class="
36
36
  themedClass(
37
37
  'iconMediaClass',
38
38
  'w-full h-full object-scale-down object-center',
@@ -44,21 +44,21 @@
44
44
  <DesignSystemOrganismsContentBlock
45
45
  class="mt-auto"
46
46
  :pretitle="pretitle"
47
- :pretitleClass="
47
+ :pretitle-class="
48
48
  themedClass(
49
49
  'pretitleClass',
50
50
  '[&>p:last-of-type]:mb-0 text-base lg:text-base font-medium',
51
51
  )
52
52
  "
53
53
  :title="title"
54
- :titleWeight="titleWeight"
55
- :titleStyle="'heading-5'"
56
- :titleClass="themedClass('titleClass', 'mb-2 font-semibold')"
54
+ :title-weight="titleWeight"
55
+ :title-style="'heading-5'"
56
+ :title-class="themedClass('titleClass', 'mb-2 font-semibold')"
57
57
  :text="text"
58
- :textClass="themedClass('textClass', '[&>p:last-of-type]:mb-0')"
58
+ :text-class="themedClass('textClass', '[&>p:last-of-type]:mb-0')"
59
59
  />
60
60
  </slot>
61
- <slot name="links"></slot>
61
+ <slot name="links" />
62
62
  </div>
63
63
  </div>
64
64
  </div>
@@ -71,7 +71,7 @@ import { tv } from 'tailwind-variants'
71
71
 
72
72
  const themedClass = useTheme('DesignSystemOrganismsSpotlightCard')
73
73
 
74
- const props = defineProps<{
74
+ defineProps<{
75
75
  pretitle?: string
76
76
  title?: string
77
77
  text?: string
@@ -140,19 +140,19 @@ const overlay = tv({
140
140
  colorScheme: {
141
141
  none: themedClass(
142
142
  'overlayVariantsColorSchemeNone',
143
- 'bg-gradient-to-t from-white/90 via-white/50 to-white/0',
143
+ 'bg-linear-to-t from-white/90 via-white/50 to-white/0',
144
144
  ),
145
145
  dark: themedClass(
146
146
  'overlayVariantsColorSchemeDark',
147
- 'bg-gradient-to-t from-black/90 via-black/50 to-black/0',
147
+ 'bg-linear-to-t from-black/90 via-black/50 to-black/0',
148
148
  ),
149
149
  light: themedClass(
150
150
  'overlayVariantsColorSchemeLight',
151
- 'bg-gradient-to-t from-white/90 via-white/50 to-white/0',
151
+ 'bg-linear-to-t from-white/90 via-white/50 to-white/0',
152
152
  ),
153
153
  accent: themedClass(
154
154
  'overlayVariantsColorSchemeAccent',
155
- 'bg-gradient-to-t from-black/90 via-black/50 to-black/0',
155
+ 'bg-linear-to-t from-black/90 via-black/50 to-black/0',
156
156
  ),
157
157
  },
158
158
  },