@servicetitan/navigation 11.0.0-canary.237.0c461af.0 → 11.0.0-canary.237.1f404bf.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/dist/components/badge-tag.d.ts +1 -1
- package/dist/components/badge-tag.d.ts.map +1 -1
- package/dist/components/logo/logo-titan-text.d.ts +1 -1
- package/dist/components/logo/logo-titan-text.d.ts.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown.module.less +2 -0
- package/dist/components/titan-layout/layout-context.js +1 -1
- package/dist/components/titan-layout/layout-context.js.map +1 -1
- package/dist/components/titan-layout/layout-header.d.ts +2 -0
- package/dist/components/titan-layout/layout-header.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-header.js +3 -4
- package/dist/components/titan-layout/layout-header.js.map +1 -1
- package/dist/components/titan-layout/layout-header.module.less +55 -36
- package/dist/components/titan-layout/layout-logo.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-logo.js +2 -1
- package/dist/components/titan-layout/layout-logo.js.map +1 -1
- package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-profile.js +20 -6
- package/dist/components/titan-layout/layout-profile.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +2 -2
- package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links-internal.js +2 -2
- package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links.js +10 -3
- package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.d.ts +2 -0
- package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.js +6 -4
- package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.module.less +25 -5
- package/dist/components/titan-layout/notifications-context.d.ts +13 -0
- package/dist/components/titan-layout/notifications-context.d.ts.map +1 -0
- package/dist/components/titan-layout/notifications-context.js +23 -0
- package/dist/components/titan-layout/notifications-context.js.map +1 -0
- package/dist/components/titan-layout/titan-layout.d.ts +5 -3
- package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.js +73 -28
- package/dist/components/titan-layout/titan-layout.js.map +1 -1
- package/dist/components/titan-layout/titan-layout.module.less +9 -6
- package/dist/components/titan-layout/titan-layout.stories.d.ts +2 -0
- package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.stories.js +8 -5
- package/dist/components/titan-layout/titan-layout.stories.js.map +1 -1
- package/dist/test/data.d.ts +4 -1
- package/dist/test/data.d.ts.map +1 -1
- package/dist/test/data.js +2 -3
- package/dist/test/data.js.map +1 -1
- package/dist/utils/use-breakpoint.d.ts +1 -0
- package/dist/utils/use-breakpoint.d.ts.map +1 -1
- package/dist/utils/use-breakpoint.js +3 -2
- package/dist/utils/use-breakpoint.js.map +1 -1
- package/package.json +2 -2
- package/src/components/badge-tag.tsx +1 -1
- package/src/components/logo/logo-titan-text.tsx +1 -1
- package/src/components/profile-dropdown/profile-dropdown.module.less +2 -0
- package/src/components/titan-layout/layout-context.tsx +1 -1
- package/src/components/titan-layout/layout-header.module.less +55 -36
- package/src/components/titan-layout/layout-header.module.less.d.ts +2 -0
- package/src/components/titan-layout/layout-header.tsx +12 -5
- package/src/components/titan-layout/layout-logo.tsx +13 -6
- package/src/components/titan-layout/layout-profile.tsx +41 -20
- package/src/components/titan-layout/layout-sidebar-links-internal.tsx +6 -3
- package/src/components/titan-layout/layout-sidebar-links.tsx +16 -3
- package/src/components/titan-layout/layout-sidebar.module.less +25 -5
- package/src/components/titan-layout/layout-sidebar.module.less.d.ts +1 -0
- package/src/components/titan-layout/layout-sidebar.tsx +14 -5
- package/src/components/titan-layout/notifications-context.tsx +44 -0
- package/src/components/titan-layout/titan-layout.module.less +9 -6
- package/src/components/titan-layout/titan-layout.module.less.d.ts +1 -0
- package/src/components/titan-layout/titan-layout.stories.tsx +13 -4
- package/src/components/titan-layout/titan-layout.tsx +203 -107
- package/src/test/data.tsx +2 -3
- package/src/utils/use-breakpoint.ts +3 -1
|
@@ -3,10 +3,11 @@ import { useMemo } from 'react';
|
|
|
3
3
|
export const useTitanBreakpoint = () => {
|
|
4
4
|
const breakpoint = useBreakpoint();
|
|
5
5
|
return useMemo(() => {
|
|
6
|
-
var _a;
|
|
6
|
+
var _a, _b;
|
|
7
7
|
return ({
|
|
8
8
|
name: (_a = breakpoint === null || breakpoint === void 0 ? void 0 : breakpoint.name) !== null && _a !== void 0 ? _a : 'xl',
|
|
9
|
-
isMobile: breakpoint ? breakpoint.innerWidth
|
|
9
|
+
isMobile: breakpoint ? breakpoint.innerWidth < 768 : false,
|
|
10
|
+
width: (_b = breakpoint === null || breakpoint === void 0 ? void 0 : breakpoint.innerWidth) !== null && _b !== void 0 ? _b : 0,
|
|
10
11
|
});
|
|
11
12
|
}, [breakpoint]);
|
|
12
13
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-breakpoint.js","sourceRoot":"","sources":["../../src/utils/use-breakpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"use-breakpoint.js","sourceRoot":"","sources":["../../src/utils/use-breakpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAQhC,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAoB,EAAE;IACpD,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,OAAO,OAAO,CACV,GAAG,EAAE;;QAAC,OAAA,CAAC;YACH,IAAI,EAAE,MAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,IAAI,mCAAI,IAAI;YAC9B,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK;YAC1D,KAAK,EAAE,MAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,UAAU,mCAAI,CAAC;SACrC,CAAC,CAAA;KAAA,EACF,CAAC,UAAU,CAAC,CACf,CAAC;AACN,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/navigation",
|
|
3
|
-
"version": "11.0.0-canary.237.
|
|
3
|
+
"version": "11.0.0-canary.237.1f404bf.0",
|
|
4
4
|
"description": "Navigation components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"less": true,
|
|
43
43
|
"webpack": false
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "1f404bfa38754f8912de600c4fd1b2587c240a95"
|
|
46
46
|
}
|
|
@@ -3,7 +3,7 @@ import { CSSProperties, FC, ReactNode } from 'react';
|
|
|
3
3
|
import { LogoTitanSvg } from './logo-titan';
|
|
4
4
|
import * as Styles from './logo-titan-text.module.less';
|
|
5
5
|
|
|
6
|
-
export type WrapperProps = FC<{ className
|
|
6
|
+
export type WrapperProps = FC<{ className?: string; children: ReactNode; style?: CSSProperties }>;
|
|
7
7
|
|
|
8
8
|
export interface LogoTitanProps {
|
|
9
9
|
mantleFill?: string;
|
|
@@ -19,7 +19,7 @@ export interface TitanLayoutContextType {
|
|
|
19
19
|
|
|
20
20
|
export const LayoutContext = createContext<TitanLayoutContextType>({
|
|
21
21
|
NavigationComponent: DefaultNavLinkComponent,
|
|
22
|
-
breakpoint: { name: 'lg', isMobile: false },
|
|
22
|
+
breakpoint: { name: 'lg', isMobile: false, width: 0 },
|
|
23
23
|
isTitanLayout: false,
|
|
24
24
|
sidebar: { styles: { popoverContent: {} } },
|
|
25
25
|
});
|
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
@size-links-tiny: 24px;
|
|
5
5
|
|
|
6
6
|
.header {
|
|
7
|
+
--nav-top-content-height: 32px;
|
|
7
8
|
display: flex;
|
|
8
9
|
justify-content: space-between;
|
|
9
10
|
|
|
10
11
|
background-color: @color-white;
|
|
11
12
|
color: @color-black;
|
|
12
|
-
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
outline: 1px solid @color-neutral-60;
|
|
13
15
|
|
|
14
16
|
& > * {
|
|
15
17
|
overflow-y: hidden;
|
|
@@ -20,6 +22,10 @@
|
|
|
20
22
|
align-items: center;
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
.he-top-center {
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
.he-top-right {
|
|
24
30
|
& > * {
|
|
25
31
|
color: @color-black;
|
|
@@ -84,29 +90,59 @@
|
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
92
|
|
|
93
|
+
.header-mobile {
|
|
94
|
+
padding: @spacing-2 @spacing-0;
|
|
95
|
+
height: var(--nav-offset-top);
|
|
96
|
+
|
|
97
|
+
--nav-top-content-height: 40px;
|
|
98
|
+
|
|
99
|
+
.navigation-link {
|
|
100
|
+
padding: 10px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.he-top-center {
|
|
104
|
+
max-width: unset;
|
|
105
|
+
flex: 1;
|
|
106
|
+
margin-left: @spacing-3;
|
|
107
|
+
margin-right: @spacing-3;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.he-top-left {
|
|
111
|
+
margin-left: @spacing-half;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.he-top-right {
|
|
115
|
+
margin-right: @spacing-half;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
87
119
|
// desktop
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
padding: 6px 6px;
|
|
94
|
-
}
|
|
120
|
+
.header-desktop {
|
|
121
|
+
height: var(--nav-offset-top);
|
|
122
|
+
.navigation-link {
|
|
123
|
+
margin: 6px 2px;
|
|
124
|
+
padding: 6px 6px;
|
|
95
125
|
|
|
96
|
-
.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
.he-top-center {
|
|
100
|
-
flex: 1;
|
|
101
|
-
margin-left: @spacing-2;
|
|
102
|
-
margin-right: @spacing-2;
|
|
103
|
-
max-width: 400px;
|
|
126
|
+
.navigation-item-counter {
|
|
127
|
+
min-width: 12px !important;
|
|
128
|
+
height: 12px !important;
|
|
104
129
|
}
|
|
105
130
|
}
|
|
131
|
+
|
|
132
|
+
.he-top-left {
|
|
133
|
+
padding-left: @spacing-1;
|
|
134
|
+
}
|
|
135
|
+
.he-top-center {
|
|
136
|
+
flex: 1;
|
|
137
|
+
margin-left: @spacing-2;
|
|
138
|
+
margin-right: @spacing-2;
|
|
139
|
+
max-width: 400px;
|
|
140
|
+
}
|
|
106
141
|
}
|
|
142
|
+
|
|
107
143
|
// desktop wide
|
|
108
144
|
@media only screen and (min-width: 1200px) {
|
|
109
|
-
.header {
|
|
145
|
+
.header-desktop {
|
|
110
146
|
display: grid;
|
|
111
147
|
grid-template-columns: repeat(3, 1fr);
|
|
112
148
|
grid-template-rows: 48px;
|
|
@@ -123,24 +159,6 @@
|
|
|
123
159
|
}
|
|
124
160
|
}
|
|
125
161
|
|
|
126
|
-
// mobile
|
|
127
|
-
@media only screen and (max-width: 768px) {
|
|
128
|
-
.header {
|
|
129
|
-
padding: @spacing-1 @spacing-half;
|
|
130
|
-
|
|
131
|
-
.navigation-link {
|
|
132
|
-
padding: 10px;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
.he-top-center {
|
|
136
|
-
max-width: unset;
|
|
137
|
-
flex: 1;
|
|
138
|
-
margin-left: @spacing-3;
|
|
139
|
-
margin-right: @spacing-3;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
162
|
.navigation-link {
|
|
145
163
|
// styles specific to extra nav links
|
|
146
164
|
color: @color-black;
|
|
@@ -154,7 +172,8 @@
|
|
|
154
172
|
color: @color-white;
|
|
155
173
|
font-weight: @font-weight-semibold;
|
|
156
174
|
font-size: 8px !important;
|
|
157
|
-
min-width:
|
|
175
|
+
min-width: 16px !important;
|
|
176
|
+
height: 16px !important;
|
|
158
177
|
position: absolute;
|
|
159
178
|
top: 4px;
|
|
160
179
|
right: -2px;
|
|
@@ -4,6 +4,8 @@ export const heTopLeft: string;
|
|
|
4
4
|
export const heTopRight: string;
|
|
5
5
|
export const heTopRightText: string;
|
|
6
6
|
export const header: string;
|
|
7
|
+
export const headerDesktop: string;
|
|
8
|
+
export const headerMobile: string;
|
|
7
9
|
export const navigationIcon: string;
|
|
8
10
|
export const navigationIconActive: string;
|
|
9
11
|
export const navigationItemActive: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import SvgBurgerMenu from '@servicetitan/anvil2/assets/icons/material/round/menu.svg';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { ComponentPropsWithoutRef, FC, ReactElement, ReactNode } from 'react';
|
|
4
|
-
import { LayoutPlacementContext
|
|
4
|
+
import { LayoutPlacementContext } from './layout-context';
|
|
5
5
|
import { LayoutHeaderNavigationTrigger } from './layout-header-links';
|
|
6
6
|
import * as Styles from './layout-header.module.less';
|
|
7
7
|
import { TitanLayoutLogoProps } from './layout-logo';
|
|
@@ -25,6 +25,8 @@ export type LayoutHeaderProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
25
25
|
logo: ReactElement<TitanLayoutLogoProps>;
|
|
26
26
|
profile?: ReactElement;
|
|
27
27
|
|
|
28
|
+
isMobile: boolean;
|
|
29
|
+
hasNotifications: boolean;
|
|
28
30
|
onBurgerClick?: (e: MouseEvent) => void;
|
|
29
31
|
};
|
|
30
32
|
|
|
@@ -35,22 +37,26 @@ export const LayoutHeader: FC<LayoutHeaderProps> = ({
|
|
|
35
37
|
rightClassName,
|
|
36
38
|
center,
|
|
37
39
|
centerClassName,
|
|
40
|
+
isMobile,
|
|
41
|
+
hasNotifications,
|
|
38
42
|
logo,
|
|
39
43
|
profile,
|
|
40
44
|
onBurgerClick,
|
|
41
45
|
...rest
|
|
42
46
|
}) => {
|
|
43
|
-
const { breakpoint } = useTitanLayoutContext();
|
|
44
|
-
|
|
45
47
|
return (
|
|
46
48
|
<LayoutPlacementContext.Provider value="top">
|
|
47
49
|
<div
|
|
48
|
-
className={classNames(
|
|
50
|
+
className={classNames(
|
|
51
|
+
Styles.header,
|
|
52
|
+
isMobile ? Styles.headerMobile : Styles.headerDesktop,
|
|
53
|
+
className
|
|
54
|
+
)}
|
|
49
55
|
{...rest}
|
|
50
56
|
data-cy="header-navigation"
|
|
51
57
|
>
|
|
52
58
|
<div className={classNames(Styles.heTopLeft)} data-cy="navigation-left">
|
|
53
|
-
{
|
|
59
|
+
{isMobile && (
|
|
54
60
|
<LayoutHeaderNavigationTrigger
|
|
55
61
|
id="burger"
|
|
56
62
|
title=""
|
|
@@ -58,6 +64,7 @@ export const LayoutHeader: FC<LayoutHeaderProps> = ({
|
|
|
58
64
|
iconActive={SvgBurgerMenu}
|
|
59
65
|
className="m-r-1"
|
|
60
66
|
onClick={onBurgerClick}
|
|
67
|
+
tag={{ value: hasNotifications }}
|
|
61
68
|
/>
|
|
62
69
|
)}
|
|
63
70
|
{logo}
|
|
@@ -33,20 +33,27 @@ export const TitanLayoutLogo: FC<TitanLayoutLogoProps> = ({
|
|
|
33
33
|
const Wrapper = logoWrapper;
|
|
34
34
|
const logoSize = isMobile ? 44 : 56;
|
|
35
35
|
const logoCompanySize = 48;
|
|
36
|
+
const showCompanyTitle = title === true && !isMobile;
|
|
36
37
|
|
|
37
38
|
return (
|
|
38
|
-
<div
|
|
39
|
-
{
|
|
39
|
+
<div
|
|
40
|
+
className={classNames(
|
|
41
|
+
'd-f align-items-center',
|
|
42
|
+
{ 'p-t-half': showCompanyTitle },
|
|
43
|
+
className
|
|
44
|
+
)}
|
|
45
|
+
>
|
|
46
|
+
{showCompanyTitle ? (
|
|
47
|
+
<Wrapper>
|
|
48
|
+
<LogoCompanyTitle height={logoCompanySize} />
|
|
49
|
+
</Wrapper>
|
|
50
|
+
) : typeof title === 'string' ? (
|
|
40
51
|
<Fragment>
|
|
41
52
|
<LogoTitan size={logoSize} mantleFill={mantleFill} logoWrapper={Wrapper} />
|
|
42
53
|
{!isMobile && (
|
|
43
54
|
<LogoTitanTitle className="c-inherit m-l-1">{title}</LogoTitanTitle>
|
|
44
55
|
)}
|
|
45
56
|
</Fragment>
|
|
46
|
-
) : title === true && !isMobile ? (
|
|
47
|
-
<Wrapper className="">
|
|
48
|
-
<LogoCompanyTitle height={logoCompanySize} />
|
|
49
|
-
</Wrapper>
|
|
50
57
|
) : (
|
|
51
58
|
<LogoTitan size={logoSize} mantleFill={mantleFill} logoWrapper={Wrapper} />
|
|
52
59
|
)}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import SvgAccountActive from '@servicetitan/anvil2/assets/icons/st/gnav_account_active.svg';
|
|
2
2
|
import SvgAccountInactive from '@servicetitan/anvil2/assets/icons/st/gnav_account_inactive.svg';
|
|
3
3
|
|
|
4
|
-
import { FC, useState } from 'react';
|
|
4
|
+
import { FC, MouseEvent, useEffect, useState } from 'react';
|
|
5
5
|
import { NavLinkComponentProps, NavigationComponentContext } from '../../utils/navigation-context';
|
|
6
6
|
import {
|
|
7
7
|
ProfileDropdown as DesktopProfileDropdown,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
InternalSideNavigationGroupLink,
|
|
18
18
|
InternalSideNavigationGroupTrigger,
|
|
19
19
|
} from './layout-sidebar-links-internal';
|
|
20
|
+
import { useNotificationsContext, useNotificationsState } from './notifications-context';
|
|
20
21
|
|
|
21
22
|
export type {
|
|
22
23
|
ProfileDropdownProps,
|
|
@@ -24,8 +25,10 @@ export type {
|
|
|
24
25
|
ProfileDropdownLinkProps,
|
|
25
26
|
} from '../profile-dropdown/profile-dropdown';
|
|
26
27
|
|
|
27
|
-
const ExternalNavComponent: FC<NavLinkComponentProps> = ({ children, isActive, ...props }) => (
|
|
28
|
-
<a {...props}
|
|
28
|
+
const ExternalNavComponent: FC<NavLinkComponentProps> = ({ children, isActive, to, ...props }) => (
|
|
29
|
+
<a {...props} href={to}>
|
|
30
|
+
{children}
|
|
31
|
+
</a>
|
|
29
32
|
);
|
|
30
33
|
|
|
31
34
|
const ProfileDropdownContent: FC<ProfileDropdownProps> = props => {
|
|
@@ -44,24 +47,37 @@ const MobileProfileDropdown: FC<ProfileDropdownProps & NavigationComponentProps>
|
|
|
44
47
|
children,
|
|
45
48
|
...props
|
|
46
49
|
}) => {
|
|
50
|
+
const id = '__profile';
|
|
47
51
|
const [expanded, setExpanded] = useState(false);
|
|
48
|
-
const
|
|
52
|
+
const { hasNotifications, NotificationsContextProvider } = useNotificationsState();
|
|
53
|
+
const { onNotificationsUpdate } = useNotificationsContext();
|
|
54
|
+
const onExpandToggle = (e: MouseEvent<never>) => {
|
|
55
|
+
e.stopPropagation();
|
|
56
|
+
setExpanded(!expanded);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
onNotificationsUpdate(id, hasNotifications);
|
|
61
|
+
}, [hasNotifications, onNotificationsUpdate]);
|
|
62
|
+
|
|
49
63
|
return (
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
<NotificationsContextProvider>
|
|
65
|
+
<InternalSideNavigationGroup
|
|
66
|
+
id={id}
|
|
67
|
+
to={undefined}
|
|
68
|
+
title="Profile"
|
|
69
|
+
icon={SvgAccountInactive}
|
|
70
|
+
iconActive={SvgAccountActive}
|
|
71
|
+
isActive={expanded}
|
|
72
|
+
{...props}
|
|
73
|
+
submenuExpanded={expanded}
|
|
74
|
+
onExpandToggle={onExpandToggle}
|
|
75
|
+
onClick={onExpandToggle}
|
|
76
|
+
tag={{ value: hasNotifications }}
|
|
77
|
+
>
|
|
78
|
+
{children}
|
|
79
|
+
</InternalSideNavigationGroup>
|
|
80
|
+
</NotificationsContextProvider>
|
|
65
81
|
);
|
|
66
82
|
};
|
|
67
83
|
|
|
@@ -110,17 +126,22 @@ const ProfileDropdownLink: FC<ProfileDropdownLinkProps> = props => {
|
|
|
110
126
|
);
|
|
111
127
|
};
|
|
112
128
|
const MobileProfileDropdownLink: FC<ProfileDropdownLinkProps & NavigationComponentProps> = ({
|
|
129
|
+
external,
|
|
113
130
|
to,
|
|
114
131
|
navigationComponent,
|
|
115
132
|
...props
|
|
116
133
|
}) => {
|
|
134
|
+
const { onNotificationsUpdate } = useNotificationsContext();
|
|
117
135
|
const text = getText(props);
|
|
136
|
+
const isExternalLink = external ?? to?.startsWith('http');
|
|
137
|
+
onNotificationsUpdate(props.id, !!props.tag?.value);
|
|
138
|
+
|
|
118
139
|
return text ? (
|
|
119
140
|
<InternalSideNavigationGroupLink
|
|
120
141
|
{...props}
|
|
121
142
|
to={to}
|
|
122
143
|
title={text}
|
|
123
|
-
navigationComponent={
|
|
144
|
+
navigationComponent={isExternalLink ? ExternalNavComponent : navigationComponent}
|
|
124
145
|
/>
|
|
125
146
|
) : null;
|
|
126
147
|
};
|
|
@@ -156,7 +156,9 @@ export const InternalSideNavigationLink: FC<InternalSideNavigationLinkProps> = (
|
|
|
156
156
|
|
|
157
157
|
/** Side Navigation menu trigger (for internal usage) */
|
|
158
158
|
export const InternalSideNavigationTrigger: FC<
|
|
159
|
-
Omit<InternalSideNavigationLinkProps, 'to' | 'navigationComponent'> & {
|
|
159
|
+
Omit<InternalSideNavigationLinkProps, 'to' | 'navigationComponent'> & {
|
|
160
|
+
onClick?: (e: MouseEvent<never>) => void;
|
|
161
|
+
}
|
|
160
162
|
> = ({ className, dataPrefix, isActive, submenuExpanded, onExpandToggle, onClick, ...props }) => {
|
|
161
163
|
return (
|
|
162
164
|
<div
|
|
@@ -211,12 +213,13 @@ export const InternalSideNavigationGroupLink: FC<
|
|
|
211
213
|
|
|
212
214
|
export const InternalSideNavigationGroupTrigger: FC<
|
|
213
215
|
Omit<NavigationSubmenuItemData, 'to'> & { onClick?: (e: MouseEvent<any>) => void }
|
|
214
|
-
> = ({ id, counter, onClick, tag, title, isActive }) => {
|
|
216
|
+
> = ({ id, counter, onClick, tag, title, isActive, ...rest }) => {
|
|
215
217
|
return (
|
|
216
218
|
<div
|
|
217
219
|
data-cy={`navigation-item-${id}`}
|
|
218
220
|
data-pendo={`navigation-item-${id}`}
|
|
219
221
|
key={id}
|
|
222
|
+
{...rest}
|
|
220
223
|
className={classNames(Styles.submenuItem, {
|
|
221
224
|
[Styles.submenuLink]: !!onClick,
|
|
222
225
|
[Styles.submenuLinkActive]: isActive === true,
|
|
@@ -241,7 +244,7 @@ export const InternalSideNavigationGroup: FC<
|
|
|
241
244
|
onExpandToggle?: (e: MouseEvent<never>) => void;
|
|
242
245
|
tag: BadgeTagProps | undefined;
|
|
243
246
|
to: NavigationItemData['to'] | undefined;
|
|
244
|
-
onClick?: () => void;
|
|
247
|
+
onClick?: (e: MouseEvent<never>) => void;
|
|
245
248
|
}
|
|
246
249
|
> = ({ children, submenuExpanded, to, onExpandToggle, onClick, ...props }) => {
|
|
247
250
|
return (
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
InternalSideNavigationLink,
|
|
7
7
|
InternalSideNavigationTrigger,
|
|
8
8
|
} from './layout-sidebar-links-internal';
|
|
9
|
+
import { useNotificationsContext } from './notifications-context';
|
|
9
10
|
|
|
10
11
|
const WrappedLink: FC<{
|
|
11
12
|
children: ReactElement<any>;
|
|
@@ -21,6 +22,10 @@ export function TitanLayoutSidebarLink({ wrapper, ...props }: TitanLayoutSidebar
|
|
|
21
22
|
NavigationComponent,
|
|
22
23
|
breakpoint: { isMobile },
|
|
23
24
|
} = useTitanLayoutContext();
|
|
25
|
+
const { onNotificationsUpdate } = useNotificationsContext();
|
|
26
|
+
const tag = getCounterTag(props.counter, props.tag);
|
|
27
|
+
|
|
28
|
+
onNotificationsUpdate(props.id, !!tag);
|
|
24
29
|
|
|
25
30
|
const element = (
|
|
26
31
|
<InternalSideNavigationLink
|
|
@@ -28,7 +33,7 @@ export function TitanLayoutSidebarLink({ wrapper, ...props }: TitanLayoutSidebar
|
|
|
28
33
|
navigationComponent={NavigationComponent}
|
|
29
34
|
submenuExpanded={undefined}
|
|
30
35
|
dataPrefix="navigation-link"
|
|
31
|
-
tag={
|
|
36
|
+
tag={tag}
|
|
32
37
|
/>
|
|
33
38
|
);
|
|
34
39
|
|
|
@@ -45,15 +50,23 @@ export function TitanLayoutSidebarTrigger({
|
|
|
45
50
|
const {
|
|
46
51
|
breakpoint: { isMobile },
|
|
47
52
|
} = useTitanLayoutContext();
|
|
53
|
+
const { onNotificationsUpdate } = useNotificationsContext();
|
|
54
|
+
const tag = getCounterTag(props.counter, props.tag);
|
|
55
|
+
|
|
56
|
+
onNotificationsUpdate(props.id, !!tag);
|
|
48
57
|
|
|
49
58
|
const element = (
|
|
50
59
|
<InternalSideNavigationTrigger
|
|
51
60
|
{...props}
|
|
52
61
|
submenuExpanded={undefined}
|
|
53
62
|
dataPrefix="navigation-trigger"
|
|
54
|
-
tag={
|
|
63
|
+
tag={tag}
|
|
55
64
|
onClick={isMobile && !!onMobileClick ? onMobileClick : onClick}
|
|
56
65
|
/>
|
|
57
66
|
);
|
|
58
|
-
return wrapper && !isMobile
|
|
67
|
+
return wrapper && (!isMobile || !onMobileClick) ? (
|
|
68
|
+
<WrappedLink wrapper={wrapper}>{element}</WrappedLink>
|
|
69
|
+
) : (
|
|
70
|
+
element
|
|
71
|
+
);
|
|
59
72
|
}
|
|
@@ -17,15 +17,20 @@
|
|
|
17
17
|
|
|
18
18
|
// mobile version
|
|
19
19
|
.nav-drawer {
|
|
20
|
-
display: none;
|
|
20
|
+
// display: none;
|
|
21
21
|
position: fixed;
|
|
22
22
|
max-width: 400px;
|
|
23
23
|
width: 0;
|
|
24
|
+
height: 100vh;
|
|
24
25
|
top: 0;
|
|
25
|
-
|
|
26
|
-
left: 0;
|
|
26
|
+
left: -100vh;
|
|
27
27
|
z-index: 991;
|
|
28
28
|
|
|
29
|
+
-webkit-transition: width 200ms ease-in-out;
|
|
30
|
+
-moz-transition: width 200ms ease-in-out;
|
|
31
|
+
-o-transition: width 200ms ease-in-out;
|
|
32
|
+
transition: width 200ms ease-in-out;
|
|
33
|
+
|
|
29
34
|
.nav-main {
|
|
30
35
|
padding-left: @spacing-2;
|
|
31
36
|
padding-right: @spacing-2;
|
|
@@ -39,6 +44,7 @@
|
|
|
39
44
|
padding-top: @spacing-2;
|
|
40
45
|
padding-left: @spacing-2;
|
|
41
46
|
padding-right: @spacing-2;
|
|
47
|
+
cursor: pointer;
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
|
|
@@ -61,10 +67,21 @@
|
|
|
61
67
|
}
|
|
62
68
|
}
|
|
63
69
|
|
|
70
|
+
.nav-drawer-backdrop {
|
|
71
|
+
position: fixed;
|
|
72
|
+
height: 100vh;
|
|
73
|
+
width: 100vw;
|
|
74
|
+
top: 0;
|
|
75
|
+
left: 0;
|
|
76
|
+
z-index: 991;
|
|
77
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
78
|
+
}
|
|
79
|
+
|
|
64
80
|
// mobile version opened
|
|
65
81
|
.nav-drawer-opened {
|
|
66
82
|
display: flex;
|
|
67
83
|
width: 90vw;
|
|
84
|
+
left: 0;
|
|
68
85
|
}
|
|
69
86
|
|
|
70
87
|
@media only screen and (min-width: 361px) {
|
|
@@ -142,6 +159,11 @@
|
|
|
142
159
|
.nav-wide {
|
|
143
160
|
width: var(--nav-offset-left);
|
|
144
161
|
|
|
162
|
+
.nav-item {
|
|
163
|
+
margin-left: @spacing-1;
|
|
164
|
+
margin-right: @spacing-1;
|
|
165
|
+
}
|
|
166
|
+
|
|
145
167
|
.toggle {
|
|
146
168
|
.toggle-content {
|
|
147
169
|
margin: @spacing-2;
|
|
@@ -171,8 +193,6 @@
|
|
|
171
193
|
.nav-wide {
|
|
172
194
|
.nav-item {
|
|
173
195
|
flex-direction: row;
|
|
174
|
-
margin-left: @spacing-1;
|
|
175
|
-
margin-right: @spacing-1;
|
|
176
196
|
|
|
177
197
|
.nav-item-icon-wrapper {
|
|
178
198
|
flex: 1;
|
|
@@ -5,6 +5,7 @@ export const navBottom: string;
|
|
|
5
5
|
export const navClose: string;
|
|
6
6
|
export const navCloseWrapper: string;
|
|
7
7
|
export const navDrawer: string;
|
|
8
|
+
export const navDrawerBackdrop: string;
|
|
8
9
|
export const navDrawerOpened: string;
|
|
9
10
|
export const navFooter: string;
|
|
10
11
|
export const navGroupItem: string;
|
|
@@ -33,9 +33,11 @@ export interface LayoutSidebarProps {
|
|
|
33
33
|
mainItems?: NavigationItemData[];
|
|
34
34
|
barExpanded: boolean;
|
|
35
35
|
submenuExpanded: string | undefined;
|
|
36
|
+
drawerOpened: boolean;
|
|
36
37
|
mobile: boolean;
|
|
37
38
|
navigationComponent: FC<NavLinkComponentProps>;
|
|
38
39
|
onBarExpandChange(expanded: boolean): void;
|
|
40
|
+
onDrawerOpenChange(expanded: boolean): void;
|
|
39
41
|
onSubmenuExpandChange(id: string, expanded: boolean): void;
|
|
40
42
|
}
|
|
41
43
|
|
|
@@ -44,29 +46,36 @@ export const LayoutSidebar: FC<LayoutSidebarProps> = ({
|
|
|
44
46
|
mobile,
|
|
45
47
|
barExpanded,
|
|
46
48
|
submenuExpanded,
|
|
49
|
+
drawerOpened,
|
|
47
50
|
onBarExpandChange,
|
|
48
51
|
onSubmenuExpandChange,
|
|
52
|
+
onDrawerOpenChange,
|
|
49
53
|
mainItems,
|
|
50
54
|
top,
|
|
51
55
|
bottom,
|
|
52
56
|
navigationComponent,
|
|
53
57
|
}) => {
|
|
54
|
-
const
|
|
55
|
-
|
|
58
|
+
const closeDrawer = () => {
|
|
59
|
+
if (mobile) {
|
|
60
|
+
onDrawerOpenChange?.(false);
|
|
61
|
+
}
|
|
56
62
|
};
|
|
57
63
|
|
|
58
64
|
return (
|
|
59
65
|
<LayoutPlacementContext.Provider value="side">
|
|
66
|
+
{mobile && drawerOpened && (
|
|
67
|
+
<div className={Styles.navDrawerBackdrop} onClick={closeDrawer} />
|
|
68
|
+
)}
|
|
60
69
|
<div
|
|
61
70
|
className={classNames(
|
|
62
71
|
Styles.nav,
|
|
63
72
|
mobile && Styles.navDrawer,
|
|
64
|
-
mobile &&
|
|
73
|
+
mobile && drawerOpened && Styles.navDrawerOpened,
|
|
65
74
|
!mobile && (barExpanded ? Styles.navWide : Styles.navSlim),
|
|
66
75
|
className
|
|
67
76
|
)}
|
|
68
77
|
data-cy="side-navigation"
|
|
69
|
-
onClick={
|
|
78
|
+
onClick={closeDrawer}
|
|
70
79
|
>
|
|
71
80
|
<ThemeProvider mode="dark" className={Styles.navMain}>
|
|
72
81
|
{mobile && (
|
|
@@ -86,7 +95,7 @@ export const LayoutSidebar: FC<LayoutSidebarProps> = ({
|
|
|
86
95
|
item.submenu ? (
|
|
87
96
|
<SideNavigationGroupItem
|
|
88
97
|
key={item.id}
|
|
89
|
-
barExpanded={barExpanded}
|
|
98
|
+
barExpanded={mobile ? drawerOpened : barExpanded}
|
|
90
99
|
submenuExpanded={!!item.id && submenuExpanded === item.id}
|
|
91
100
|
onSubmenuExpand={onSubmenuExpandChange}
|
|
92
101
|
navigationComponent={navigationComponent}
|