@iqual/nuxt-icms 1.3.1 → 1.4.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/symbols/chevron-right.svg +1 -1
- package/components/Blokkli/HeroImage/index.vue +1 -1
- package/components/Blokkli/Teasers/icon.svg +3 -3
- package/components/DesignSystem/Atoms/Button.vue +86 -36
- package/components/DesignSystem/Atoms/Caption.vue +10 -10
- package/components/DesignSystem/Atoms/Container.vue +10 -6
- package/components/DesignSystem/Atoms/GridRow.vue +4 -3
- package/components/DesignSystem/Atoms/LinkListItem.vue +31 -8
- package/components/DesignSystem/Molecules/ButtonGroup.vue +18 -3
- package/components/DesignSystem/Molecules/Card.vue +86 -31
- package/components/DesignSystem/Molecules/IconText.vue +37 -16
- package/components/DesignSystem/Molecules/MediaLightbox.vue +213 -58
- package/components/DesignSystem/Molecules/MediaSlider.vue +88 -25
- package/components/DesignSystem/Molecules/Partnership.vue +40 -9
- package/components/DesignSystem/Molecules/Table.vue +90 -25
- package/components/DesignSystem/Molecules/TitleComposition.vue +15 -12
- package/components/DesignSystem/Organisms/ContentBlock.vue +61 -15
- package/components/DesignSystem/Organisms/FacetedListing.vue +170 -0
- package/components/DesignSystem/Organisms/FlipTeaser.vue +119 -47
- package/components/DesignSystem/Organisms/HeaderHero.vue +167 -0
- package/components/DesignSystem/Organisms/HeaderTextImage.vue +71 -0
- package/components/DesignSystem/Organisms/LogoElement.vue +33 -10
- package/components/DesignSystem/Organisms/Map.vue +11 -6
- package/components/DesignSystem/Organisms/SearchResults.vue +41 -0
- package/components/DesignSystem/Organisms/TeamElement.vue +84 -20
- package/components/DesignSystem/Organisms/TeaserCard.vue +87 -34
- package/components/DesignSystem/Organisms/Testimonial.vue +82 -12
- package/components/DesignSystem/Organisms/TimelineElement.vue +42 -12
- package/components/DesignSystem/Organisms/TwoColumnTextElement.vue +44 -9
- package/components/DesignSystem/Pages/Search.vue +39 -0
- package/components/Drupal/Breadcrumb/index.vue +16 -5
- package/components/Drupal/Messages/index.vue +16 -5
- package/components/Drupal/Webform/fragment.graphql +8 -5
- package/components/Drupal/Webform/index.vue +20 -9
- package/components/Drupal/Webform/query.graphql +18 -16
- package/components/Form/CheckboxInput.vue +6 -6
- package/components/Form/CheckboxInputs.vue +5 -5
- package/components/Form/FileUploadInput.vue +6 -6
- package/components/Form/RadioButtonsInput.vue +5 -5
- package/components/Form/SelectInput.vue +7 -7
- package/components/Form/SubmitButton.vue +1 -1
- package/components/Form/TextAreaInput.vue +2 -2
- package/components/Form/TextEmailInput.vue +2 -2
- package/components/Form/TextInput.vue +2 -2
- package/components/Form/TextPhoneInput.vue +2 -2
- package/components/Form/composables/useFormElement.ts +5 -5
- package/components/Form/utils/types.ts +8 -7
- package/components/Media/Icon/index.vue +10 -6
- package/components/Media/Image/index.vue +26 -20
- package/components/Media/RemoteVideo/index.vue +34 -21
- package/components/Media/Video/index.vue +6 -5
- package/components/Node/Icms/Page/Teaser/index.vue +6 -4
- package/components/Node/Icms/Page/index.vue +2 -2
- package/components/Paragraph/Button/Element/index.vue +9 -2
- package/components/Paragraph/CallToAction/index.vue +43 -10
- package/components/Paragraph/Card/Element/index.vue +2 -1
- package/components/Paragraph/Card/Layout/index.vue +29 -10
- package/components/Paragraph/Contact/index.vue +41 -12
- package/components/Paragraph/Downloads/index.vue +82 -33
- package/components/Paragraph/FAQ/Element/index.vue +41 -12
- package/components/Paragraph/FAQ/Layout/index.vue +47 -13
- package/components/Paragraph/FlipTeasers/index.vue +26 -6
- package/components/Paragraph/Gallery/index.vue +42 -10
- package/components/Paragraph/HeroImage/index.vue +62 -16
- package/components/Paragraph/IconText/Element/index.vue +7 -1
- package/components/Paragraph/IconText/Layout/index.vue +39 -12
- package/components/Paragraph/Introduction/index.vue +50 -15
- package/components/Paragraph/Logo/Element/fragment.graphql +1 -0
- package/components/Paragraph/Logo/Element/index.vue +7 -2
- package/components/Paragraph/Media/index.vue +32 -31
- package/components/Paragraph/Partnerships/Element/fragment.graphql +1 -0
- package/components/Paragraph/Partnerships/Element/index.vue +7 -0
- package/components/Paragraph/Partnerships/Layout/index.vue +100 -27
- package/components/Paragraph/SingleTestimonial/index.vue +58 -15
- package/components/Paragraph/Table/index.vue +32 -9
- package/components/Paragraph/Tabs/Element/index.vue +44 -10
- package/components/Paragraph/Tabs/Layout/index.vue +123 -37
- package/components/Paragraph/Team/Element/index.vue +18 -1
- package/components/Paragraph/Team/Layout/index.vue +30 -7
- package/components/Paragraph/Teasers/index.vue +33 -7
- package/components/Paragraph/Testimonial/Element/index.vue +30 -5
- package/components/Paragraph/Testimonial/Layout/index.vue +78 -24
- package/components/Paragraph/Text/index.vue +32 -10
- package/components/Paragraph/TextMedia/index.vue +44 -13
- package/components/Paragraph/Timeline/Element/index.vue +23 -7
- package/components/Paragraph/Timeline/Layout/index.vue +232 -67
- package/components/Paragraph/TwoColumnText/Element/index.vue +20 -3
- package/components/Paragraph/TwoColumnText/Layout/index.vue +8 -1
- package/components/Paragraph/iFrame/index.vue +31 -11
- package/components/Search/Facets/FacetDropdownUI.vue +351 -77
- package/components/Search/Facets/FacetedSearchUI.vue +257 -101
- package/components/Search/Facets/fragment.graphql +5 -1
- package/components/Search/Input/index.vue +78 -20
- package/components/Section/Footer/index.vue +170 -30
- package/components/Section/Header/Buttons.vue +34 -0
- package/components/Section/Header/DesktopMainMenu.vue +160 -0
- package/components/Section/Header/DesktopMainMenuDropdown.vue +170 -0
- package/components/Section/Header/LanguageDropdown.vue +95 -64
- package/components/Section/Header/LanguageLinks.vue +39 -0
- package/components/Section/Header/Logo.vue +24 -0
- package/components/Section/Header/MainButtons.vue +31 -0
- package/components/Section/Header/MenuIcon.vue +61 -49
- package/components/Section/Header/MetaButtons.vue +31 -0
- package/components/Section/Header/MetaMenu.vue +55 -53
- package/components/Section/Header/MobileMainMenu.vue +23 -0
- package/components/Section/Header/MobileMainMenuItem.vue +191 -0
- package/components/Section/Header/index.vue +183 -185
- package/composables/useMenu.ts +2 -2
- package/composables/useMobileMenuOverlayBus.ts +44 -0
- package/composables/useNavigationOffset.ts +2 -2
- package/composables/useTheme.ts +75 -0
- package/formkit.theme.ts +541 -586
- package/layouts/default.vue +7 -35
- package/layouts/error.vue +7 -32
- package/nuxt.config.ts +13 -0
- package/package.json +1 -1
- package/plugins/initData.ts +8 -5
- package/queries/query.initData.graphql +4 -2
- package/tailwind.config.ts +11 -11
- package/types/global.ts +1 -0
- package/components/Section/Header/GlobalMenu.vue +0 -335
- package/components/Section/Header/LanguageSwitcher.vue +0 -37
package/layouts/default.vue
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<SectionHeader
|
|
4
|
-
@menu:open="menuOpen"
|
|
5
|
-
@menu:close:start="menuCloseStart"
|
|
6
|
-
@menu:close:finished="menuCloseFinish"
|
|
7
|
-
/>
|
|
3
|
+
<SectionHeader />
|
|
8
4
|
|
|
9
5
|
<!-- <NuxtPageDependency>
|
|
10
6
|
<DrupalBreadcrumb v-if="showBreadcrumb" :links="breadcrumb" />
|
|
@@ -25,16 +21,6 @@
|
|
|
25
21
|
const route = useRoute()
|
|
26
22
|
const drupalUser = useDrupalUser()
|
|
27
23
|
const language = useCurrentLanguage()
|
|
28
|
-
const breadcrumb = useBreadcrumbLinks()
|
|
29
|
-
const viewport = useViewport()
|
|
30
|
-
|
|
31
|
-
const isEditing = computed(
|
|
32
|
-
() =>
|
|
33
|
-
!!(route.query.blokkliEditing || route.query.blokkliPreview) &&
|
|
34
|
-
drupalUser.value.accessToolbar,
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
const showBreadcrumb = computed(() => !route.meta.hideBreadcrumb)
|
|
38
24
|
|
|
39
25
|
useHead({
|
|
40
26
|
htmlAttrs: {
|
|
@@ -42,25 +28,11 @@ useHead({
|
|
|
42
28
|
},
|
|
43
29
|
})
|
|
44
30
|
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
isMenuOpen.value = true
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function menuCloseStart() {
|
|
54
|
-
if (viewport.isLessThan('2xl')) {
|
|
55
|
-
isMenuOpen.value = false
|
|
56
|
-
hasMenuFinishedClosing.value = false
|
|
57
|
-
}
|
|
58
|
-
}
|
|
31
|
+
const isEditing = computed(
|
|
32
|
+
() =>
|
|
33
|
+
!!(route.query.blokkliEditing || route.query.blokkliPreview) &&
|
|
34
|
+
drupalUser.value.accessToolbar,
|
|
35
|
+
)
|
|
59
36
|
|
|
60
|
-
|
|
61
|
-
if (viewport.isLessThan('2xl')) {
|
|
62
|
-
window.document.body.classList.remove('overflow-y-hidden')
|
|
63
|
-
hasMenuFinishedClosing.value = true
|
|
64
|
-
}
|
|
65
|
-
}
|
|
37
|
+
const showBreadcrumb = computed(() => !route.meta.hideBreadcrumb)
|
|
66
38
|
</script>
|
package/layouts/error.vue
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<SectionHeader
|
|
4
|
-
@menu:open="menuOpen"
|
|
5
|
-
@menu:close:start="menuCloseStart"
|
|
6
|
-
@menu:close:finished="menuCloseFinish"
|
|
7
|
-
/>
|
|
3
|
+
<SectionHeader />
|
|
8
4
|
|
|
9
5
|
<!-- <NuxtPageDependency>
|
|
10
6
|
<DrupalBreadcrumb v-if="showBreadcrumb" :links="breadcrumb" />
|
|
@@ -33,14 +29,15 @@
|
|
|
33
29
|
</template>
|
|
34
30
|
|
|
35
31
|
<script setup lang="ts">
|
|
36
|
-
import { useError } from '#app'
|
|
37
|
-
import { useHead } from '#imports'
|
|
38
|
-
|
|
39
32
|
const route = useRoute()
|
|
40
33
|
const drupalUser = useDrupalUser()
|
|
41
34
|
const language = useCurrentLanguage()
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
|
|
36
|
+
useHead({
|
|
37
|
+
htmlAttrs: {
|
|
38
|
+
lang: language.value,
|
|
39
|
+
},
|
|
40
|
+
})
|
|
44
41
|
|
|
45
42
|
const isEditing = computed(
|
|
46
43
|
() =>
|
|
@@ -71,26 +68,4 @@ const errorMessage = computed(() => {
|
|
|
71
68
|
useHead({
|
|
72
69
|
title: errorMessage,
|
|
73
70
|
})
|
|
74
|
-
|
|
75
|
-
const isMenuOpen = ref(false)
|
|
76
|
-
const hasMenuFinishedClosing = ref(true)
|
|
77
|
-
|
|
78
|
-
function menuOpen() {
|
|
79
|
-
window.document.body.classList.add('overflow-y-hidden')
|
|
80
|
-
isMenuOpen.value = true
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function menuCloseStart() {
|
|
84
|
-
if (viewport.isLessThan('2xl')) {
|
|
85
|
-
isMenuOpen.value = false
|
|
86
|
-
hasMenuFinishedClosing.value = false
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function menuCloseFinish() {
|
|
91
|
-
if (viewport.isLessThan('2xl')) {
|
|
92
|
-
window.document.body.classList.remove('overflow-y-hidden')
|
|
93
|
-
hasMenuFinishedClosing.value = true
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
71
|
</script>
|
package/nuxt.config.ts
CHANGED
|
@@ -249,6 +249,9 @@ export default defineNuxtConfig({
|
|
|
249
249
|
allowedHosts: true,
|
|
250
250
|
},
|
|
251
251
|
plugins: [],
|
|
252
|
+
optimizeDeps: {
|
|
253
|
+
include: ['maplibre-gl'],
|
|
254
|
+
},
|
|
252
255
|
},
|
|
253
256
|
|
|
254
257
|
/*
|
|
@@ -496,6 +499,16 @@ export default defineNuxtConfig({
|
|
|
496
499
|
label: 'Reverse columns',
|
|
497
500
|
default: false,
|
|
498
501
|
},
|
|
502
|
+
imageAlignment: {
|
|
503
|
+
type: 'radios',
|
|
504
|
+
label: 'Image Alingment',
|
|
505
|
+
default: 'center',
|
|
506
|
+
options: {
|
|
507
|
+
top: 'Top',
|
|
508
|
+
center: 'Center',
|
|
509
|
+
bottom: 'Bottom',
|
|
510
|
+
},
|
|
511
|
+
},
|
|
499
512
|
},
|
|
500
513
|
translations: {
|
|
501
514
|
en: {
|
package/package.json
CHANGED
package/plugins/initData.ts
CHANGED
|
@@ -11,6 +11,9 @@ export type MappedMenuLink = {
|
|
|
11
11
|
id: string
|
|
12
12
|
label: string
|
|
13
13
|
href?: string
|
|
14
|
+
target?: string
|
|
15
|
+
rel?: string
|
|
16
|
+
additionalClass?: string
|
|
14
17
|
children?: MappedMenuLink[]
|
|
15
18
|
}
|
|
16
19
|
export interface InitData {
|
|
@@ -32,9 +35,6 @@ export function mapMenuLinkTree(
|
|
|
32
35
|
}
|
|
33
36
|
return menuLinks.map((menuLink) => {
|
|
34
37
|
const id = `menu-item-${context.count++}`
|
|
35
|
-
// Extract the basic properties
|
|
36
|
-
const label = menuLink.link.label
|
|
37
|
-
const href = menuLink.link.url?.path
|
|
38
38
|
// Process children if they exist
|
|
39
39
|
const children =
|
|
40
40
|
'subtree' in menuLink && menuLink.subtree && menuLink.subtree.length > 0
|
|
@@ -43,8 +43,11 @@ export function mapMenuLinkTree(
|
|
|
43
43
|
// Return the mapped menu link
|
|
44
44
|
return {
|
|
45
45
|
id,
|
|
46
|
-
label,
|
|
47
|
-
href,
|
|
46
|
+
label: menuLink.link.label,
|
|
47
|
+
href: menuLink.link.url?.path,
|
|
48
|
+
target: menuLink.link?.target,
|
|
49
|
+
rel: menuLink.link?.rel,
|
|
50
|
+
additionalClass: menuLink.link?.additionalClass,
|
|
48
51
|
children,
|
|
49
52
|
}
|
|
50
53
|
})
|
|
@@ -56,11 +56,13 @@ fragment menuLinkTreeElementFirst on MenuLinkTreeElement {
|
|
|
56
56
|
|
|
57
57
|
fragment menuLinkTree on MenuLinkTreeElement {
|
|
58
58
|
link {
|
|
59
|
+
label
|
|
59
60
|
url {
|
|
60
61
|
path
|
|
61
62
|
}
|
|
62
|
-
attribute(name: "target")
|
|
63
|
-
|
|
63
|
+
target: attribute(name: "target")
|
|
64
|
+
rel: attribute(name: "rel")
|
|
65
|
+
additionalClass: attribute(name: "class")
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
|
package/tailwind.config.ts
CHANGED
|
@@ -39,18 +39,18 @@ const colors = {
|
|
|
39
39
|
'950': 'rgb(11, 45, 70)',
|
|
40
40
|
},
|
|
41
41
|
gray: {
|
|
42
|
-
DEFAULT: 'rgb(
|
|
42
|
+
DEFAULT: 'rgb(116, 116, 116)',
|
|
43
43
|
'50': 'rgb(246, 246, 246)',
|
|
44
|
-
'100': 'rgb(
|
|
45
|
-
'200': 'rgb(
|
|
46
|
-
'300': 'rgb(
|
|
47
|
-
'400': 'rgb(
|
|
48
|
-
'500': 'rgb(
|
|
49
|
-
'600': 'rgb(
|
|
50
|
-
'700': 'rgb(
|
|
51
|
-
'800': 'rgb(
|
|
52
|
-
'900': 'rgb(
|
|
53
|
-
'950': 'rgb(
|
|
44
|
+
'100': 'rgb(235, 235, 235)',
|
|
45
|
+
'200': 'rgb(218, 218, 218)',
|
|
46
|
+
'300': 'rgb(182, 182, 182)',
|
|
47
|
+
'400': 'rgb(150, 150, 150)',
|
|
48
|
+
'500': 'rgb(116, 116, 116)',
|
|
49
|
+
'600': 'rgb(94, 94, 94)',
|
|
50
|
+
'700': 'rgb(73, 73, 73)',
|
|
51
|
+
'800': 'rgb(57, 57, 57)',
|
|
52
|
+
'900': 'rgb(44, 44, 44)',
|
|
53
|
+
'950': 'rgb(36, 36, 36)',
|
|
54
54
|
},
|
|
55
55
|
error: {
|
|
56
56
|
DEFAULT: 'rgb(229, 62, 62)',
|
package/types/global.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ColorScheme = 'none' | 'dark' | 'light' | 'accent' | undefined
|
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<nav
|
|
3
|
-
ref="globalMenu"
|
|
4
|
-
class="border-b-1 z-30 mb-8 border-b-gray-100 py-8 2xl:mb-0 2xl:h-full 2xl:border-0 2xl:py-0 2xl:pl-12"
|
|
5
|
-
v-on="!isMobile ? { mouseleave: onNavbarMouseLeave } : {}"
|
|
6
|
-
>
|
|
7
|
-
<ul
|
|
8
|
-
role="menu"
|
|
9
|
-
class="flex flex-col flex-wrap justify-end text-base 2xl:h-full 2xl:flex-row 2xl:items-center 2xl:gap-8 2xl:border-0 2xl:font-medium"
|
|
10
|
-
>
|
|
11
|
-
<li
|
|
12
|
-
v-for="(link, mainIndex) in menuItems"
|
|
13
|
-
:key="`global_${mainIndex}`"
|
|
14
|
-
role="menuitem"
|
|
15
|
-
class="group/main relative flex flex-col items-stretch 2xl:h-full 2xl:flex-row"
|
|
16
|
-
>
|
|
17
|
-
<VuepalLink
|
|
18
|
-
:to="link?.href"
|
|
19
|
-
:aria-controls="'firstLevel-' + mainIndex"
|
|
20
|
-
:aria-expanded="hoverMain === mainIndex"
|
|
21
|
-
:aria-haspopup="!!link.children?.length"
|
|
22
|
-
class="group-hover/main:text-primary-500 flex w-full items-center justify-between whitespace-nowrap motion-safe:transition-colors motion-safe:duration-200 2xl:size-auto 2xl:py-0"
|
|
23
|
-
:class="
|
|
24
|
-
link?.href === menuItemActive?.href
|
|
25
|
-
? 'text-primary-500'
|
|
26
|
-
: 'text-black'
|
|
27
|
-
"
|
|
28
|
-
@mouseenter="!isMobile && onMenuInteraction('main', mainIndex)"
|
|
29
|
-
@mouseleave="!isMobile && onMouseLeave()"
|
|
30
|
-
@click="onLinkClick"
|
|
31
|
-
>
|
|
32
|
-
{{ link.label }}
|
|
33
|
-
<div
|
|
34
|
-
class="grid size-10 place-content-center 2xl:size-auto"
|
|
35
|
-
@click.prevent.stop="
|
|
36
|
-
isMobile && onMenuInteraction('main', mainIndex)
|
|
37
|
-
"
|
|
38
|
-
>
|
|
39
|
-
<SpriteSymbol
|
|
40
|
-
v-show="link?.children?.length"
|
|
41
|
-
name="chevron-down"
|
|
42
|
-
:aria-label="
|
|
43
|
-
isMobile
|
|
44
|
-
? $texts('header.submenu_toggle', 'Toggle submenu')
|
|
45
|
-
: undefined
|
|
46
|
-
"
|
|
47
|
-
:aria-hidden="!isMobile"
|
|
48
|
-
class="size-5 cursor-pointer text-black transition-transform duration-300 2xl:ml-2"
|
|
49
|
-
:class="{
|
|
50
|
-
'rotate-180': isMobile ? hoverMain === mainIndex : false,
|
|
51
|
-
'2xl:rotate-180': !isMobile && hoverMain === mainIndex,
|
|
52
|
-
}"
|
|
53
|
-
/>
|
|
54
|
-
</div>
|
|
55
|
-
</VuepalLink>
|
|
56
|
-
|
|
57
|
-
<!-- First level menu -->
|
|
58
|
-
<transition :name="isMobile ? 'slideDown' : 'fade'">
|
|
59
|
-
<div
|
|
60
|
-
v-show="link.children?.length && hoverMain === mainIndex"
|
|
61
|
-
:id="'firstLevel-' + mainIndex"
|
|
62
|
-
class="w-max min-w-full 2xl:absolute 2xl:left-0 2xl:top-full 2xl:border 2xl:border-gray-100 2xl:bg-white 2xl:text-sm"
|
|
63
|
-
>
|
|
64
|
-
<ul role="menu" class="ml-4 2xl:ml-0">
|
|
65
|
-
<li
|
|
66
|
-
v-for="(firstLevelLink, firstLevelIndex) in link.children"
|
|
67
|
-
:key="`firstLevel_${firstLevelIndex}`"
|
|
68
|
-
role="menuitem"
|
|
69
|
-
class="group/first relative"
|
|
70
|
-
@mouseleave="!isMobile && onMouseLeave()"
|
|
71
|
-
>
|
|
72
|
-
<VuepalLink
|
|
73
|
-
:to="firstLevelLink.href"
|
|
74
|
-
:aria-controls="'secondLevel-' + firstLevelIndex"
|
|
75
|
-
:aria-expanded="hoverFirst === firstLevelIndex"
|
|
76
|
-
:aria-haspopup="!!firstLevelLink?.children?.length"
|
|
77
|
-
class="group-hover/first:text-primary-500 flex w-full items-center justify-between whitespace-nowrap no-underline motion-safe:transition-colors motion-safe:duration-200 2xl:px-4 2xl:py-3"
|
|
78
|
-
:class="
|
|
79
|
-
firstLevelLink?.href === menuItemActiveLevel1?.href
|
|
80
|
-
? 'text-primary-500'
|
|
81
|
-
: 'text-black'
|
|
82
|
-
"
|
|
83
|
-
@mouseenter="
|
|
84
|
-
!isMobile && onMenuInteraction('first', firstLevelIndex)
|
|
85
|
-
"
|
|
86
|
-
@mouseleave="!isMobile && onMouseLeave()"
|
|
87
|
-
@click="onLinkClick"
|
|
88
|
-
>
|
|
89
|
-
{{ firstLevelLink.label }}
|
|
90
|
-
<div
|
|
91
|
-
class="grid size-10 place-content-center 2xl:size-auto"
|
|
92
|
-
@click.prevent.stop="
|
|
93
|
-
isMobile && onMenuInteraction('first', firstLevelIndex)
|
|
94
|
-
"
|
|
95
|
-
>
|
|
96
|
-
<SpriteSymbol
|
|
97
|
-
v-show="firstLevelLink?.children?.length"
|
|
98
|
-
name="chevron-down"
|
|
99
|
-
:aria-label="
|
|
100
|
-
isMobile
|
|
101
|
-
? $texts('header.submenu_toggle', 'Toggle submenu')
|
|
102
|
-
: undefined
|
|
103
|
-
"
|
|
104
|
-
:aria-hidden="!isMobile"
|
|
105
|
-
class="size-5 cursor-pointer text-black transition-transform duration-300 2xl:ml-2 2xl:size-4 2xl:-rotate-90"
|
|
106
|
-
:class="{
|
|
107
|
-
'rotate-180': isMobile
|
|
108
|
-
? hoverFirst === firstLevelIndex
|
|
109
|
-
: false,
|
|
110
|
-
}"
|
|
111
|
-
/>
|
|
112
|
-
</div>
|
|
113
|
-
</VuepalLink>
|
|
114
|
-
|
|
115
|
-
<!-- Second level menu -->
|
|
116
|
-
<transition :name="isMobile ? 'slideDown' : 'fade'">
|
|
117
|
-
<div
|
|
118
|
-
v-show="
|
|
119
|
-
firstLevelLink.children?.length &&
|
|
120
|
-
hoverFirst === firstLevelIndex
|
|
121
|
-
"
|
|
122
|
-
:id="'secondLevel-' + firstLevelIndex"
|
|
123
|
-
class="min-w-full 2xl:absolute 2xl:-top-px 2xl:left-full 2xl:border 2xl:border-gray-100 2xl:bg-white 2xl:text-sm"
|
|
124
|
-
>
|
|
125
|
-
<ul role="menu" class="ml-4 2xl:ml-0">
|
|
126
|
-
<li
|
|
127
|
-
v-for="(
|
|
128
|
-
secondLevelLink, secondLevelIndex
|
|
129
|
-
) in firstLevelLink.children"
|
|
130
|
-
:key="`secondLevel_${secondLevelIndex}`"
|
|
131
|
-
role="menuitem"
|
|
132
|
-
class="group/second relative"
|
|
133
|
-
>
|
|
134
|
-
<VuepalLink
|
|
135
|
-
:to="secondLevelLink.href"
|
|
136
|
-
:aria-controls="'thirdLevel-' + secondLevelIndex"
|
|
137
|
-
:aria-expanded="hoverSecond === secondLevelIndex"
|
|
138
|
-
:aria-haspopup="!!secondLevelLink?.children?.length"
|
|
139
|
-
class="group-hover/second:text-primary-500 flex w-full items-center justify-between whitespace-nowrap no-underline motion-safe:transition-colors motion-safe:duration-200 2xl:px-4 2xl:py-3"
|
|
140
|
-
:class="
|
|
141
|
-
secondLevelLink?.href === menuItemActiveLevel2?.href
|
|
142
|
-
? 'text-primary-500'
|
|
143
|
-
: 'text-black'
|
|
144
|
-
"
|
|
145
|
-
@mouseenter="
|
|
146
|
-
!isMobile &&
|
|
147
|
-
onMenuInteraction('second', secondLevelIndex)
|
|
148
|
-
"
|
|
149
|
-
@mouseleave="!isMobile && onMouseLeave()"
|
|
150
|
-
@click="onLinkClick"
|
|
151
|
-
>
|
|
152
|
-
{{ secondLevelLink.label }}
|
|
153
|
-
<div
|
|
154
|
-
class="grid size-10 place-content-center 2xl:size-auto"
|
|
155
|
-
@click.prevent.stop="
|
|
156
|
-
isMobile &&
|
|
157
|
-
onMenuInteraction('first', firstLevelIndex)
|
|
158
|
-
"
|
|
159
|
-
>
|
|
160
|
-
<SpriteSymbol
|
|
161
|
-
v-show="secondLevelLink?.children?.length"
|
|
162
|
-
name="chevron-down"
|
|
163
|
-
:aria-label="
|
|
164
|
-
isMobile
|
|
165
|
-
? $texts(
|
|
166
|
-
'header.submenu_toggle',
|
|
167
|
-
'Toggle submenu',
|
|
168
|
-
)
|
|
169
|
-
: undefined
|
|
170
|
-
"
|
|
171
|
-
:aria-hidden="!isMobile"
|
|
172
|
-
class="size-5 cursor-pointer text-black transition-transform duration-300 2xl:ml-2 2xl:size-4 2xl:-rotate-90"
|
|
173
|
-
:class="{
|
|
174
|
-
'rotate-180': isMobile
|
|
175
|
-
? hoverSecond === secondLevelIndex
|
|
176
|
-
: false,
|
|
177
|
-
}"
|
|
178
|
-
/>
|
|
179
|
-
</div>
|
|
180
|
-
</VuepalLink>
|
|
181
|
-
|
|
182
|
-
<!-- Third level menu -->
|
|
183
|
-
<transition :name="isMobile ? 'slideDown' : 'fade'">
|
|
184
|
-
<div
|
|
185
|
-
v-show="
|
|
186
|
-
secondLevelLink.children?.length &&
|
|
187
|
-
hoverSecond === secondLevelIndex
|
|
188
|
-
"
|
|
189
|
-
:id="'thirdLevel-' + secondLevelIndex"
|
|
190
|
-
class="min-w-full 2xl:absolute 2xl:-top-px 2xl:left-full 2xl:border 2xl:border-gray-100 2xl:bg-white 2xl:text-sm"
|
|
191
|
-
>
|
|
192
|
-
<ul role="menu" class="ml-4 2xl:ml-0">
|
|
193
|
-
<li
|
|
194
|
-
v-for="(
|
|
195
|
-
thirdLevelLink, thirdLevelIndex
|
|
196
|
-
) in secondLevelLink.children"
|
|
197
|
-
:key="`thirdLevel_${thirdLevelIndex}`"
|
|
198
|
-
role="menuitem"
|
|
199
|
-
class="group/third relative"
|
|
200
|
-
>
|
|
201
|
-
<VuepalLink
|
|
202
|
-
:to="thirdLevelLink.href"
|
|
203
|
-
class="group-hover/third:text-primary-500 flex h-10 w-full items-center whitespace-nowrap no-underline motion-safe:transition-colors motion-safe:duration-200 2xl:h-auto 2xl:px-4 2xl:py-3"
|
|
204
|
-
:class="
|
|
205
|
-
thirdLevelLink?.href ===
|
|
206
|
-
menuTiemActiveLevel3?.href
|
|
207
|
-
? 'text-primary-500'
|
|
208
|
-
: 'text-black'
|
|
209
|
-
"
|
|
210
|
-
@mouseenter="
|
|
211
|
-
onMenuInteraction('third', thirdLevelIndex)
|
|
212
|
-
"
|
|
213
|
-
@click="onLinkClick"
|
|
214
|
-
>
|
|
215
|
-
{{ thirdLevelLink.label }}
|
|
216
|
-
</VuepalLink>
|
|
217
|
-
</li>
|
|
218
|
-
</ul>
|
|
219
|
-
</div>
|
|
220
|
-
</transition>
|
|
221
|
-
</li>
|
|
222
|
-
</ul>
|
|
223
|
-
</div>
|
|
224
|
-
</transition>
|
|
225
|
-
</li>
|
|
226
|
-
</ul>
|
|
227
|
-
</div>
|
|
228
|
-
</transition>
|
|
229
|
-
</li>
|
|
230
|
-
</ul>
|
|
231
|
-
</nav>
|
|
232
|
-
</template>
|
|
233
|
-
|
|
234
|
-
<script lang="ts" setup>
|
|
235
|
-
type menuLevel = 'main' | 'first' | 'second' | 'third'
|
|
236
|
-
|
|
237
|
-
const globalMenu = ref<HTMLElement | null>(null)
|
|
238
|
-
const { isMobile } = useIsMobile()
|
|
239
|
-
const {
|
|
240
|
-
menuItems,
|
|
241
|
-
menuItemActive,
|
|
242
|
-
menuItemActiveLevel1,
|
|
243
|
-
menuItemActiveLevel2,
|
|
244
|
-
menuTiemActiveLevel3,
|
|
245
|
-
} = await useMenu('mainMenu')
|
|
246
|
-
const hoverMain = ref(-1)
|
|
247
|
-
const hoverFirst = ref(-1)
|
|
248
|
-
const hoverSecond = ref(-1)
|
|
249
|
-
const hoverThird = ref(-1)
|
|
250
|
-
let timeout: any = null
|
|
251
|
-
|
|
252
|
-
const emit = defineEmits(['menu:link-click'])
|
|
253
|
-
|
|
254
|
-
const { $texts } = useNuxtApp()
|
|
255
|
-
|
|
256
|
-
defineExpose({
|
|
257
|
-
element: globalMenu,
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
function setActive(level: menuLevel, index: number) {
|
|
261
|
-
const hoverStates = {
|
|
262
|
-
main: hoverMain,
|
|
263
|
-
first: hoverFirst,
|
|
264
|
-
second: hoverSecond,
|
|
265
|
-
third: hoverThird,
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (level === 'main') {
|
|
269
|
-
hoverFirst.value = -1
|
|
270
|
-
hoverSecond.value = -1
|
|
271
|
-
hoverThird.value = -1
|
|
272
|
-
} else if (level === 'first') {
|
|
273
|
-
hoverSecond.value = -1
|
|
274
|
-
hoverThird.value = -1
|
|
275
|
-
} else if (level === 'second') {
|
|
276
|
-
hoverThird.value = -1
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const state = hoverStates[level]
|
|
280
|
-
if (isMobile.value) {
|
|
281
|
-
state.value = state.value === index ? -1 : index
|
|
282
|
-
} else {
|
|
283
|
-
state.value = index
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function onMenuInteraction(level: menuLevel, index: number) {
|
|
288
|
-
clearTimeout(timeout)
|
|
289
|
-
timeout = setTimeout(() => {
|
|
290
|
-
setActive(level, index)
|
|
291
|
-
}, 100)
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
function onMouseLeave() {
|
|
295
|
-
clearTimeout(timeout)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function onNavbarMouseLeave() {
|
|
299
|
-
hoverMain.value = -1
|
|
300
|
-
hoverFirst.value = -1
|
|
301
|
-
hoverSecond.value = -1
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function onLinkClick() {
|
|
305
|
-
emit('menu:link-click')
|
|
306
|
-
}
|
|
307
|
-
</script>
|
|
308
|
-
|
|
309
|
-
<style lang="postcss" scoped>
|
|
310
|
-
.fade-enter-active,
|
|
311
|
-
.fade-leave-active {
|
|
312
|
-
@apply transition-opacity duration-200 ease-out;
|
|
313
|
-
}
|
|
314
|
-
.fade-enter,
|
|
315
|
-
.fade-leave-active {
|
|
316
|
-
@apply opacity-0;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
.slideDown-enter-active,
|
|
320
|
-
.slideDown-leave-active {
|
|
321
|
-
transition: max-height 1s ease-in-out;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
.slideDown-enter-to,
|
|
325
|
-
.slideDown-leave-from {
|
|
326
|
-
overflow: hidden;
|
|
327
|
-
max-height: 400px;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
.slideDown-enter-from,
|
|
331
|
-
.slideDown-leave-to {
|
|
332
|
-
overflow: hidden;
|
|
333
|
-
max-height: 0;
|
|
334
|
-
}
|
|
335
|
-
</style>
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<ClientOnly>
|
|
3
|
-
<div class="flex items-center">
|
|
4
|
-
<ul class="flex uppercase gap-4">
|
|
5
|
-
<li v-for="(lang, i) in links" :key="i">
|
|
6
|
-
<NuxtLink
|
|
7
|
-
v-if="lang.enabled"
|
|
8
|
-
:to="lang.to"
|
|
9
|
-
class="hover:text-primary-500 block"
|
|
10
|
-
:class="{
|
|
11
|
-
'font-bold': lang.active,
|
|
12
|
-
}"
|
|
13
|
-
@click="onLangDropdownLinkClick"
|
|
14
|
-
>
|
|
15
|
-
{{ lang.code }}
|
|
16
|
-
</NuxtLink>
|
|
17
|
-
<div v-else class="cursor-not-allowed text-gray-300">
|
|
18
|
-
{{ lang.code }}
|
|
19
|
-
</div>
|
|
20
|
-
</li>
|
|
21
|
-
</ul>
|
|
22
|
-
</div>
|
|
23
|
-
</ClientOnly>
|
|
24
|
-
</template>
|
|
25
|
-
|
|
26
|
-
<script lang="ts" setup>
|
|
27
|
-
const emit = defineEmits(['lang-dropdown:change'])
|
|
28
|
-
const links = useLanguageLinks()
|
|
29
|
-
|
|
30
|
-
const langSwitchDropdownOpen = ref(false)
|
|
31
|
-
|
|
32
|
-
const onLangDropdownLinkClick = () => {
|
|
33
|
-
emit('lang-dropdown:change')
|
|
34
|
-
langSwitchDropdownOpen.value = false
|
|
35
|
-
}
|
|
36
|
-
</script>
|
|
37
|
-
|