@apptegy/nuxt-navigation 0.1.5 → 0.1.7
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/dist/module.json +1 -1
- package/dist/runtime/components/Nav/Header.vue +3 -7
- package/dist/runtime/components/Nav/OrgSelect.vue +75 -70
- package/dist/runtime/components/Nav/Sidebar.vue +8 -10
- package/dist/runtime/components/Nav/SidebarSection.vue +0 -1
- package/dist/runtime/components/Nav/SidebarToggle.vue +3 -5
- package/dist/runtime/components/Nav/{UserDropdown/index.vue → UserDropdown.vue} +9 -4
- package/dist/runtime/composables/useDropdown.js +6 -0
- package/dist/runtime/composables/useSidebar.d.ts +5 -0
- package/dist/runtime/composables/useSidebar.js +13 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -4,18 +4,17 @@
|
|
|
4
4
|
:class="{ sticky }"
|
|
5
5
|
role="banner"
|
|
6
6
|
>
|
|
7
|
-
<NavSidebarToggle
|
|
7
|
+
<NavSidebarToggle />
|
|
8
8
|
<div class="header__breadcrumbs">
|
|
9
9
|
<slot name="breadcrumbs" />
|
|
10
10
|
</div>
|
|
11
11
|
<slot name="org-select" />
|
|
12
12
|
<slot name="user-controls" />
|
|
13
|
-
<NavUserDropdown :user="user" :user-dropdown-options="userDropdownOptions"
|
|
13
|
+
<NavUserDropdown :user="user" :user-dropdown-options="userDropdownOptions" @select-option="(index) => $emit('selected-option', index)"/>
|
|
14
14
|
</header>
|
|
15
15
|
</template>
|
|
16
16
|
|
|
17
17
|
<script setup lang="ts">
|
|
18
|
-
|
|
19
18
|
interface IHeaderProps {
|
|
20
19
|
sticky?: boolean;
|
|
21
20
|
}
|
|
@@ -26,13 +25,10 @@ interface IUserDropdown {
|
|
|
26
25
|
avatar?: string;
|
|
27
26
|
};
|
|
28
27
|
userDropdownOptions: Array<unknown>;
|
|
29
|
-
selectedOption?: unknown
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
|
|
33
30
|
defineProps<IHeaderProps & IUserDropdown>();
|
|
34
|
-
defineEmits(['
|
|
35
|
-
|
|
31
|
+
defineEmits(['selected-option']);
|
|
36
32
|
</script>
|
|
37
33
|
|
|
38
34
|
<style scoped>
|
|
@@ -1,69 +1,11 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="org-selection">
|
|
3
|
-
<label id="org-dropdown-label" class="sr-only">
|
|
4
|
-
{{ $t("navigation.orgDropdown") }}
|
|
5
|
-
</label>
|
|
6
|
-
<div
|
|
7
|
-
ref="dropdownTriggerRef"
|
|
8
|
-
aria-labelledby="org-dropdown-label"
|
|
9
|
-
aria-controls="organizations-options-list"
|
|
10
|
-
:aria-expanded="active"
|
|
11
|
-
aria-haspopup="listbox"
|
|
12
|
-
role="combobox"
|
|
13
|
-
class="dropdown-trigger"
|
|
14
|
-
>
|
|
15
|
-
<input
|
|
16
|
-
ref="inputRef"
|
|
17
|
-
type="text"
|
|
18
|
-
class="org-title"
|
|
19
|
-
:placeholder="$t('navigation.orgPlaceholder')"
|
|
20
|
-
:value="active ? searchQuery : selectedOrg?.name"
|
|
21
|
-
@keydown="keydownActionsOnTrigger"
|
|
22
|
-
@click.prevent="toggleDropdown"
|
|
23
|
-
@input="handleDropdownSearch"
|
|
24
|
-
>
|
|
25
|
-
<span v-if="selectedOrg?.intranet" class="badge selected">
|
|
26
|
-
<a-icon icon="16:lock-locked" />
|
|
27
|
-
{{ $t("navigation.orgBadge") }}
|
|
28
|
-
</span>
|
|
29
|
-
</div>
|
|
30
|
-
<div
|
|
31
|
-
v-show="active"
|
|
32
|
-
id="organizations-options-list"
|
|
33
|
-
class="dropdown"
|
|
34
|
-
role="listbox"
|
|
35
|
-
>
|
|
36
|
-
<div
|
|
37
|
-
v-for="(option) in sortedOrgs"
|
|
38
|
-
:key="option.id"
|
|
39
|
-
ref="optionRef"
|
|
40
|
-
v-on-click-outside="onClickOutsideHandler"
|
|
41
|
-
role="option"
|
|
42
|
-
class="org-option"
|
|
43
|
-
:class="{ selected: option.id === modelValue }"
|
|
44
|
-
:aria-selected="option.id === modelValue"
|
|
45
|
-
tabindex="-1"
|
|
46
|
-
@keydown="handleSelectedOrg($event, option.id)"
|
|
47
|
-
@click="handleSelectedOrg($event, option.id)"
|
|
48
|
-
>
|
|
49
|
-
<span :class="{ pinned: option.pinned, 'item-flex': true }"
|
|
50
|
-
>{{ option.name }}
|
|
51
|
-
<span v-if="option.intranet" class="badge selected">
|
|
52
|
-
<a-icon icon="16:lock-locked" />
|
|
53
|
-
{{ $t("navigation.orgBadge") }}
|
|
54
|
-
</span>
|
|
55
|
-
</span>
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
</template>
|
|
60
|
-
|
|
61
1
|
<script setup lang="ts">
|
|
62
|
-
import { useDropdown, useNuxtApp } from "#imports";
|
|
2
|
+
import { useDropdown, useNuxtApp, useAppConfig } from "#imports";
|
|
63
3
|
import { vOnClickOutside } from "@vueuse/components";
|
|
64
4
|
import { ref, computed } from "vue";
|
|
65
5
|
|
|
66
6
|
const { $t } = useNuxtApp();
|
|
7
|
+
const appConfig = useAppConfig();
|
|
8
|
+
const zIndex = computed(() => appConfig?.navigation?.zIndex || 100)
|
|
67
9
|
|
|
68
10
|
interface IOrg {
|
|
69
11
|
name: string;
|
|
@@ -74,17 +16,17 @@ interface IOrg {
|
|
|
74
16
|
|
|
75
17
|
interface IOrgSelectProps {
|
|
76
18
|
orgs: Array<IOrg>;
|
|
77
|
-
modelValue: number
|
|
19
|
+
modelValue: number;
|
|
78
20
|
}
|
|
79
21
|
|
|
80
22
|
const emit = defineEmits<{
|
|
81
|
-
|
|
82
|
-
|
|
23
|
+
"update:model-value": [index: number];
|
|
24
|
+
}>();
|
|
83
25
|
|
|
84
26
|
const dropdownTriggerRef = ref();
|
|
85
27
|
const optionRef = ref();
|
|
86
28
|
const selectedOrg = computed(() => {
|
|
87
|
-
return props.orgs.find(({id}) => id == props.modelValue);
|
|
29
|
+
return props.orgs.find(({ id }) => id == props.modelValue);
|
|
88
30
|
});
|
|
89
31
|
|
|
90
32
|
const props = defineProps<IOrgSelectProps>();
|
|
@@ -116,16 +58,76 @@ const sortedOrgs = computed(() => {
|
|
|
116
58
|
});
|
|
117
59
|
|
|
118
60
|
function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
|
|
119
|
-
if($event.type ==
|
|
61
|
+
if ($event.type == "click") {
|
|
120
62
|
emit("update:model-value", orgId);
|
|
121
63
|
closeDropdown();
|
|
122
|
-
} else if ($event.type ==
|
|
64
|
+
} else if ($event.type == "keydown") {
|
|
123
65
|
emit("update:model-value", orgId);
|
|
124
66
|
handleKeydown($event as KeyboardEvent, orgId);
|
|
125
67
|
}
|
|
126
68
|
}
|
|
127
69
|
</script>
|
|
128
70
|
|
|
71
|
+
<template>
|
|
72
|
+
<div class="org-selection">
|
|
73
|
+
<label id="org-dropdown-label" class="sr-only">
|
|
74
|
+
{{ $t("navigation.orgDropdown") }}
|
|
75
|
+
</label>
|
|
76
|
+
<div
|
|
77
|
+
ref="dropdownTriggerRef"
|
|
78
|
+
aria-labelledby="org-dropdown-label"
|
|
79
|
+
aria-controls="organizations-options-list"
|
|
80
|
+
:aria-expanded="active"
|
|
81
|
+
aria-haspopup="listbox"
|
|
82
|
+
role="combobox"
|
|
83
|
+
class="dropdown-trigger"
|
|
84
|
+
>
|
|
85
|
+
<input
|
|
86
|
+
ref="inputRef"
|
|
87
|
+
type="text"
|
|
88
|
+
class="org-title"
|
|
89
|
+
:placeholder="$t('navigation.orgPlaceholder')"
|
|
90
|
+
:value="active ? searchQuery : selectedOrg?.name"
|
|
91
|
+
@keydown="keydownActionsOnTrigger"
|
|
92
|
+
@click.prevent="toggleDropdown"
|
|
93
|
+
@input="handleDropdownSearch"
|
|
94
|
+
>
|
|
95
|
+
<span v-if="selectedOrg?.intranet" class="badge selected">
|
|
96
|
+
<a-icon icon="16:lock-locked" />
|
|
97
|
+
{{ $t("navigation.orgBadge") }}
|
|
98
|
+
</span>
|
|
99
|
+
</div>
|
|
100
|
+
<div
|
|
101
|
+
v-show="active"
|
|
102
|
+
id="organizations-options-list"
|
|
103
|
+
class="dropdown"
|
|
104
|
+
role="listbox"
|
|
105
|
+
>
|
|
106
|
+
<div
|
|
107
|
+
v-for="option in sortedOrgs"
|
|
108
|
+
:key="option.id"
|
|
109
|
+
ref="optionRef"
|
|
110
|
+
v-on-click-outside="onClickOutsideHandler"
|
|
111
|
+
role="option"
|
|
112
|
+
class="org-option"
|
|
113
|
+
:class="{ selected: option.id === modelValue }"
|
|
114
|
+
:aria-selected="option.id === modelValue"
|
|
115
|
+
tabindex="-1"
|
|
116
|
+
@keydown="handleSelectedOrg($event, option.id)"
|
|
117
|
+
@click="handleSelectedOrg($event, option.id)"
|
|
118
|
+
>
|
|
119
|
+
<span :class="{ pinned: option.pinned, 'item-flex': true }"
|
|
120
|
+
>{{ option.name }}
|
|
121
|
+
<span v-if="option.intranet" class="badge selected">
|
|
122
|
+
<a-icon icon="16:lock-locked" />
|
|
123
|
+
{{ $t("navigation.orgBadge") }}
|
|
124
|
+
</span>
|
|
125
|
+
</span>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</template>
|
|
130
|
+
|
|
129
131
|
<style scoped>
|
|
130
132
|
#organizations-options-list {
|
|
131
133
|
position: absolute;
|
|
@@ -133,7 +135,7 @@ function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
|
|
|
133
135
|
max-height: 300px;
|
|
134
136
|
overflow-y: auto;
|
|
135
137
|
background-color: var(--primary-white);
|
|
136
|
-
z-index:
|
|
138
|
+
z-index: v-bind(zIndex);
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
.org-selection {
|
|
@@ -171,8 +173,11 @@ function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
|
|
|
171
173
|
.org-selection .dropdown-trigger .org-title:focus {
|
|
172
174
|
outline: none;
|
|
173
175
|
}
|
|
176
|
+
.org-selection .dropdown {
|
|
177
|
+
border-radius: 0 0 4px 4px;
|
|
178
|
+
box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.06);
|
|
179
|
+
}
|
|
174
180
|
.org-selection .dropdown .org-option {
|
|
175
|
-
display: block;
|
|
176
181
|
padding: 12px;
|
|
177
182
|
min-height: 40px;
|
|
178
183
|
line-height: 16px;
|
|
@@ -200,7 +205,7 @@ function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
|
|
|
200
205
|
background-color: var(--purple-50);
|
|
201
206
|
padding: 2px 4px;
|
|
202
207
|
color: white;
|
|
203
|
-
border-radius:
|
|
208
|
+
border-radius: 2px;
|
|
204
209
|
text-transform: uppercase;
|
|
205
210
|
}
|
|
206
211
|
.org-selection .badge svg {
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
<NavSidebarSection
|
|
21
21
|
:application="application"
|
|
22
22
|
:active="currentApplication === application.text"
|
|
23
|
-
:navbar-expanded="expanded"
|
|
24
23
|
>
|
|
25
24
|
<slot v-if="currentApplication === application.text" />
|
|
26
25
|
</NavSidebarSection>
|
|
@@ -28,7 +27,6 @@
|
|
|
28
27
|
<li>
|
|
29
28
|
<NavHelpArticles
|
|
30
29
|
v-if="showHelpArticles"
|
|
31
|
-
:navbar-expanded="expanded"
|
|
32
30
|
:help-article-options="helpArticleOptions"
|
|
33
31
|
/>
|
|
34
32
|
</li>
|
|
@@ -45,8 +43,7 @@
|
|
|
45
43
|
<slot name="logo">
|
|
46
44
|
<NuxtLink :to="homepageUrl">
|
|
47
45
|
<div class="navbar--logo">
|
|
48
|
-
<img
|
|
49
|
-
<img v-else :src="logo.iconSrc" :alt="logo.alt">
|
|
46
|
+
<img :src="logo.src" :alt="logo.alt">
|
|
50
47
|
</div>
|
|
51
48
|
</NuxtLink>
|
|
52
49
|
</slot>
|
|
@@ -54,8 +51,9 @@
|
|
|
54
51
|
</template>
|
|
55
52
|
|
|
56
53
|
<script setup lang="ts">
|
|
57
|
-
import { useNuxtApp } from '#imports';
|
|
54
|
+
import { useNuxtApp, useSidebar } from '#imports';
|
|
58
55
|
const { $t } = useNuxtApp();
|
|
56
|
+
const { state: expanded } = useSidebar();
|
|
59
57
|
|
|
60
58
|
interface IApplications {
|
|
61
59
|
id: number;
|
|
@@ -81,7 +79,6 @@ interface ILogo {
|
|
|
81
79
|
interface ISidebarProps {
|
|
82
80
|
applications: Array<IApplications>;
|
|
83
81
|
currentApplication?: IApplications['text'];
|
|
84
|
-
expanded?: boolean;
|
|
85
82
|
homepageUrl?: string;
|
|
86
83
|
showHelpArticles?: boolean;
|
|
87
84
|
helpArticleOptions?: Array<unknown>;
|
|
@@ -94,7 +91,6 @@ withDefaults(defineProps<ISidebarProps>(), {
|
|
|
94
91
|
currentApplication: 'media',
|
|
95
92
|
homepageUrl: '/',
|
|
96
93
|
showHelpArticles: true,
|
|
97
|
-
expanded: true,
|
|
98
94
|
helpArticleOptions: () => [],
|
|
99
95
|
impersonatedUser: () => ({
|
|
100
96
|
show: false,
|
|
@@ -109,6 +105,8 @@ withDefaults(defineProps<ISidebarProps>(), {
|
|
|
109
105
|
iconSrc: 'logo.svg',
|
|
110
106
|
})
|
|
111
107
|
})
|
|
108
|
+
|
|
109
|
+
|
|
112
110
|
</script>
|
|
113
111
|
|
|
114
112
|
<style scoped>
|
|
@@ -119,10 +117,10 @@ withDefaults(defineProps<ISidebarProps>(), {
|
|
|
119
117
|
font: var(--font-regular);
|
|
120
118
|
background-color: var(--dscl-nav-background-color, var(--purple-70));
|
|
121
119
|
color: var(--dscl-nav-font-color, var(--dscl-light-font, var(--primary-white)));
|
|
122
|
-
transition:
|
|
120
|
+
transition: width 0.3s ease-in-out, translate 0.2s ease-in-out;
|
|
123
121
|
height: 100vh;
|
|
124
122
|
overflow-y: auto;
|
|
125
|
-
min-width: 0px;
|
|
123
|
+
/* min-width: 0px; */
|
|
126
124
|
translate: -256px;
|
|
127
125
|
}
|
|
128
126
|
.navbar a:focus-visible {
|
|
@@ -131,7 +129,7 @@ withDefaults(defineProps<ISidebarProps>(), {
|
|
|
131
129
|
box-shadow: inset 0 0 0px 4px var(--primary-white);
|
|
132
130
|
}
|
|
133
131
|
.navbar.expanded {
|
|
134
|
-
transition:
|
|
132
|
+
transition: width 0.3s ease-in-out, translate 0.2s ease-in-out;
|
|
135
133
|
min-width: 256px;
|
|
136
134
|
translate: 0px;
|
|
137
135
|
}
|
|
@@ -5,12 +5,10 @@
|
|
|
5
5
|
</button>
|
|
6
6
|
</template>
|
|
7
7
|
|
|
8
|
-
<script setup>
|
|
9
|
-
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
import { useSidebar } from '#imports';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
emit("toggle-sidebar");
|
|
13
|
-
}
|
|
11
|
+
const { toggleSidebar } = useSidebar();
|
|
14
12
|
</script>
|
|
15
13
|
|
|
16
14
|
<style scoped>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { useDropdown, useAppConfig } from "#imports";
|
|
2
3
|
import { ref } from "vue";
|
|
3
|
-
import { useDropdown } from "#imports";
|
|
4
4
|
import { vOnClickOutside } from "@vueuse/components";
|
|
5
5
|
|
|
6
6
|
interface IUserDropdown {
|
|
@@ -11,6 +11,10 @@ interface IUserDropdown {
|
|
|
11
11
|
userDropdownOptions: Array<{ label: string; url: string; icon: string }>;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
const appConfig = useAppConfig();
|
|
15
|
+
const zIndex = computed(() => appConfig?.navigation?.zIndex || 100)
|
|
16
|
+
|
|
17
|
+
|
|
14
18
|
const props = defineProps<IUserDropdown>();
|
|
15
19
|
const dropdownTriggerRef = ref<HTMLDivElement>();
|
|
16
20
|
const dropdownOptionsRef = ref<Array<HTMLDivElement>>();
|
|
@@ -29,7 +33,7 @@ const {
|
|
|
29
33
|
);
|
|
30
34
|
|
|
31
35
|
const emit = defineEmits<{
|
|
32
|
-
|
|
36
|
+
"select-option": [index: number];
|
|
33
37
|
}>();
|
|
34
38
|
|
|
35
39
|
function handleSelectedClick(index: number) {
|
|
@@ -60,7 +64,7 @@ function handleKeydownAction($event: KeyboardEvent, index: number) {
|
|
|
60
64
|
>
|
|
61
65
|
<NavAvatar :name="user.name" :src="user.avatar" />
|
|
62
66
|
<NavIconsUserDropdownMenu />
|
|
63
|
-
<span class="sr-only">{{ $t(
|
|
67
|
+
<span class="sr-only">{{ $t("navigation.userDropdown") }}</span>
|
|
64
68
|
</div>
|
|
65
69
|
<div
|
|
66
70
|
v-show="active"
|
|
@@ -79,6 +83,7 @@ function handleKeydownAction($event: KeyboardEvent, index: number) {
|
|
|
79
83
|
@keydown="handleKeydownAction($event, idx)"
|
|
80
84
|
@click="handleSelectedClick(idx)"
|
|
81
85
|
>
|
|
86
|
+
<!-- because of the the above handler, this component is never treated as a link and can't redirect natively? -->
|
|
82
87
|
<NuxtLink class="option" :to="option.url">
|
|
83
88
|
{{ option.label }}
|
|
84
89
|
<a-icon :icon="option.icon" font-size="24px" />
|
|
@@ -123,7 +128,7 @@ function handleKeydownAction($event: KeyboardEvent, index: number) {
|
|
|
123
128
|
border-radius: 4px;
|
|
124
129
|
box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.06);
|
|
125
130
|
padding: 8px;
|
|
126
|
-
z-index:
|
|
131
|
+
z-index: v-bind(zIndex);
|
|
127
132
|
}
|
|
128
133
|
.options-dropdown .option-wrapper {
|
|
129
134
|
padding: 8px;
|
|
@@ -50,6 +50,9 @@ export function useDropdown(options, dropdownOptionsRef, dropdownTriggerRef, con
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
break;
|
|
53
|
+
case "ArrowLeft":
|
|
54
|
+
case "ArrowRight":
|
|
55
|
+
break;
|
|
53
56
|
case " ":
|
|
54
57
|
if (active.value) {
|
|
55
58
|
closeDropdown();
|
|
@@ -141,6 +144,9 @@ export function useDropdown(options, dropdownOptionsRef, dropdownTriggerRef, con
|
|
|
141
144
|
dropdownOptionsRef.value[index - 1].focus();
|
|
142
145
|
});
|
|
143
146
|
return index;
|
|
147
|
+
case "ArrowLeft":
|
|
148
|
+
case "ArrowRight":
|
|
149
|
+
break;
|
|
144
150
|
case "Home":
|
|
145
151
|
nextTick(() => {
|
|
146
152
|
dropdownOptionsRef.value[0].focus();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useState, ref, computed } from "#imports";
|
|
2
|
+
export function useSidebar() {
|
|
3
|
+
const state = useState("navigation:sidebar", () => ref(true));
|
|
4
|
+
function toggleSidebar() {
|
|
5
|
+
state.value = !state.value;
|
|
6
|
+
}
|
|
7
|
+
const sidebarWidth = computed(() => state.value ? "256px" : "0px");
|
|
8
|
+
return {
|
|
9
|
+
state,
|
|
10
|
+
toggleSidebar,
|
|
11
|
+
sidebarWidth
|
|
12
|
+
};
|
|
13
|
+
}
|