@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.
Files changed (122) hide show
  1. package/assets/symbols/chevron-right.svg +1 -1
  2. package/components/Blokkli/HeroImage/index.vue +1 -1
  3. package/components/Blokkli/Teasers/icon.svg +3 -3
  4. package/components/DesignSystem/Atoms/Button.vue +86 -36
  5. package/components/DesignSystem/Atoms/Caption.vue +10 -10
  6. package/components/DesignSystem/Atoms/Container.vue +10 -6
  7. package/components/DesignSystem/Atoms/GridRow.vue +4 -3
  8. package/components/DesignSystem/Atoms/LinkListItem.vue +31 -8
  9. package/components/DesignSystem/Molecules/ButtonGroup.vue +18 -3
  10. package/components/DesignSystem/Molecules/Card.vue +86 -31
  11. package/components/DesignSystem/Molecules/IconText.vue +37 -16
  12. package/components/DesignSystem/Molecules/MediaLightbox.vue +213 -58
  13. package/components/DesignSystem/Molecules/MediaSlider.vue +88 -25
  14. package/components/DesignSystem/Molecules/Partnership.vue +40 -9
  15. package/components/DesignSystem/Molecules/Table.vue +90 -25
  16. package/components/DesignSystem/Molecules/TitleComposition.vue +15 -12
  17. package/components/DesignSystem/Organisms/ContentBlock.vue +61 -15
  18. package/components/DesignSystem/Organisms/FacetedListing.vue +170 -0
  19. package/components/DesignSystem/Organisms/FlipTeaser.vue +119 -47
  20. package/components/DesignSystem/Organisms/HeaderHero.vue +167 -0
  21. package/components/DesignSystem/Organisms/HeaderTextImage.vue +71 -0
  22. package/components/DesignSystem/Organisms/LogoElement.vue +33 -10
  23. package/components/DesignSystem/Organisms/Map.vue +11 -6
  24. package/components/DesignSystem/Organisms/SearchResults.vue +41 -0
  25. package/components/DesignSystem/Organisms/TeamElement.vue +84 -20
  26. package/components/DesignSystem/Organisms/TeaserCard.vue +87 -34
  27. package/components/DesignSystem/Organisms/Testimonial.vue +82 -12
  28. package/components/DesignSystem/Organisms/TimelineElement.vue +42 -12
  29. package/components/DesignSystem/Organisms/TwoColumnTextElement.vue +44 -9
  30. package/components/DesignSystem/Pages/Search.vue +39 -0
  31. package/components/Drupal/Breadcrumb/index.vue +16 -5
  32. package/components/Drupal/Messages/index.vue +16 -5
  33. package/components/Drupal/Webform/fragment.graphql +8 -5
  34. package/components/Drupal/Webform/index.vue +20 -9
  35. package/components/Drupal/Webform/query.graphql +18 -16
  36. package/components/Form/CheckboxInput.vue +6 -6
  37. package/components/Form/CheckboxInputs.vue +5 -5
  38. package/components/Form/FileUploadInput.vue +6 -6
  39. package/components/Form/RadioButtonsInput.vue +5 -5
  40. package/components/Form/SelectInput.vue +7 -7
  41. package/components/Form/SubmitButton.vue +1 -1
  42. package/components/Form/TextAreaInput.vue +2 -2
  43. package/components/Form/TextEmailInput.vue +2 -2
  44. package/components/Form/TextInput.vue +2 -2
  45. package/components/Form/TextPhoneInput.vue +2 -2
  46. package/components/Form/composables/useFormElement.ts +5 -5
  47. package/components/Form/utils/types.ts +8 -7
  48. package/components/Media/Icon/index.vue +10 -6
  49. package/components/Media/Image/index.vue +26 -20
  50. package/components/Media/RemoteVideo/index.vue +34 -21
  51. package/components/Media/Video/index.vue +6 -5
  52. package/components/Node/Icms/Page/Teaser/index.vue +6 -4
  53. package/components/Node/Icms/Page/index.vue +2 -2
  54. package/components/Paragraph/Button/Element/index.vue +9 -2
  55. package/components/Paragraph/CallToAction/index.vue +43 -10
  56. package/components/Paragraph/Card/Element/index.vue +2 -1
  57. package/components/Paragraph/Card/Layout/index.vue +29 -10
  58. package/components/Paragraph/Contact/index.vue +41 -12
  59. package/components/Paragraph/Downloads/index.vue +82 -33
  60. package/components/Paragraph/FAQ/Element/index.vue +41 -12
  61. package/components/Paragraph/FAQ/Layout/index.vue +47 -13
  62. package/components/Paragraph/FlipTeasers/index.vue +26 -6
  63. package/components/Paragraph/Gallery/index.vue +42 -10
  64. package/components/Paragraph/HeroImage/index.vue +62 -16
  65. package/components/Paragraph/IconText/Element/index.vue +7 -1
  66. package/components/Paragraph/IconText/Layout/index.vue +39 -12
  67. package/components/Paragraph/Introduction/index.vue +50 -15
  68. package/components/Paragraph/Logo/Element/fragment.graphql +1 -0
  69. package/components/Paragraph/Logo/Element/index.vue +7 -2
  70. package/components/Paragraph/Media/index.vue +32 -31
  71. package/components/Paragraph/Partnerships/Element/fragment.graphql +1 -0
  72. package/components/Paragraph/Partnerships/Element/index.vue +7 -0
  73. package/components/Paragraph/Partnerships/Layout/index.vue +100 -27
  74. package/components/Paragraph/SingleTestimonial/index.vue +58 -15
  75. package/components/Paragraph/Table/index.vue +32 -9
  76. package/components/Paragraph/Tabs/Element/index.vue +44 -10
  77. package/components/Paragraph/Tabs/Layout/index.vue +123 -37
  78. package/components/Paragraph/Team/Element/index.vue +18 -1
  79. package/components/Paragraph/Team/Layout/index.vue +30 -7
  80. package/components/Paragraph/Teasers/index.vue +33 -7
  81. package/components/Paragraph/Testimonial/Element/index.vue +30 -5
  82. package/components/Paragraph/Testimonial/Layout/index.vue +78 -24
  83. package/components/Paragraph/Text/index.vue +32 -10
  84. package/components/Paragraph/TextMedia/index.vue +44 -13
  85. package/components/Paragraph/Timeline/Element/index.vue +23 -7
  86. package/components/Paragraph/Timeline/Layout/index.vue +232 -67
  87. package/components/Paragraph/TwoColumnText/Element/index.vue +20 -3
  88. package/components/Paragraph/TwoColumnText/Layout/index.vue +8 -1
  89. package/components/Paragraph/iFrame/index.vue +31 -11
  90. package/components/Search/Facets/FacetDropdownUI.vue +351 -77
  91. package/components/Search/Facets/FacetedSearchUI.vue +257 -101
  92. package/components/Search/Facets/fragment.graphql +5 -1
  93. package/components/Search/Input/index.vue +78 -20
  94. package/components/Section/Footer/index.vue +170 -30
  95. package/components/Section/Header/Buttons.vue +34 -0
  96. package/components/Section/Header/DesktopMainMenu.vue +160 -0
  97. package/components/Section/Header/DesktopMainMenuDropdown.vue +170 -0
  98. package/components/Section/Header/LanguageDropdown.vue +95 -64
  99. package/components/Section/Header/LanguageLinks.vue +39 -0
  100. package/components/Section/Header/Logo.vue +24 -0
  101. package/components/Section/Header/MainButtons.vue +31 -0
  102. package/components/Section/Header/MenuIcon.vue +61 -49
  103. package/components/Section/Header/MetaButtons.vue +31 -0
  104. package/components/Section/Header/MetaMenu.vue +55 -53
  105. package/components/Section/Header/MobileMainMenu.vue +23 -0
  106. package/components/Section/Header/MobileMainMenuItem.vue +191 -0
  107. package/components/Section/Header/index.vue +183 -185
  108. package/composables/useMenu.ts +2 -2
  109. package/composables/useMobileMenuOverlayBus.ts +44 -0
  110. package/composables/useNavigationOffset.ts +2 -2
  111. package/composables/useTheme.ts +75 -0
  112. package/formkit.theme.ts +541 -586
  113. package/layouts/default.vue +7 -35
  114. package/layouts/error.vue +7 -32
  115. package/nuxt.config.ts +13 -0
  116. package/package.json +1 -1
  117. package/plugins/initData.ts +8 -5
  118. package/queries/query.initData.graphql +4 -2
  119. package/tailwind.config.ts +11 -11
  120. package/types/global.ts +1 -0
  121. package/components/Section/Header/GlobalMenu.vue +0 -335
  122. package/components/Section/Header/LanguageSwitcher.vue +0 -37
@@ -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 isMenuOpen = ref(false)
46
- const hasMenuFinishedClosing = ref(true)
47
-
48
- function menuOpen() {
49
- window.document.body.classList.add('overflow-y-hidden')
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
- function menuCloseFinish() {
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
- const breadcrumb = useBreadcrumbLinks()
43
- const viewport = useViewport()
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iqual/nuxt-icms",
3
- "version": "1.3.1",
3
+ "version": "1.4.1",
4
4
  "description": "ICMS Base",
5
5
  "type": "module",
6
6
  "private": false,
@@ -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
- label
63
+ target: attribute(name: "target")
64
+ rel: attribute(name: "rel")
65
+ additionalClass: attribute(name: "class")
64
66
  }
65
67
  }
66
68
 
@@ -39,18 +39,18 @@ const colors = {
39
39
  '950': 'rgb(11, 45, 70)',
40
40
  },
41
41
  gray: {
42
- DEFAULT: 'rgb(61, 61, 61)',
42
+ DEFAULT: 'rgb(116, 116, 116)',
43
43
  '50': 'rgb(246, 246, 246)',
44
- '100': 'rgb(231, 231, 231)',
45
- '200': 'rgb(209, 209, 209)',
46
- '300': 'rgb(176, 176, 176)',
47
- '400': 'rgb(136, 136, 136)',
48
- '500': 'rgb(109, 109, 109)',
49
- '600': 'rgb(93, 93, 93)',
50
- '700': 'rgb(79, 79, 79)',
51
- '800': 'rgb(69, 69, 69)',
52
- '900': 'rgb(61, 61, 61)',
53
- '950': 'rgb(17, 17, 17)',
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)',
@@ -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
-