@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.
- package/assets/css/ckeditor.css +4 -0
- package/assets/css/components/container.css +2 -2
- package/assets/css/tailwind.css +1 -1
- package/assets/css/typography.css +4 -0
- package/assets/symbols/download.svg +3 -0
- package/bundles.ts +4 -1
- package/components/Blokkli/TextMedia/index.vue +1 -2
- package/components/Blokkli/Timeline/Element/icms_timeline_element.svg +7 -0
- package/components/Blokkli/Timeline/Element/icon.svg +7 -0
- package/components/Blokkli/Timeline/Element/index.vue +14 -0
- package/components/Blokkli/Timeline/Layout/icms_layout_timeline.svg +16 -0
- package/components/Blokkli/Timeline/Layout/icon.svg +16 -0
- package/components/Blokkli/Timeline/Layout/index.vue +14 -0
- package/components/Blokkli/iFrame/icon-blokkli-option-large-spacing-bottom.svg +1 -0
- package/components/Blokkli/iFrame/icon-blokkli-option-large-spacing-top.svg +1 -0
- package/components/Blokkli/iFrame/icon-blokkli-option-no-spacing.svg +1 -0
- package/components/Blokkli/iFrame/icon-blokkli-option-small-spacing-bottom.svg +1 -0
- package/components/Blokkli/iFrame/icon-blokkli-option-small-spacing-top.svg +1 -0
- package/components/Blokkli/iFrame/{Layout/index.vue → index.vue} +2 -6
- package/components/DesignSystem/Atoms/Caption.vue +15 -0
- package/components/DesignSystem/Atoms/LinkListItem.vue +21 -0
- package/components/DesignSystem/Molecules/MediaSlider.vue +25 -8
- package/components/DesignSystem/Organisms/Map.vue +61 -0
- package/components/DesignSystem/Organisms/TimelineElement.vue +92 -0
- package/components/Media/Image/index.vue +4 -162
- package/components/Node/Icms/Page/SearchResult/fragment.graphql +8 -0
- package/components/Node/Icms/Page/SearchResult/index.vue +12 -0
- package/components/Node/Icms/Page/Teaser/fragment.graphql +17 -0
- package/components/Node/Icms/Page/Teaser/index.vue +20 -0
- package/components/Node/Icms/Page/fragment.graphql +18 -0
- package/components/Paragraph/CallToAction/index.vue +12 -8
- package/components/Paragraph/Card/Layout/index.vue +2 -2
- package/components/Paragraph/Downloads/index.vue +3 -14
- package/components/Paragraph/FAQ/Layout/index.vue +23 -1
- package/components/Paragraph/FlipTeasers/index.vue +2 -2
- package/components/Paragraph/Gallery/index.vue +32 -171
- package/components/Paragraph/HeroImage/index.vue +13 -4
- package/components/Paragraph/Media/index.vue +7 -2
- package/components/Paragraph/Table/index.vue +2 -2
- package/components/Paragraph/Team/Layout/index.vue +2 -2
- package/components/Paragraph/Teasers/fragment.graphql +2 -15
- package/components/Paragraph/Teasers/index.vue +11 -14
- package/components/Paragraph/TextMedia/index.vue +40 -33
- package/components/Paragraph/Timeline/Element/fragment.graphql +16 -0
- package/components/Paragraph/Timeline/Element/index.vue +31 -0
- package/components/Paragraph/Timeline/Layout/fragment.graphql +15 -0
- package/components/Paragraph/Timeline/Layout/index.vue +325 -0
- package/components/Paragraph/iFrame/{Layout/fragment.graphql → fragment.graphql} +2 -6
- package/components/Paragraph/iFrame/index.vue +56 -0
- package/components/Search/Facets/FacetDropdownUI.vue +222 -0
- package/components/Search/Facets/FacetedSearchUI.vue +397 -0
- package/components/Search/Facets/fragment.graphql +40 -0
- package/components/Section/Header/LanguageDropdown.vue +60 -73
- package/components/Section/Header/LanguageSwitcher.vue +37 -0
- package/components/Section/Header/MetaMenu.vue +10 -1
- package/components/Section/Header/index.vue +80 -67
- package/components/ui/accordion/Accordion.vue +2 -2
- package/components/ui/accordion/AccordionContent.vue +5 -5
- package/components/ui/accordion/AccordionItem.vue +9 -10
- package/components/ui/accordion/AccordionTrigger.vue +5 -5
- package/components/ui/alert/Alert.vue +17 -0
- package/components/ui/alert/AlertDescription.vue +14 -0
- package/components/ui/alert/AlertTitle.vue +14 -0
- package/components/ui/alert/index.ts +24 -0
- package/components/ui/alert-dialog/AlertDialog.vue +15 -0
- package/components/ui/alert-dialog/AlertDialogAction.vue +22 -0
- package/components/ui/alert-dialog/AlertDialogCancel.vue +29 -0
- package/components/ui/alert-dialog/AlertDialogContent.vue +43 -0
- package/components/ui/alert-dialog/AlertDialogDescription.vue +27 -0
- package/components/ui/alert-dialog/AlertDialogFooter.vue +21 -0
- package/components/ui/alert-dialog/AlertDialogHeader.vue +16 -0
- package/components/ui/alert-dialog/AlertDialogTitle.vue +24 -0
- package/components/ui/alert-dialog/AlertDialogTrigger.vue +12 -0
- package/components/ui/alert-dialog/index.ts +9 -0
- package/components/ui/aspect-ratio/AspectRatio.vue +12 -0
- package/components/ui/aspect-ratio/index.ts +1 -0
- package/components/ui/auto-form/AutoForm.vue +106 -0
- package/components/ui/auto-form/AutoFormField.vue +45 -0
- package/components/ui/auto-form/AutoFormFieldArray.vue +110 -0
- package/components/ui/auto-form/AutoFormFieldBoolean.vue +41 -0
- package/components/ui/auto-form/AutoFormFieldDate.vue +57 -0
- package/components/ui/auto-form/AutoFormFieldEnum.vue +49 -0
- package/components/ui/auto-form/AutoFormFieldFile.vue +74 -0
- package/components/ui/auto-form/AutoFormFieldInput.vue +36 -0
- package/components/ui/auto-form/AutoFormFieldNumber.vue +32 -0
- package/components/ui/auto-form/AutoFormFieldObject.vue +78 -0
- package/components/ui/auto-form/AutoFormLabel.vue +14 -0
- package/components/ui/auto-form/constant.ts +40 -0
- package/components/ui/auto-form/dependencies.ts +93 -0
- package/components/ui/auto-form/index.ts +15 -0
- package/components/ui/auto-form/interface.ts +95 -0
- package/components/ui/auto-form/utils.ts +188 -0
- package/components/ui/avatar/Avatar.vue +22 -0
- package/components/ui/avatar/AvatarFallback.vue +12 -0
- package/components/ui/avatar/AvatarImage.vue +10 -0
- package/components/ui/avatar/index.ts +25 -0
- package/components/ui/badge/Badge.vue +17 -0
- package/components/ui/badge/index.ts +26 -0
- package/components/ui/breadcrumb/Breadcrumb.vue +13 -0
- package/components/ui/breadcrumb/BreadcrumbEllipsis.vue +22 -0
- package/components/ui/breadcrumb/BreadcrumbItem.vue +16 -0
- package/components/ui/breadcrumb/BreadcrumbLink.vue +20 -0
- package/components/ui/breadcrumb/BreadcrumbList.vue +16 -0
- package/components/ui/breadcrumb/BreadcrumbPage.vue +19 -0
- package/components/ui/breadcrumb/BreadcrumbSeparator.vue +21 -0
- package/components/ui/breadcrumb/index.ts +7 -0
- package/components/ui/button/Button.vue +4 -2
- package/components/ui/button/index.ts +9 -9
- package/components/ui/calendar/Calendar.vue +62 -0
- package/components/ui/calendar/CalendarCell.vue +26 -0
- package/components/ui/calendar/CalendarCellTrigger.vue +40 -0
- package/components/ui/calendar/CalendarGrid.vue +26 -0
- package/components/ui/calendar/CalendarGridBody.vue +12 -0
- package/components/ui/calendar/CalendarGridHead.vue +12 -0
- package/components/ui/calendar/CalendarGridRow.vue +23 -0
- package/components/ui/calendar/CalendarHeadCell.vue +23 -0
- package/components/ui/calendar/CalendarHeader.vue +23 -0
- package/components/ui/calendar/CalendarHeading.vue +33 -0
- package/components/ui/calendar/CalendarNextButton.vue +34 -0
- package/components/ui/calendar/CalendarPrevButton.vue +34 -0
- package/components/ui/calendar/index.ts +12 -0
- package/components/ui/card/Card.vue +21 -0
- package/components/ui/card/CardContent.vue +14 -0
- package/components/ui/card/CardDescription.vue +14 -0
- package/components/ui/card/CardFooter.vue +14 -0
- package/components/ui/card/CardHeader.vue +14 -0
- package/components/ui/card/CardTitle.vue +18 -0
- package/components/ui/card/index.ts +6 -0
- package/components/ui/carousel/Carousel.vue +3 -23
- package/components/ui/carousel/CarouselContent.vue +1 -2
- package/components/ui/carousel/CarouselItem.vue +5 -7
- package/components/ui/carousel/CarouselNext.vue +7 -9
- package/components/ui/carousel/CarouselPrevious.vue +7 -9
- package/components/ui/carousel/index.ts +3 -1
- package/components/ui/carousel/interface.ts +3 -1
- package/components/ui/carousel/useCarousel.ts +13 -23
- package/components/ui/chart/ChartCrosshair.vue +45 -0
- package/components/ui/chart/ChartLegend.vue +50 -0
- package/components/ui/chart/ChartSingleTooltip.vue +64 -0
- package/components/ui/chart/ChartTooltip.vue +40 -0
- package/components/ui/chart/index.ts +18 -0
- package/components/ui/chart/interface.ts +64 -0
- package/components/ui/chart-area/AreaChart.vue +141 -0
- package/components/ui/chart-area/index.ts +66 -0
- package/components/ui/chart-bar/BarChart.vue +116 -0
- package/components/ui/chart-bar/index.ts +66 -0
- package/components/ui/chart-donut/DonutChart.vue +101 -0
- package/components/ui/chart-donut/index.ts +39 -0
- package/components/ui/chart-line/LineChart.vue +107 -0
- package/components/ui/chart-line/index.ts +66 -0
- package/components/ui/checkbox/Checkbox.vue +1 -1
- package/components/ui/collapsible/Collapsible.vue +15 -0
- package/components/ui/collapsible/CollapsibleContent.vue +12 -0
- package/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
- package/components/ui/collapsible/index.ts +3 -0
- package/components/ui/command/Command.vue +31 -0
- package/components/ui/command/CommandDialog.vue +21 -0
- package/components/ui/command/CommandEmpty.vue +21 -0
- package/components/ui/command/CommandGroup.vue +30 -0
- package/components/ui/command/CommandInput.vue +35 -0
- package/components/ui/command/CommandItem.vue +27 -0
- package/components/ui/command/CommandList.vue +28 -0
- package/components/ui/command/CommandSeparator.vue +24 -0
- package/components/ui/command/CommandShortcut.vue +14 -0
- package/components/ui/command/index.ts +9 -0
- package/components/ui/context-menu/ContextMenu.vue +15 -0
- package/components/ui/context-menu/ContextMenuCheckboxItem.vue +41 -0
- package/components/ui/context-menu/ContextMenuContent.vue +37 -0
- package/components/ui/context-menu/ContextMenuGroup.vue +12 -0
- package/components/ui/context-menu/ContextMenuItem.vue +35 -0
- package/components/ui/context-menu/ContextMenuLabel.vue +27 -0
- package/components/ui/context-menu/ContextMenuPortal.vue +12 -0
- package/components/ui/context-menu/ContextMenuRadioGroup.vue +19 -0
- package/components/ui/context-menu/ContextMenuRadioItem.vue +41 -0
- package/components/ui/context-menu/ContextMenuSeparator.vue +22 -0
- package/components/ui/context-menu/ContextMenuShortcut.vue +14 -0
- package/components/ui/context-menu/ContextMenuSub.vue +19 -0
- package/components/ui/context-menu/ContextMenuSubContent.vue +36 -0
- package/components/ui/context-menu/ContextMenuSubTrigger.vue +36 -0
- package/components/ui/context-menu/ContextMenuTrigger.vue +14 -0
- package/components/ui/context-menu/index.ts +14 -0
- package/components/ui/dialog/Dialog.vue +2 -6
- package/components/ui/dialog/DialogClose.vue +2 -1
- package/components/ui/dialog/DialogContent.vue +10 -12
- package/components/ui/dialog/DialogDescription.vue +6 -10
- package/components/ui/dialog/DialogScrollContent.vue +15 -21
- package/components/ui/dialog/DialogTitle.vue +9 -6
- package/components/ui/dialog/DialogTrigger.vue +2 -1
- package/components/ui/drawer/Drawer.vue +19 -0
- package/components/ui/drawer/DrawerContent.vue +28 -0
- package/components/ui/drawer/DrawerDescription.vue +21 -0
- package/components/ui/drawer/DrawerFooter.vue +14 -0
- package/components/ui/drawer/DrawerHeader.vue +14 -0
- package/components/ui/drawer/DrawerOverlay.vue +19 -0
- package/components/ui/drawer/DrawerTitle.vue +21 -0
- package/components/ui/drawer/index.ts +8 -0
- package/components/ui/dropdown-menu/DropdownMenu.vue +15 -0
- package/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +41 -0
- package/components/ui/dropdown-menu/DropdownMenuContent.vue +39 -0
- package/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
- package/components/ui/dropdown-menu/DropdownMenuItem.vue +30 -0
- package/components/ui/dropdown-menu/DropdownMenuLabel.vue +26 -0
- package/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +19 -0
- package/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +42 -0
- package/components/ui/dropdown-menu/DropdownMenuSeparator.vue +24 -0
- package/components/ui/dropdown-menu/DropdownMenuShortcut.vue +14 -0
- package/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
- package/components/ui/dropdown-menu/DropdownMenuSubContent.vue +31 -0
- package/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +35 -0
- package/components/ui/dropdown-menu/DropdownMenuTrigger.vue +14 -0
- package/components/ui/dropdown-menu/index.ts +16 -0
- package/components/ui/form/FormControl.vue +16 -0
- package/components/ui/form/FormDescription.vue +20 -0
- package/components/ui/form/FormItem.vue +20 -0
- package/components/ui/form/FormLabel.vue +23 -0
- package/components/ui/form/FormMessage.vue +16 -0
- package/components/ui/form/index.ts +7 -0
- package/components/ui/form/injectionKeys.ts +4 -0
- package/components/ui/form/useFormField.ts +30 -0
- package/components/ui/hover-card/HoverCard.vue +15 -0
- package/components/ui/hover-card/HoverCardContent.vue +43 -0
- package/components/ui/hover-card/HoverCardTrigger.vue +12 -0
- package/components/ui/hover-card/index.ts +3 -0
- package/components/ui/input/Input.vue +1 -1
- package/components/ui/menubar/Menubar.vue +36 -0
- package/components/ui/menubar/MenubarCheckboxItem.vue +41 -0
- package/components/ui/menubar/MenubarContent.vue +45 -0
- package/components/ui/menubar/MenubarGroup.vue +12 -0
- package/components/ui/menubar/MenubarItem.vue +36 -0
- package/components/ui/menubar/MenubarLabel.vue +14 -0
- package/components/ui/menubar/MenubarMenu.vue +12 -0
- package/components/ui/menubar/MenubarRadioGroup.vue +20 -0
- package/components/ui/menubar/MenubarRadioItem.vue +41 -0
- package/components/ui/menubar/MenubarSeparator.vue +21 -0
- package/components/ui/menubar/MenubarShortcut.vue +14 -0
- package/components/ui/menubar/MenubarSub.vue +20 -0
- package/components/ui/menubar/MenubarSubContent.vue +40 -0
- package/components/ui/menubar/MenubarSubTrigger.vue +32 -0
- package/components/ui/menubar/MenubarTrigger.vue +31 -0
- package/components/ui/menubar/index.ts +15 -0
- package/components/ui/navigation-menu/NavigationMenu.vue +34 -0
- package/components/ui/navigation-menu/NavigationMenuContent.vue +35 -0
- package/components/ui/navigation-menu/NavigationMenuIndicator.vue +26 -0
- package/components/ui/navigation-menu/NavigationMenuItem.vue +12 -0
- package/components/ui/navigation-menu/NavigationMenuLink.vue +19 -0
- package/components/ui/navigation-menu/NavigationMenuList.vue +31 -0
- package/components/ui/navigation-menu/NavigationMenuTrigger.vue +36 -0
- package/components/ui/navigation-menu/NavigationMenuViewport.vue +35 -0
- package/components/ui/navigation-menu/index.ts +14 -0
- package/components/ui/number-field/NumberField.vue +24 -0
- package/components/ui/number-field/NumberFieldContent.vue +14 -0
- package/components/ui/number-field/NumberFieldDecrement.vue +26 -0
- package/components/ui/number-field/NumberFieldIncrement.vue +26 -0
- package/components/ui/number-field/NumberFieldInput.vue +16 -0
- package/components/ui/number-field/index.ts +5 -0
- package/components/ui/pagination/PaginationEllipsis.vue +24 -0
- package/components/ui/pagination/PaginationFirst.vue +31 -0
- package/components/ui/pagination/PaginationLast.vue +31 -0
- package/components/ui/pagination/PaginationNext.vue +31 -0
- package/components/ui/pagination/PaginationPrev.vue +31 -0
- package/components/ui/pagination/index.ts +10 -0
- package/components/ui/pin-input/PinInput.vue +25 -0
- package/components/ui/pin-input/PinInputGroup.vue +20 -0
- package/components/ui/pin-input/PinInputInput.vue +20 -0
- package/components/ui/pin-input/PinInputSeparator.vue +16 -0
- package/components/ui/pin-input/index.ts +4 -0
- package/components/ui/popover/Popover.vue +15 -0
- package/components/ui/popover/PopoverContent.vue +49 -0
- package/components/ui/popover/PopoverTrigger.vue +12 -0
- package/components/ui/popover/index.ts +3 -0
- package/components/ui/progress/Progress.vue +41 -0
- package/components/ui/progress/index.ts +1 -0
- package/components/ui/radio-group/RadioGroupItem.vue +1 -1
- package/components/ui/range-calendar/RangeCalendar.vue +62 -0
- package/components/ui/range-calendar/RangeCalendarCell.vue +26 -0
- package/components/ui/range-calendar/RangeCalendarCellTrigger.vue +42 -0
- package/components/ui/range-calendar/RangeCalendarGrid.vue +26 -0
- package/components/ui/range-calendar/RangeCalendarGridBody.vue +12 -0
- package/components/ui/range-calendar/RangeCalendarGridHead.vue +12 -0
- package/components/ui/range-calendar/RangeCalendarGridRow.vue +23 -0
- package/components/ui/range-calendar/RangeCalendarHeadCell.vue +23 -0
- package/components/ui/range-calendar/RangeCalendarHeader.vue +23 -0
- package/components/ui/range-calendar/RangeCalendarHeading.vue +33 -0
- package/components/ui/range-calendar/RangeCalendarNextButton.vue +34 -0
- package/components/ui/range-calendar/RangeCalendarPrevButton.vue +34 -0
- package/components/ui/range-calendar/index.ts +12 -0
- package/components/ui/resizable/ResizableHandle.vue +28 -0
- package/components/ui/resizable/ResizablePanelGroup.vue +23 -0
- package/components/ui/resizable/index.ts +3 -0
- package/components/ui/scroll-area/ScrollArea.vue +31 -0
- package/components/ui/scroll-area/ScrollBar.vue +32 -0
- package/components/ui/scroll-area/index.ts +2 -0
- package/components/ui/select/SelectContent.vue +1 -1
- package/components/ui/select/SelectItem.vue +1 -1
- package/components/ui/select/SelectSeparator.vue +1 -1
- package/components/ui/select/SelectTrigger.vue +1 -1
- package/components/ui/separator/Separator.vue +37 -0
- package/components/ui/separator/index.ts +1 -0
- package/components/ui/sheet/Sheet.vue +15 -0
- package/components/ui/sheet/SheetClose.vue +12 -0
- package/components/ui/sheet/SheetContent.vue +58 -0
- package/components/ui/sheet/SheetDescription.vue +24 -0
- package/components/ui/sheet/SheetFooter.vue +19 -0
- package/components/ui/sheet/SheetHeader.vue +16 -0
- package/components/ui/sheet/SheetTitle.vue +24 -0
- package/components/ui/sheet/SheetTrigger.vue +12 -0
- package/components/ui/sheet/index.ts +32 -0
- package/components/ui/sidebar/Sidebar.vue +85 -0
- package/components/ui/sidebar/SidebarContent.vue +17 -0
- package/components/ui/sidebar/SidebarFooter.vue +17 -0
- package/components/ui/sidebar/SidebarGroup.vue +17 -0
- package/components/ui/sidebar/SidebarGroupAction.vue +26 -0
- package/components/ui/sidebar/SidebarGroupContent.vue +17 -0
- package/components/ui/sidebar/SidebarGroupLabel.vue +24 -0
- package/components/ui/sidebar/SidebarHeader.vue +17 -0
- package/components/ui/sidebar/SidebarInput.vue +21 -0
- package/components/ui/sidebar/SidebarInset.vue +20 -0
- package/components/ui/sidebar/SidebarMenu.vue +17 -0
- package/components/ui/sidebar/SidebarMenuAction.vue +34 -0
- package/components/ui/sidebar/SidebarMenuBadge.vue +25 -0
- package/components/ui/sidebar/SidebarMenuButton.vue +51 -0
- package/components/ui/sidebar/SidebarMenuButtonChild.vue +35 -0
- package/components/ui/sidebar/SidebarMenuItem.vue +17 -0
- package/components/ui/sidebar/SidebarMenuSkeleton.vue +34 -0
- package/components/ui/sidebar/SidebarMenuSub.vue +21 -0
- package/components/ui/sidebar/SidebarMenuSubButton.vue +35 -0
- package/components/ui/sidebar/SidebarMenuSubItem.vue +8 -0
- package/components/ui/sidebar/SidebarProvider.vue +81 -0
- package/components/ui/sidebar/SidebarRail.vue +32 -0
- package/components/ui/sidebar/SidebarSeparator.vue +18 -0
- package/components/ui/sidebar/SidebarTrigger.vue +26 -0
- package/components/ui/sidebar/index.ts +60 -0
- package/components/ui/sidebar/utils.ts +19 -0
- package/components/ui/skeleton/Skeleton.vue +14 -0
- package/components/ui/skeleton/index.ts +1 -0
- package/components/ui/slider/Slider.vue +37 -0
- package/components/ui/slider/index.ts +1 -0
- package/components/ui/sonner/Sonner.vue +23 -0
- package/components/ui/sonner/index.ts +1 -0
- package/components/ui/stepper/Stepper.vue +32 -0
- package/components/ui/stepper/StepperDescription.vue +24 -0
- package/components/ui/stepper/StepperIndicator.vue +36 -0
- package/components/ui/stepper/StepperItem.vue +28 -0
- package/components/ui/stepper/StepperSeparator.vue +32 -0
- package/components/ui/stepper/StepperTitle.vue +24 -0
- package/components/ui/stepper/StepperTrigger.vue +27 -0
- package/components/ui/stepper/index.ts +7 -0
- package/components/ui/switch/Switch.vue +40 -0
- package/components/ui/switch/index.ts +1 -0
- package/components/ui/table/Table.vue +16 -0
- package/components/ui/table/TableBody.vue +14 -0
- package/components/ui/table/TableCaption.vue +14 -0
- package/components/ui/table/TableCell.vue +21 -0
- package/components/ui/table/TableEmpty.vue +38 -0
- package/components/ui/table/TableFooter.vue +14 -0
- package/components/ui/table/TableHead.vue +14 -0
- package/components/ui/table/TableHeader.vue +14 -0
- package/components/ui/table/TableRow.vue +14 -0
- package/components/ui/table/index.ts +9 -0
- package/components/ui/tabs/TabsContent.vue +6 -11
- package/components/ui/tabs/TabsList.vue +8 -8
- package/components/ui/tabs/TabsTrigger.vue +9 -11
- package/components/ui/tags-input/TagsInput.vue +24 -0
- package/components/ui/tags-input/TagsInputInput.vue +21 -0
- package/components/ui/tags-input/TagsInputItem.vue +24 -0
- package/components/ui/tags-input/TagsInputItemDelete.vue +26 -0
- package/components/ui/tags-input/TagsInputItemText.vue +21 -0
- package/components/ui/tags-input/index.ts +5 -0
- package/components/ui/textarea/Textarea.vue +1 -1
- package/components/ui/toast/Toast.vue +30 -0
- package/components/ui/toast/ToastAction.vue +21 -0
- package/components/ui/toast/ToastClose.vue +24 -0
- package/components/ui/toast/ToastDescription.vue +21 -0
- package/components/ui/toast/ToastProvider.vue +12 -0
- package/components/ui/toast/ToastTitle.vue +21 -0
- package/components/ui/toast/ToastViewport.vue +19 -0
- package/components/ui/toast/Toaster.vue +30 -0
- package/components/ui/toast/index.ts +39 -0
- package/components/ui/toast/use-toast.ts +165 -0
- package/components/ui/toggle/Toggle.vue +38 -0
- package/components/ui/toggle/index.ts +28 -0
- package/components/ui/toggle-group/ToggleGroup.vue +36 -0
- package/components/ui/toggle-group/ToggleGroupItem.vue +37 -0
- package/components/ui/toggle-group/index.ts +2 -0
- package/components/ui/tooltip/Tooltip.vue +15 -0
- package/components/ui/tooltip/TooltipContent.vue +33 -0
- package/components/ui/tooltip/TooltipProvider.vue +12 -0
- package/components/ui/tooltip/TooltipTrigger.vue +12 -0
- package/components/ui/tooltip/index.ts +4 -0
- package/components/ui/v-calendar/Calendar.vue +343 -0
- package/components/ui/v-calendar/index.ts +22 -0
- package/composables/useAccordionScroll.ts +1 -1
- package/composables/useContentSearch.ts +0 -0
- package/composables/useImageSources.ts +208 -0
- package/composables/useLightbox.ts +81 -0
- package/composables/useMainMenuLinks.ts +1 -1
- package/composables/useMessageBus.ts +74 -0
- package/composables/useMetaMenuLinks.ts +1 -1
- package/composables/useNavigationOffset.ts +1 -1
- package/layouts/default.vue +2 -2
- package/layouts/error.vue +8 -10
- package/modules/dynamicEntityComponentResolver.ts +182 -0
- package/modules/dynamicParagraphResolver.ts +1 -1
- package/nuxt.config.ts +28 -32
- package/package.json +3 -2
- package/pages/[...slug]/index.vue +2 -2
- package/pages/index.vue +2 -2
- package/pages/node/[nid]/index.vue +2 -2
- package/queries/query.contentSearch.graphql +17 -0
- package/tailwind.config.ts +1 -0
- package/types/fslightbox-vue.d.ts +1 -0
- package/components/Blokkli/iFrame/Element/icon.svg +0 -5
- package/components/Blokkli/iFrame/Element/index.vue +0 -14
- package/components/Paragraph/iFrame/Element/fragment.graphql +0 -9
- package/components/Paragraph/iFrame/Element/index.vue +0 -16
- package/components/Paragraph/iFrame/Layout/index.vue +0 -161
- package/composables/languageLinks.ts +0 -31
- package/modules/dynamicNodeResolver.ts +0 -95
- package/pages/search/index.vue +0 -69
- package/pages/static-page/example.vue +0 -40
- package/queries/fragment.routeQuery.graphql +0 -51
- /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-large-spacing-bottom.svg +0 -0
- /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-large-spacing-top.svg +0 -0
- /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-no-spacing.svg +0 -0
- /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-small-spacing-bottom.svg +0 -0
- /package/components/Blokkli/{iFrame → Timeline}/Layout/icon-blokkli-option-small-spacing-top.svg +0 -0
- /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
|
+
}
|
|
@@ -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
|
+
}
|
package/layouts/default.vue
CHANGED
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:
|
|
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: '
|
|
46
|
+
name: 'dynamicParagraphResolver',
|
|
47
47
|
},
|
|
48
48
|
setup(_options, nuxt) {
|
|
49
49
|
// Collect all paragraph fragments from the Nuxt layers.
|