@cnamts/synapse 0.0.0-alpha.0 → 0.0.3-alpha
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/README.md +72 -2
- package/dist/design-system-v3.d.ts +234 -2
- package/dist/design-system-v3.js +1413 -4404
- package/dist/design-system-v3.umd.cjs +1 -2
- package/dist/style.css +1 -1
- package/package.json +37 -36
- package/src/components/Alert/Alert.vue +8 -8
- package/src/components/CollapsibleList/CollapsibleList.mdx +47 -0
- package/src/components/CollapsibleList/CollapsibleList.stories.ts +52 -0
- package/src/components/CollapsibleList/CollapsibleList.vue +157 -0
- package/src/components/CollapsibleList/tests/CollapsibleList.spec.ts +60 -0
- package/src/components/CollapsibleList/types.d.ts +5 -0
- package/src/components/Customs/CustomInputSelect/CustomInputSelect.mdx +42 -0
- package/src/components/Customs/CustomInputSelect/CustomInputSelect.stories.ts +154 -0
- package/src/components/Customs/CustomInputSelect/CustomInputSelect.vue +185 -0
- package/src/components/Customs/CustomInputSelect/tests/CustomInputSelect.spec.ts +216 -0
- package/src/components/Customs/CustomSelect/CustomSelect.mdx +47 -0
- package/src/components/Customs/CustomSelect/CustomSelect.stories.ts +182 -0
- package/src/components/Customs/CustomSelect/CustomSelect.vue +188 -0
- package/src/components/Customs/CustomSelect/tests/CustomSelect.spec.ts +236 -0
- package/src/components/FooterBar/A11yCompliance.ts +9 -0
- package/src/components/FooterBar/FooterBar.mdx +115 -0
- package/src/components/FooterBar/FooterBar.stories.ts +632 -0
- package/src/components/FooterBar/FooterBar.vue +330 -0
- package/src/components/FooterBar/config.ts +20 -0
- package/src/components/FooterBar/defaultSocialMediaLinks.ts +21 -0
- package/src/components/FooterBar/locales.ts +16 -0
- package/src/components/FooterBar/tests/FooterBar.spec.ts +167 -0
- package/src/components/FooterBar/tests/FooterBarConfig.spec.ts +36 -0
- package/src/components/FooterBar/tests/__snapshots__/FooterBar.spec.ts.snap +27 -0
- package/src/components/FooterBar/types.d.ts +10 -0
- package/src/components/FranceConnectBtn/FranceConnectBtn.vue +2 -2
- package/src/components/HeaderBar/HeaderBar.mdx +137 -0
- package/src/components/HeaderBar/HeaderBar.stories.ts +159 -0
- package/src/components/HeaderBar/HeaderBar.vue +238 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderComplexMenu.stories.ts +272 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderComplexMenu.vue +205 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuItem/HeaderMenuItem.stories.ts +49 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuItem/HeaderMenuItem.vue +51 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuItem/tests/HeaderMenuItem.spec.ts +16 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuItem/tests/__snapshots__/HeaderMenuItem.spec.ts.snap +3 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuSection/HeaderMenuSection.stories.ts +56 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuSection/HeaderMenuSection.vue +51 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuSection/tests/HeaderMenuSection.spec.ts +33 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderSubMenu/HeaderSubMenu.stories.ts +137 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderSubMenu/HeaderSubMenu.vue +180 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderSubMenu/tests/HeaderSubMenu.spec.ts +63 -0
- package/src/components/HeaderBar/HeaderComplexMenu/conts.ts +1 -0
- package/src/components/HeaderBar/HeaderComplexMenu/locals.ts +4 -0
- package/src/components/HeaderBar/HeaderComplexMenu/tests/HeaderComplexMenu.spec.ts +129 -0
- package/src/components/HeaderBar/HeaderComplexMenu/tests/__snapshots__/HeaderComplexMenu.spec.ts.snap +18 -0
- package/src/components/HeaderBar/HeaderComplexMenu/tests/useHandleSubMenus.spec.ts +158 -0
- package/src/components/HeaderBar/HeaderComplexMenu/useHandleSubMenus.ts +49 -0
- package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +106 -0
- package/src/components/HeaderBar/HeaderLogo/locales.ts +3 -0
- package/src/components/HeaderBar/HeaderLogo/logos/Logo-mobile.vue +117 -0
- package/src/components/HeaderBar/HeaderLogo/logos/Logo.vue +279 -0
- package/src/components/HeaderBar/HeaderLogo/tests/HeaderLogo.spec.ts +71 -0
- package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +88 -0
- package/src/components/HeaderBar/HeaderMenuBtn/locals.ts +4 -0
- package/src/components/HeaderBar/consts.scss +7 -0
- package/src/components/HeaderBar/consts.ts +2 -0
- package/src/components/HeaderBar/locales.ts +3 -0
- package/src/components/HeaderBar/tests/HeaderBar.spec.ts +210 -0
- package/src/components/HeaderBar/tests/__snapshots__/HeaderBar.spec.ts.snap +50 -0
- package/src/components/HeaderBar/tests/useHeaderResponsiveMode.spec.ts +26 -0
- package/src/components/HeaderBar/tests/useScrollDirection.spec.ts +34 -0
- package/src/components/HeaderBar/useHeaderResponsiveMode.ts +25 -0
- package/src/components/HeaderBar/useScrollDirection.ts +26 -0
- package/src/components/LangBtn/LangBtn.mdx +2 -1
- package/src/components/LangBtn/LangBtn.vue +3 -3
- package/src/components/Logo/Logo.mdx +26 -0
- package/src/components/Logo/Logo.stories.ts +217 -0
- package/src/components/Logo/Logo.vue +397 -0
- package/src/components/Logo/LogoSize.ts +7 -0
- package/src/components/Logo/locales.ts +6 -0
- package/src/components/Logo/logoDimensionsMapping.ts +16 -0
- package/src/components/Logo/tests/Logo.spec.ts +75 -0
- package/src/components/Logo/types.d.ts +8 -0
- package/src/components/NotificationBar/NotificationBar.vue +5 -7
- package/src/components/PageContainer/PageContainer.vue +0 -1
- package/src/components/SocialMediaLinks/DefaultSocialMediaLinks.ts +21 -0
- package/src/components/SocialMediaLinks/SocialMediaLinks.mdx +15 -0
- package/src/components/SocialMediaLinks/SocialMediaLinks.stories.ts +72 -0
- package/src/components/SocialMediaLinks/SocialMediaLinks.vue +92 -0
- package/src/components/SocialMediaLinks/locales.ts +3 -0
- package/src/components/SocialMediaLinks/tests/DefaultSocialMediaLinks.spec.ts +21 -0
- package/src/components/SocialMediaLinks/tests/SocialMediaLinks.spec.ts +89 -0
- package/src/components/SocialMediaLinks/tests/__snapshots__/SocialMediaLinks.spec.ts.snap +24 -0
- package/src/components/SocialMediaLinks/types.d.ts +5 -0
- package/src/components/index.ts +6 -0
- package/src/directives/clickOutside.ts +24 -0
- package/src/temp/TestDTComponent.vue +6 -10
- package/src/temp/gridsTests.vue +0 -4
- package/src/utils/propValidator/index.ts +20 -0
- package/src/utils/propValidator/tests/propValidator.spec.ts +40 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Controls, Canvas, Meta, Source } from "@storybook/blocks";
|
|
2
|
+
import * as HeaderBarStories from "./HeaderBar.stories";
|
|
3
|
+
|
|
4
|
+
Work in progress
|
|
5
|
+
===
|
|
6
|
+
|
|
7
|
+
Pour voir l'utilisation du menu, veuillez consulter le composant `HeaderComplexMenu` dans le menu de gauche.
|
|
8
|
+
|
|
9
|
+
# HeaderBar
|
|
10
|
+
|
|
11
|
+
<Canvas of={HeaderBarStories.Default} />
|
|
12
|
+
|
|
13
|
+
## API
|
|
14
|
+
|
|
15
|
+
<Controls of={HeaderBarStories.Default} />
|
|
16
|
+
|
|
17
|
+
## Les slots
|
|
18
|
+
|
|
19
|
+
Le composant `HeaderBar` possède les slots suivants :
|
|
20
|
+
|
|
21
|
+
### Prepend
|
|
22
|
+
|
|
23
|
+
Le slot `prepend` permet d'ajouter du contenu en haut du header, il suivra le comportement du header au scroll.
|
|
24
|
+
Il est possible de récuperer le status du Menu de header en utilisant la prop `isMenuOpen` du slot `prepend`. (Fonctionne uniquement pour les menu s'enregistrant via la fonction injectée `registerHeaderMenu`, ce qui est le cas pour le composant `HeaderComplexMenu`)
|
|
25
|
+
|
|
26
|
+
<Source
|
|
27
|
+
dark
|
|
28
|
+
code={`
|
|
29
|
+
<template>
|
|
30
|
+
<HeaderBar>
|
|
31
|
+
<template #menu>
|
|
32
|
+
<HeaderComplexMenu>
|
|
33
|
+
...
|
|
34
|
+
</HeaderComplexMenu>
|
|
35
|
+
</template>
|
|
36
|
+
<template #prepend="{ isMenuOpen }">
|
|
37
|
+
<div v-if="isMenuOpen">Menu ouvert</div>
|
|
38
|
+
<div v-else>Menu fermé</div>
|
|
39
|
+
</template>
|
|
40
|
+
</HeaderBar>
|
|
41
|
+
</template>
|
|
42
|
+
`}
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
### Append
|
|
46
|
+
|
|
47
|
+
Le slot `append` permet d'ajouter du contenu en bas du header, il suivra le comportement du header au scroll.
|
|
48
|
+
Il est également possible de récuperer le status du Menu de header en utilisant la prop `isMenuOpen` du slot `append`.
|
|
49
|
+
|
|
50
|
+
<Source
|
|
51
|
+
dark
|
|
52
|
+
code={`
|
|
53
|
+
<template>
|
|
54
|
+
<HeaderBar>
|
|
55
|
+
<template #menu>
|
|
56
|
+
<HeaderComplexMenu>
|
|
57
|
+
...
|
|
58
|
+
</HeaderComplexMenu>
|
|
59
|
+
</template>
|
|
60
|
+
<template #append="{ isMenuOpen }">
|
|
61
|
+
<div v-if="isMenuOpen">Menu ouvert</div>
|
|
62
|
+
<div v-else>Menu fermé</div>
|
|
63
|
+
</template>
|
|
64
|
+
</HeaderBar>
|
|
65
|
+
</template>
|
|
66
|
+
`}
|
|
67
|
+
/>
|
|
68
|
+
|
|
69
|
+
### Menu
|
|
70
|
+
|
|
71
|
+
Le slot `menu` permet d'ajouter un menu au header. Il est recommandé d'utiliser le composant `HeaderComplexMenu` du design system Pour tout menu contenant plus de 5 éléments.
|
|
72
|
+
|
|
73
|
+
<Source
|
|
74
|
+
dark
|
|
75
|
+
code={`
|
|
76
|
+
<template>
|
|
77
|
+
<HeaderBar>
|
|
78
|
+
<template #menu>
|
|
79
|
+
<HeaderComplexMenu>
|
|
80
|
+
...
|
|
81
|
+
</HeaderComplexMenu>
|
|
82
|
+
</template>
|
|
83
|
+
</HeaderBar>
|
|
84
|
+
</template>
|
|
85
|
+
`}
|
|
86
|
+
/>
|
|
87
|
+
|
|
88
|
+
### Logo
|
|
89
|
+
|
|
90
|
+
Le slot `logo` permet d'ecraser le logo par défaut du header. Il est déconseillé de l'utiliser. Si cela n'est pas possible l'intégration d'un nouveau logo doit se faire en respectant les guidelines de la charte graphique.
|
|
91
|
+
|
|
92
|
+
<Source
|
|
93
|
+
dark
|
|
94
|
+
code={`
|
|
95
|
+
<template>
|
|
96
|
+
<HeaderBar>
|
|
97
|
+
<template #logo>
|
|
98
|
+
<img src="https://via.placeholder.com/150" alt="Logo" />
|
|
99
|
+
</template>
|
|
100
|
+
</HeaderBar>
|
|
101
|
+
</template>
|
|
102
|
+
`}
|
|
103
|
+
/>
|
|
104
|
+
|
|
105
|
+
### HeaderSide
|
|
106
|
+
|
|
107
|
+
Le slot `header-side` permet d'ajouter du contenu à droite du header. Il est possible d'ajouter plusieurs éléments dans ce slot.
|
|
108
|
+
Il sera principalement utilisé pour ajouter un boutton de connexion, d'accès à un compte ou de recherche.
|
|
109
|
+
Il est necessaire de faire attention à la place que prendront les éléments en mode mobile et de prévoir un mode réduit ou bien de les déporter dans le menu burger.
|
|
110
|
+
|
|
111
|
+
<Source dark code={`
|
|
112
|
+
<script setup lang="ts">
|
|
113
|
+
import { mdiMagnify, mdiAccountCircleOutline } from '@mdi/js'
|
|
114
|
+
</script>
|
|
115
|
+
|
|
116
|
+
<template>
|
|
117
|
+
<HeaderBar>
|
|
118
|
+
<template #header-side>
|
|
119
|
+
<div class="d-flex justify-center h-100 ga-4 pr-4">
|
|
120
|
+
<VBtn
|
|
121
|
+
variant="text"
|
|
122
|
+
:prepend-icon="mdiMagnify"
|
|
123
|
+
color="primary"
|
|
124
|
+
>
|
|
125
|
+
Rechercher
|
|
126
|
+
</VBtn>
|
|
127
|
+
<VBtn
|
|
128
|
+
color="primary"
|
|
129
|
+
:prepend-icon="mdiAccountCircleOutline"
|
|
130
|
+
>
|
|
131
|
+
Login
|
|
132
|
+
</VBtn>
|
|
133
|
+
</div>
|
|
134
|
+
</template>
|
|
135
|
+
</HeaderBar>
|
|
136
|
+
</template>
|
|
137
|
+
`} />
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
|
|
3
|
+
import HeaderBar from './HeaderBar.vue'
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: 'Components/HeaderBar',
|
|
7
|
+
component: HeaderBar,
|
|
8
|
+
argTypes: {
|
|
9
|
+
'serviceTitle': {
|
|
10
|
+
control: { type: 'text' },
|
|
11
|
+
description: 'Le nom du service tel qu\'il sera affiché a coté du logo.',
|
|
12
|
+
table: {
|
|
13
|
+
type: {
|
|
14
|
+
summary: 'string',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
'serviceSubtitle': {
|
|
19
|
+
control: { type: 'text' },
|
|
20
|
+
description: 'Le sous-titre du service.',
|
|
21
|
+
table: {
|
|
22
|
+
type: {
|
|
23
|
+
summary: 'string',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
'homeAriaLabel': {
|
|
28
|
+
control: { type: 'text' },
|
|
29
|
+
description: 'Le texte de l\'attribut aria-label pour le logo du header.',
|
|
30
|
+
table: {
|
|
31
|
+
type: {
|
|
32
|
+
summary: 'string',
|
|
33
|
+
},
|
|
34
|
+
defaultValue: {
|
|
35
|
+
summary:
|
|
36
|
+
'Logo de l\'Assurance Maladie, cliquez pour revenir à l\'accueil',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
'sticky': {
|
|
41
|
+
control: { type: 'boolean' },
|
|
42
|
+
description:
|
|
43
|
+
'Si le header doit rester collé en haut de la page lors du scroll.',
|
|
44
|
+
table: {
|
|
45
|
+
type: {
|
|
46
|
+
summary: 'boolean',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
'hideWhenDown': {
|
|
51
|
+
control: { type: 'boolean' },
|
|
52
|
+
description:
|
|
53
|
+
'Si le header doit se cacher lors du scroll vers le bas en mode mobile. \n Cette propriété est ignorée en mode desktop. \n Présuppose que le header est en mode sticky.',
|
|
54
|
+
table: {
|
|
55
|
+
type: {
|
|
56
|
+
summary: 'boolean',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
'prepend': {
|
|
61
|
+
control: { type: 'text' },
|
|
62
|
+
table: {
|
|
63
|
+
type: {
|
|
64
|
+
summary: '{ menu-open: boolean }',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
'append': {
|
|
69
|
+
control: { type: 'text' },
|
|
70
|
+
table: {
|
|
71
|
+
type: {
|
|
72
|
+
summary: '{ menu-open: boolean }',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
'menu': {
|
|
77
|
+
control: { type: 'text' },
|
|
78
|
+
table: {
|
|
79
|
+
type: {
|
|
80
|
+
summary: '{ menu-open: boolean }',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
'logo': {
|
|
85
|
+
control: { type: 'text' },
|
|
86
|
+
table: {
|
|
87
|
+
type: {
|
|
88
|
+
summary: `{
|
|
89
|
+
menu-open: boolean,
|
|
90
|
+
home-aria-label: string,
|
|
91
|
+
service-title: string,
|
|
92
|
+
service-subtitle: string,
|
|
93
|
+
}`,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
'header-side': {
|
|
98
|
+
control: { type: 'text' },
|
|
99
|
+
table: {
|
|
100
|
+
type: {
|
|
101
|
+
summary: '{ menu-open: boolean }',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
} satisfies Meta<typeof HeaderBar>
|
|
107
|
+
|
|
108
|
+
export default meta
|
|
109
|
+
|
|
110
|
+
type Story = StoryObj<typeof meta>
|
|
111
|
+
|
|
112
|
+
export const Default: Story = {
|
|
113
|
+
args: {
|
|
114
|
+
serviceTitle: 'Synapse',
|
|
115
|
+
serviceSubtitle: 'Design System',
|
|
116
|
+
},
|
|
117
|
+
decorators: [
|
|
118
|
+
() => ({
|
|
119
|
+
template: `<div class="position: relative"><story/></div>`,
|
|
120
|
+
}),
|
|
121
|
+
],
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const Sticky: Story = {
|
|
125
|
+
args: {
|
|
126
|
+
serviceTitle: 'Synapse',
|
|
127
|
+
serviceSubtitle: 'Design System',
|
|
128
|
+
},
|
|
129
|
+
decorators: [
|
|
130
|
+
() => ({
|
|
131
|
+
template: `<div class="position: relative">
|
|
132
|
+
<story/>
|
|
133
|
+
<div
|
|
134
|
+
style="height: 200vh; background-color: #f5f5f5; margin: auto; margin-top: 2rem; max-width: 1200px; padding: 1em;"
|
|
135
|
+
>Contenu de la page</div>
|
|
136
|
+
</div>`,
|
|
137
|
+
}),
|
|
138
|
+
],
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export const WithExternalTopMenu: Story = {
|
|
142
|
+
args: {
|
|
143
|
+
serviceTitle: 'Synapse',
|
|
144
|
+
serviceSubtitle: 'Design System',
|
|
145
|
+
},
|
|
146
|
+
decorators: [
|
|
147
|
+
() => ({
|
|
148
|
+
template: `<div class="position: relative">
|
|
149
|
+
<div style="background-color: orange; margin:auto; max-width: 1712px; padding: 1rem 4rem">
|
|
150
|
+
Menu supèrieur externe au composant
|
|
151
|
+
</div>
|
|
152
|
+
<story/>
|
|
153
|
+
<div
|
|
154
|
+
style="height: 200vh; background-color: #f5f5f5; margin: auto; margin-top: 2rem; max-width: 1200px; padding: 1em;"
|
|
155
|
+
>Contenu de la page</div>
|
|
156
|
+
</div>`,
|
|
157
|
+
}),
|
|
158
|
+
],
|
|
159
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, onMounted, onUnmounted, provide, ref, watch, type CSSProperties, type Ref } from 'vue'
|
|
3
|
+
import HeaderLogo from './HeaderLogo/HeaderLogo.vue'
|
|
4
|
+
import { registerHeaderMenuKey } from './consts'
|
|
5
|
+
import { locales } from './locales'
|
|
6
|
+
import useHeaderResponsiveMode from './useHeaderResponsiveMode'
|
|
7
|
+
import useScrollDirection from './useScrollDirection'
|
|
8
|
+
|
|
9
|
+
const menuOpen = ref<boolean>()
|
|
10
|
+
|
|
11
|
+
type SlotProps = {
|
|
12
|
+
menuOpen: boolean | undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type LogoProps = {
|
|
16
|
+
homeAriaLabel?: string
|
|
17
|
+
serviceTitle?: string
|
|
18
|
+
serviceSubtitle?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
defineSlots<{
|
|
22
|
+
'prepend': (props: SlotProps) => unknown
|
|
23
|
+
'append': (props: SlotProps) => unknown
|
|
24
|
+
'menu': (props: SlotProps) => unknown
|
|
25
|
+
'logo': (props: SlotProps & LogoProps) => unknown
|
|
26
|
+
'header-side': (props: SlotProps) => unknown
|
|
27
|
+
}>()
|
|
28
|
+
|
|
29
|
+
const props = withDefaults(defineProps<{
|
|
30
|
+
/** Keep the header visible */
|
|
31
|
+
sticky?: boolean
|
|
32
|
+
/**
|
|
33
|
+
* Show the header at sticky only when the user scroll up in mobile
|
|
34
|
+
* Need 'sticky' at true,
|
|
35
|
+
*/
|
|
36
|
+
hideWhenDown?: boolean
|
|
37
|
+
} & LogoProps>(),
|
|
38
|
+
{
|
|
39
|
+
sticky: true,
|
|
40
|
+
hideWhenDown: false,
|
|
41
|
+
homeAriaLabel: locales.homeAriaLabel,
|
|
42
|
+
serviceTitle: undefined,
|
|
43
|
+
serviceSubtitle: undefined,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
function registerHeaderMenu(childMenuStatus: Ref<boolean>) {
|
|
47
|
+
watch(childMenuStatus, (newVal) => {
|
|
48
|
+
menuOpen.value = newVal
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
provide(registerHeaderMenuKey, registerHeaderMenu)
|
|
52
|
+
|
|
53
|
+
const header = ref<HTMLElement | null>(null)
|
|
54
|
+
const headerSticky = ref<HTMLElement | null>(null)
|
|
55
|
+
|
|
56
|
+
/** The height of the header to reserve */
|
|
57
|
+
const headerMinHeight = ref('auto')
|
|
58
|
+
/** The position of the header (when static) from the top of the page */
|
|
59
|
+
const headerOffset = ref(0)
|
|
60
|
+
/** Is the top of the header visible in the viewport when static */
|
|
61
|
+
const isTopOfHeaderVisible = ref(true)
|
|
62
|
+
/** Is the header out of the viewport */
|
|
63
|
+
const isScrollBelowHeader = ref(false)
|
|
64
|
+
/** Activate the hide animation */
|
|
65
|
+
const shouldAnimateHideHeader = ref(false)
|
|
66
|
+
|
|
67
|
+
function handleScroll() {
|
|
68
|
+
const headerRec = header.value!.getBoundingClientRect()
|
|
69
|
+
headerOffset.value = headerRec.top + window.scrollY
|
|
70
|
+
headerMinHeight.value = isTopOfHeaderVisible.value ? 'auto' : `${header.value!.offsetHeight}px`
|
|
71
|
+
isTopOfHeaderVisible.value = window.scrollY <= headerOffset.value
|
|
72
|
+
isScrollBelowHeader.value = window.scrollY > headerOffset.value + headerRec.height
|
|
73
|
+
|
|
74
|
+
// activate the header animation with a delay to avoid a flicker effect when the user scroll down
|
|
75
|
+
shouldAnimateHideHeader.value = window.scrollY > headerOffset.value + (headerRec.height * 2)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
onMounted(() => {
|
|
79
|
+
handleScroll()
|
|
80
|
+
window.addEventListener('scroll', handleScroll)
|
|
81
|
+
window.addEventListener('resize', handleScroll)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
onUnmounted(() => {
|
|
85
|
+
window.removeEventListener('scroll', handleScroll)
|
|
86
|
+
window.removeEventListener('resize', handleScroll)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const headerStyle = computed<CSSProperties>(() => {
|
|
90
|
+
return {
|
|
91
|
+
minHeight: headerMinHeight.value,
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const { scrollDirection } = useScrollDirection()
|
|
96
|
+
const { isDesktop } = useHeaderResponsiveMode()
|
|
97
|
+
|
|
98
|
+
const headerStickyStyle = computed<CSSProperties>(() => {
|
|
99
|
+
if (
|
|
100
|
+
props.hideWhenDown
|
|
101
|
+
&& !isDesktop.value
|
|
102
|
+
&& !menuOpen.value
|
|
103
|
+
) {
|
|
104
|
+
const staticHeader = (
|
|
105
|
+
(scrollDirection.value === '' && isTopOfHeaderVisible.value)
|
|
106
|
+
|| (scrollDirection.value === 'bottom' && !isScrollBelowHeader.value)
|
|
107
|
+
|| (scrollDirection.value === 'top' && isTopOfHeaderVisible.value)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
const hide = (
|
|
111
|
+
scrollDirection.value === 'bottom'
|
|
112
|
+
&& isScrollBelowHeader.value
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
position: staticHeader ? 'relative' : 'fixed',
|
|
117
|
+
top: staticHeader ? 'auto' : '0',
|
|
118
|
+
transform: hide ? 'translateY(-100%)' : 'none',
|
|
119
|
+
transition: shouldAnimateHideHeader.value ? 'transform 0.3s ease' : 'none',
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
position: !isTopOfHeaderVisible.value && props.sticky ? 'fixed' : 'relative',
|
|
125
|
+
top: !isTopOfHeaderVisible.value && props.sticky ? '0' : 'auto',
|
|
126
|
+
transform: 'none',
|
|
127
|
+
transition: 'none',
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
</script>
|
|
131
|
+
|
|
132
|
+
<template>
|
|
133
|
+
<header
|
|
134
|
+
ref="header"
|
|
135
|
+
class="header"
|
|
136
|
+
:style="headerStyle"
|
|
137
|
+
>
|
|
138
|
+
<div
|
|
139
|
+
ref="headerSticky"
|
|
140
|
+
class="sticky-header"
|
|
141
|
+
:style="headerStickyStyle"
|
|
142
|
+
>
|
|
143
|
+
<div
|
|
144
|
+
v-if="$slots.prepend"
|
|
145
|
+
class="header-prepend"
|
|
146
|
+
>
|
|
147
|
+
<slot
|
|
148
|
+
name="prepend"
|
|
149
|
+
:menu-open
|
|
150
|
+
/>
|
|
151
|
+
</div>
|
|
152
|
+
<div class="inner-header d-flex">
|
|
153
|
+
<slot
|
|
154
|
+
name="menu"
|
|
155
|
+
:menu-open
|
|
156
|
+
/>
|
|
157
|
+
|
|
158
|
+
<div class="header-logo">
|
|
159
|
+
<slot
|
|
160
|
+
name="logo"
|
|
161
|
+
:menu-open
|
|
162
|
+
:home-aria-label
|
|
163
|
+
:service-title
|
|
164
|
+
:service-subtitle
|
|
165
|
+
>
|
|
166
|
+
<HeaderLogo
|
|
167
|
+
:aria-label="homeAriaLabel"
|
|
168
|
+
:service-title="serviceTitle"
|
|
169
|
+
:service-subtitle="serviceSubtitle"
|
|
170
|
+
/>
|
|
171
|
+
</slot>
|
|
172
|
+
</div>
|
|
173
|
+
<div
|
|
174
|
+
v-if="$slots['header-side']"
|
|
175
|
+
class="header-side"
|
|
176
|
+
>
|
|
177
|
+
<slot
|
|
178
|
+
name="header-side"
|
|
179
|
+
:menu-open
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
<div
|
|
184
|
+
v-if="$slots.append"
|
|
185
|
+
class="header-append"
|
|
186
|
+
>
|
|
187
|
+
<slot
|
|
188
|
+
name="append"
|
|
189
|
+
:menu-open
|
|
190
|
+
/>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
</header>
|
|
194
|
+
</template>
|
|
195
|
+
|
|
196
|
+
<style lang="scss" scoped>
|
|
197
|
+
@use '@/assets/tokens.scss' as *;
|
|
198
|
+
@use './consts' as *;
|
|
199
|
+
|
|
200
|
+
.header {
|
|
201
|
+
top: 0;
|
|
202
|
+
width: 100%;
|
|
203
|
+
height: $header-height;
|
|
204
|
+
max-width: $header-max-width;
|
|
205
|
+
margin: 0 auto;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.sticky-header {
|
|
209
|
+
background-color: $neutral-white;
|
|
210
|
+
border-bottom: solid 1px $blue-lighten-80;
|
|
211
|
+
width: 100%;
|
|
212
|
+
height: $header-height;
|
|
213
|
+
max-width: $header-max-width;
|
|
214
|
+
z-index: 1000;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.inner-header {
|
|
218
|
+
display: flex;
|
|
219
|
+
align-items: center;
|
|
220
|
+
height: 100%;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.header-logo {
|
|
224
|
+
margin-left: 2rem;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.header-side {
|
|
228
|
+
display: flex;
|
|
229
|
+
align-items: center;
|
|
230
|
+
margin-left: auto;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@media screen and (min-width: $header-breakpoint) {
|
|
234
|
+
.header, .sticky-header {
|
|
235
|
+
height: $header-height-desktop;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
</style>
|