@iqual/nuxt-icms 1.0.14 → 1.2.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 (427) hide show
  1. package/assets/css/ckeditor.css +4 -0
  2. package/assets/css/components/container.css +2 -2
  3. package/assets/css/tailwind.css +1 -1
  4. package/assets/css/typography.css +4 -0
  5. package/assets/symbols/download.svg +3 -0
  6. package/bundles.ts +4 -1
  7. package/components/Blokkli/TextMedia/index.vue +1 -2
  8. package/components/Blokkli/Timeline/Element/icms_timeline_element.svg +7 -0
  9. package/components/Blokkli/Timeline/Element/icon.svg +7 -0
  10. package/components/Blokkli/Timeline/Element/index.vue +14 -0
  11. package/components/Blokkli/Timeline/Layout/icms_layout_timeline.svg +16 -0
  12. package/components/Blokkli/Timeline/Layout/icon.svg +16 -0
  13. package/components/Blokkli/Timeline/Layout/index.vue +14 -0
  14. package/components/Blokkli/iFrame/icon-blokkli-option-large-spacing-bottom.svg +1 -0
  15. package/components/Blokkli/iFrame/icon-blokkli-option-large-spacing-top.svg +1 -0
  16. package/components/Blokkli/iFrame/icon-blokkli-option-no-spacing.svg +1 -0
  17. package/components/Blokkli/iFrame/icon-blokkli-option-small-spacing-bottom.svg +1 -0
  18. package/components/Blokkli/iFrame/icon-blokkli-option-small-spacing-top.svg +1 -0
  19. package/components/Blokkli/iFrame/{Layout/index.vue → index.vue} +2 -6
  20. package/components/DesignSystem/Atoms/Caption.vue +15 -0
  21. package/components/DesignSystem/Atoms/LinkListItem.vue +21 -0
  22. package/components/DesignSystem/Molecules/MediaSlider.vue +25 -8
  23. package/components/DesignSystem/Organisms/Map.vue +61 -0
  24. package/components/DesignSystem/Organisms/TimelineElement.vue +92 -0
  25. package/components/Media/Image/index.vue +4 -162
  26. package/components/Node/Icms/Page/SearchResult/fragment.graphql +8 -0
  27. package/components/Node/Icms/Page/SearchResult/index.vue +12 -0
  28. package/components/Node/Icms/Page/Teaser/fragment.graphql +17 -0
  29. package/components/Node/Icms/Page/Teaser/index.vue +20 -0
  30. package/components/Node/Icms/Page/fragment.graphql +18 -0
  31. package/components/Paragraph/CallToAction/index.vue +12 -8
  32. package/components/Paragraph/Card/Layout/index.vue +2 -2
  33. package/components/Paragraph/Downloads/index.vue +3 -14
  34. package/components/Paragraph/FAQ/Layout/index.vue +23 -1
  35. package/components/Paragraph/FlipTeasers/index.vue +2 -2
  36. package/components/Paragraph/Gallery/index.vue +32 -171
  37. package/components/Paragraph/HeroImage/index.vue +13 -4
  38. package/components/Paragraph/Media/index.vue +7 -2
  39. package/components/Paragraph/Table/index.vue +2 -2
  40. package/components/Paragraph/Team/Layout/index.vue +2 -2
  41. package/components/Paragraph/Teasers/fragment.graphql +2 -15
  42. package/components/Paragraph/Teasers/index.vue +11 -14
  43. package/components/Paragraph/TextMedia/index.vue +40 -33
  44. package/components/Paragraph/Timeline/Element/fragment.graphql +16 -0
  45. package/components/Paragraph/Timeline/Element/index.vue +31 -0
  46. package/components/Paragraph/Timeline/Layout/fragment.graphql +15 -0
  47. package/components/Paragraph/Timeline/Layout/index.vue +325 -0
  48. package/components/Paragraph/iFrame/{Layout/fragment.graphql → fragment.graphql} +2 -6
  49. package/components/Paragraph/iFrame/index.vue +56 -0
  50. package/components/Search/Facets/FacetDropdownUI.vue +222 -0
  51. package/components/Search/Facets/FacetedSearchUI.vue +397 -0
  52. package/components/Search/Facets/fragment.graphql +40 -0
  53. package/components/Section/Header/LanguageDropdown.vue +60 -73
  54. package/components/Section/Header/LanguageSwitcher.vue +37 -0
  55. package/components/Section/Header/MetaMenu.vue +10 -1
  56. package/components/Section/Header/index.vue +80 -67
  57. package/components/ui/accordion/Accordion.vue +2 -2
  58. package/components/ui/accordion/AccordionContent.vue +5 -5
  59. package/components/ui/accordion/AccordionItem.vue +9 -10
  60. package/components/ui/accordion/AccordionTrigger.vue +5 -5
  61. package/components/ui/alert/Alert.vue +17 -0
  62. package/components/ui/alert/AlertDescription.vue +14 -0
  63. package/components/ui/alert/AlertTitle.vue +14 -0
  64. package/components/ui/alert/index.ts +24 -0
  65. package/components/ui/alert-dialog/AlertDialog.vue +15 -0
  66. package/components/ui/alert-dialog/AlertDialogAction.vue +22 -0
  67. package/components/ui/alert-dialog/AlertDialogCancel.vue +29 -0
  68. package/components/ui/alert-dialog/AlertDialogContent.vue +43 -0
  69. package/components/ui/alert-dialog/AlertDialogDescription.vue +27 -0
  70. package/components/ui/alert-dialog/AlertDialogFooter.vue +21 -0
  71. package/components/ui/alert-dialog/AlertDialogHeader.vue +16 -0
  72. package/components/ui/alert-dialog/AlertDialogTitle.vue +24 -0
  73. package/components/ui/alert-dialog/AlertDialogTrigger.vue +12 -0
  74. package/components/ui/alert-dialog/index.ts +9 -0
  75. package/components/ui/aspect-ratio/AspectRatio.vue +12 -0
  76. package/components/ui/aspect-ratio/index.ts +1 -0
  77. package/components/ui/auto-form/AutoForm.vue +106 -0
  78. package/components/ui/auto-form/AutoFormField.vue +45 -0
  79. package/components/ui/auto-form/AutoFormFieldArray.vue +110 -0
  80. package/components/ui/auto-form/AutoFormFieldBoolean.vue +41 -0
  81. package/components/ui/auto-form/AutoFormFieldDate.vue +57 -0
  82. package/components/ui/auto-form/AutoFormFieldEnum.vue +49 -0
  83. package/components/ui/auto-form/AutoFormFieldFile.vue +74 -0
  84. package/components/ui/auto-form/AutoFormFieldInput.vue +36 -0
  85. package/components/ui/auto-form/AutoFormFieldNumber.vue +32 -0
  86. package/components/ui/auto-form/AutoFormFieldObject.vue +78 -0
  87. package/components/ui/auto-form/AutoFormLabel.vue +14 -0
  88. package/components/ui/auto-form/constant.ts +40 -0
  89. package/components/ui/auto-form/dependencies.ts +93 -0
  90. package/components/ui/auto-form/index.ts +15 -0
  91. package/components/ui/auto-form/interface.ts +95 -0
  92. package/components/ui/auto-form/utils.ts +188 -0
  93. package/components/ui/avatar/Avatar.vue +22 -0
  94. package/components/ui/avatar/AvatarFallback.vue +12 -0
  95. package/components/ui/avatar/AvatarImage.vue +10 -0
  96. package/components/ui/avatar/index.ts +25 -0
  97. package/components/ui/badge/Badge.vue +17 -0
  98. package/components/ui/badge/index.ts +26 -0
  99. package/components/ui/breadcrumb/Breadcrumb.vue +13 -0
  100. package/components/ui/breadcrumb/BreadcrumbEllipsis.vue +22 -0
  101. package/components/ui/breadcrumb/BreadcrumbItem.vue +16 -0
  102. package/components/ui/breadcrumb/BreadcrumbLink.vue +20 -0
  103. package/components/ui/breadcrumb/BreadcrumbList.vue +16 -0
  104. package/components/ui/breadcrumb/BreadcrumbPage.vue +19 -0
  105. package/components/ui/breadcrumb/BreadcrumbSeparator.vue +21 -0
  106. package/components/ui/breadcrumb/index.ts +7 -0
  107. package/components/ui/button/Button.vue +4 -2
  108. package/components/ui/button/index.ts +9 -9
  109. package/components/ui/calendar/Calendar.vue +62 -0
  110. package/components/ui/calendar/CalendarCell.vue +26 -0
  111. package/components/ui/calendar/CalendarCellTrigger.vue +40 -0
  112. package/components/ui/calendar/CalendarGrid.vue +26 -0
  113. package/components/ui/calendar/CalendarGridBody.vue +12 -0
  114. package/components/ui/calendar/CalendarGridHead.vue +12 -0
  115. package/components/ui/calendar/CalendarGridRow.vue +23 -0
  116. package/components/ui/calendar/CalendarHeadCell.vue +23 -0
  117. package/components/ui/calendar/CalendarHeader.vue +23 -0
  118. package/components/ui/calendar/CalendarHeading.vue +33 -0
  119. package/components/ui/calendar/CalendarNextButton.vue +34 -0
  120. package/components/ui/calendar/CalendarPrevButton.vue +34 -0
  121. package/components/ui/calendar/index.ts +12 -0
  122. package/components/ui/card/Card.vue +21 -0
  123. package/components/ui/card/CardContent.vue +14 -0
  124. package/components/ui/card/CardDescription.vue +14 -0
  125. package/components/ui/card/CardFooter.vue +14 -0
  126. package/components/ui/card/CardHeader.vue +14 -0
  127. package/components/ui/card/CardTitle.vue +18 -0
  128. package/components/ui/card/index.ts +6 -0
  129. package/components/ui/carousel/Carousel.vue +3 -23
  130. package/components/ui/carousel/CarouselContent.vue +1 -2
  131. package/components/ui/carousel/CarouselItem.vue +5 -7
  132. package/components/ui/carousel/CarouselNext.vue +7 -9
  133. package/components/ui/carousel/CarouselPrevious.vue +7 -9
  134. package/components/ui/carousel/index.ts +3 -1
  135. package/components/ui/carousel/interface.ts +3 -1
  136. package/components/ui/carousel/useCarousel.ts +13 -23
  137. package/components/ui/chart/ChartCrosshair.vue +45 -0
  138. package/components/ui/chart/ChartLegend.vue +50 -0
  139. package/components/ui/chart/ChartSingleTooltip.vue +64 -0
  140. package/components/ui/chart/ChartTooltip.vue +40 -0
  141. package/components/ui/chart/index.ts +18 -0
  142. package/components/ui/chart/interface.ts +64 -0
  143. package/components/ui/chart-area/AreaChart.vue +141 -0
  144. package/components/ui/chart-area/index.ts +66 -0
  145. package/components/ui/chart-bar/BarChart.vue +116 -0
  146. package/components/ui/chart-bar/index.ts +66 -0
  147. package/components/ui/chart-donut/DonutChart.vue +101 -0
  148. package/components/ui/chart-donut/index.ts +39 -0
  149. package/components/ui/chart-line/LineChart.vue +107 -0
  150. package/components/ui/chart-line/index.ts +66 -0
  151. package/components/ui/checkbox/Checkbox.vue +1 -1
  152. package/components/ui/collapsible/Collapsible.vue +15 -0
  153. package/components/ui/collapsible/CollapsibleContent.vue +12 -0
  154. package/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
  155. package/components/ui/collapsible/index.ts +3 -0
  156. package/components/ui/command/Command.vue +31 -0
  157. package/components/ui/command/CommandDialog.vue +21 -0
  158. package/components/ui/command/CommandEmpty.vue +21 -0
  159. package/components/ui/command/CommandGroup.vue +30 -0
  160. package/components/ui/command/CommandInput.vue +35 -0
  161. package/components/ui/command/CommandItem.vue +27 -0
  162. package/components/ui/command/CommandList.vue +28 -0
  163. package/components/ui/command/CommandSeparator.vue +24 -0
  164. package/components/ui/command/CommandShortcut.vue +14 -0
  165. package/components/ui/command/index.ts +9 -0
  166. package/components/ui/context-menu/ContextMenu.vue +15 -0
  167. package/components/ui/context-menu/ContextMenuCheckboxItem.vue +41 -0
  168. package/components/ui/context-menu/ContextMenuContent.vue +37 -0
  169. package/components/ui/context-menu/ContextMenuGroup.vue +12 -0
  170. package/components/ui/context-menu/ContextMenuItem.vue +35 -0
  171. package/components/ui/context-menu/ContextMenuLabel.vue +27 -0
  172. package/components/ui/context-menu/ContextMenuPortal.vue +12 -0
  173. package/components/ui/context-menu/ContextMenuRadioGroup.vue +19 -0
  174. package/components/ui/context-menu/ContextMenuRadioItem.vue +41 -0
  175. package/components/ui/context-menu/ContextMenuSeparator.vue +22 -0
  176. package/components/ui/context-menu/ContextMenuShortcut.vue +14 -0
  177. package/components/ui/context-menu/ContextMenuSub.vue +19 -0
  178. package/components/ui/context-menu/ContextMenuSubContent.vue +36 -0
  179. package/components/ui/context-menu/ContextMenuSubTrigger.vue +36 -0
  180. package/components/ui/context-menu/ContextMenuTrigger.vue +14 -0
  181. package/components/ui/context-menu/index.ts +14 -0
  182. package/components/ui/dialog/Dialog.vue +2 -6
  183. package/components/ui/dialog/DialogClose.vue +2 -1
  184. package/components/ui/dialog/DialogContent.vue +10 -12
  185. package/components/ui/dialog/DialogDescription.vue +6 -10
  186. package/components/ui/dialog/DialogScrollContent.vue +15 -21
  187. package/components/ui/dialog/DialogTitle.vue +9 -6
  188. package/components/ui/dialog/DialogTrigger.vue +2 -1
  189. package/components/ui/drawer/Drawer.vue +19 -0
  190. package/components/ui/drawer/DrawerContent.vue +28 -0
  191. package/components/ui/drawer/DrawerDescription.vue +21 -0
  192. package/components/ui/drawer/DrawerFooter.vue +14 -0
  193. package/components/ui/drawer/DrawerHeader.vue +14 -0
  194. package/components/ui/drawer/DrawerOverlay.vue +19 -0
  195. package/components/ui/drawer/DrawerTitle.vue +21 -0
  196. package/components/ui/drawer/index.ts +8 -0
  197. package/components/ui/dropdown-menu/DropdownMenu.vue +15 -0
  198. package/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +41 -0
  199. package/components/ui/dropdown-menu/DropdownMenuContent.vue +39 -0
  200. package/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
  201. package/components/ui/dropdown-menu/DropdownMenuItem.vue +30 -0
  202. package/components/ui/dropdown-menu/DropdownMenuLabel.vue +26 -0
  203. package/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +19 -0
  204. package/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +42 -0
  205. package/components/ui/dropdown-menu/DropdownMenuSeparator.vue +24 -0
  206. package/components/ui/dropdown-menu/DropdownMenuShortcut.vue +14 -0
  207. package/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
  208. package/components/ui/dropdown-menu/DropdownMenuSubContent.vue +31 -0
  209. package/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +35 -0
  210. package/components/ui/dropdown-menu/DropdownMenuTrigger.vue +14 -0
  211. package/components/ui/dropdown-menu/index.ts +16 -0
  212. package/components/ui/form/FormControl.vue +16 -0
  213. package/components/ui/form/FormDescription.vue +20 -0
  214. package/components/ui/form/FormItem.vue +20 -0
  215. package/components/ui/form/FormLabel.vue +23 -0
  216. package/components/ui/form/FormMessage.vue +16 -0
  217. package/components/ui/form/index.ts +7 -0
  218. package/components/ui/form/injectionKeys.ts +4 -0
  219. package/components/ui/form/useFormField.ts +30 -0
  220. package/components/ui/hover-card/HoverCard.vue +15 -0
  221. package/components/ui/hover-card/HoverCardContent.vue +43 -0
  222. package/components/ui/hover-card/HoverCardTrigger.vue +12 -0
  223. package/components/ui/hover-card/index.ts +3 -0
  224. package/components/ui/input/Input.vue +1 -1
  225. package/components/ui/menubar/Menubar.vue +36 -0
  226. package/components/ui/menubar/MenubarCheckboxItem.vue +41 -0
  227. package/components/ui/menubar/MenubarContent.vue +45 -0
  228. package/components/ui/menubar/MenubarGroup.vue +12 -0
  229. package/components/ui/menubar/MenubarItem.vue +36 -0
  230. package/components/ui/menubar/MenubarLabel.vue +14 -0
  231. package/components/ui/menubar/MenubarMenu.vue +12 -0
  232. package/components/ui/menubar/MenubarRadioGroup.vue +20 -0
  233. package/components/ui/menubar/MenubarRadioItem.vue +41 -0
  234. package/components/ui/menubar/MenubarSeparator.vue +21 -0
  235. package/components/ui/menubar/MenubarShortcut.vue +14 -0
  236. package/components/ui/menubar/MenubarSub.vue +20 -0
  237. package/components/ui/menubar/MenubarSubContent.vue +40 -0
  238. package/components/ui/menubar/MenubarSubTrigger.vue +32 -0
  239. package/components/ui/menubar/MenubarTrigger.vue +31 -0
  240. package/components/ui/menubar/index.ts +15 -0
  241. package/components/ui/navigation-menu/NavigationMenu.vue +34 -0
  242. package/components/ui/navigation-menu/NavigationMenuContent.vue +35 -0
  243. package/components/ui/navigation-menu/NavigationMenuIndicator.vue +26 -0
  244. package/components/ui/navigation-menu/NavigationMenuItem.vue +12 -0
  245. package/components/ui/navigation-menu/NavigationMenuLink.vue +19 -0
  246. package/components/ui/navigation-menu/NavigationMenuList.vue +31 -0
  247. package/components/ui/navigation-menu/NavigationMenuTrigger.vue +36 -0
  248. package/components/ui/navigation-menu/NavigationMenuViewport.vue +35 -0
  249. package/components/ui/navigation-menu/index.ts +14 -0
  250. package/components/ui/number-field/NumberField.vue +24 -0
  251. package/components/ui/number-field/NumberFieldContent.vue +14 -0
  252. package/components/ui/number-field/NumberFieldDecrement.vue +26 -0
  253. package/components/ui/number-field/NumberFieldIncrement.vue +26 -0
  254. package/components/ui/number-field/NumberFieldInput.vue +16 -0
  255. package/components/ui/number-field/index.ts +5 -0
  256. package/components/ui/pagination/PaginationEllipsis.vue +24 -0
  257. package/components/ui/pagination/PaginationFirst.vue +31 -0
  258. package/components/ui/pagination/PaginationLast.vue +31 -0
  259. package/components/ui/pagination/PaginationNext.vue +31 -0
  260. package/components/ui/pagination/PaginationPrev.vue +31 -0
  261. package/components/ui/pagination/index.ts +10 -0
  262. package/components/ui/pin-input/PinInput.vue +25 -0
  263. package/components/ui/pin-input/PinInputGroup.vue +20 -0
  264. package/components/ui/pin-input/PinInputInput.vue +20 -0
  265. package/components/ui/pin-input/PinInputSeparator.vue +16 -0
  266. package/components/ui/pin-input/index.ts +4 -0
  267. package/components/ui/popover/Popover.vue +15 -0
  268. package/components/ui/popover/PopoverContent.vue +49 -0
  269. package/components/ui/popover/PopoverTrigger.vue +12 -0
  270. package/components/ui/popover/index.ts +3 -0
  271. package/components/ui/progress/Progress.vue +41 -0
  272. package/components/ui/progress/index.ts +1 -0
  273. package/components/ui/radio-group/RadioGroupItem.vue +1 -1
  274. package/components/ui/range-calendar/RangeCalendar.vue +62 -0
  275. package/components/ui/range-calendar/RangeCalendarCell.vue +26 -0
  276. package/components/ui/range-calendar/RangeCalendarCellTrigger.vue +42 -0
  277. package/components/ui/range-calendar/RangeCalendarGrid.vue +26 -0
  278. package/components/ui/range-calendar/RangeCalendarGridBody.vue +12 -0
  279. package/components/ui/range-calendar/RangeCalendarGridHead.vue +12 -0
  280. package/components/ui/range-calendar/RangeCalendarGridRow.vue +23 -0
  281. package/components/ui/range-calendar/RangeCalendarHeadCell.vue +23 -0
  282. package/components/ui/range-calendar/RangeCalendarHeader.vue +23 -0
  283. package/components/ui/range-calendar/RangeCalendarHeading.vue +33 -0
  284. package/components/ui/range-calendar/RangeCalendarNextButton.vue +34 -0
  285. package/components/ui/range-calendar/RangeCalendarPrevButton.vue +34 -0
  286. package/components/ui/range-calendar/index.ts +12 -0
  287. package/components/ui/resizable/ResizableHandle.vue +28 -0
  288. package/components/ui/resizable/ResizablePanelGroup.vue +23 -0
  289. package/components/ui/resizable/index.ts +3 -0
  290. package/components/ui/scroll-area/ScrollArea.vue +31 -0
  291. package/components/ui/scroll-area/ScrollBar.vue +32 -0
  292. package/components/ui/scroll-area/index.ts +2 -0
  293. package/components/ui/select/SelectContent.vue +1 -1
  294. package/components/ui/select/SelectItem.vue +1 -1
  295. package/components/ui/select/SelectSeparator.vue +1 -1
  296. package/components/ui/select/SelectTrigger.vue +1 -1
  297. package/components/ui/separator/Separator.vue +37 -0
  298. package/components/ui/separator/index.ts +1 -0
  299. package/components/ui/sheet/Sheet.vue +15 -0
  300. package/components/ui/sheet/SheetClose.vue +12 -0
  301. package/components/ui/sheet/SheetContent.vue +58 -0
  302. package/components/ui/sheet/SheetDescription.vue +24 -0
  303. package/components/ui/sheet/SheetFooter.vue +19 -0
  304. package/components/ui/sheet/SheetHeader.vue +16 -0
  305. package/components/ui/sheet/SheetTitle.vue +24 -0
  306. package/components/ui/sheet/SheetTrigger.vue +12 -0
  307. package/components/ui/sheet/index.ts +32 -0
  308. package/components/ui/sidebar/Sidebar.vue +85 -0
  309. package/components/ui/sidebar/SidebarContent.vue +17 -0
  310. package/components/ui/sidebar/SidebarFooter.vue +17 -0
  311. package/components/ui/sidebar/SidebarGroup.vue +17 -0
  312. package/components/ui/sidebar/SidebarGroupAction.vue +26 -0
  313. package/components/ui/sidebar/SidebarGroupContent.vue +17 -0
  314. package/components/ui/sidebar/SidebarGroupLabel.vue +24 -0
  315. package/components/ui/sidebar/SidebarHeader.vue +17 -0
  316. package/components/ui/sidebar/SidebarInput.vue +21 -0
  317. package/components/ui/sidebar/SidebarInset.vue +20 -0
  318. package/components/ui/sidebar/SidebarMenu.vue +17 -0
  319. package/components/ui/sidebar/SidebarMenuAction.vue +34 -0
  320. package/components/ui/sidebar/SidebarMenuBadge.vue +25 -0
  321. package/components/ui/sidebar/SidebarMenuButton.vue +51 -0
  322. package/components/ui/sidebar/SidebarMenuButtonChild.vue +35 -0
  323. package/components/ui/sidebar/SidebarMenuItem.vue +17 -0
  324. package/components/ui/sidebar/SidebarMenuSkeleton.vue +34 -0
  325. package/components/ui/sidebar/SidebarMenuSub.vue +21 -0
  326. package/components/ui/sidebar/SidebarMenuSubButton.vue +35 -0
  327. package/components/ui/sidebar/SidebarMenuSubItem.vue +8 -0
  328. package/components/ui/sidebar/SidebarProvider.vue +81 -0
  329. package/components/ui/sidebar/SidebarRail.vue +32 -0
  330. package/components/ui/sidebar/SidebarSeparator.vue +18 -0
  331. package/components/ui/sidebar/SidebarTrigger.vue +26 -0
  332. package/components/ui/sidebar/index.ts +60 -0
  333. package/components/ui/sidebar/utils.ts +19 -0
  334. package/components/ui/skeleton/Skeleton.vue +14 -0
  335. package/components/ui/skeleton/index.ts +1 -0
  336. package/components/ui/slider/Slider.vue +37 -0
  337. package/components/ui/slider/index.ts +1 -0
  338. package/components/ui/sonner/Sonner.vue +23 -0
  339. package/components/ui/sonner/index.ts +1 -0
  340. package/components/ui/stepper/Stepper.vue +32 -0
  341. package/components/ui/stepper/StepperDescription.vue +24 -0
  342. package/components/ui/stepper/StepperIndicator.vue +36 -0
  343. package/components/ui/stepper/StepperItem.vue +28 -0
  344. package/components/ui/stepper/StepperSeparator.vue +32 -0
  345. package/components/ui/stepper/StepperTitle.vue +24 -0
  346. package/components/ui/stepper/StepperTrigger.vue +27 -0
  347. package/components/ui/stepper/index.ts +7 -0
  348. package/components/ui/switch/Switch.vue +40 -0
  349. package/components/ui/switch/index.ts +1 -0
  350. package/components/ui/table/Table.vue +16 -0
  351. package/components/ui/table/TableBody.vue +14 -0
  352. package/components/ui/table/TableCaption.vue +14 -0
  353. package/components/ui/table/TableCell.vue +21 -0
  354. package/components/ui/table/TableEmpty.vue +38 -0
  355. package/components/ui/table/TableFooter.vue +14 -0
  356. package/components/ui/table/TableHead.vue +14 -0
  357. package/components/ui/table/TableHeader.vue +14 -0
  358. package/components/ui/table/TableRow.vue +14 -0
  359. package/components/ui/table/index.ts +9 -0
  360. package/components/ui/tabs/TabsContent.vue +6 -11
  361. package/components/ui/tabs/TabsList.vue +8 -8
  362. package/components/ui/tabs/TabsTrigger.vue +9 -11
  363. package/components/ui/tags-input/TagsInput.vue +24 -0
  364. package/components/ui/tags-input/TagsInputInput.vue +21 -0
  365. package/components/ui/tags-input/TagsInputItem.vue +24 -0
  366. package/components/ui/tags-input/TagsInputItemDelete.vue +26 -0
  367. package/components/ui/tags-input/TagsInputItemText.vue +21 -0
  368. package/components/ui/tags-input/index.ts +5 -0
  369. package/components/ui/textarea/Textarea.vue +1 -1
  370. package/components/ui/toast/Toast.vue +30 -0
  371. package/components/ui/toast/ToastAction.vue +21 -0
  372. package/components/ui/toast/ToastClose.vue +24 -0
  373. package/components/ui/toast/ToastDescription.vue +21 -0
  374. package/components/ui/toast/ToastProvider.vue +12 -0
  375. package/components/ui/toast/ToastTitle.vue +21 -0
  376. package/components/ui/toast/ToastViewport.vue +19 -0
  377. package/components/ui/toast/Toaster.vue +30 -0
  378. package/components/ui/toast/index.ts +39 -0
  379. package/components/ui/toast/use-toast.ts +165 -0
  380. package/components/ui/toggle/Toggle.vue +38 -0
  381. package/components/ui/toggle/index.ts +28 -0
  382. package/components/ui/toggle-group/ToggleGroup.vue +36 -0
  383. package/components/ui/toggle-group/ToggleGroupItem.vue +37 -0
  384. package/components/ui/toggle-group/index.ts +2 -0
  385. package/components/ui/tooltip/Tooltip.vue +15 -0
  386. package/components/ui/tooltip/TooltipContent.vue +33 -0
  387. package/components/ui/tooltip/TooltipProvider.vue +12 -0
  388. package/components/ui/tooltip/TooltipTrigger.vue +12 -0
  389. package/components/ui/tooltip/index.ts +4 -0
  390. package/components/ui/v-calendar/Calendar.vue +343 -0
  391. package/components/ui/v-calendar/index.ts +22 -0
  392. package/composables/useAccordionScroll.ts +1 -1
  393. package/composables/useContentSearch.ts +0 -0
  394. package/composables/useImageSources.ts +208 -0
  395. package/composables/useLightbox.ts +81 -0
  396. package/composables/useMainMenuLinks.ts +1 -1
  397. package/composables/useMessageBus.ts +74 -0
  398. package/composables/useMetaMenuLinks.ts +1 -1
  399. package/composables/useNavigationOffset.ts +1 -1
  400. package/layouts/default.vue +2 -2
  401. package/layouts/error.vue +8 -10
  402. package/modules/dynamicEntityComponentResolver.ts +182 -0
  403. package/modules/dynamicParagraphResolver.ts +1 -1
  404. package/nuxt.config.ts +28 -32
  405. package/package.json +3 -2
  406. package/pages/[...slug]/index.vue +2 -2
  407. package/pages/index.vue +2 -2
  408. package/pages/node/[nid]/index.vue +2 -2
  409. package/queries/query.contentSearch.graphql +17 -0
  410. package/tailwind.config.ts +1 -0
  411. package/types/fslightbox-vue.d.ts +1 -0
  412. package/components/Blokkli/iFrame/Element/icon.svg +0 -5
  413. package/components/Blokkli/iFrame/Element/index.vue +0 -14
  414. package/components/Paragraph/iFrame/Element/fragment.graphql +0 -9
  415. package/components/Paragraph/iFrame/Element/index.vue +0 -16
  416. package/components/Paragraph/iFrame/Layout/index.vue +0 -161
  417. package/composables/languageLinks.ts +0 -31
  418. package/modules/dynamicNodeResolver.ts +0 -95
  419. package/pages/search/index.vue +0 -69
  420. package/pages/static-page/example.vue +0 -40
  421. package/queries/fragment.routeQuery.graphql +0 -51
  422. /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-large-spacing-bottom.svg +0 -0
  423. /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-large-spacing-top.svg +0 -0
  424. /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-no-spacing.svg +0 -0
  425. /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-small-spacing-bottom.svg +0 -0
  426. /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-small-spacing-top.svg +0 -0
  427. /package/components/Blokkli/iFrame/{Layout/icon.svg → icon.svg} +0 -0
@@ -0,0 +1,208 @@
1
+ import type { ImageSizesVariant } from '@nuxt/image'
2
+ import type { MediaImageFragment } from '#graphql-operations'
3
+
4
+ interface ImageSource {
5
+ sizes?: string
6
+ srcset: string
7
+ media?: string
8
+ }
9
+
10
+ interface UseImageSourcesOptions {
11
+ media: Ref<MediaImageFragment> | MediaImageFragment
12
+ imageAspectRatios?: Ref<string | undefined> | string | undefined
13
+ imageSizes?: Ref<string | undefined> | string | undefined
14
+ }
15
+
16
+ // Local implementation of parseSizes from @nuxt/image
17
+ function parseSizes(input: Record<string, string | number> | string): Record<string, string> {
18
+ const sizes: Record<string, string> = {}
19
+ if (typeof input === "string") {
20
+ for (const entry of input.split(/[\s,]+/).filter((e) => e)) {
21
+ const s = entry.split(":")
22
+ if (s.length !== 2) {
23
+ sizes["1px"] = s[0].trim()
24
+ } else {
25
+ sizes[s[0].trim()] = s[1].trim()
26
+ }
27
+ }
28
+ } else {
29
+ Object.assign(sizes, input)
30
+ }
31
+ return sizes
32
+ }
33
+
34
+ // Helper function, copied from NuxtImage.
35
+ function getSizesVariant(key: string, size: string, hwRatio: number, img: any): ImageSizesVariant | undefined {
36
+ const screenMaxWidth = (img.options.screens && img.options.screens[key]) || Number.parseInt(key)
37
+ const isFluid = size.endsWith('vw')
38
+ if (!isFluid && /^\d+$/.test(size)) {
39
+ size = size + 'px'
40
+ }
41
+ if (!isFluid && !size.endsWith('px')) {
42
+ return undefined
43
+ }
44
+ let _cWidth = Number.parseInt(size)
45
+ if (!screenMaxWidth || !_cWidth) {
46
+ return undefined
47
+ }
48
+ if (isFluid) {
49
+ _cWidth = Math.round((_cWidth / 100) * screenMaxWidth)
50
+ }
51
+ const _cHeight = Math.round(_cWidth * hwRatio)
52
+ return {
53
+ size,
54
+ screenMaxWidth,
55
+ _cWidth,
56
+ _cHeight,
57
+ }
58
+ }
59
+
60
+ // Helper function, copied from NuxtImage.
61
+ function finaliseSizeVariants(sizeVariants: any[]) {
62
+ sizeVariants.sort((v1, v2) => v1.screenMaxWidth - v2.screenMaxWidth)
63
+
64
+ // de-duplicate size variants (by key `media`)
65
+ let previousMedia = null
66
+ for (let i = sizeVariants.length - 1; i >= 0; i--) {
67
+ const sizeVariant = sizeVariants[i]
68
+ if (sizeVariant.media === previousMedia) {
69
+ sizeVariants.splice(i, 1)
70
+ }
71
+ previousMedia = sizeVariant.media
72
+ }
73
+
74
+ for (let i = 0; i < sizeVariants.length; i++) {
75
+ sizeVariants[i].media = sizeVariants[i + 1]?.media || ''
76
+ }
77
+ }
78
+
79
+ // Helper function, copied from NuxtImage.
80
+ function finaliseSrcsetVariants(srcsetVariants: any[]) {
81
+ // sort by width
82
+ srcsetVariants.sort((v1, v2) => v1.width - v2.width)
83
+
84
+ // de-duplicate srcset variants (by key `width`)
85
+ let previousWidth = null
86
+ for (let i = srcsetVariants.length - 1; i >= 0; i--) {
87
+ const sizeVariant = srcsetVariants[i]
88
+ if (sizeVariant.width === previousWidth) {
89
+ srcsetVariants.splice(i, 1)
90
+ }
91
+ previousWidth = sizeVariant.width
92
+ }
93
+ }
94
+
95
+ export function useImageSources(options: UseImageSourcesOptions) {
96
+ const img = useImage()
97
+ const baseUrl = useRuntimeConfig().public.imageBaseUrl
98
+
99
+ // Convert props to refs if they aren't already
100
+ const mediaRef = toRef(options.media)
101
+ const imageAspectRatiosRef = toRef(options.imageAspectRatios)
102
+ const imageSizesRef = toRef(options.imageSizes)
103
+
104
+ const placeHolderImage = computed(() => {
105
+ const sourceImage = baseUrl + mediaRef.value?.sourceUrl?.path
106
+ if (!sourceImage || sourceImage === baseUrl) return ''
107
+ return img(sourceImage, { format: 'webp', width: 100, blur: 100 })
108
+ })
109
+
110
+ const imageSources = computed((): ImageSource[] => {
111
+ const sourceImage = baseUrl + mediaRef.value?.sourceUrl?.path
112
+ if (!sourceImage || sourceImage === baseUrl) return []
113
+
114
+ const sources: ImageSource[] = []
115
+ const imgSizes = imageSizesRef.value ?? Object.keys(img.options.screens).map(key => `${key}:100vw`).join(' ')
116
+
117
+ // No aspect ratios provided.
118
+ if (!imageAspectRatiosRef.value) {
119
+ const imageSize = img.getSizes(sourceImage, {
120
+ sizes: imgSizes,
121
+ modifiers: {
122
+ format: 'webp'
123
+ }
124
+ })
125
+ // Cast the ImageSizes result to our ImageSource interface
126
+ sources.push(imageSize as ImageSource)
127
+ return sources
128
+ }
129
+
130
+ // Aspect ratios provided.
131
+ const parsedAspectRatios = parseSizes(imageAspectRatiosRef.value)
132
+ const parsedImageSizes = parseSizes(imgSizes)
133
+ const densities = img.options.densities
134
+ const keys = Object.keys(parsedImageSizes)
135
+ const lastKey = keys[keys.length - 1]
136
+
137
+ for (const keyAspectRatios in parsedAspectRatios) {
138
+ const [l, h] = parsedAspectRatios[keyAspectRatios].split('/').map(Number)
139
+ const hwRatio = (l && h) ? h / l : 0
140
+ const sizeVariants = []
141
+ const srcsetVariants = []
142
+
143
+ let screenSizes = Object.keys(parsedImageSizes)
144
+ if (Object.keys(parsedImageSizes).includes(keyAspectRatios)) {
145
+ const minSizeIndex = Object.keys(parsedImageSizes).indexOf(keyAspectRatios)
146
+ screenSizes = Object.keys(parsedImageSizes).slice(minSizeIndex)
147
+ }
148
+
149
+ for (const index in screenSizes) {
150
+ const screenSize = screenSizes[index]
151
+
152
+ const variant = getSizesVariant(screenSize, String(parsedImageSizes[screenSize]), hwRatio, img)
153
+ if (variant === undefined) {
154
+ continue
155
+ }
156
+
157
+ // Add size variant with 'media'.
158
+ sizeVariants.push({
159
+ size: variant.size,
160
+ screenMaxWidth: variant.screenMaxWidth,
161
+ media: `(max-width: ${variant.screenMaxWidth}px)`,
162
+ })
163
+
164
+ // Add srcset variants and ignore densities (for current 'size' processed).
165
+ srcsetVariants.push({
166
+ width: variant._cWidth,
167
+ src: img(sourceImage, {
168
+ width: variant._cWidth ? variant._cWidth : undefined,
169
+ height: variant._cHeight ? variant._cHeight : undefined,
170
+ fit: 'cover',
171
+ format: 'webp'
172
+ }),
173
+ })
174
+
175
+ // Make sure to not create duplicate size variants for the same screen size.
176
+ if (keyAspectRatios != screenSize && Object.keys(parsedAspectRatios).includes(screenSize)) {
177
+ break
178
+ }
179
+ }
180
+
181
+ const media = sizeVariants.slice(-1)[0]?.media
182
+ finaliseSizeVariants(sizeVariants)
183
+ finaliseSrcsetVariants(srcsetVariants)
184
+
185
+ const sizesVal = sizeVariants.length ? sizeVariants.map(v => `${v.media ? v.media + ' ' : ''}${v.size}`).join(', ') : undefined
186
+ const suffix = sizesVal ? 'w' : 'x'
187
+ const srcsetVal = srcsetVariants.map(v => `${v.src} ${v.width}${suffix}`).join(', ')
188
+
189
+ const source: ImageSource = {
190
+ sizes: sizesVal,
191
+ srcset: srcsetVal,
192
+ }
193
+
194
+ if (keyAspectRatios != Object.keys(parsedAspectRatios).slice(-1)[0]) {
195
+ source.media = media
196
+ }
197
+ sources.push(source)
198
+ }
199
+ return sources
200
+ })
201
+
202
+ return {
203
+ placeHolderImage,
204
+ imageSources
205
+ }
206
+ }
207
+
208
+ export type { ImageSource }
@@ -0,0 +1,81 @@
1
+ import type { MediaFragment } from '#graphql-operations'
2
+ import { DesignSystemAtomsCaption } from '#components'
3
+
4
+ export function useLightbox(media: (MediaFragment | null)[] | undefined) {
5
+ const toggleLightbox = ref(false)
6
+ const currentSlide = ref(1)
7
+
8
+ const openLightbox = (index: number) => {
9
+ currentSlide.value = index + 1 // fsLightbox uses 1-based indexing
10
+ toggleLightbox.value = !toggleLightbox.value
11
+ }
12
+
13
+ // https://fslightbox.com/vue/documentation/sources
14
+ const computedMedia = computed(() =>
15
+ media?.map(item => {
16
+ if (!item) return ''
17
+ switch (item.type) {
18
+ case 'MediaImage':
19
+ return item.sourceUrl?.path || ''
20
+ case 'MediaVideo':
21
+ return item.url?.path || ''
22
+ case 'MediaRemoteVideo':
23
+ return item.link || ''
24
+ default:
25
+ return ''
26
+ }
27
+ }).filter(Boolean) || []
28
+ )
29
+
30
+ // https://fslightbox.com/vue/documentation/custom-attributes
31
+ const computedCustomAttributes = computed(() =>
32
+ media?.map(item => {
33
+ if (!item) return {}
34
+
35
+ switch (item.type) {
36
+ case 'MediaImage':
37
+ return {
38
+ alt: item.alt?.alt || '',
39
+ title: item.title || ''
40
+ }
41
+
42
+ case 'MediaVideo':
43
+ return {
44
+ alt: (item.thumbnailOverride || item.thumbnail)?.alt || '',
45
+ title: item.title || '',
46
+ poster: (item.thumbnailOverride || item.thumbnail)?.entity?.uri?.first?.url || '',
47
+ controls: true
48
+ }
49
+
50
+ case 'MediaRemoteVideo':
51
+ return {
52
+ alt: (item.thumbnailOverride || item.thumbnail)?.alt || '',
53
+ title: item.title || '',
54
+ poster: (item.thumbnailOverride || item.thumbnail)?.entity?.uri?.first?.url || ''
55
+ }
56
+
57
+ default:
58
+ return {}
59
+ }
60
+ }) || []
61
+ )
62
+
63
+ // https://fslightbox.com/vue/documentation/captions
64
+ const computedCaptions = computed(() =>
65
+ media?.map(item => ({
66
+ component: DesignSystemAtomsCaption,
67
+ props: {
68
+ caption: item?.caption || ''
69
+ }
70
+ })) || []
71
+ )
72
+
73
+ return {
74
+ toggleLightbox,
75
+ currentSlide,
76
+ openLightbox,
77
+ sources: computedMedia,
78
+ customAttributes: computedCustomAttributes,
79
+ captions: computedCaptions
80
+ }
81
+ }
@@ -1,4 +1,4 @@
1
- import type { InitData } from '~/composables/useInitData'
1
+ import type { InitData } from './useInitData'
2
2
  import type { MenuLinkTreeFragment } from '#graphql-operations'
3
3
 
4
4
  function isLinkTreeActive(
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Message Bus Composable
3
+ *
4
+ * This composable provides a simple in-memory message bus for communication between components.
5
+ *
6
+ * Usage:
7
+ * import { useMessageBus } from '#imports'
8
+ * const { bus, send, receive } = useMessageBus()
9
+ *
10
+ * // Send a message
11
+ * send('Hello World', 'receiverId', 'typeId')
12
+ *
13
+ * // Receive messages
14
+ * const messages = receive('receiverId', 'typeId')
15
+ *
16
+ * API:
17
+ * - bus: Ref<Array<BusMessage>>
18
+ * - send(message, receiver?, type?)
19
+ * - receive(receiver?, type?): BusMessage[]
20
+ *
21
+ * BusMessage:
22
+ * - receiver?: string
23
+ * - type?: string
24
+ * - message: any
25
+ */
26
+
27
+ /**
28
+ * Represents a message sent through the message bus.
29
+ */
30
+ export type BusMessage = {
31
+ receiver?: string
32
+ type?: string
33
+ message?: any
34
+ }
35
+
36
+ const messageBus: Ref<Array<BusMessage>> = ref([]);
37
+
38
+ /**
39
+ * Sends a message to the message bus.
40
+ *
41
+ * @param message - The message payload to send.
42
+ * @param receiver - Optional receiver identifier.
43
+ * @param type - Optional message type identifier.
44
+ */
45
+ function send(message: any, receiver?: string, type?: string) {
46
+ messageBus.value.push({ receiver, type, message });
47
+ }
48
+
49
+ /**
50
+ * Retrieves messages from the message bus matching the given receiver and type.
51
+ * Returns a deep clone of the matched messages.
52
+ *
53
+ * @param receiver - Optional receiver identifier to filter messages.
54
+ * @param type - Optional type identifier to filter messages.
55
+ * @returns Array of matching BusMessage objects (deep cloned).
56
+ */
57
+ function receive(receiver?: string, type?: string): BusMessage[] {
58
+ return messageBus.value.filter(
59
+ msg => (receiver === undefined || msg.receiver === receiver) && (type === undefined || msg.type === type)
60
+ ).map(msg => ({ ...msg, message: JSON.parse(JSON.stringify(msg.message)) }));
61
+ }
62
+
63
+ /**
64
+ * Provides access to the message bus, including send and receive functions.
65
+ *
66
+ * @returns An object containing the bus ref, send, and receive functions.
67
+ */
68
+ export function useMessageBus() {
69
+ return {
70
+ bus: messageBus,
71
+ send,
72
+ receive,
73
+ };
74
+ }
@@ -1,4 +1,4 @@
1
- import type { InitData } from '~/composables/useInitData'
1
+ import type { InitData } from './useInitData'
2
2
  import type { MenuLinkTreeFragment } from '#graphql-operations'
3
3
 
4
4
  function isLinkTreeActive(
@@ -1,4 +1,4 @@
1
- import { useIsMobile } from '@/composables/useIsMobile'
1
+ import { useIsMobile } from './useIsMobile'
2
2
 
3
3
  const mobileNavHeight: number = 73
4
4
  const desktopNavHeight: number = 114
@@ -6,9 +6,9 @@
6
6
  @menu:close:finished="menuCloseFinish"
7
7
  />
8
8
 
9
- <NuxtPageDependency>
9
+ <!-- <NuxtPageDependency>
10
10
  <DrupalBreadcrumb v-if="showBreadcrumb" :links="breadcrumb" />
11
- </NuxtPageDependency>
11
+ </NuxtPageDependency> -->
12
12
 
13
13
  <div>
14
14
  <ClientOnly>
package/layouts/error.vue CHANGED
@@ -6,16 +6,15 @@
6
6
  @menu:close:finished="menuCloseFinish"
7
7
  />
8
8
 
9
- <NuxtPageDependency>
9
+ <!-- <NuxtPageDependency>
10
10
  <DrupalBreadcrumb v-if="showBreadcrumb" :links="breadcrumb" />
11
- </NuxtPageDependency>
11
+ </NuxtPageDependency> -->
12
12
 
13
13
  <div>
14
14
  <ClientOnly>
15
15
  <DrupalMessages v-if="!isEditing" />
16
16
  </ClientOnly>
17
17
 
18
-
19
18
  <div class="container mx-auto grid grid-cols-1 gap-6 py-12">
20
19
  <div class="ck-editor text-center">
21
20
  <h1>Whooops!</h1>
@@ -24,10 +23,10 @@
24
23
  class="mt-8 inline-block underline"
25
24
  :to="`/${currentLanguage}`"
26
25
  prefetch
27
- >Go back to home</NuxtLink>
26
+ >Go back to home</NuxtLink
27
+ >
28
28
  </div>
29
29
  </div>
30
-
31
30
  </div>
32
31
  <SectionFooter />
33
32
  </div>
@@ -57,7 +56,7 @@ const error = useError()
57
56
  const errorCode = error.value?.statusCode || 'Unknown error'
58
57
 
59
58
  const errorMessages = {
60
- 404: 'We can\'t find the page \nyou are looking for.',
59
+ 404: "We can't find the page \nyou are looking for.",
61
60
  500: 'An error occurred on the server. Please try again later.',
62
61
  'Unknown error': 'An unknown error occurred.',
63
62
  }
@@ -67,10 +66,10 @@ const errorMessage = computed(() => {
67
66
  return errorMessages[errorCode]
68
67
  }
69
68
  return errorMessages['Unknown error']
70
- });
69
+ })
71
70
 
72
71
  useHead({
73
- title: errorMessage
72
+ title: errorMessage,
74
73
  })
75
74
 
76
75
  const isMenuOpen = ref(false)
@@ -94,5 +93,4 @@ function menuCloseFinish() {
94
93
  hasMenuFinishedClosing.value = true
95
94
  }
96
95
  }
97
-
98
- </script>
96
+ </script>
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Nuxt Layer Module: dynamicEntityComponentResolver
3
+ *
4
+ * Dynamically imports all Node components from every enabled Nuxt layer (including the main app),
5
+ * supports both single-file and index.vue conventions, and injects a dynamic resolver with
6
+ * proper override priority (main app overrides layers).
7
+ */
8
+
9
+ import { defineNuxtModule, addPlugin, addTemplate, createResolver } from '@nuxt/kit'
10
+ import { join } from 'pathe'
11
+
12
+ export default defineNuxtModule({
13
+ meta: { name: 'dynamicEntityComponentResolver' },
14
+ setup(_options, nuxt) {
15
+ const { resolve } = createResolver(import.meta.url)
16
+
17
+ // Gather all layer root directories (main app is always first)
18
+ const appRoot = nuxt.options.rootDir
19
+ const layerDirs = nuxt.options._layers
20
+ .map(layer => layer.cwd.replace(appRoot, '').length ? layer.cwd.replace(appRoot, '') : '/')
21
+
22
+ // Helper to get icms config from a layer
23
+ function getLayerPageComponentTypes(layer) {
24
+ return (layer.config && layer.config.icms && Array.isArray(layer.config.icms.pageComponentTypes))
25
+ ? layer.config.icms.pageComponentTypes
26
+ : [];
27
+ }
28
+
29
+ // Gather pageComponentTypes from all layers and main app
30
+ // @ts-ignore: allow access to icms
31
+ const allTypes = [Array.isArray(nuxt.options.icms?.pageComponentTypes) ? nuxt.options.icms.pageComponentTypes : []]
32
+ .concat(nuxt.options._layers.map(getLayerPageComponentTypes))
33
+ .flat()
34
+ .filter((v, i, arr) => arr.indexOf(v) === i); // dedupe
35
+
36
+ // Generate import.meta.glob for each layer's components for each type
37
+ const imports = layerDirs.map((dir, i) => {
38
+ return allTypes.map(type => {
39
+ const componentsPath = join(dir, `components/${type}/**/*.vue`)
40
+ return `const modules${i}_${type} = import.meta.glob(${JSON.stringify(componentsPath)});`;
41
+ }).join('\n');
42
+ }).join('\n');
43
+
44
+ // Merge logic (reverse order so main app overrides layers)
45
+ const mergeLogic = layerDirs
46
+ .map((_, i) => {
47
+ return allTypes.map(type => `
48
+ for (const path in modules${i}_${type}) {
49
+ const name = getComponentNameFromPath(path, "${type}");
50
+ if (name) componentMap[name] = defineAsyncComponent(modules${i}_${type}[path]);
51
+ }
52
+ `).join('\n');
53
+ })
54
+ .reverse()
55
+ .join('\n');
56
+
57
+ // Create the plugin template
58
+ addTemplate({
59
+ filename: 'dynamic-entity-component-resolver.plugin.mjs',
60
+ getContents: () => `
61
+ import { defineNuxtPlugin } from '#app'
62
+ import { defineAsyncComponent } from 'vue'
63
+
64
+ /**
65
+ * Extracts a normalized component name from a file path for dynamic component mapping.
66
+ *
67
+ * Supports both single-file and directory-based Vue component structures:
68
+ * - /components/Type/Foo.vue -> TypeFoo
69
+ * - /components/Type/Foo/index.vue -> TypeFoo
70
+ * - /components/Type/Bar/Baz.vue -> TypeBarBaz
71
+ * - /components/Type/Bar/Baz/index.vue -> TypeBarBaz
72
+ *
73
+ * @param {string} path - The absolute or relative file path to the Vue component.
74
+ * @param {string} type - The entity type (e.g., 'Node', 'TaxonomyTerm').
75
+ * @returns {string|null} The normalized component name (e.g., 'NodeFoo' or 'TaxonomyTermBarBaz'), or null if the path does not match.
76
+ */
77
+ function getComponentNameFromPath(path, type) {
78
+ // Escape type for RegExp
79
+ var escType = type.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
80
+ var re = new RegExp('/' + escType + '/(.+?)/?(index)?\\.vue$');
81
+ var match = path.match(re);
82
+ if (match) {
83
+ var parts = match[1].split('/').map(function(part) {
84
+ return part.charAt(0).toUpperCase() + part.slice(1);
85
+ });
86
+ return type + parts.join('');
87
+ }
88
+ return null;
89
+ }
90
+
91
+ export default defineNuxtPlugin(() => {
92
+ ${imports}
93
+ var componentMap = {};
94
+ ${mergeLogic}
95
+ return {
96
+ provide: {
97
+ resolveDynamicEntityComponent: function(name) { return componentMap[name] || null; }
98
+ }
99
+ };
100
+ });
101
+ `
102
+ })
103
+
104
+ // Register the generated plugin
105
+ addPlugin({
106
+ src: resolve(nuxt.options.buildDir, 'dynamic-entity-component-resolver.plugin.mjs')
107
+ })
108
+
109
+ // Collect all page teaser fragments from the Nuxt layers.
110
+ const paragraphFragments = nuxt.options._layers
111
+ .map(layer => layer.config?.icms?.components?.fragments)
112
+ .filter(Boolean)
113
+ .flat()
114
+ .map((fragmentName) => {
115
+ return `...${fragmentName}`
116
+ })
117
+
118
+ const fragment = `
119
+ fragment paragraph on Paragraph {
120
+ id
121
+ parentId
122
+ ${paragraphFragments.join('\n ')}
123
+ }
124
+ `
125
+ nuxt.hooks.hookOnce('nuxt-graphql-middleware:init', (context) => {
126
+ context.addDocument('fragment.paragraph.graphql', fragment)
127
+ })
128
+
129
+ // Private helper to extract unique fragment values from any routeQueries object
130
+ function extractFragments(routeQueries: any): string[] {
131
+ const fragments = new Set<string>();
132
+
133
+ function traverse(obj: any) {
134
+ if (Array.isArray(obj)) {
135
+ obj.forEach(item => traverse(item));
136
+ } else if (obj && typeof obj === 'object') {
137
+ for (const key in obj) {
138
+ if (key === 'fragments' && Array.isArray(obj[key])) {
139
+ obj[key].forEach(frag => {
140
+ if (typeof frag === 'string') fragments.add(frag);
141
+ });
142
+ } else {
143
+ traverse(obj[key]);
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ traverse(routeQueries);
150
+ return Array.from(fragments);
151
+ }
152
+
153
+ const entityFragments = nuxt.options._layers
154
+ .map((layer, idx) => {
155
+ const queries = layer.config?.vuepal?.drupalRoute?.routeQueries;
156
+ const fragments = extractFragments(queries);
157
+ return fragments;
158
+ })
159
+ .filter(arr => Array.isArray(arr) && arr.length)
160
+ .flat()
161
+ .filter(Boolean);
162
+
163
+ const entityTeaserFagment = `
164
+ fragment entityTeaser on Entity {
165
+ __typename
166
+ ${entityFragments.map((fragmentName) => fragmentName ? `...${fragmentName}Teaser` : '').join('\n ')}
167
+ }
168
+ `
169
+ const entitySearchResultFagment = `
170
+ fragment entitySearchResult on Entity {
171
+ __typename
172
+ ${entityFragments.map((fragmentName) => fragmentName ? `...${fragmentName}SearchResult` : '').join('\n ')}
173
+ }
174
+ `
175
+ nuxt.hooks.hookOnce('nuxt-graphql-middleware:init', (context) => {
176
+ context.addDocument('fragment.entityTeaser.graphql', entityTeaserFagment)
177
+ context.addDocument('fragment.entitySearchResult.graphql', entitySearchResultFagment)
178
+ })
179
+ }
180
+ })
181
+
182
+
@@ -43,7 +43,7 @@ import { defineNuxtModule } from 'nuxt/kit'
43
43
  */
44
44
  export default defineNuxtModule({
45
45
  meta: {
46
- name: 'nuxt-graphql-middleware-playground',
46
+ name: 'dynamicParagraphResolver',
47
47
  },
48
48
  setup(_options, nuxt) {
49
49
  // Collect all paragraph fragments from the Nuxt layers.