1
1
<script setup lang="ts">
2
2
import { ref , onMounted , onBeforeUnmount , type PropType } from ' vue' ;
3
- import OdsDesktopNavigationPanel from ' @/components/OdsDesktopNavigationPanel.vue' ;
4
3
import OdsButton from ' ./OdsButton.vue' ;
4
+ import SvgIcon from ' ./SvgIcon.vue' ;
5
5
import type { OdsNavTabItem } from ' ./headers/model/ods-nav-tab-item' ;
6
6
7
7
const props = defineProps ({
@@ -36,23 +36,62 @@ const isOpen = ref(false);
36
36
const dropdownRef = ref <HTMLElement | null >(null );
37
37
38
38
function toggleDropdown() {
39
- console .log (' toggleDropdown' );
40
39
isOpen .value = ! isOpen .value ;
41
40
}
42
41
43
42
43
+ const parentLabelStack = ref <string []>([props .menu .label ]);
44
+
45
+ const menuStack = ref <OdsNavTabItem [][]>([]);
46
+
47
+ const menuKey = computed (() => menuStack .value .length );
48
+
49
+ const currentMenu = computed (() => {
50
+
51
+ if (menuStack .value .length === 0 ) {
52
+ return props .menu .subMenu ?? []
53
+ };
54
+ return menuStack .value [menuStack .value .length - 1 ];
55
+ });
56
+
57
+ const direction = ref <' forward' | ' backward' >(' forward' );
58
+
59
+ const transitionName = computed (() => direction .value === ' forward' ? ' slide-menu-right' : ' slide-menu-left' );
60
+
61
+
62
+ function drillDown(item : OdsNavTabItem ) {
63
+ if (item .subMenu && item .subMenu .length > 0 ) {
64
+ direction .value = ' forward' ;
65
+ menuStack .value .push (item .subMenu );
66
+ parentLabelStack .value .push (item .label );
67
+ }
68
+ }
69
+
70
+ function goBack() {
71
+ if (menuStack .value .length > 0 ) {
72
+ direction .value = ' backward' ;
73
+ menuStack .value .pop ();
74
+ parentLabelStack .value .pop ();
75
+ }
76
+ };
77
+
78
+ // Close dropdown when clicking outside
44
79
function handleClickOutside(event : MouseEvent ) {
45
80
if (dropdownRef .value && ! dropdownRef .value .contains (event .target as Node )) {
46
81
isOpen .value = false ;
47
82
}
48
83
}
49
84
85
+ // start listening for clicks outside the dropdown
50
86
onMounted (() => {
51
87
document .addEventListener (' mousedown' , handleClickOutside );
52
88
});
89
+
90
+ // stop listening when component is unmounted
53
91
onBeforeUnmount (() => {
54
92
document .removeEventListener (' mousedown' , handleClickOutside );
55
93
});
94
+
56
95
</script >
57
96
58
97
<template >
@@ -63,25 +102,58 @@ onBeforeUnmount(() => {
63
102
</a >
64
103
<div v-if =" isOpen" id =" desktop-menu__drawer" class =" desktop-menu__drawer ods-drop-down-panel" >
65
104
<div class =" close-button-container" >
105
+ <SvgIcon v-if =" menuStack.length > 0" icon =" ArrowLeft" size =" lg" @click.prevent =" goBack" />
106
+
107
+ <div v-else />
108
+ <!-- <li v-if="menuStack.length > 0" style="border-bottom: none;" @click="goBack">
109
+ <a style="padding-top: 12px; padding-bottom: 12px;">
110
+ <span>
111
+ <SvgIcon icon="ArrowLeft" size="lg"/>
112
+ </span>
113
+ </a>
114
+ </li>-->
66
115
<OdsButton
67
- icon =" Cancel"
68
- title =" close menu"
69
- variant =" bare"
70
- size =" sm"
71
- icon-right
72
- class =" ods-close"
73
- @click =" isOpen = false"
74
- >
116
+ icon =" Cancel"
117
+ title =" close menu"
118
+ variant =" bare"
119
+ size =" sm"
120
+ icon-right
121
+ class =" ods-close"
122
+ @click =" isOpen = false"
123
+ >
75
124
<span class =" ods-close" >Schliessen</span >
76
125
</OdsButton >
77
126
</div >
78
- <OdsDesktopNavigationPanel :menu =" props.menu" />
79
- <!-- <div v-for="subItem in props.subMenu" :key="subItem.to">
80
- <NuxtLinkLocale :to="subItem.to" @click="isOpen = false">
81
- {{ props.t(subItem.label) }}
82
- </NuxtLinkLocale>
83
- </div>-->
127
+ <Transition :name =" transitionName" mode =" out-in" >
128
+ <div :key =" menuKey" >
129
+ <div class =" navy" >
130
+ <h2 class =" navy__title" >{{ t(parentLabelStack[parentLabelStack.length - 1] ?? '') }}</h2 >
84
131
132
+ <nav class =" navy__level-0 navy-menu__level-0" >
133
+ <ul >
134
+ <template v-for =" item in currentMenu " :key =" item .label " >
135
+ <li v-if =" item.to" >
136
+ <NuxtLinkLocale
137
+ :to =" item.to"
138
+ active-class =" active"
139
+ :aria-label =" t(item.label)"
140
+ @click =" isOpen = false"
141
+ >
142
+ <span >{{t(item.label)}}</span >
143
+ </NuxtLinkLocale ><div />
144
+ </li >
145
+ <li
146
+ v-else-if =" (item.subMenu?.length ?? -1) > 0"
147
+ @click =" drillDown(item)"
148
+ >
149
+ <a >{{t(item.label)}} <SvgIcon size =" lg" icon =" ArrowRight" /></a >
150
+ </li >
151
+ </template >
152
+ </ul >
153
+ </nav >
154
+ </div >
155
+ </div >
156
+ </Transition >
85
157
</div >
86
158
</div >
87
159
</template >
@@ -90,7 +162,7 @@ onBeforeUnmount(() => {
90
162
91
163
.close-button-container {
92
164
display : flex ;
93
- justify-content : flex-end ;
165
+ justify-content : space-between ;
94
166
}
95
167
.ods-close {
96
168
white-space : nowrap ;
@@ -110,6 +182,7 @@ onBeforeUnmount(() => {
110
182
padding-right : 48px ;
111
183
padding-bottom : 48px ;
112
184
padding-top : 24px ;
185
+ z-index : 100 ;
113
186
}
114
187
.ods-dropdown {
115
188
position : relative ;
@@ -147,4 +220,108 @@ onBeforeUnmount(() => {
147
220
.ods-dropdown__menu a :hover {
148
221
background : #f5f5f5 ;
149
222
}
223
+
224
+ .holly {
225
+ margin-top : -40px ;
226
+ }
227
+ // list styles
228
+ .navy {
229
+ position : unset !important ;
230
+ perspective : none !important ;
231
+ }
232
+
233
+ .navy__level-0 {
234
+ position : unset ;
235
+ ul {
236
+ display : block ;
237
+ }
238
+ }
239
+ .navy__title {
240
+ margin-top : 0 ;
241
+ margin-left : 12px
242
+ }
243
+
244
+ li {
245
+ border-bottom-width : 1px ;
246
+ font-size : 0.875rem ;
247
+ width : 100% ;
248
+ cursor : pointer ;
249
+ line-height : 24px ;
250
+ height : 46px ;
251
+ margin-top : 0 !important ;
252
+
253
+ }
254
+ li :hover {
255
+ background-color : var (--color-secondary-50 );
256
+ }
257
+
258
+ #mobile-menu {
259
+ width : 100vw ;
260
+ }
261
+
262
+ ul {
263
+ list-style : none !important ;
264
+ margin : 0 !important ;
265
+ padding : 0 !important ;
266
+ }
267
+
268
+ a {
269
+ text-decoration : none ;
270
+ display : flex ;
271
+ align-items : center ;
272
+ justify-content : space-between ;
273
+ height : 100% ;
274
+ padding-left : 16px ;
275
+ padding-right : 32px ;
276
+ color : black ;
277
+ }
278
+
279
+ .submenu-arrow {
280
+ float : right ;
281
+ font-size : 1.2em ;
282
+ margin-left : 8px ;
283
+ }
284
+ .back-btn {
285
+ font-weight : bold ;
286
+ color : #2ecc40 ;
287
+ cursor : pointer ;
288
+ }
289
+ .slide-menu-right-enter-active , .slide-menu-right-leave-active {
290
+ transition : transform 0.3s cubic-bezier (0.4 ,0 ,0.2 ,1 ), opacity 0.3s cubic-bezier (0.4 ,0 ,0.2 ,1 );
291
+ }
292
+ .slide-menu-right-enter-from {
293
+ transform : translateX (100% );
294
+ opacity : 0 ;
295
+ }
296
+ .slide-menu-right-enter-to {
297
+ transform : translateX (0 );
298
+ opacity : 1 ;
299
+ }
300
+ .slide-menu-right-leave-from {
301
+ transform : translateX (0 );
302
+ opacity : 1 ;
303
+ }
304
+ .slide-menu-right-leave-to {
305
+ transform : translateX (-100% );
306
+ opacity : 0 ;
307
+ }
308
+ .slide-menu-left-enter-active , .slide-menu-left-leave-active {
309
+ transition : transform 0.3s cubic-bezier (0.4 ,0 ,0.2 ,1 ), opacity 0.3s cubic-bezier (0.4 ,0 ,0.2 ,1 );
310
+ }
311
+ .slide-menu-left-enter-from {
312
+ transform : translateX (-100% );
313
+ opacity : 0 ;
314
+ }
315
+ .slide-menu-left-enter-to {
316
+ transform : translateX (0 );
317
+ opacity : 1 ;
318
+ }
319
+ .slide-menu-left-leave-from {
320
+ transform : translateX (0 );
321
+ opacity : 1 ;
322
+ }
323
+ .slide-menu-left-leave-to {
324
+ transform : translateX (100% );
325
+ opacity : 0 ;
326
+ }
150
327
</style >
0 commit comments