@apptegy/nuxt-navigation 0.1.4 → 0.1.5

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 CHANGED
@@ -2,83 +2,18 @@
2
2
  Get your module up and running quickly.
3
3
 
4
4
  Find and replace all on all files (CMD+SHIFT+F):
5
- - Name: My Module
6
- - Package name: my-module
7
- - Description: My new Nuxt module
5
+ - Name: Navigation
6
+ - Package name: @apptegy/nuxt-navigation
7
+ - Description:Apptegy navigation components and patterns module.
8
8
  -->
9
9
 
10
- # My Module
10
+ # Navigation
11
11
 
12
12
  [![npm version][npm-version-src]][npm-version-href]
13
13
  [![npm downloads][npm-downloads-src]][npm-downloads-href]
14
14
  [![License][license-src]][license-href]
15
15
  [![Nuxt][nuxt-src]][nuxt-href]
16
16
 
17
- My new Nuxt module for doing amazing things.
18
17
 
19
- - [  Release Notes](/CHANGELOG.md)
20
- <!-- - [🏀 Online playground](https://stackblitz.com/github/your-org/my-module?file=playground%2Fapp.vue) -->
18
+ <!-- - [🏀 Online playground](https://stackblitz.com/github/your-org/@apptegy/nuxt-navigation?file=playground%2Fapp.vue) -->
21
19
  <!-- - [📖 &nbsp;Documentation](https://example.com) -->
22
-
23
- ## Features
24
-
25
- <!-- Highlight some of the features your module provide here -->
26
- - ⛰ &nbsp;Foo
27
- - 🚠 &nbsp;Bar
28
- - 🌲 &nbsp;Baz
29
-
30
- ## Quick Setup
31
-
32
- Install the module to your Nuxt application with one command:
33
-
34
- ```bash
35
- npx nuxi module add my-module
36
- ```
37
-
38
- That's it! You can now use My Module in your Nuxt app ✨
39
-
40
-
41
- ## Contribution
42
-
43
- <details>
44
- <summary>Local development</summary>
45
-
46
- ```bash
47
- # Install dependencies
48
- npm install
49
-
50
- # Generate type stubs
51
- npm run dev:prepare
52
-
53
- # Develop with the playground
54
- npm run dev
55
-
56
- # Build the playground
57
- npm run dev:build
58
-
59
- # Run ESLint
60
- npm run lint
61
-
62
- # Run Vitest
63
- npm run test
64
- npm run test:watch
65
-
66
- # Release new version
67
- npm run release
68
- ```
69
-
70
- </details>
71
-
72
-
73
- <!-- Badges -->
74
- [npm-version-src]: https://img.shields.io/npm/v/my-module/latest.svg?style=flat&colorA=020420&colorB=00DC82
75
- [npm-version-href]: https://npmjs.com/package/my-module
76
-
77
- [npm-downloads-src]: https://img.shields.io/npm/dm/my-module.svg?style=flat&colorA=020420&colorB=00DC82
78
- [npm-downloads-href]: https://npmjs.com/package/my-module
79
-
80
- [license-src]: https://img.shields.io/npm/l/my-module.svg?style=flat&colorA=020420&colorB=00DC82
81
- [license-href]: https://npmjs.com/package/my-module
82
-
83
- [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js
84
- [nuxt-href]: https://nuxt.com
package/dist/module.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@apptegy/nuxt-navigation",
3
3
  "configKey": "@apptegy/nuxt-navigation",
4
- "version": "0.1.4",
4
+ "version": "0.1.5",
5
5
  "builder": {
6
- "@nuxt/module-builder": "0.8.1",
6
+ "@nuxt/module-builder": "0.8.3",
7
7
  "unbuild": "unknown"
8
8
  }
9
9
  }
@@ -0,0 +1,4 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="4.3335" y="5.5" width="15.3333" height="13" rx="0.666667" stroke="#662E80"/>
3
+ <path d="M10 6L10 18" stroke="#662E80" stroke-linecap="round"/>
4
+ </svg>
@@ -44,7 +44,7 @@ span {
44
44
  border-radius: 50%;
45
45
  background-color: var(--brand-1, var(--purple));
46
46
  color: var(--text-2, var(--primary-white));
47
- outline: 1px solid var(--primary-white);
47
+ border: 1px solid var(--primary-white);
48
48
  }
49
49
 
50
50
  img {
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <header
3
+ class="header"
3
4
  :class="{ sticky }"
4
5
  role="banner"
5
6
  >
@@ -9,7 +10,7 @@
9
10
  </div>
10
11
  <slot name="org-select" />
11
12
  <slot name="user-controls" />
12
- <NavUserDropdown :user :user-dropdown-options :selected-option @select-option="$emit('selectedOption')"/>
13
+ <NavUserDropdown :user="user" :user-dropdown-options="userDropdownOptions" :selected-option="selectedOptions" @select-option="$emit('selectedOption')"/>
13
14
  </header>
14
15
  </template>
15
16
 
@@ -35,25 +36,25 @@ defineEmits(['toggle-sidebar', 'selectedOption']);
35
36
  </script>
36
37
 
37
38
  <style scoped>
38
- header {
39
+ header.header {
39
40
  grid-area: navheader;
40
41
  display: grid;
41
42
  grid-auto-flow: column;
42
43
  grid-template-columns: auto 1fr auto;
43
44
  gap: 16px;
44
45
  align-items: center;
45
- padding: 24px 64px 24px 36px;
46
+ padding: 24px 64px;
46
47
  width: 100%;
47
48
  background-color: var(--primary-white);
48
49
  font: var(--font-regular);
49
50
  }
50
51
  @media only screen and (max-width: 960px) {
51
- header {
52
+ header.header {
52
53
  padding-left: 32px;
53
54
  padding-right: 32px;
54
55
  }
55
56
  }
56
- header.sticky {
57
+ header.header.sticky {
57
58
  position: sticky;
58
59
  }
59
60
  </style>
@@ -0,0 +1,6 @@
1
+ <template>
2
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden>
3
+ <rect x="4.3335" y="5.5" width="15.3333" height="13" rx="0.666667" stroke="currentColor"/>
4
+ <path d="M10 6L10 18" stroke="currentColor" stroke-linecap="round"/>
5
+ </svg>
6
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M5 8H19M5 12H19M19 16H5" stroke="currentColor" stroke-linecap="round"/>
4
+ </svg>
5
+ </template>
@@ -29,7 +29,6 @@
29
29
  import { ref, onMounted } from '#imports';
30
30
 
31
31
  interface IPanelProps {
32
- navbarExpanded: boolean;
33
32
  impersonatedUser: {
34
33
  name: string,
35
34
  email: string,
@@ -14,15 +14,15 @@
14
14
  >
15
15
  <input
16
16
  ref="inputRef"
17
- class="org-title"
18
17
  type="text"
18
+ class="org-title"
19
19
  :placeholder="$t('navigation.orgPlaceholder')"
20
- :value="active ? searchQuery : selectedOrg.name"
20
+ :value="active ? searchQuery : selectedOrg?.name"
21
21
  @keydown="keydownActionsOnTrigger"
22
22
  @click.prevent="toggleDropdown"
23
23
  @input="handleDropdownSearch"
24
24
  >
25
- <span v-if="selectedOrg.intranet" class="badge selected">
25
+ <span v-if="selectedOrg?.intranet" class="badge selected">
26
26
  <a-icon icon="16:lock-locked" />
27
27
  {{ $t("navigation.orgBadge") }}
28
28
  </span>
@@ -34,21 +34,21 @@
34
34
  role="listbox"
35
35
  >
36
36
  <div
37
- v-for="(option, idx) in sortedOrgs"
38
- :key="idx"
37
+ v-for="(option) in sortedOrgs"
38
+ :key="option.id"
39
39
  ref="optionRef"
40
40
  v-on-click-outside="onClickOutsideHandler"
41
41
  role="option"
42
42
  class="org-option"
43
- :class="{ selected: option === selectedOrg }"
44
- :aria-selected="!!String(option === selectedOrg)"
43
+ :class="{ selected: option.id === modelValue }"
44
+ :aria-selected="option.id === modelValue"
45
45
  tabindex="-1"
46
- @keydown="handleKeydownAction($event, idx)"
47
- @click="handleSelectedClick(idx)"
46
+ @keydown="handleSelectedOrg($event, option.id)"
47
+ @click="handleSelectedOrg($event, option.id)"
48
48
  >
49
49
  <span :class="{ pinned: option.pinned, 'item-flex': true }"
50
- >{{ option.name }}
51
- <span v-if="option.intranet" class="badge selected">
50
+ >{{ option.name }}
51
+ <span v-if="option.intranet" class="badge selected">
52
52
  <a-icon icon="16:lock-locked" />
53
53
  {{ $t("navigation.orgBadge") }}
54
54
  </span>
@@ -67,27 +67,28 @@ const { $t } = useNuxtApp();
67
67
 
68
68
  interface IOrg {
69
69
  name: string;
70
- intranet: boolean;
71
- pinned: boolean;
70
+ id: number;
71
+ intranet?: boolean;
72
+ pinned?: boolean;
72
73
  }
73
74
 
74
75
  interface IOrgSelectProps {
75
76
  orgs: Array<IOrg>;
76
- selectedOrg?: IOrg;
77
+ modelValue: number
77
78
  }
78
79
 
79
- const emit = defineEmits(["selected"]);
80
+ const emit = defineEmits<{
81
+ 'update:model-value': [index: number]
82
+ }>();
80
83
 
81
84
  const dropdownTriggerRef = ref();
82
85
  const optionRef = ref();
83
- const props = withDefaults(defineProps<IOrgSelectProps>(), {
84
- selectedOrg: () => ({
85
- name: "",
86
- intranet: false,
87
- pinned: false,
88
- }),
86
+ const selectedOrg = computed(() => {
87
+ return props.orgs.find(({id}) => id == props.modelValue);
89
88
  });
90
89
 
90
+ const props = defineProps<IOrgSelectProps>();
91
+
91
92
  const {
92
93
  active,
93
94
  searchQuery,
@@ -114,14 +115,14 @@ const sortedOrgs = computed(() => {
114
115
  });
115
116
  });
116
117
 
117
- function handleSelectedClick(index: number) {
118
- emit("selected", index);
119
- closeDropdown();
120
- }
121
-
122
- function handleKeydownAction($event: { key: string | boolean }, index: number) {
123
- emit("selected", index);
124
- handleKeydown($event, index);
118
+ function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
119
+ if($event.type == 'click') {
120
+ emit("update:model-value", orgId);
121
+ closeDropdown();
122
+ } else if ($event.type == 'keydown') {
123
+ emit("update:model-value", orgId);
124
+ handleKeydown($event as KeyboardEvent, orgId);
125
+ }
125
126
  }
126
127
  </script>
127
128
 
@@ -131,39 +132,44 @@ function handleKeydownAction($event: { key: string | boolean }, index: number) {
131
132
  width: 300px;
132
133
  max-height: 300px;
133
134
  overflow-y: auto;
134
- background-color: white;
135
+ background-color: var(--primary-white);
135
136
  z-index: 50;
136
137
  }
137
138
 
138
139
  .org-selection {
139
- width: 300px;
140
- margin-right: 25px;
140
+ border-radius: 4px 4px 0 0;
141
141
  }
142
- .org-selection .dropdown-trigger:focus-visible {
143
- outline: 2px #000fff solid;
142
+ .org-selection:focus-within {
143
+ outline: 2px var(--purple) solid;
144
+ }
145
+ .org-selection .dropdown-trigger {
146
+ width: 300px;
147
+ padding: 0 8px;
148
+ display: flex;
149
+ align-items: center;
150
+ gap: 8px;
151
+ justify-content: space-between;
152
+ border-radius: 4px 4px 0 0;
153
+ border: 0;
154
+ border-bottom: 1px solid var(--dscl-forms-underline, var(--grey-50));
155
+ background: var(--dscl-forms-bg, var(--grey-10));
144
156
  }
145
157
  .org-selection .dropdown-trigger .org-title {
146
158
  line-height: 16px;
147
- width: 300px;
159
+ width: 100%;
148
160
  padding: 12px;
149
161
  letter-spacing: 0.4px;
150
162
  touch-action: manipulation;
151
- color: #333;
163
+ color: var(--primary-dark);
152
164
  height: 40px;
153
- display: flex;
154
- justify-content: space-between;
155
- align-items: center;
156
- padding: 8px;
157
- border-radius: 4px 4px 0 0;
158
165
  border: 0;
159
- border-bottom: 1px solid var(--dscl-forms-underline, #747474);
160
- background: var(--dscl-forms-bg, #fbfbfb);
166
+ padding: 8px;
167
+ background: var(--dscl-forms-bg, var(--grey-10));
161
168
  white-space: nowrap;
162
169
  cursor: pointer;
163
170
  }
164
- .org-selection .badge {
165
- background-color: var(--purple-50);
166
- text-transform: uppercase;
171
+ .org-selection .dropdown-trigger .org-title:focus {
172
+ outline: none;
167
173
  }
168
174
  .org-selection .dropdown .org-option {
169
175
  display: block;
@@ -183,7 +189,7 @@ function handleKeydownAction($event: { key: string | boolean }, index: number) {
183
189
  }
184
190
  .org-selection .item-flex {
185
191
  display: flex;
186
- gap: 10px;
192
+ gap: 8px;
187
193
  align-items: center;
188
194
  width: 100%;
189
195
  justify-content: space-between;
@@ -14,6 +14,7 @@
14
14
  {{ $t('navigation.skipToContent') }}
15
15
  </a>
16
16
  <div class="navbar--content">
17
+ <slot name="switcher" />
17
18
  <ul class="navbar-applications">
18
19
  <li v-for="application of applications" :key="application.id">
19
20
  <NavSidebarSection
@@ -85,7 +86,7 @@ interface ISidebarProps {
85
86
  showHelpArticles?: boolean;
86
87
  helpArticleOptions?: Array<unknown>;
87
88
  impersonatedUser?: IUser;
88
- logo: ILogo;
89
+ logo?: ILogo;
89
90
  }
90
91
 
91
92
  withDefaults(defineProps<ISidebarProps>(), {
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <button class="sidebar-toggle" @click="toggleSidebar">
3
- <a-icon class="icon" icon="16:apptegy" />
4
- <span>Menu</span>
3
+ <NavIconsSidebarToggle />
4
+ <span> {{ $t('navigation.sidebarToggle') }}</span>
5
5
  </button>
6
6
  </template>
7
7
 
@@ -6,10 +6,9 @@ import { vOnClickOutside } from "@vueuse/components";
6
6
  interface IUserDropdown {
7
7
  user: {
8
8
  name: string;
9
- avatar: string;
9
+ avatar?: string;
10
10
  };
11
11
  userDropdownOptions: Array<{ label: string; url: string; icon: string }>;
12
- selectedOption: number;
13
12
  }
14
13
 
15
14
  const props = defineProps<IUserDropdown>();
@@ -30,7 +29,7 @@ const {
30
29
  );
31
30
 
32
31
  const emit = defineEmits<{
33
- 'select-option': [id: number]
32
+ 'select-option': [index: number]
34
33
  }>();
35
34
 
36
35
  function handleSelectedClick(index: number) {
@@ -59,9 +58,9 @@ function handleKeydownAction($event: KeyboardEvent, index: number) {
59
58
  @keydown="keydownActionsOnTrigger"
60
59
  @click.prevent="toggleDropdown"
61
60
  >
62
- <NavUserDropdownAvatar :name="user.name" :src="user.avatar" />
63
- <a-icon class="icon" icon="24:hamburger" />
64
- <span class="sr-only">Account Settings</span>
61
+ <NavAvatar :name="user.name" :src="user.avatar" />
62
+ <NavIconsUserDropdownMenu />
63
+ <span class="sr-only">{{ $t('navigation.userDropdown') }}</span>
65
64
  </div>
66
65
  <div
67
66
  v-show="active"
@@ -82,7 +81,7 @@ function handleKeydownAction($event: KeyboardEvent, index: number) {
82
81
  >
83
82
  <NuxtLink class="option" :to="option.url">
84
83
  {{ option.label }}
85
- <a-icon :icon="option.icon" color="black" font-size="32px" />
84
+ <a-icon :icon="option.icon" font-size="24px" />
86
85
  </NuxtLink>
87
86
  </div>
88
87
  </div>
@@ -120,24 +119,29 @@ function handleKeydownAction($event: KeyboardEvent, index: number) {
120
119
  max-width: 512px;
121
120
  right: 65px;
122
121
  top: 80px;
123
- background-color: #ffffff;
122
+ background-color: var(--primary-white);
124
123
  border-radius: 4px;
125
124
  box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.06);
126
- padding: 12px 0;
125
+ padding: 8px;
127
126
  z-index: 10;
128
127
  }
129
128
  .options-dropdown .option-wrapper {
130
- padding: 12px 16px;
129
+ padding: 8px;
130
+ border-radius: 4px;
131
131
  cursor: pointer;
132
132
  }
133
133
  .options-dropdown .option-wrapper .option {
134
134
  display: flex;
135
+ gap: 8px;
135
136
  justify-content: space-between;
136
137
  align-items: center;
137
- color: #333;
138
+ color: var(--primary-dark);
138
139
  text-decoration: none;
139
140
  }
140
141
  .options-dropdown .option-wrapper:focus-visible, .options-dropdown .option-wrapper:hover {
141
- background-color: #f8f6fc;
142
+ background-color: var(--purple-20);
143
+ }
144
+ .options-dropdown .option-wrapper:focus-visible .option, .options-dropdown .option-wrapper:hover .option {
145
+ color: var(--purple);
142
146
  }
143
147
  </style>
@@ -5,7 +5,7 @@ export declare function useDropdown(options: Array<unknown>, dropdownOptionsRef:
5
5
  }): {
6
6
  active: Ref<boolean>;
7
7
  searchQuery: Ref<string>;
8
- toggleDropdown: ($event: KeyboardEvent & MouseEvent) => Promise<void>;
8
+ toggleDropdown: ($event: KeyboardEvent | MouseEvent) => Promise<void>;
9
9
  openDropdown: () => void;
10
10
  closeDropdown: () => void;
11
11
  onClickOutsideHandler: () => void;
@@ -5,7 +5,7 @@ export function useDropdown(options, dropdownOptionsRef, dropdownTriggerRef, con
5
5
  const searchQuery = ref("");
6
6
  async function toggleDropdown($event) {
7
7
  active.value = !active.value;
8
- if (active.value && $event.key === "ArrowDown") {
8
+ if ($event instanceof KeyboardEvent && active.value && $event.key === "ArrowDown") {
9
9
  await nextTick(() => {
10
10
  dropdownOptionsRef.value[0].focus();
11
11
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apptegy/nuxt-navigation",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -26,26 +26,24 @@
26
26
  "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
27
27
  },
28
28
  "dependencies": {
29
- "@nuxt/kit": "^3.12.3"
29
+ "@nuxt/kit": "^3.12.4",
30
+ "@vueuse/components": "11.0.1",
31
+ "lodash": "^4.17.21"
30
32
  },
31
33
  "devDependencies": {
32
- "@iconify/vue": "^4.1.2",
33
- "@nuxt/devtools": "^1.3.9",
34
- "@nuxt/eslint-config": "^0.3.13",
35
- "@apptegy/icons": "2.10.0",
36
- "@nuxt/module-builder": "^0.8.1",
37
- "@nuxt/schema": "^3.12.3",
38
- "@nuxt/test-utils": "^3.13.1",
39
- "@types/node": "^20.14.10",
40
- "@vueuse/components": "10.11.0",
34
+ "@nuxt/devtools": "^1.3.14",
35
+ "@nuxt/eslint-config": "^0.5.1",
36
+ "@nuxt/module-builder": "^0.8.3",
37
+ "@nuxt/schema": "^3.12.4",
38
+ "@nuxt/test-utils": "^3.14.1",
39
+ "@types/node": "^20.16.1",
41
40
  "changelogen": "^0.5.5",
42
- "eslint": "^9.7.0",
43
- "lodash": "^4.17.21",
44
- "nuxt": "^3.12.3",
41
+ "eslint": "^9.9.0",
42
+ "nuxt": "^3.12.4",
45
43
  "sass": "^1.77.8",
46
- "typescript": "^5.5.3",
44
+ "typescript": "^5.5.4",
47
45
  "vitest": "^1.6.0",
48
- "vue": "^3.4.21",
49
- "vue-tsc": "^2.0.26"
46
+ "vue": "^3.4.38",
47
+ "vue-tsc": "^2.0.29"
50
48
  }
51
49
  }