@bobbykim/mcl-header 0.2.0
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/CHANGELOG.md +14 -0
- package/LICENSE.md +9 -0
- package/README.md +21 -0
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/index.ts +4 -0
- package/lib/common/HamburgerMenu.vue +121 -0
- package/lib/common/HamburgerMenu.vue.d.ts +43 -0
- package/lib/mcl-header-a/MclHeaderA.vue +382 -0
- package/lib/mcl-header-a/MclHeaderA.vue.d.ts +150 -0
- package/lib/mcl-header-a/NavCollapse.vue +173 -0
- package/lib/mcl-header-a/NavCollapse.vue.d.ts +76 -0
- package/lib/mcl-header-a/NavDropdown.vue +168 -0
- package/lib/mcl-header-a/NavDropdown.vue.d.ts +72 -0
- package/lib/mcl-header-a/NavLink.vue +89 -0
- package/lib/mcl-header-a/NavLink.vue.d.ts +62 -0
- package/lib/mcl-header-a/index.types.d.ts +20 -0
- package/lib/mcl-header-a/index.types.js +1 -0
- package/lib/mcl-header-a/index.types.ts +24 -0
- package/package.json +1 -0
- package/tsconfig.json +9 -0
- package/tsconfig.vue.json +9 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type { BodyText, ColorPalette, CtaTarget, HeadingSize } from '@bobbykim/manguito-theme';
|
|
2
|
+
import type { MenuCollapseType, MenuItemType } from './index.types';
|
|
3
|
+
declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
|
|
4
|
+
logo: string;
|
|
5
|
+
logoSmall?: string | undefined;
|
|
6
|
+
logoAlt?: string | undefined;
|
|
7
|
+
logoAsLink?: boolean | undefined;
|
|
8
|
+
logoLink: string;
|
|
9
|
+
logoLinkTarget?: CtaTarget | undefined;
|
|
10
|
+
title: string;
|
|
11
|
+
titleSize?: HeadingSize | undefined;
|
|
12
|
+
titleColor?: ColorPalette | undefined;
|
|
13
|
+
titleAsLink?: boolean | undefined;
|
|
14
|
+
titleLink: string;
|
|
15
|
+
titleLinkTarget?: CtaTarget | undefined;
|
|
16
|
+
menuItems: (MenuItemType | MenuCollapseType)[];
|
|
17
|
+
menuItemAsLink?: boolean | undefined;
|
|
18
|
+
menuTextSize?: BodyText | undefined;
|
|
19
|
+
menuTextColor?: ColorPalette | undefined;
|
|
20
|
+
menuTextBold?: boolean | undefined;
|
|
21
|
+
displayHighlight?: boolean | undefined;
|
|
22
|
+
highlightColor?: ColorPalette | undefined;
|
|
23
|
+
bgColor?: ColorPalette | undefined;
|
|
24
|
+
mobileMenuBgColor?: ColorPalette | undefined;
|
|
25
|
+
secondaryColor?: ColorPalette | undefined;
|
|
26
|
+
hamburgerBorder?: boolean | undefined;
|
|
27
|
+
fadeInOnScroll?: boolean | undefined;
|
|
28
|
+
scrollDistance?: number | undefined;
|
|
29
|
+
}>, {
|
|
30
|
+
logoAsLink: boolean;
|
|
31
|
+
logoLinkTarget: string;
|
|
32
|
+
titleSize: string;
|
|
33
|
+
titleColor: string;
|
|
34
|
+
titleAsLink: boolean;
|
|
35
|
+
titleLinkTarget: string;
|
|
36
|
+
menuItemAsLink: boolean;
|
|
37
|
+
menuTextSize: string;
|
|
38
|
+
menuTextColor: string;
|
|
39
|
+
menuTextBold: boolean;
|
|
40
|
+
displayHighlight: boolean;
|
|
41
|
+
highlightColor: string;
|
|
42
|
+
bgColor: string;
|
|
43
|
+
mobileMenuBgColor: string;
|
|
44
|
+
secondaryColor: string;
|
|
45
|
+
hamburgerBorder: boolean;
|
|
46
|
+
fadeInOnScroll: boolean;
|
|
47
|
+
scrollDistance: number;
|
|
48
|
+
}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
49
|
+
"toggle-menu": (...args: any[]) => void;
|
|
50
|
+
"menu-click": (...args: any[]) => void;
|
|
51
|
+
"title-click": (...args: any[]) => void;
|
|
52
|
+
"logo-click": (...args: any[]) => void;
|
|
53
|
+
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
|
|
54
|
+
logo: string;
|
|
55
|
+
logoSmall?: string | undefined;
|
|
56
|
+
logoAlt?: string | undefined;
|
|
57
|
+
logoAsLink?: boolean | undefined;
|
|
58
|
+
logoLink: string;
|
|
59
|
+
logoLinkTarget?: CtaTarget | undefined;
|
|
60
|
+
title: string;
|
|
61
|
+
titleSize?: HeadingSize | undefined;
|
|
62
|
+
titleColor?: ColorPalette | undefined;
|
|
63
|
+
titleAsLink?: boolean | undefined;
|
|
64
|
+
titleLink: string;
|
|
65
|
+
titleLinkTarget?: CtaTarget | undefined;
|
|
66
|
+
menuItems: (MenuItemType | MenuCollapseType)[];
|
|
67
|
+
menuItemAsLink?: boolean | undefined;
|
|
68
|
+
menuTextSize?: BodyText | undefined;
|
|
69
|
+
menuTextColor?: ColorPalette | undefined;
|
|
70
|
+
menuTextBold?: boolean | undefined;
|
|
71
|
+
displayHighlight?: boolean | undefined;
|
|
72
|
+
highlightColor?: ColorPalette | undefined;
|
|
73
|
+
bgColor?: ColorPalette | undefined;
|
|
74
|
+
mobileMenuBgColor?: ColorPalette | undefined;
|
|
75
|
+
secondaryColor?: ColorPalette | undefined;
|
|
76
|
+
hamburgerBorder?: boolean | undefined;
|
|
77
|
+
fadeInOnScroll?: boolean | undefined;
|
|
78
|
+
scrollDistance?: number | undefined;
|
|
79
|
+
}>, {
|
|
80
|
+
logoAsLink: boolean;
|
|
81
|
+
logoLinkTarget: string;
|
|
82
|
+
titleSize: string;
|
|
83
|
+
titleColor: string;
|
|
84
|
+
titleAsLink: boolean;
|
|
85
|
+
titleLinkTarget: string;
|
|
86
|
+
menuItemAsLink: boolean;
|
|
87
|
+
menuTextSize: string;
|
|
88
|
+
menuTextColor: string;
|
|
89
|
+
menuTextBold: boolean;
|
|
90
|
+
displayHighlight: boolean;
|
|
91
|
+
highlightColor: string;
|
|
92
|
+
bgColor: string;
|
|
93
|
+
mobileMenuBgColor: string;
|
|
94
|
+
secondaryColor: string;
|
|
95
|
+
hamburgerBorder: boolean;
|
|
96
|
+
fadeInOnScroll: boolean;
|
|
97
|
+
scrollDistance: number;
|
|
98
|
+
}>>> & {
|
|
99
|
+
"onToggle-menu"?: ((...args: any[]) => any) | undefined;
|
|
100
|
+
"onMenu-click"?: ((...args: any[]) => any) | undefined;
|
|
101
|
+
"onTitle-click"?: ((...args: any[]) => any) | undefined;
|
|
102
|
+
"onLogo-click"?: ((...args: any[]) => any) | undefined;
|
|
103
|
+
}, {
|
|
104
|
+
titleColor: ColorPalette;
|
|
105
|
+
bgColor: ColorPalette;
|
|
106
|
+
menuTextSize: BodyText;
|
|
107
|
+
menuTextColor: ColorPalette;
|
|
108
|
+
menuTextBold: boolean;
|
|
109
|
+
displayHighlight: boolean;
|
|
110
|
+
highlightColor: ColorPalette;
|
|
111
|
+
logoAsLink: boolean;
|
|
112
|
+
logoLinkTarget: CtaTarget;
|
|
113
|
+
titleSize: HeadingSize;
|
|
114
|
+
titleAsLink: boolean;
|
|
115
|
+
titleLinkTarget: CtaTarget;
|
|
116
|
+
menuItemAsLink: boolean;
|
|
117
|
+
mobileMenuBgColor: ColorPalette;
|
|
118
|
+
secondaryColor: ColorPalette;
|
|
119
|
+
hamburgerBorder: boolean;
|
|
120
|
+
fadeInOnScroll: boolean;
|
|
121
|
+
scrollDistance: number;
|
|
122
|
+
}, {}>, {
|
|
123
|
+
"nav-slot"?(_: {}): any;
|
|
124
|
+
"mobile-slot"?(_: {
|
|
125
|
+
closeNav: () => void;
|
|
126
|
+
}): any;
|
|
127
|
+
}>;
|
|
128
|
+
export default _default;
|
|
129
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
130
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
131
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
132
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
133
|
+
} : {
|
|
134
|
+
type: import('vue').PropType<T[K]>;
|
|
135
|
+
required: true;
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
type __VLS_WithDefaults<P, D> = {
|
|
139
|
+
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
|
|
140
|
+
default: D[K];
|
|
141
|
+
}> : P[K];
|
|
142
|
+
};
|
|
143
|
+
type __VLS_Prettify<T> = {
|
|
144
|
+
[K in keyof T]: T[K];
|
|
145
|
+
} & {};
|
|
146
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
147
|
+
new (): {
|
|
148
|
+
$slots: S;
|
|
149
|
+
};
|
|
150
|
+
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type {
|
|
3
|
+
BodyText,
|
|
4
|
+
CollapseEvent,
|
|
5
|
+
ColorPalette,
|
|
6
|
+
} from '@bobbykim/manguito-theme'
|
|
7
|
+
import generateClass, { Collapse, vCollapse } from '@bobbykim/manguito-theme'
|
|
8
|
+
import { computed, ref } from 'vue'
|
|
9
|
+
import type {
|
|
10
|
+
MenuCollapseType,
|
|
11
|
+
MenuItemType,
|
|
12
|
+
NavChildClickEventType,
|
|
13
|
+
} from './index.types'
|
|
14
|
+
|
|
15
|
+
const props = withDefaults(
|
|
16
|
+
defineProps<{
|
|
17
|
+
navId: string
|
|
18
|
+
navAccordionGroup: string
|
|
19
|
+
navItem: MenuCollapseType
|
|
20
|
+
bgColor?: ColorPalette
|
|
21
|
+
hoverBgColor?: ColorPalette
|
|
22
|
+
menuTextSize?: BodyText
|
|
23
|
+
menuTextColor?: ColorPalette
|
|
24
|
+
menuTextBold?: boolean
|
|
25
|
+
displayHighlight?: boolean
|
|
26
|
+
highlightColor?: ColorPalette
|
|
27
|
+
asLink?: boolean
|
|
28
|
+
}>(),
|
|
29
|
+
{
|
|
30
|
+
menuTextSize: 'md',
|
|
31
|
+
bgColor: 'light-2',
|
|
32
|
+
hoverBgColor: 'dark-1',
|
|
33
|
+
menuTextColor: 'dark-3',
|
|
34
|
+
menuTextBold: false,
|
|
35
|
+
displayHighlight: true,
|
|
36
|
+
highlightColor: 'primary',
|
|
37
|
+
asLink: true,
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
const emit = defineEmits(['nav-link'])
|
|
42
|
+
const toggle = ref<boolean>(false)
|
|
43
|
+
const handleNavId = computed<string>(() => {
|
|
44
|
+
const { navId } = props
|
|
45
|
+
const navLower = navId.toLowerCase()
|
|
46
|
+
// @ts-ignore: Unreachable code error
|
|
47
|
+
const navKebab = navLower.replaceAll(' ', '-')
|
|
48
|
+
return `nav-${navKebab}`
|
|
49
|
+
})
|
|
50
|
+
const handleNavAccordionGroupName = computed<string>(() => {
|
|
51
|
+
const { navAccordionGroup } = props
|
|
52
|
+
const toLowerCase = navAccordionGroup.toLocaleLowerCase()
|
|
53
|
+
// @ts-ignore: Unreachable code error
|
|
54
|
+
const toKebabCase = toLowerCase.replaceAll(' ', '-')
|
|
55
|
+
return `accordion-${toKebabCase}`
|
|
56
|
+
})
|
|
57
|
+
const toggleAction = (e: CollapseEvent): void => {
|
|
58
|
+
toggle.value = e.visible
|
|
59
|
+
// emit('nav-link', { event: e, title: props.navItem.title })
|
|
60
|
+
}
|
|
61
|
+
const navItemClick = (e: Event, item: MenuItemType) => {
|
|
62
|
+
const { asLink } = props
|
|
63
|
+
!asLink && e.preventDefault()
|
|
64
|
+
const customEvent: NavChildClickEventType = {
|
|
65
|
+
event: e,
|
|
66
|
+
item,
|
|
67
|
+
}
|
|
68
|
+
emit('nav-link', customEvent)
|
|
69
|
+
}
|
|
70
|
+
const getMenuItemClass = (
|
|
71
|
+
size: BodyText,
|
|
72
|
+
color: ColorPalette,
|
|
73
|
+
bold: boolean
|
|
74
|
+
): string => {
|
|
75
|
+
/**
|
|
76
|
+
* @param {BodyText} size - menuTextSize
|
|
77
|
+
* @param {ColorPalette} color - menuTextColor
|
|
78
|
+
* @param {boolean} bold - menuTextBold
|
|
79
|
+
*/
|
|
80
|
+
const classArray: string[] = [
|
|
81
|
+
generateClass('BODYTEXT', size),
|
|
82
|
+
generateClass('TEXTCOLOR', color),
|
|
83
|
+
]
|
|
84
|
+
if (bold) {
|
|
85
|
+
classArray.push('font-bold')
|
|
86
|
+
}
|
|
87
|
+
return classArray.join(' ')
|
|
88
|
+
}
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<template>
|
|
92
|
+
<div class="flex flex-col w-full">
|
|
93
|
+
<div class="self-center">
|
|
94
|
+
<button
|
|
95
|
+
class="tracking-wider align-middle outline-none nav__text flex items-center gap-3xs"
|
|
96
|
+
:class="getMenuItemClass(menuTextSize, menuTextColor, menuTextBold)"
|
|
97
|
+
v-collapse:[handleNavId]
|
|
98
|
+
>
|
|
99
|
+
<span>
|
|
100
|
+
{{ navItem.title }}
|
|
101
|
+
</span>
|
|
102
|
+
<svg
|
|
103
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
104
|
+
viewBox="0 0 448 512"
|
|
105
|
+
class="h-[0.8rem] fill-current"
|
|
106
|
+
:class="[
|
|
107
|
+
toggle ? 'rotate-180' : 'rotate-0',
|
|
108
|
+
'transition-transform duration-300 ease-in',
|
|
109
|
+
]"
|
|
110
|
+
>
|
|
111
|
+
<!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
|
112
|
+
<path
|
|
113
|
+
d="M224 416c-8.188 0-16.38-3.125-22.62-9.375l-192-192c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L224 338.8l169.4-169.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-192 192C240.4 412.9 232.2 416 224 416z"
|
|
114
|
+
/>
|
|
115
|
+
</svg>
|
|
116
|
+
</button>
|
|
117
|
+
<div
|
|
118
|
+
v-if="displayHighlight"
|
|
119
|
+
class="relative -top-[2px] h-[6px] nav__decorator"
|
|
120
|
+
:class="generateClass('BEFOREBG', highlightColor)"
|
|
121
|
+
></div>
|
|
122
|
+
</div>
|
|
123
|
+
<collapse
|
|
124
|
+
:id="handleNavId"
|
|
125
|
+
:visible="false"
|
|
126
|
+
:accordion="handleNavAccordionGroupName"
|
|
127
|
+
@open="toggleAction"
|
|
128
|
+
@close="toggleAction"
|
|
129
|
+
>
|
|
130
|
+
<div class="relative pt-2xs">
|
|
131
|
+
<div
|
|
132
|
+
v-if="displayHighlight"
|
|
133
|
+
class="absolute w-md bg-opacity-25 -left-4 h-full"
|
|
134
|
+
:class="generateClass('BGCOLOR', highlightColor)"
|
|
135
|
+
></div>
|
|
136
|
+
<div class="relative flex flex-col">
|
|
137
|
+
<a
|
|
138
|
+
v-for="(item, idx) in navItem.children"
|
|
139
|
+
:href="item.url"
|
|
140
|
+
:target="item.target"
|
|
141
|
+
class="w-full pb-2xs last:pb-0"
|
|
142
|
+
:key="idx"
|
|
143
|
+
:class="[
|
|
144
|
+
generateClass('TEXTCOLOR', menuTextColor),
|
|
145
|
+
generateClass('BODYTEXT', menuTextSize),
|
|
146
|
+
]"
|
|
147
|
+
@click="navItemClick($event, item)"
|
|
148
|
+
>
|
|
149
|
+
{{ item.title }}
|
|
150
|
+
</a>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
</collapse>
|
|
154
|
+
</div>
|
|
155
|
+
</template>
|
|
156
|
+
|
|
157
|
+
<style scoped lang="scss">
|
|
158
|
+
.nav__decorator {
|
|
159
|
+
&::before {
|
|
160
|
+
content: '';
|
|
161
|
+
position: absolute;
|
|
162
|
+
bottom: 0;
|
|
163
|
+
left: 0;
|
|
164
|
+
height: 100%;
|
|
165
|
+
width: 0;
|
|
166
|
+
transition: width 0.3s linear;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
.nav__text:focus + .nav__decorator::before,
|
|
170
|
+
.nav__text:hover + .nav__decorator::before {
|
|
171
|
+
width: 100%;
|
|
172
|
+
}
|
|
173
|
+
</style>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { BodyText, ColorPalette } from '@bobbykim/manguito-theme';
|
|
2
|
+
import type { MenuCollapseType } from './index.types';
|
|
3
|
+
declare const _default: import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
|
|
4
|
+
navId: string;
|
|
5
|
+
navAccordionGroup: string;
|
|
6
|
+
navItem: MenuCollapseType;
|
|
7
|
+
bgColor?: ColorPalette | undefined;
|
|
8
|
+
hoverBgColor?: ColorPalette | undefined;
|
|
9
|
+
menuTextSize?: BodyText | undefined;
|
|
10
|
+
menuTextColor?: ColorPalette | undefined;
|
|
11
|
+
menuTextBold?: boolean | undefined;
|
|
12
|
+
displayHighlight?: boolean | undefined;
|
|
13
|
+
highlightColor?: ColorPalette | undefined;
|
|
14
|
+
asLink?: boolean | undefined;
|
|
15
|
+
}>, {
|
|
16
|
+
menuTextSize: string;
|
|
17
|
+
bgColor: string;
|
|
18
|
+
hoverBgColor: string;
|
|
19
|
+
menuTextColor: string;
|
|
20
|
+
menuTextBold: boolean;
|
|
21
|
+
displayHighlight: boolean;
|
|
22
|
+
highlightColor: string;
|
|
23
|
+
asLink: boolean;
|
|
24
|
+
}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
25
|
+
"nav-link": (...args: any[]) => void;
|
|
26
|
+
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
|
|
27
|
+
navId: string;
|
|
28
|
+
navAccordionGroup: string;
|
|
29
|
+
navItem: MenuCollapseType;
|
|
30
|
+
bgColor?: ColorPalette | undefined;
|
|
31
|
+
hoverBgColor?: ColorPalette | undefined;
|
|
32
|
+
menuTextSize?: BodyText | undefined;
|
|
33
|
+
menuTextColor?: ColorPalette | undefined;
|
|
34
|
+
menuTextBold?: boolean | undefined;
|
|
35
|
+
displayHighlight?: boolean | undefined;
|
|
36
|
+
highlightColor?: ColorPalette | undefined;
|
|
37
|
+
asLink?: boolean | undefined;
|
|
38
|
+
}>, {
|
|
39
|
+
menuTextSize: string;
|
|
40
|
+
bgColor: string;
|
|
41
|
+
hoverBgColor: string;
|
|
42
|
+
menuTextColor: string;
|
|
43
|
+
menuTextBold: boolean;
|
|
44
|
+
displayHighlight: boolean;
|
|
45
|
+
highlightColor: string;
|
|
46
|
+
asLink: boolean;
|
|
47
|
+
}>>> & {
|
|
48
|
+
"onNav-link"?: ((...args: any[]) => any) | undefined;
|
|
49
|
+
}, {
|
|
50
|
+
bgColor: ColorPalette;
|
|
51
|
+
hoverBgColor: ColorPalette;
|
|
52
|
+
menuTextSize: BodyText;
|
|
53
|
+
menuTextColor: ColorPalette;
|
|
54
|
+
menuTextBold: boolean;
|
|
55
|
+
displayHighlight: boolean;
|
|
56
|
+
highlightColor: ColorPalette;
|
|
57
|
+
asLink: boolean;
|
|
58
|
+
}, {}>;
|
|
59
|
+
export default _default;
|
|
60
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
61
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
62
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
63
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
64
|
+
} : {
|
|
65
|
+
type: import('vue').PropType<T[K]>;
|
|
66
|
+
required: true;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
type __VLS_WithDefaults<P, D> = {
|
|
70
|
+
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
|
|
71
|
+
default: D[K];
|
|
72
|
+
}> : P[K];
|
|
73
|
+
};
|
|
74
|
+
type __VLS_Prettify<T> = {
|
|
75
|
+
[K in keyof T]: T[K];
|
|
76
|
+
} & {};
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BodyText, ColorPalette } from '@bobbykim/manguito-theme'
|
|
3
|
+
import generateClass, {
|
|
4
|
+
DropdownContainer,
|
|
5
|
+
DropdownContent,
|
|
6
|
+
} from '@bobbykim/manguito-theme'
|
|
7
|
+
import { ref } from 'vue'
|
|
8
|
+
import type {
|
|
9
|
+
MenuCollapseType,
|
|
10
|
+
MenuItemType,
|
|
11
|
+
NavChildClickEventType,
|
|
12
|
+
} from './index.types'
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(
|
|
15
|
+
defineProps<{
|
|
16
|
+
navItem: MenuCollapseType
|
|
17
|
+
bgColor?: ColorPalette
|
|
18
|
+
hoverBgColor?: ColorPalette
|
|
19
|
+
menuTextSize?: BodyText
|
|
20
|
+
menuTextColor?: ColorPalette
|
|
21
|
+
menuTextBold?: boolean
|
|
22
|
+
displayHighlight?: boolean
|
|
23
|
+
highlightColor?: ColorPalette
|
|
24
|
+
asLink?: boolean
|
|
25
|
+
}>(),
|
|
26
|
+
{
|
|
27
|
+
menuTextSize: 'md',
|
|
28
|
+
bgColor: 'light-1',
|
|
29
|
+
hoverBgColor: 'dark-1',
|
|
30
|
+
menuTextColor: 'dark-3',
|
|
31
|
+
menuTextBold: false,
|
|
32
|
+
displayHighlight: true,
|
|
33
|
+
highlightColor: 'primary',
|
|
34
|
+
asLink: true,
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
const emit = defineEmits(['nav-link'])
|
|
39
|
+
const navIndexRef = ref<number>(-1)
|
|
40
|
+
const navItemRef = ref<HTMLButtonElement[]>()
|
|
41
|
+
|
|
42
|
+
const getMenuItemClass = (
|
|
43
|
+
size: BodyText,
|
|
44
|
+
color: ColorPalette,
|
|
45
|
+
bold: boolean
|
|
46
|
+
): string => {
|
|
47
|
+
/**
|
|
48
|
+
* @param {BodyText} size - menuTextSize
|
|
49
|
+
* @param {ColorPalette} color - menuTextColor
|
|
50
|
+
* @param {boolean} bold - menuTextBold
|
|
51
|
+
*/
|
|
52
|
+
const classArray: string[] = [
|
|
53
|
+
generateClass('BODYTEXT', size),
|
|
54
|
+
generateClass('TEXTCOLOR', color),
|
|
55
|
+
]
|
|
56
|
+
if (bold) {
|
|
57
|
+
classArray.push('font-bold')
|
|
58
|
+
}
|
|
59
|
+
return classArray.join(' ')
|
|
60
|
+
}
|
|
61
|
+
type KeyDirection = 'up' | 'down'
|
|
62
|
+
const navKeyUp = (direction: KeyDirection): void => {
|
|
63
|
+
const itemLength: number = props.navItem.children.length
|
|
64
|
+
if (navItemRef.value === undefined) {
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
if (direction === 'down' && navIndexRef.value < itemLength - 1) {
|
|
68
|
+
navIndexRef.value++
|
|
69
|
+
}
|
|
70
|
+
if (direction === 'up' && navIndexRef.value > 0) {
|
|
71
|
+
navIndexRef.value--
|
|
72
|
+
}
|
|
73
|
+
navItemRef.value[navIndexRef.value].focus()
|
|
74
|
+
}
|
|
75
|
+
const dropdownButtonClick = (e: Event): void => {
|
|
76
|
+
// resets index
|
|
77
|
+
navIndexRef.value = -1
|
|
78
|
+
}
|
|
79
|
+
const navItemClick = (e: Event, item: MenuItemType) => {
|
|
80
|
+
const { asLink } = props
|
|
81
|
+
!asLink && e.preventDefault()
|
|
82
|
+
const customEvent: NavChildClickEventType = {
|
|
83
|
+
event: e,
|
|
84
|
+
item,
|
|
85
|
+
}
|
|
86
|
+
emit('nav-link', customEvent)
|
|
87
|
+
}
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<template>
|
|
91
|
+
<div @keyup.down="navKeyUp('down')" @keyup.up="navKeyUp('up')">
|
|
92
|
+
<dropdown-container>
|
|
93
|
+
<template #toggler="{ toggle, dropdownState }">
|
|
94
|
+
<div>
|
|
95
|
+
<button
|
|
96
|
+
class="tracking-wider align-middle outline-none nav__text flex items-center gap-3xs"
|
|
97
|
+
:class="getMenuItemClass(menuTextSize, menuTextColor, menuTextBold)"
|
|
98
|
+
@click="toggle($event), dropdownButtonClick($event)"
|
|
99
|
+
>
|
|
100
|
+
<span>
|
|
101
|
+
{{ navItem.title }}
|
|
102
|
+
</span>
|
|
103
|
+
<svg
|
|
104
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
105
|
+
viewBox="0 0 448 512"
|
|
106
|
+
class="h-[0.8rem] fill-current"
|
|
107
|
+
:class="[
|
|
108
|
+
dropdownState ? 'rotate-180' : 'rotate-0',
|
|
109
|
+
'transition-transform duration-300 ease-in',
|
|
110
|
+
]"
|
|
111
|
+
>
|
|
112
|
+
<!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
|
113
|
+
<path
|
|
114
|
+
d="M224 416c-8.188 0-16.38-3.125-22.62-9.375l-192-192c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L224 338.8l169.4-169.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-192 192C240.4 412.9 232.2 416 224 416z"
|
|
115
|
+
/>
|
|
116
|
+
</svg>
|
|
117
|
+
</button>
|
|
118
|
+
<div
|
|
119
|
+
v-if="displayHighlight"
|
|
120
|
+
class="relative -top-[2px] h-[6px] nav__decorator"
|
|
121
|
+
:class="generateClass('BEFOREBG', highlightColor)"
|
|
122
|
+
></div>
|
|
123
|
+
</div>
|
|
124
|
+
</template>
|
|
125
|
+
<dropdown-content
|
|
126
|
+
v-slot="{ itemClick }"
|
|
127
|
+
className="border drop-shadow-sm"
|
|
128
|
+
>
|
|
129
|
+
<a
|
|
130
|
+
v-for="(item, idx) in navItem.children"
|
|
131
|
+
:href="item.url"
|
|
132
|
+
:target="item.target"
|
|
133
|
+
:key="idx"
|
|
134
|
+
ref="navItemRef"
|
|
135
|
+
class="px-xs py-2xs block w-full hover:bg-opacity-50 focus:bg-opacity-50"
|
|
136
|
+
:class="[
|
|
137
|
+
generateClass('BGCOLOR', bgColor),
|
|
138
|
+
generateClass('HVBGCOLOR', hoverBgColor),
|
|
139
|
+
generateClass('FCBGCOLOR', hoverBgColor),
|
|
140
|
+
generateClass('TEXTCOLOR', menuTextColor),
|
|
141
|
+
generateClass('BODYTEXT', menuTextSize),
|
|
142
|
+
]"
|
|
143
|
+
@click="itemClick(), navItemClick($event, item)"
|
|
144
|
+
>
|
|
145
|
+
{{ item.title }}
|
|
146
|
+
</a>
|
|
147
|
+
</dropdown-content>
|
|
148
|
+
</dropdown-container>
|
|
149
|
+
</div>
|
|
150
|
+
</template>
|
|
151
|
+
|
|
152
|
+
<style scoped lang="scss">
|
|
153
|
+
.nav__decorator {
|
|
154
|
+
&::before {
|
|
155
|
+
content: '';
|
|
156
|
+
position: absolute;
|
|
157
|
+
bottom: 0;
|
|
158
|
+
left: 0;
|
|
159
|
+
height: 100%;
|
|
160
|
+
width: 0;
|
|
161
|
+
transition: width 0.3s linear;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
.nav__text:focus + .nav__decorator::before,
|
|
165
|
+
.nav__text:hover + .nav__decorator::before {
|
|
166
|
+
width: 100%;
|
|
167
|
+
}
|
|
168
|
+
</style>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { BodyText, ColorPalette } from '@bobbykim/manguito-theme';
|
|
2
|
+
import type { MenuCollapseType } from './index.types';
|
|
3
|
+
declare const _default: import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
|
|
4
|
+
navItem: MenuCollapseType;
|
|
5
|
+
bgColor?: ColorPalette | undefined;
|
|
6
|
+
hoverBgColor?: ColorPalette | undefined;
|
|
7
|
+
menuTextSize?: BodyText | undefined;
|
|
8
|
+
menuTextColor?: ColorPalette | undefined;
|
|
9
|
+
menuTextBold?: boolean | undefined;
|
|
10
|
+
displayHighlight?: boolean | undefined;
|
|
11
|
+
highlightColor?: ColorPalette | undefined;
|
|
12
|
+
asLink?: boolean | undefined;
|
|
13
|
+
}>, {
|
|
14
|
+
menuTextSize: string;
|
|
15
|
+
bgColor: string;
|
|
16
|
+
hoverBgColor: string;
|
|
17
|
+
menuTextColor: string;
|
|
18
|
+
menuTextBold: boolean;
|
|
19
|
+
displayHighlight: boolean;
|
|
20
|
+
highlightColor: string;
|
|
21
|
+
asLink: boolean;
|
|
22
|
+
}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
23
|
+
"nav-link": (...args: any[]) => void;
|
|
24
|
+
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
|
|
25
|
+
navItem: MenuCollapseType;
|
|
26
|
+
bgColor?: ColorPalette | undefined;
|
|
27
|
+
hoverBgColor?: ColorPalette | undefined;
|
|
28
|
+
menuTextSize?: BodyText | undefined;
|
|
29
|
+
menuTextColor?: ColorPalette | undefined;
|
|
30
|
+
menuTextBold?: boolean | undefined;
|
|
31
|
+
displayHighlight?: boolean | undefined;
|
|
32
|
+
highlightColor?: ColorPalette | undefined;
|
|
33
|
+
asLink?: boolean | undefined;
|
|
34
|
+
}>, {
|
|
35
|
+
menuTextSize: string;
|
|
36
|
+
bgColor: string;
|
|
37
|
+
hoverBgColor: string;
|
|
38
|
+
menuTextColor: string;
|
|
39
|
+
menuTextBold: boolean;
|
|
40
|
+
displayHighlight: boolean;
|
|
41
|
+
highlightColor: string;
|
|
42
|
+
asLink: boolean;
|
|
43
|
+
}>>> & {
|
|
44
|
+
"onNav-link"?: ((...args: any[]) => any) | undefined;
|
|
45
|
+
}, {
|
|
46
|
+
bgColor: ColorPalette;
|
|
47
|
+
hoverBgColor: ColorPalette;
|
|
48
|
+
menuTextSize: BodyText;
|
|
49
|
+
menuTextColor: ColorPalette;
|
|
50
|
+
menuTextBold: boolean;
|
|
51
|
+
displayHighlight: boolean;
|
|
52
|
+
highlightColor: ColorPalette;
|
|
53
|
+
asLink: boolean;
|
|
54
|
+
}, {}>;
|
|
55
|
+
export default _default;
|
|
56
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
57
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
58
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
59
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
60
|
+
} : {
|
|
61
|
+
type: import('vue').PropType<T[K]>;
|
|
62
|
+
required: true;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
type __VLS_WithDefaults<P, D> = {
|
|
66
|
+
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
|
|
67
|
+
default: D[K];
|
|
68
|
+
}> : P[K];
|
|
69
|
+
};
|
|
70
|
+
type __VLS_Prettify<T> = {
|
|
71
|
+
[K in keyof T]: T[K];
|
|
72
|
+
} & {};
|