@buerokratt-ria/menu 0.0.1

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/.eslintrc.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
3
+ "ignorePatterns": ["!**/*"],
4
+ "overrides": [
5
+ {
6
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7
+ "rules": {}
8
+ },
9
+ {
10
+ "files": ["*.ts", "*.tsx"],
11
+ "rules": {}
12
+ },
13
+ {
14
+ "files": ["*.js", "*.jsx"],
15
+ "rules": {}
16
+ }
17
+ ]
18
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ All changes to this project will be documented in this file.
4
+
5
+ ## [0.0.1] - 07-12-2023
6
+
7
+ - Initial package structure for menu.
@@ -0,0 +1,8 @@
1
+ ## Making Changes
2
+
3
+ #### If you want to make changes to export menu component:
4
+ * Make necessary changes
5
+ * Update version in file [package.json](package.json)
6
+ * Template: `major v.mid v.minor v`
7
+ * Add brief description to [changelog file](CHANGELOG.md)
8
+ * Proceed with deploying or testing package locally by information provided by [readme](README.md)
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ ## MainNavigation component
2
+
3
+ ### General information
4
+
5
+ Changelog file could be found here [link](CHANGELOG.md)
6
+
7
+ ## Creating package
8
+
9
+ To create npm package for future usage:
10
+ * Navigate to the root directory of the package.
11
+ * Run `npm pack` command, to create package file.
12
+ * If you made updates to the package please relate to this [file](MAKING_CHANGES.md) before creating package
13
+
14
+ To publish created package:
15
+ * Run `npm publish --access public`
16
+ * Authorize in npm and package would be published
17
+
18
+ ## Adding dependency from remote
19
+ - Since this package currently being deployed to @buerokratt-ria account therefore it would need to be related as @buerokratt-ria
20
+ - Add to `package.json` @buerokratt-ria/menu: followed by version, list of available version could be found [here](CHANGELOG.md)
21
+
22
+ ## Adding dependency as local package
23
+ - When you build the package file, put it in `root` directory of the application
24
+ - Add to `package.json` @buerokratt-ria/header: file:name-of-the-generated-package
25
+ - If having import issues like `NOT FOUND` try adding to `vite.config.ts`
26
+ `resolve: {
27
+ alias: {
28
+ '@buerokratt-ria': `${path.resolve(__dirname, 'node_modules/@buerokratt-ria/menu/src')}`
29
+ },
30
+ }`
31
+
32
+ ## Using package
33
+ * Importing component
34
+ * `import { MainNavigation } from '@buerokratt-ria/menu/src'` for Header and Menu
35
+ * If you want to use local package, put created package to the root of react app and add dependency like "@buerokratt-ria/header": "file:buerokratt-ria-menu-0.0.5.tgz" (use proper version)
36
+ ### Using MainNavigation component
37
+ * In Layout component you need to provide fetching and caching the `menu.json` file, code snippet would be:
38
+ ```
39
+ const CACHE_NAME = 'mainmenu-cache';
40
+ const [MainMenuItems, setMainMenuItems] = useState([])
41
+ const {data, isLoading, status} = useQuery({
42
+ queryKey: [import.meta.env.REACT_APP_MENU_URL + import.meta.env.REACT_APP_MENU_PATH],
43
+ onSuccess: (res: any) => {
44
+ try {
45
+ setMainMenuItems(res);
46
+ localStorage.setItem(CACHE_NAME, JSON.stringify(res));
47
+ } catch (e) {
48
+ console.log(e);
49
+ }
50
+ },
51
+ onError: (error: any) => {
52
+ setMainMenuItems(getCache());
53
+ }
54
+
55
+ });
56
+
57
+ function getCache(): any {
58
+ const cache = localStorage.getItem(CACHE_NAME) || '{}';
59
+ return JSON.parse(cache);
60
+ }
61
+ ```
62
+ * Then pass this MainMenu items to menu component `<MainNavigation serviceId={import.meta.env.REACT_APP_SERVICE_ID.split(',')} items={MainMenuItems}/>`
63
+ * If you want to use only local file provided by package then pass empty array instead `[]`
64
+ * REACT_APP_SERVICE_ID set of values seperated by comma resembling current module, examples of this value could
65
+ be found in following links
66
+
67
+ ### Implemented examples:
68
+ * https://github.com/buerokratt/Training-Module
69
+ * https://github.com/buerokratt/Service-Module
70
+ * https://github.com/buerokratt/Analytics-Module
Binary file
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@buerokratt-ria/menu",
3
+ "version": "0.0.1",
4
+ "description": "Generic MainNavigation component that would be injected as dependency.",
5
+ "main": "index.js",
6
+ "scripts": {},
7
+ "author": "ExiRain",
8
+ "license": "ISC",
9
+ "peerDependencies": {
10
+ "@radix-ui/react-accessible-icon": "^1.0.3",
11
+ "@radix-ui/react-dialog": "^1.0.4",
12
+ "@radix-ui/react-switch": "^1.0.3",
13
+ "@radix-ui/react-toast": "^1.1.4",
14
+ "@tanstack/react-query": "^4.32.1",
15
+ "clsx": "^1.2.1",
16
+ "i18next": "^23.2.3",
17
+ "i18next-browser-languagedetector": "^7.1.0",
18
+ "path": "^0.12.7",
19
+ "react": "^18.2.0",
20
+ "react-cookie": "^4.1.1",
21
+ "react-dom": "^18.2.0",
22
+ "react-hook-form": "^7.45.4",
23
+ "react-i18next": "^12.1.1",
24
+ "react-icons": "^4.10.1",
25
+ "react-idle-timer": "^5.7.2",
26
+ "react-router-dom": "^6.14.2",
27
+ "rxjs": "^7.8.1",
28
+ "tslib": "^2.3.0",
29
+ "vite-plugin-dts": "^3.5.2",
30
+ "vite-plugin-svgr": "^3.2.0",
31
+ "zustand": "^4.4.0"
32
+ },
33
+ "dependencies": {
34
+ "react": "^18.2.0",
35
+ "@types/react": "^18.2.21",
36
+ "@buerokratt-ria/styles": "^0.0.1"
37
+ },
38
+ "devDependencies": {
39
+ "@types/react": "^18.0.26",
40
+ "@types/react-dom": "^18.0.9"
41
+ }
42
+ }
package/project.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "header",
3
+ "sourceRoot": "header/src",
4
+ "projectType": "library",
5
+ "tags": ["scope:header"],
6
+ "targets": {
7
+ "lint": {
8
+ "executor": "@nrwl/linter:eslint",
9
+ "outputs": ["{options.outputFile}"],
10
+ "options": {
11
+ "lintFilePatterns": ["header/**/*.{ts,tsx,js,jsx}"]
12
+ }
13
+ },
14
+ "build": {
15
+ "executor": "@nrwl/vite:build",
16
+ "outputs": ["{options.outputPath}"],
17
+ "defaultConfiguration": "production",
18
+ "options": {
19
+ "project": "./ng-package.json",
20
+ "outputPath": "dist/header"
21
+ },
22
+ "configurations": {
23
+ "production": {
24
+ "tsConfig": "./tsconfig.lib.prod.json",
25
+ "mode": "production"
26
+ },
27
+ "development": {
28
+ "tsConfig": "./tsconfig.lib.json",
29
+ "mode": "development"
30
+ }
31
+ }
32
+ },
33
+ "test": {
34
+ "executor": "@nrwl/vite:test",
35
+ "outputs": ["{projectRoot}/coverage"],
36
+ "options": {
37
+ "passWithNoTests": true
38
+ }
39
+ },
40
+ "version": {
41
+ "executor": "@jscutlery/semver:version",
42
+ "options": {
43
+ "preset": "angular",
44
+ "baseBranch": "main",
45
+ "push": true,
46
+ "noVerify": true,
47
+ "commitMessageFormat": "chore(${projectName}): release version ${version} [skip ci]",
48
+ "skipCommitTypes": ["chore", "ci", "docs", "style", "test", "format"]
49
+ }
50
+ }
51
+ }
52
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export {
2
+ default as MainNavigation
3
+ } from './menu';
@@ -0,0 +1,32 @@
1
+ import React, {
2
+ CSSProperties,
3
+ forwardRef,
4
+ ReactNode,
5
+ StyleHTMLAttributes,
6
+ } from 'react';
7
+ import * as AccessibleIcon from '@radix-ui/react-accessible-icon';
8
+ import clsx from 'clsx';
9
+
10
+ import '../icon.scss';
11
+
12
+ type IconProps = StyleHTMLAttributes<CSSProperties> & {
13
+ label?: string | null;
14
+ icon: ReactNode;
15
+ size?: 'small' | 'medium';
16
+ };
17
+
18
+ const IconComponent = forwardRef<HTMLSpanElement, IconProps>(
19
+ ({ label, icon, size = 'small', ...rest }, ref) => {
20
+ const iconClasses = clsx('icon', `icon--${size}`);
21
+
22
+ return (
23
+ <AccessibleIcon.Root label={label ?? ''}>
24
+ <span ref={ref} className={iconClasses} style={rest.style}>
25
+ {icon}
26
+ </span>
27
+ </AccessibleIcon.Root>
28
+ );
29
+ }
30
+ );
31
+
32
+ export default IconComponent;
@@ -0,0 +1,17 @@
1
+ @import '@buerokratt-ria/styles/styles/tools/spacing';
2
+
3
+ .icon {
4
+ display: inline-flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+
8
+ &--small {
9
+ width: get-spacing(haapsalu);
10
+ height: get-spacing(haapsalu);
11
+ }
12
+
13
+ &--medium {
14
+ width: get-spacing(kuressaare);
15
+ height: get-spacing(kuressaare);
16
+ }
17
+ }
@@ -0,0 +1,343 @@
1
+ [
2
+ {
3
+ "id": "conversations",
4
+ "label": {
5
+ "et": "Vestlused",
6
+ "en": "Conversations"
7
+ },
8
+ "path": "/chat",
9
+ "children": [
10
+ {
11
+ "label": {
12
+ "et": "Vastamata",
13
+ "en": "Unanswered"
14
+ },
15
+ "path": "/unanswered"
16
+ },
17
+ {
18
+ "label": {
19
+ "et": "Aktiivsed",
20
+ "en": "Active"
21
+ },
22
+ "path": "/active"
23
+ },
24
+ {
25
+ "label": {
26
+ "et": "Ajalugu",
27
+ "en": "History"
28
+ },
29
+ "path": "/history"
30
+ }
31
+ ]
32
+ },
33
+ {
34
+ "id": "training",
35
+ "label": {
36
+ "et": "Treening",
37
+ "en": "Training"
38
+ },
39
+ "path": "/training",
40
+ "children": [
41
+ {
42
+ "label": {
43
+ "et": "Treening",
44
+ "en": "Training"
45
+ },
46
+ "path": "/training",
47
+ "children": [
48
+ {
49
+ "label": {
50
+ "et": "Teemad",
51
+ "en": "Themes"
52
+ },
53
+ "path": "/training/intents"
54
+ },
55
+ {
56
+ "label": {
57
+ "et": "Avalikud teemad",
58
+ "en": "Public themes"
59
+ },
60
+ "path": "/training/common-intents"
61
+ },
62
+ {
63
+ "label": {
64
+ "et": "Teemade järeltreenimine",
65
+ "en": "Post training themes"
66
+ },
67
+ "path": "/training/intents-followup-training"
68
+ },
69
+ {
70
+ "label": {
71
+ "et": "Vastused",
72
+ "en": "Answers"
73
+ },
74
+ "path": "/training/responses"
75
+ },
76
+ {
77
+ "label": {
78
+ "et": "Kasutuslood",
79
+ "en": "User Stories"
80
+ },
81
+ "path": "/training/stories"
82
+ },
83
+ {
84
+ "label": {
85
+ "et": "Konfiguratsioon",
86
+ "en": "Configuration"
87
+ },
88
+ "path": "/training/configuration"
89
+ },
90
+ {
91
+ "label": {
92
+ "et": "Vormid",
93
+ "en": "Forms"
94
+ },
95
+ "path": "/training/forms"
96
+ },
97
+ {
98
+ "label": {
99
+ "et": "Mälukohad",
100
+ "en": "Slots"
101
+ },
102
+ "path": "/training/slots"
103
+ }
104
+ ]
105
+ },
106
+ {
107
+ "label": {
108
+ "et": "Ajaloolised vestlused",
109
+ "en": "Historical conversations"
110
+ },
111
+ "path": "/history",
112
+ "children": [
113
+ {
114
+ "label": {
115
+ "et": "Ajalugu",
116
+ "en": "History"
117
+ },
118
+ "path": "/history/history"
119
+ },
120
+ {
121
+ "label": {
122
+ "et": "Pöördumised",
123
+ "en": "Appeals"
124
+ },
125
+ "path": "/history/appeal"
126
+ }
127
+ ]
128
+ },
129
+ {
130
+ "label": {
131
+ "et": "Mudelipank ja analüütika",
132
+ "en": "Modelbank and analytics"
133
+ },
134
+ "path": "/analytics",
135
+ "children": [
136
+ {
137
+ "label": {
138
+ "et": "Teemade ülevaade",
139
+ "en": "Overview of topics"
140
+ },
141
+ "path": "/analytics/overview"
142
+ },
143
+ {
144
+ "label": {
145
+ "et": "Mudelite võrdlus",
146
+ "en": "Comparison of models"
147
+ },
148
+ "path": "/analytics/models"
149
+ },
150
+ {
151
+ "label": {
152
+ "et": "Testlood",
153
+ "en": "testTracks"
154
+ },
155
+ "path": "/analytics/testcases"
156
+ }
157
+ ]
158
+ },
159
+ {
160
+ "label": {
161
+ "et": "Treeni uus mudel",
162
+ "en": "Train new model"
163
+ },
164
+ "path": "/training/train-new-model"
165
+ }
166
+ ]
167
+ },
168
+ {
169
+ "id": "analytics",
170
+ "label": {
171
+ "et": "Analüütika",
172
+ "en": "Analytics"
173
+ },
174
+ "path": "/analytics",
175
+ "children": [
176
+ {
177
+ "label": {
178
+ "et": "Ülevaade",
179
+ "en": "Overview"
180
+ },
181
+ "path": "/overview"
182
+ },
183
+ {
184
+ "label": {
185
+ "et": "Vestlused",
186
+ "en": "Chats"
187
+ },
188
+ "path": "/chats"
189
+ },
190
+ {
191
+ "label": {
192
+ "et": "Bürokratt",
193
+ "en": "Burokratt"
194
+ },
195
+ "path": "/burokratt"
196
+ },
197
+ {
198
+ "label": {
199
+ "et": "Tagasiside",
200
+ "en": "Feedback"
201
+ },
202
+ "path": "/feedback"
203
+ },
204
+ {
205
+ "label": {
206
+ "et": "Nõustajad",
207
+ "en": "Advisors"
208
+ },
209
+ "path": "/advisors"
210
+ },
211
+ {
212
+ "label": {
213
+ "et": "Avaandmed",
214
+ "en": "Reports"
215
+ },
216
+ "path": "/reports"
217
+ }
218
+ ]
219
+ },
220
+ {
221
+ "id": "services",
222
+ "label": {
223
+ "et": "Teenused",
224
+ "en": "Services"
225
+ },
226
+ "path": "/services",
227
+ "children": [
228
+ {
229
+ "label": {
230
+ "et": "Ülevaade",
231
+ "en": "Overview"
232
+ },
233
+ "path": "/overview"
234
+ },
235
+ {
236
+ "label": {
237
+ "et": "Uus teenus",
238
+ "en": "New Service"
239
+ },
240
+ "path": "/newService"
241
+ },
242
+ {
243
+ "label": {
244
+ "et": "Teemade järeltreenimine",
245
+ "en": "Followup Training"
246
+ },
247
+ "path": "/followupTraining"
248
+ },
249
+ {
250
+ "label": {
251
+ "et": "Probleemsed teenused",
252
+ "en": "Faulty Services"
253
+ },
254
+ "path": "/faultyServices"
255
+ }
256
+ ]
257
+ },
258
+ {
259
+ "id": "settings",
260
+ "label": {
261
+ "et": "Haldus",
262
+ "en": "Administration"
263
+ },
264
+ "path": "/settings",
265
+ "children": [
266
+ {
267
+ "label": {
268
+ "et": "Kasutajad",
269
+ "en": "Users"
270
+ },
271
+ "path": "/users"
272
+ },
273
+ {
274
+ "label": {
275
+ "et": "Vestlusbot",
276
+ "en": "Chatbot"
277
+ },
278
+ "path": "/chatbot",
279
+ "children": [
280
+ {
281
+ "label": {
282
+ "et": "Seaded",
283
+ "en": "Settings"
284
+ },
285
+ "path": "/chatbot/settings"
286
+ },
287
+ {
288
+ "label": {
289
+ "et": "Tervitussõnum",
290
+ "en": "Welcome message"
291
+ },
292
+ "path": "/chatbot/welcome-message"
293
+ },
294
+ {
295
+ "label": {
296
+ "et": "Välimus ja käitumine",
297
+ "en": "Appearance and behavior"
298
+ },
299
+ "path": "/chatbot/appearance"
300
+ },
301
+ {
302
+ "label": {
303
+ "et": "Erakorralised teated",
304
+ "en": "Emergency notices"
305
+ },
306
+ "path": "/chatbot/emergency-notices"
307
+ }
308
+ ]
309
+ },
310
+ {
311
+ "label": {
312
+ "et": "Asutuse tööaeg",
313
+ "en": "Office opening hours"
314
+ },
315
+ "path": "/working-time"
316
+ },
317
+ {
318
+ "label": {
319
+ "et": "Sessiooni pikkus",
320
+ "en": "Session length"
321
+ },
322
+ "path": "/session-length"
323
+ }
324
+ ]
325
+ },
326
+ {
327
+ "id": "monitoring",
328
+ "label": {
329
+ "et": "Seire",
330
+ "en": "Monitoring"
331
+ },
332
+ "path": "/monitoring",
333
+ "children": [
334
+ {
335
+ "label": {
336
+ "et": "Aktiivaeg",
337
+ "en": "Working hours"
338
+ },
339
+ "path": "/uptime"
340
+ }
341
+ ]
342
+ }
343
+ ]
@@ -0,0 +1,153 @@
1
+ import React, {FC, MouseEvent, useEffect, useState} from 'react';
2
+
3
+ import {NavLink, useLocation} from 'react-router-dom';
4
+ import {MdClose, MdKeyboardArrowDown, MdMiscellaneousServices} from 'react-icons/md';
5
+ import clsx from 'clsx';
6
+ import { MdOutlineForum, MdOutlineAdb, MdOutlineEqualizer, MdSettings, MdOutlineMonitorWeight } from 'react-icons/md';
7
+ import Icon from './components/icons/icon/icon';
8
+ import './main-navigation.scss';
9
+ import { useQuery } from '@tanstack/react-query';
10
+ import {useTranslation} from "react-i18next";
11
+ import menuStructure from './data/menu-structure.json';
12
+
13
+ interface MenuItem {
14
+ id?: string;
15
+ label: TranslatedLabel;
16
+ path?: string;
17
+ target?: '_blank' | '_self';
18
+ children?: MenuItem[];
19
+ }
20
+
21
+ interface TranslatedLabel {
22
+ [lang: string] : string;
23
+ }
24
+
25
+ const MainNavigation: FC<{items: MenuItem[], serviceId: string[]}> = ( {items, serviceId}) => {
26
+ if(!items.isArray || items.length === 0) {
27
+ items = menuStructure;
28
+ }
29
+
30
+ const { t, i18n } = useTranslation();
31
+ const currentlySelectedLanguage = i18n.language;
32
+ const [menuItems, setMenuItems] = useState<MenuItem[]>([]);
33
+ const menuData = [
34
+ {
35
+ id: 'conversations',
36
+ icon: <MdOutlineForum />,
37
+ url: import.meta.env.REACT_APP_CONVERSATIONS_BASE_URL,
38
+ },
39
+ {
40
+ id: 'training',
41
+ icon: <MdOutlineAdb />,
42
+ url: import.meta.env.REACT_APP_TRAINING_BASE_URL,
43
+ },
44
+ {
45
+ id: 'analytics',
46
+ icon: <MdOutlineEqualizer />,
47
+ url: import.meta.env.REACT_APP_ANALYTICS_BASE_URL,
48
+ },
49
+ {
50
+ id: "services",
51
+ icon: <MdMiscellaneousServices />,
52
+ url: import.meta.env.REACT_APP_SERVICES_BASE_URL,
53
+ },
54
+ {
55
+ id: 'settings',
56
+ icon: <MdSettings />,
57
+ url: import.meta.env.REACT_APP_SETTINGS_BASE_URL,
58
+ },
59
+ {
60
+ id: 'monitoring',
61
+ icon: <MdOutlineMonitorWeight />,
62
+ url: import.meta.env.REACT_APP_MONITORING_BASE_URL,
63
+ },
64
+ ];
65
+
66
+ let activeMenuId;
67
+
68
+ const { data } = useQuery({
69
+ queryKey: ['cs-get-user-role', 'prod'],
70
+ onSuccess: (res: any) => {
71
+ const filteredItems = items.filter((item) => {
72
+ const role = res.data.get_user[0].authorities[0]
73
+ switch (role) {
74
+ case 'ROLE_ADMINISTRATOR': return item.id
75
+ case 'ROLE_SERVICE_MANAGER': return item.id != 'settings' && item.id != 'training'
76
+ case 'ROLE_CUSTOMER_SUPPORT_AGENT': return item.id != 'settings' && item.id != 'analytics'
77
+ case 'ROLE_CHATBOT_TRAINER': return item.id != 'settings' && item.id != 'conversations'
78
+ case 'ROLE_ANALYST': return item.id == 'analytics'
79
+ case 'ROLE_UNAUTHENTICATED': return
80
+ default: return
81
+ }
82
+ }) ?? []
83
+ setMenuItems(filteredItems)
84
+ }
85
+
86
+ });
87
+
88
+ const location = useLocation();
89
+ const [navCollapsed, setNavCollapsed] = useState(false);
90
+
91
+ const handleNavToggle = (event: MouseEvent) => {
92
+ const isExpanded = event.currentTarget.getAttribute('aria-expanded') === 'true';
93
+ event.currentTarget.setAttribute('aria-expanded', isExpanded ? 'false' : 'true');
94
+ };
95
+
96
+ const renderMenuTree = (menuItems: MenuItem[]) => {
97
+ return menuItems.map((menuItem) => (
98
+ <li key={menuItem.label[currentlySelectedLanguage]}>
99
+ {!!menuItem.children ? (
100
+ <>
101
+ <button
102
+ className={clsx('nav__toggle', { 'nav__toggle--icon': !!menuItem.id })}
103
+ aria-expanded={menuItem.path && (isSameRoot(menuItem)) ? 'true' : 'false'}
104
+ onClick={handleNavToggle}
105
+ >
106
+ { menuItem.id && (
107
+ <Icon icon={menuData.find(dataItem => dataItem.id === menuItem.id)?.icon} />
108
+ )}
109
+
110
+ <span>{menuItem.label[currentlySelectedLanguage]}</span>
111
+ <Icon icon={<MdKeyboardArrowDown />} />
112
+ </button>
113
+ <ul className='nav__submenu'>
114
+ {renderMenuTree(menuItem.children.map((item) => ({id: menuItem.id, ...item})))}
115
+ </ul>
116
+ </>
117
+ ) : (
118
+
119
+ (serviceId.includes(menuItem.id)) ?
120
+ <NavLink to={menuItem.path || '#'}>{menuItem.label[currentlySelectedLanguage] }</NavLink> :
121
+ <a href={menuData.find(dataItem => dataItem.id === menuItem.id)?.url + menuItem.path}>{menuItem.label[currentlySelectedLanguage]}</a>
122
+
123
+ )}
124
+ </li>),
125
+ );
126
+ };
127
+
128
+ const base = window.location.pathname.split("/")[1];
129
+ const currentService = base === 'chat' ? serviceId : [base];
130
+ const isSameRoot = (menuItem) => {
131
+ let result = false;
132
+ if(currentService.includes(menuItem.id)){
133
+ result = menuItem.children.some((item: MenuItem) => item.path?.includes("/" + window.location.pathname.split("/")[2]));
134
+ }
135
+ return result;
136
+ }
137
+
138
+ if (!menuItems) return null;
139
+
140
+ return (
141
+ <nav className={clsx('nav', { 'nav--collapsed': navCollapsed })}>
142
+ <button className='nav__menu-toggle' onClick={() => setNavCollapsed(!navCollapsed)}>
143
+ <Icon icon={<MdClose />} />
144
+ {t('mainMenu.closeMenu')}
145
+ </button>
146
+ <ul className='nav__menu'>
147
+ {renderMenuTree(menuItems)}
148
+ </ul>
149
+ </nav>
150
+ );
151
+ };
152
+
153
+ export default MainNavigation;
@@ -0,0 +1,119 @@
1
+ @import '@buerokratt-ria/styles/styles/tools/spacing';
2
+ @import '@buerokratt-ria/styles/styles/tools/color';
3
+ @import '@buerokratt-ria/styles/styles/settings/variables/typography';
4
+
5
+ .nav {
6
+ $self: &;
7
+ width: 208px;
8
+ background-color: get-color(sapphire-blue-10);
9
+ overflow: auto;
10
+ scrollbar-width: none;
11
+ transition: width .1s ease-out;
12
+
13
+ &::-webkit-scrollbar {
14
+ display: none;
15
+ }
16
+
17
+ li, a, .nav__toggle, .nav__menu-toggle {
18
+ font-size: 14px;
19
+ line-height: 1.5;
20
+ }
21
+
22
+ &__menu-toggle {
23
+ display: flex;
24
+ align-items: center;
25
+
26
+ &:hover {
27
+ background-color: get-color(sapphire-blue-8);
28
+ }
29
+
30
+ &:active {
31
+ background-color: get-color(sapphire-blue-7);
32
+ }
33
+ }
34
+
35
+ a, .nav__toggle {
36
+ width: 100%;
37
+ display: flex;
38
+ align-items: center;
39
+ gap: get-spacing(paldiski);
40
+ color: get-color(black-coral-0);
41
+ padding: 14px 8px 14px 32px;
42
+ box-shadow: inset 0 -1px 0 get-color(sapphire-blue-14);
43
+
44
+ span:not(.icon) {
45
+ flex: 1;
46
+ display: block;
47
+ }
48
+
49
+ &:hover {
50
+ background-color: get-color(sapphire-blue-8);
51
+ }
52
+
53
+ &:active {
54
+ background-color: get-color(sapphire-blue-7);
55
+ }
56
+
57
+ &.active {
58
+ font-weight: 700;
59
+ }
60
+
61
+ &:focus {
62
+ }
63
+ }
64
+
65
+ &__toggle {
66
+ &[aria-expanded=true] {
67
+ font-weight: 700;
68
+
69
+ .icon {
70
+ transform: rotate(180deg);
71
+ }
72
+
73
+ + ul {
74
+ display: block;
75
+ }
76
+ }
77
+
78
+ &.nav__toggle--icon {
79
+ padding-left: 8px;
80
+
81
+ .icon:first-child {
82
+ transform: none;
83
+ }
84
+ }
85
+ }
86
+
87
+ &__toggle-icon {
88
+ margin-left: auto;
89
+ }
90
+
91
+ &__menu-toggle {
92
+ display: flex;
93
+ align-items: center;
94
+ gap: get-spacing(paldiski);
95
+ width: 100%;
96
+ color: get-color(white);
97
+ padding: 14px 8px;
98
+ box-shadow: inset 0 -1px 0 get-color(sapphire-blue-14);
99
+ }
100
+
101
+ &__submenu {
102
+ display: none;
103
+
104
+ a, .nav__toggle {
105
+ background-color: get-color(sapphire-blue-14);
106
+ box-shadow: inset 0 -1px 0 get-color(sapphire-blue-17);
107
+ }
108
+
109
+ #{$self} {
110
+ &__submenu {
111
+ a {
112
+ background-color: get-color(sapphire-blue-17);
113
+ box-shadow: inset 0 -1px 0 get-color(black);
114
+ padding: 14px 48px 14px 40px;
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "compileOnSave": false,
3
+ "compilerOptions": {
4
+ "rootDir": ".",
5
+ "sourceMap": true,
6
+ "declaration": false,
7
+ "moduleResolution": "node",
8
+ "emitDecoratorMetadata": true,
9
+ "esModuleInterop": true,
10
+ "experimentalDecorators": true,
11
+ "allowSyntheticDefaultImports": true,
12
+ "importHelpers": true,
13
+ "target": "es2015",
14
+ "module": "esnext",
15
+ "lib": ["es2017", "dom", "dom.Iterable"],
16
+ "skipLibCheck": true,
17
+ "skipDefaultLibCheck": true,
18
+ "baseUrl": ".",
19
+ },
20
+ "exclude": ["node_modules", "tmp"]
21
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "esModuleInterop": true,
4
+ "resolveJsonModule": true,
5
+ "jsx": "react-jsx",
6
+ "allowJs": false,
7
+ "allowSyntheticDefaultImports": true,
8
+ "strict": true,
9
+ "types": ["vite/client"]
10
+ },
11
+ "files": [],
12
+ "include": [],
13
+ "extends": "./tsconfig.base.json"
14
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "types": ["vitest/globals", "node"]
6
+ },
7
+ "include": [
8
+ "vite.config.ts",
9
+ "src/**/*.test.ts",
10
+ "src/**/*.spec.ts",
11
+ "src/**/*.test.tsx",
12
+ "src/**/*.spec.tsx",
13
+ "src/**/*.test.js",
14
+ "src/**/*.spec.js",
15
+ "src/**/*.test.jsx",
16
+ "src/**/*.spec.jsx",
17
+ "src/**/*.d.ts"
18
+ ]
19
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,67 @@
1
+ /// <reference types="vitest" />
2
+ import { defineConfig } from 'vite';
3
+ import react from '@vitejs/plugin-react';
4
+ import tsconfigPaths from 'vite-tsconfig-paths';
5
+ import dts from 'vite-plugin-dts';
6
+ import { join, path } from 'path';
7
+
8
+ export default defineConfig({
9
+ plugins: [
10
+ dts({
11
+ tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
12
+ // Faster builds by skipping tests. Set this to false to enable type checking.
13
+ skipDiagnostics: true,
14
+ }),
15
+ react(),
16
+ tsconfigPaths({
17
+ root: './',
18
+ }),
19
+ ],
20
+ resolve: {
21
+ alias: {
22
+ '@': `${path.resolve(__dirname, './src')}`,
23
+ '~@fontsource': path.resolve(__dirname, 'node_modules/@fontsource'),
24
+ },
25
+ },
26
+ css: {
27
+ preprocessorOptions: {
28
+ scss: {
29
+ additionalData: `@import "@/styles/main.scss";`,
30
+ },
31
+ },
32
+ },
33
+
34
+ // Configuration for building your library.
35
+ // See: https://vitejs.dev/guide/build.html#library-mode
36
+ build: {
37
+ lib: {
38
+ // Could also be a dictionary or array of multiple entry points.
39
+ entry: 'src/index.ts',
40
+ name: 'header',
41
+ fileName: 'index',
42
+ // Change this to the formats you want to support.
43
+ // Don't forgot to update your package.json as well.
44
+ formats: ['es', 'cjs'],
45
+ },
46
+ rollupOptions: {
47
+ // External packages that should not be bundled into your library.
48
+ // external: ['react','react-dom', 'react/jsx-runtime'],
49
+ output: {
50
+ globals: {
51
+ react: 'React',
52
+ 'react-dom': 'ReactDOM',
53
+ },
54
+ },
55
+
56
+ },
57
+ },
58
+
59
+ test: {
60
+ globals: true,
61
+ cache: {
62
+ dir: '../../node_modules/.vitest',
63
+ },
64
+ environment: 'jsdom',
65
+ include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
66
+ },
67
+ });