@servicetitan/navigation 11.0.0-canary.237.0ce6038.0 → 11.0.0-canary.237.4786284.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/header-navigation/header-navigation-stacked.stories.js +1 -1
- package/dist/components/header-navigation/header-navigation-stacked.stories.js.map +1 -1
- package/dist/components/header-navigation/header-navigation.stories.js +1 -1
- package/dist/components/header-navigation/header-navigation.stories.js.map +1 -1
- package/dist/components/left-navigation/header-navigation-tiny.stories.js +2 -2
- package/dist/components/left-navigation/header-navigation-tiny.stories.js.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown.d.ts +10 -7
- package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown.js +2 -2
- package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
- package/dist/components/titan-layout/layout-header.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-header.js +1 -1
- package/dist/components/titan-layout/layout-header.js.map +1 -1
- package/dist/components/titan-layout/layout-header.module.less +36 -16
- package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-profile.js +14 -4
- package/dist/components/titan-layout/layout-profile.js.map +1 -1
- package/dist/components/titan-layout/layout-profile.stories.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-profile.stories.js +1 -1
- package/dist/components/titan-layout/layout-profile.stories.js.map +1 -1
- 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 +2 -2
- package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.module.less +4 -1
- 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 +45 -11
- package/dist/components/titan-layout/titan-layout.js.map +1 -1
- package/dist/components/titan-layout/titan-layout.module.less +56 -16
- package/dist/components/titan-layout/titan-layout.stories.d.ts +13 -11
- package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.stories.js +30 -12
- package/dist/components/titan-layout/titan-layout.stories.js.map +1 -1
- package/package.json +2 -2
- package/src/components/header-navigation/header-navigation-stacked.stories.tsx +1 -1
- package/src/components/header-navigation/header-navigation.stories.tsx +1 -1
- package/src/components/left-navigation/header-navigation-tiny.stories.tsx +2 -2
- package/src/components/profile-dropdown/profile-dropdown.tsx +13 -6
- package/src/components/titan-layout/layout-header.module.less +36 -16
- package/src/components/titan-layout/layout-header.tsx +5 -1
- package/src/components/titan-layout/layout-profile.stories.tsx +10 -1
- package/src/components/titan-layout/layout-profile.tsx +24 -8
- package/src/components/titan-layout/layout-sidebar-links-internal.tsx +12 -2
- package/src/components/titan-layout/layout-sidebar-links.tsx +5 -2
- package/src/components/titan-layout/layout-sidebar.module.less +4 -1
- package/src/components/titan-layout/titan-layout.module.less +56 -16
- package/src/components/titan-layout/titan-layout.module.less.d.ts +3 -0
- package/src/components/titan-layout/titan-layout.stories.tsx +156 -18
- package/src/components/titan-layout/titan-layout.tsx +101 -18
|
@@ -2,7 +2,7 @@ import SvgAccountActive from '@servicetitan/anvil2/assets/icons/st/gnav_account_
|
|
|
2
2
|
import SvgAccountInactive from '@servicetitan/anvil2/assets/icons/st/gnav_account_inactive.svg';
|
|
3
3
|
|
|
4
4
|
import { FC, useState } from 'react';
|
|
5
|
-
import { NavigationComponentContext } from '../../utils/navigation-context';
|
|
5
|
+
import { NavLinkComponentProps, NavigationComponentContext } from '../../utils/navigation-context';
|
|
6
6
|
import {
|
|
7
7
|
ProfileDropdown as DesktopProfileDropdown,
|
|
8
8
|
ProfileDropdownLinkProps,
|
|
@@ -24,6 +24,10 @@ export type {
|
|
|
24
24
|
ProfileDropdownLinkProps,
|
|
25
25
|
} from '../profile-dropdown/profile-dropdown';
|
|
26
26
|
|
|
27
|
+
const ExternalNavComponent: FC<NavLinkComponentProps> = ({ children, isActive, ...props }) => (
|
|
28
|
+
<a {...props}>{children}</a>
|
|
29
|
+
);
|
|
30
|
+
|
|
27
31
|
const ProfileDropdownContent: FC<ProfileDropdownProps> = props => {
|
|
28
32
|
const { breakpoint, NavigationComponent } = useTitanLayoutContext();
|
|
29
33
|
return breakpoint.isMobile ? (
|
|
@@ -70,6 +74,18 @@ const ProfileDropdownDivider: FC = () => {
|
|
|
70
74
|
);
|
|
71
75
|
};
|
|
72
76
|
|
|
77
|
+
const getText = (props: any): string | undefined => {
|
|
78
|
+
if (typeof props.children === 'string') {
|
|
79
|
+
return props.children;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (typeof props.text === 'string') {
|
|
83
|
+
return props.text;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return undefined;
|
|
87
|
+
};
|
|
88
|
+
|
|
73
89
|
const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = props => {
|
|
74
90
|
const { breakpoint } = useTitanLayoutContext();
|
|
75
91
|
return breakpoint.isMobile ? (
|
|
@@ -79,9 +95,9 @@ const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = props => {
|
|
|
79
95
|
);
|
|
80
96
|
};
|
|
81
97
|
const MobileProfileDropdownSection: FC<ProfileDropdownSectionProps> = props => {
|
|
82
|
-
const
|
|
83
|
-
return
|
|
84
|
-
<InternalSideNavigationGroupTrigger id={props.id} title={
|
|
98
|
+
const text = getText(props);
|
|
99
|
+
return text ? (
|
|
100
|
+
<InternalSideNavigationGroupTrigger id={props.id} title={text} onClick={props.onClick} />
|
|
85
101
|
) : null;
|
|
86
102
|
};
|
|
87
103
|
|
|
@@ -98,13 +114,13 @@ const MobileProfileDropdownLink: FC<ProfileDropdownLinkProps & NavigationCompone
|
|
|
98
114
|
navigationComponent,
|
|
99
115
|
...props
|
|
100
116
|
}) => {
|
|
101
|
-
const
|
|
102
|
-
return
|
|
117
|
+
const text = getText(props);
|
|
118
|
+
return text ? (
|
|
103
119
|
<InternalSideNavigationGroupLink
|
|
104
120
|
{...props}
|
|
105
121
|
to={to}
|
|
106
|
-
title={
|
|
107
|
-
navigationComponent={navigationComponent}
|
|
122
|
+
title={text}
|
|
123
|
+
navigationComponent={props.external ? ExternalNavComponent : navigationComponent}
|
|
108
124
|
/>
|
|
109
125
|
) : null;
|
|
110
126
|
};
|
|
@@ -180,12 +180,22 @@ export const InternalSideNavigationTrigger: FC<
|
|
|
180
180
|
|
|
181
181
|
export const InternalSideNavigationGroupLink: FC<
|
|
182
182
|
NavigationSubmenuItemData & NavigationComponentProps
|
|
183
|
-
> = ({
|
|
183
|
+
> = ({
|
|
184
|
+
id,
|
|
185
|
+
counter,
|
|
186
|
+
tag,
|
|
187
|
+
title,
|
|
188
|
+
to,
|
|
189
|
+
isActive,
|
|
190
|
+
navigationComponent: NavigationComponent,
|
|
191
|
+
...rest
|
|
192
|
+
}) => {
|
|
184
193
|
return (
|
|
185
194
|
<NavigationComponent
|
|
195
|
+
key={id}
|
|
186
196
|
data-cy={`navigation-item-${id}`}
|
|
187
197
|
data-pendo={`navigation-item-${id}`}
|
|
188
|
-
|
|
198
|
+
{...rest}
|
|
189
199
|
to={to}
|
|
190
200
|
className={classNames(Styles.submenuItem, Styles.submenuLink, {
|
|
191
201
|
[Styles.submenuLinkActive]: isActive === true,
|
|
@@ -17,7 +17,10 @@ const WrappedLink: FC<{
|
|
|
17
17
|
|
|
18
18
|
/** Side Navigation menu link */
|
|
19
19
|
export function TitanLayoutSidebarLink({ wrapper, ...props }: TitanLayoutSidebarLinkProps) {
|
|
20
|
-
const {
|
|
20
|
+
const {
|
|
21
|
+
NavigationComponent,
|
|
22
|
+
breakpoint: { isMobile },
|
|
23
|
+
} = useTitanLayoutContext();
|
|
21
24
|
|
|
22
25
|
const element = (
|
|
23
26
|
<InternalSideNavigationLink
|
|
@@ -29,7 +32,7 @@ export function TitanLayoutSidebarLink({ wrapper, ...props }: TitanLayoutSidebar
|
|
|
29
32
|
/>
|
|
30
33
|
);
|
|
31
34
|
|
|
32
|
-
return wrapper ? <WrappedLink wrapper={wrapper}>{element}</WrappedLink> : element;
|
|
35
|
+
return wrapper && !isMobile ? <WrappedLink wrapper={wrapper}>{element}</WrappedLink> : element;
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
/** Side Navigation menu trigger */
|
|
@@ -141,7 +141,6 @@
|
|
|
141
141
|
// desktop version expanded
|
|
142
142
|
.nav-wide {
|
|
143
143
|
width: var(--nav-offset-left);
|
|
144
|
-
padding-top: @spacing-2;
|
|
145
144
|
|
|
146
145
|
.toggle {
|
|
147
146
|
.toggle-content {
|
|
@@ -162,6 +161,10 @@
|
|
|
162
161
|
margin-top: @spacing-1;
|
|
163
162
|
margin-bottom: @spacing-1;
|
|
164
163
|
}
|
|
164
|
+
|
|
165
|
+
.nav-main {
|
|
166
|
+
padding-top: @spacing-1;
|
|
167
|
+
}
|
|
165
168
|
}
|
|
166
169
|
|
|
167
170
|
.nav-drawer,
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
margin-top: var(--nav-offset-top);
|
|
14
14
|
|
|
15
15
|
display: flex;
|
|
16
|
-
flex-direction:
|
|
16
|
+
flex-direction: column;
|
|
17
17
|
|
|
18
18
|
.side {
|
|
19
19
|
flex-basis: var(--nav-offset-left);
|
|
@@ -26,27 +26,45 @@
|
|
|
26
26
|
|
|
27
27
|
display: flex;
|
|
28
28
|
flex-direction: column;
|
|
29
|
-
overflow: hidden;
|
|
29
|
+
overflow-y: hidden;
|
|
30
|
+
overflow-x: auto;
|
|
31
|
+
|
|
32
|
+
.content-page {
|
|
33
|
+
position: relative;
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
flex-grow: 1;
|
|
37
|
+
flex-basis: 0;
|
|
38
|
+
overflow-y: hidden;
|
|
39
|
+
}
|
|
30
40
|
}
|
|
31
41
|
}
|
|
32
42
|
|
|
33
|
-
.layout-legacy,
|
|
34
43
|
.layout-anvil2 {
|
|
44
|
+
.header {
|
|
45
|
+
position: sticky;
|
|
46
|
+
top: var(--nav-offset-top);
|
|
47
|
+
z-index: 989;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.layout-desktop {
|
|
35
52
|
padding-left: var(--nav-offset-left);
|
|
36
53
|
|
|
37
|
-
.
|
|
38
|
-
|
|
54
|
+
.side {
|
|
55
|
+
position: fixed;
|
|
56
|
+
top: var(--nav-offset-top);
|
|
57
|
+
bottom: 0;
|
|
58
|
+
left: 0;
|
|
59
|
+
right: 0;
|
|
60
|
+
z-index: @z-index-global-nav;
|
|
39
61
|
}
|
|
62
|
+
}
|
|
40
63
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
bottom: 0;
|
|
46
|
-
left: 0;
|
|
47
|
-
right: 0;
|
|
48
|
-
z-index: @z-index-global-nav;
|
|
49
|
-
}
|
|
64
|
+
.layout-legacy,
|
|
65
|
+
.layout-anvil2 {
|
|
66
|
+
.top-placeholder {
|
|
67
|
+
height: var(--nav-offset-top);
|
|
50
68
|
}
|
|
51
69
|
}
|
|
52
70
|
|
|
@@ -58,11 +76,11 @@
|
|
|
58
76
|
--nav-offset-left: 0;
|
|
59
77
|
}
|
|
60
78
|
|
|
61
|
-
&.layout-nav-slim {
|
|
79
|
+
&.layout-desktop.layout-nav-slim {
|
|
62
80
|
--nav-offset-left: 64px;
|
|
63
81
|
}
|
|
64
82
|
|
|
65
|
-
&.layout-nav-wide {
|
|
83
|
+
&.layout-desktop.layout-nav-wide {
|
|
66
84
|
--nav-offset-left: 212px;
|
|
67
85
|
}
|
|
68
86
|
|
|
@@ -73,4 +91,26 @@
|
|
|
73
91
|
right: 0;
|
|
74
92
|
z-index: 991;
|
|
75
93
|
}
|
|
94
|
+
|
|
95
|
+
.content {
|
|
96
|
+
overflow-x: auto;
|
|
97
|
+
|
|
98
|
+
.header {
|
|
99
|
+
position: sticky;
|
|
100
|
+
left: 0;
|
|
101
|
+
right: 0;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@media print {
|
|
107
|
+
.layout {
|
|
108
|
+
--nav-offset-left: 0px !important;
|
|
109
|
+
--nav-offset-right: 0px !important;
|
|
110
|
+
|
|
111
|
+
.side,
|
|
112
|
+
.top {
|
|
113
|
+
display: none !important;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
76
116
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export const __esModule: true;
|
|
2
2
|
export const content: string;
|
|
3
|
+
export const contentPage: string;
|
|
4
|
+
export const header: string;
|
|
3
5
|
export const layout: string;
|
|
4
6
|
export const layoutAnvil1: string;
|
|
5
7
|
export const layoutAnvil2: string;
|
|
8
|
+
export const layoutDesktop: string;
|
|
6
9
|
export const layoutLegacy: string;
|
|
7
10
|
export const layoutMobile: string;
|
|
8
11
|
export const layoutNavSlim: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Page as Anvil2Page, Popover } from '@servicetitan/anvil2';
|
|
1
|
+
import { Announcement, Page as Anvil2Page, Button, Popover, TextField } from '@servicetitan/anvil2';
|
|
2
2
|
import SvgSearch from '@servicetitan/anvil2/assets/icons/material/round/search.svg';
|
|
3
3
|
import SvgAtlas from '@servicetitan/anvil2/assets/icons/st/atlas_logo.svg';
|
|
4
4
|
import SvgSettingsActive from '@servicetitan/anvil2/assets/icons/st/gnav_settings_active.svg';
|
|
@@ -20,11 +20,28 @@ import { SideNavigationLinkWrapperProps } from '../left-navigation';
|
|
|
20
20
|
import { HeaderNavigationLink, HeaderNavigationTrigger } from '../links';
|
|
21
21
|
import { ProfileDropdown, TitanLayout, TitanLayoutProps, TitanLayoutState } from './';
|
|
22
22
|
|
|
23
|
+
interface LayoutContentArgs {
|
|
24
|
+
header: boolean;
|
|
25
|
+
sideTop: boolean;
|
|
26
|
+
extraText: boolean;
|
|
27
|
+
search: boolean;
|
|
28
|
+
longContent: boolean;
|
|
29
|
+
wideContent: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
export default {
|
|
24
33
|
title: 'Navigation/TitanLayout',
|
|
25
|
-
component: TitanLayout,
|
|
26
34
|
decorators: [withDefaultRedirects, withMemoryRouter, withAnvil],
|
|
27
35
|
parameters: {},
|
|
36
|
+
argTypes: {},
|
|
37
|
+
args: {
|
|
38
|
+
header: true,
|
|
39
|
+
sideTop: true,
|
|
40
|
+
extraText: true,
|
|
41
|
+
search: true,
|
|
42
|
+
longContent: true,
|
|
43
|
+
wideContent: false,
|
|
44
|
+
} as LayoutContentArgs,
|
|
28
45
|
};
|
|
29
46
|
|
|
30
47
|
const mainNavItems = [
|
|
@@ -131,9 +148,9 @@ const SideLinkPopoverWrapper: FC<SideNavigationLinkWrapperProps> = ({ children,
|
|
|
131
148
|
};
|
|
132
149
|
|
|
133
150
|
const sidebarTop = () => [
|
|
134
|
-
<TitanLayout.
|
|
135
|
-
<TitanLayout.
|
|
136
|
-
<TitanLayout.
|
|
151
|
+
<TitanLayout.Link key="tasks" {...items.tasks} />,
|
|
152
|
+
<TitanLayout.Link key="calls" {...items.calls} />,
|
|
153
|
+
<TitanLayout.Trigger
|
|
137
154
|
key="marketing"
|
|
138
155
|
{...items.marketing}
|
|
139
156
|
isActive={false}
|
|
@@ -142,51 +159,172 @@ const sidebarTop = () => [
|
|
|
142
159
|
counter={50}
|
|
143
160
|
/>,
|
|
144
161
|
];
|
|
145
|
-
const
|
|
162
|
+
const ContentHeader = () => {
|
|
163
|
+
const [longInfo, setLongInfo] = useState(false);
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<Fragment>
|
|
167
|
+
<Announcement title="Some info" status="info" />
|
|
168
|
+
<Announcement title="Some warning" status="warning" />
|
|
169
|
+
<div
|
|
170
|
+
className="d-f justify-content-center align-items-center bg-purple-100-i"
|
|
171
|
+
style={{ height: longInfo ? '120px' : '48px' }}
|
|
172
|
+
>
|
|
173
|
+
<div className="d-f align-items-center gap-1">
|
|
174
|
+
custom content{' '}
|
|
175
|
+
<Button onClick={() => setLongInfo(!longInfo)} size="small" aria-label="test">
|
|
176
|
+
{longInfo ? '↑' : '↓'}
|
|
177
|
+
</Button>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</Fragment>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
const SearchBar = () => <TextField size="small" placeholder="Search" className="w-100-i" />;
|
|
184
|
+
|
|
185
|
+
const useLayoutProps = (args: LayoutContentArgs): TitanLayoutProps => {
|
|
146
186
|
const [state, setState] = useState<TitanLayoutState | undefined>(undefined);
|
|
147
187
|
|
|
148
188
|
return {
|
|
149
189
|
state,
|
|
150
190
|
onStateChange: setState,
|
|
151
191
|
|
|
192
|
+
navigationComponent: NavLinkMock,
|
|
152
193
|
navigationMainItems: mainNavItems,
|
|
194
|
+
|
|
153
195
|
profile,
|
|
196
|
+
top: args.search ? <SearchBar /> : undefined,
|
|
197
|
+
header: args.header ? <ContentHeader /> : undefined,
|
|
198
|
+
|
|
154
199
|
extraLinks,
|
|
155
200
|
extraLinksTop,
|
|
201
|
+
extraText: args.extraText ? 'EST (-8 hrs)' : undefined,
|
|
156
202
|
|
|
157
|
-
|
|
158
|
-
navigationComponent: NavLinkMock,
|
|
159
|
-
extraText: 'EST (-8 hrs)',
|
|
203
|
+
sideTop: args.sideTop ? sidebarTop() : undefined,
|
|
160
204
|
};
|
|
161
205
|
};
|
|
162
206
|
|
|
163
|
-
|
|
164
|
-
|
|
207
|
+
const Content = (args: LayoutContentArgs) => {
|
|
208
|
+
return (
|
|
209
|
+
<Fragment>
|
|
210
|
+
<LocationInfo />
|
|
211
|
+
{args.wideContent && (
|
|
212
|
+
<div style={{ width: '1200px' }}>
|
|
213
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
214
|
+
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
|
|
215
|
+
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
|
216
|
+
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
|
|
217
|
+
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
|
|
218
|
+
culpa qui officia deserunt mollit anim id est laborum.
|
|
219
|
+
</div>
|
|
220
|
+
)}
|
|
221
|
+
|
|
222
|
+
{args.longContent && (
|
|
223
|
+
<div>
|
|
224
|
+
<p>Lorem</p>
|
|
225
|
+
<p>ipsum</p>
|
|
226
|
+
<p>dolor</p>
|
|
227
|
+
<p>sit</p>
|
|
228
|
+
<p>amet,</p>
|
|
229
|
+
<p>consectetur</p>
|
|
230
|
+
<p>adipiscing</p>
|
|
231
|
+
<p>elit,</p>
|
|
232
|
+
<p>sed</p>
|
|
233
|
+
<p>do</p>
|
|
234
|
+
<p>eiusmod</p>
|
|
235
|
+
<p>tempor</p>
|
|
236
|
+
<p>incididunt</p>
|
|
237
|
+
<p>ut</p>
|
|
238
|
+
<p>labore</p>
|
|
239
|
+
<p>et</p>
|
|
240
|
+
<p>dolore</p>
|
|
241
|
+
<p>magna</p>
|
|
242
|
+
<p>aliqua.</p>
|
|
243
|
+
<p>Ut</p>
|
|
244
|
+
<p>enim</p>
|
|
245
|
+
<p>ad</p>
|
|
246
|
+
<p>minim</p>
|
|
247
|
+
<p>veniam,</p>
|
|
248
|
+
<p>quis</p>
|
|
249
|
+
<p>nostrud</p>
|
|
250
|
+
<p>exercitation</p>
|
|
251
|
+
<p>ullamco</p>
|
|
252
|
+
<p>laboris</p>
|
|
253
|
+
<p>nisi</p>
|
|
254
|
+
<p>ut</p>
|
|
255
|
+
<p>aliquip</p>
|
|
256
|
+
<p>ex</p>
|
|
257
|
+
<p>ea</p>
|
|
258
|
+
<p>commodo</p>
|
|
259
|
+
<p>consequat.</p>
|
|
260
|
+
<p>Duis</p>
|
|
261
|
+
<p>aute</p>
|
|
262
|
+
<p>irure</p>
|
|
263
|
+
<p>dolor</p>
|
|
264
|
+
<p>in</p>
|
|
265
|
+
<p>reprehenderit</p>
|
|
266
|
+
<p>in</p>
|
|
267
|
+
<p>voluptate</p>
|
|
268
|
+
<p>velit</p>
|
|
269
|
+
<p>esse</p>
|
|
270
|
+
<p>cillum</p>
|
|
271
|
+
<p>dolore</p>
|
|
272
|
+
<p>eu</p>
|
|
273
|
+
<p>fugiat</p>
|
|
274
|
+
<p>nulla</p>
|
|
275
|
+
<p>pariatur.</p>
|
|
276
|
+
<p>Excepteur</p>
|
|
277
|
+
<p>sint</p>
|
|
278
|
+
<p>occaecat</p>
|
|
279
|
+
<p>cupidatat</p>
|
|
280
|
+
<p>non</p>
|
|
281
|
+
<p>proident,</p>
|
|
282
|
+
<p>sunt</p>
|
|
283
|
+
<p>in</p>
|
|
284
|
+
<p>culpa</p>
|
|
285
|
+
<p>qui</p>
|
|
286
|
+
<p>officia</p>
|
|
287
|
+
<p>deserunt</p>
|
|
288
|
+
<p>mollit</p>
|
|
289
|
+
<p>anim</p>
|
|
290
|
+
<p>id</p>
|
|
291
|
+
<p>est</p>
|
|
292
|
+
<p>laborum.</p>
|
|
293
|
+
</div>
|
|
294
|
+
)}
|
|
295
|
+
</Fragment>
|
|
296
|
+
);
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export const TitanLayoutLegacy = (args: LayoutContentArgs) => (
|
|
300
|
+
<TitanLayout {...useLayoutProps(args)} appearance="legacy">
|
|
165
301
|
<TitanLayout.Logo title />
|
|
166
302
|
<TitanLayout.Content>
|
|
167
|
-
<
|
|
303
|
+
<div className="p-3">
|
|
304
|
+
<Content {...args} />
|
|
305
|
+
</div>
|
|
168
306
|
</TitanLayout.Content>
|
|
169
307
|
</TitanLayout>
|
|
170
308
|
);
|
|
171
309
|
|
|
172
|
-
export const TitanLayoutAnvil1 = () => (
|
|
173
|
-
<TitanLayout {...useLayoutProps()} appearance="anvil1">
|
|
310
|
+
export const TitanLayoutAnvil1 = (args: LayoutContentArgs) => (
|
|
311
|
+
<TitanLayout {...useLayoutProps(args)} appearance="anvil1">
|
|
174
312
|
<TitanLayout.Logo title />
|
|
175
313
|
<TitanLayout.Content>
|
|
176
314
|
<Anvil1Page>
|
|
177
|
-
<
|
|
315
|
+
<Content {...args} />
|
|
178
316
|
</Anvil1Page>
|
|
179
317
|
</TitanLayout.Content>
|
|
180
318
|
</TitanLayout>
|
|
181
319
|
);
|
|
182
320
|
|
|
183
|
-
export const TitanLayoutAnvil2 = () => (
|
|
184
|
-
<TitanLayout {...useLayoutProps()} appearance="anvil2">
|
|
321
|
+
export const TitanLayoutAnvil2 = (args: LayoutContentArgs) => (
|
|
322
|
+
<TitanLayout {...useLayoutProps(args)} appearance="anvil2">
|
|
185
323
|
<TitanLayout.Logo title />
|
|
186
324
|
<TitanLayout.Content>
|
|
187
325
|
<Anvil2Page>
|
|
188
326
|
<Anvil2Page.Content>
|
|
189
|
-
<
|
|
327
|
+
<Content {...args} />
|
|
190
328
|
</Anvil2Page.Content>
|
|
191
329
|
</Anvil2Page>
|
|
192
330
|
</TitanLayout.Content>
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
useCallback,
|
|
12
12
|
useEffect,
|
|
13
13
|
useMemo,
|
|
14
|
+
useRef,
|
|
14
15
|
useState,
|
|
15
16
|
} from 'react';
|
|
16
17
|
import { NavigationItemData } from '../../utils/navigation';
|
|
@@ -50,11 +51,13 @@ export type TitanLayoutProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
50
51
|
onStateChange?: (state: TitanLayoutState) => void;
|
|
51
52
|
|
|
52
53
|
header?: ReactElement;
|
|
54
|
+
top?: ReactElement;
|
|
55
|
+
sideTop?: ReactElement[];
|
|
53
56
|
profile?: ReactElement;
|
|
54
57
|
extraLinks?: ReactElement;
|
|
55
58
|
extraLinksTop?: ReactElement;
|
|
56
59
|
extraText?: string;
|
|
57
|
-
|
|
60
|
+
minContentWidth?: number;
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
const defaultSidebarContext: TitanLayoutSidebarContextType = {
|
|
@@ -115,6 +118,7 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
115
118
|
children,
|
|
116
119
|
navigationComponent,
|
|
117
120
|
header,
|
|
121
|
+
top,
|
|
118
122
|
profile,
|
|
119
123
|
state,
|
|
120
124
|
onStateChange,
|
|
@@ -122,7 +126,8 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
122
126
|
extraLinks,
|
|
123
127
|
extraLinksTop,
|
|
124
128
|
extraText,
|
|
125
|
-
|
|
129
|
+
minContentWidth,
|
|
130
|
+
sideTop,
|
|
126
131
|
}) => {
|
|
127
132
|
const breakpoint = useTitanBreakpoint();
|
|
128
133
|
const isMobile = breakpoint.isMobile;
|
|
@@ -154,6 +159,13 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
154
159
|
return () => document.removeEventListener('click', listener);
|
|
155
160
|
}, [isMobile]);
|
|
156
161
|
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (variant.isAnvil1) {
|
|
164
|
+
document.body.classList.add('of-hidden-i');
|
|
165
|
+
return () => document.body.classList.remove('of-hidden');
|
|
166
|
+
}
|
|
167
|
+
}, [variant.isAnvil1]);
|
|
168
|
+
|
|
157
169
|
const onBurgerClick = useCallback((e: MouseEvent) => {
|
|
158
170
|
setMobileDrawerOpened(true);
|
|
159
171
|
e.stopPropagation();
|
|
@@ -179,8 +191,6 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
179
191
|
[state, onStateChange]
|
|
180
192
|
);
|
|
181
193
|
|
|
182
|
-
const [layoutStyles] = useState<object>({});
|
|
183
|
-
|
|
184
194
|
const layoutClass = variant.isLegacy
|
|
185
195
|
? Styles.layoutLegacy
|
|
186
196
|
: variant.isAnvil1
|
|
@@ -194,21 +204,19 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
194
204
|
id={id}
|
|
195
205
|
className={classNames(
|
|
196
206
|
Styles.layout,
|
|
197
|
-
isMobile
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
: Styles.layoutNavWide,
|
|
207
|
+
isMobile ? Styles.layoutMobile : Styles.layoutDesktop,
|
|
208
|
+
!isMobile && state?.navCollapsed
|
|
209
|
+
? Styles.layoutNavSlim
|
|
210
|
+
: Styles.layoutNavWide,
|
|
202
211
|
layoutClass
|
|
203
212
|
)}
|
|
204
|
-
style={layoutStyles}
|
|
205
213
|
>
|
|
206
214
|
{variant.isSequent && <div className={Styles.topPlaceholder} />}
|
|
207
215
|
<LayoutHeader
|
|
208
216
|
className={Styles.top}
|
|
209
217
|
logo={logo}
|
|
210
218
|
profile={isMobile ? undefined : profile}
|
|
211
|
-
center={
|
|
219
|
+
center={top}
|
|
212
220
|
rightText={isMobile ? undefined : extraText}
|
|
213
221
|
right={
|
|
214
222
|
<Fragment>
|
|
@@ -226,7 +234,7 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
226
234
|
submenuExpanded={state?.submenuExpanded}
|
|
227
235
|
onBarExpandChange={onBarExpandChange}
|
|
228
236
|
onSubmenuExpandChange={onSubmenuExpandChange}
|
|
229
|
-
top={
|
|
237
|
+
top={sideTop}
|
|
230
238
|
mainItems={navigationMainItems}
|
|
231
239
|
navigationComponent={context.NavigationComponent}
|
|
232
240
|
bottom={
|
|
@@ -250,23 +258,98 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
250
258
|
}
|
|
251
259
|
/>
|
|
252
260
|
|
|
253
|
-
|
|
261
|
+
<LayoutContent
|
|
262
|
+
header={header}
|
|
263
|
+
anvil2={variant.isAnvil2}
|
|
264
|
+
anvil1={variant.isAnvil1}
|
|
265
|
+
minWidth={minContentWidth}
|
|
266
|
+
>
|
|
267
|
+
{content}
|
|
268
|
+
</LayoutContent>
|
|
254
269
|
</div>
|
|
255
270
|
</LayoutPlacementContext.Provider>
|
|
256
271
|
</LayoutContext.Provider>
|
|
257
272
|
);
|
|
258
273
|
};
|
|
259
274
|
|
|
275
|
+
const TitanLayoutHeaderObserved: FC<{
|
|
276
|
+
children: ReactNode;
|
|
277
|
+
heightChange?(value: number): void;
|
|
278
|
+
}> = ({ children, heightChange }) => {
|
|
279
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
280
|
+
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
if (ref.current) {
|
|
283
|
+
const updatePosition = () => {
|
|
284
|
+
if (ref.current && heightChange) {
|
|
285
|
+
const pos = ref.current.getBoundingClientRect();
|
|
286
|
+
heightChange(pos.height);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const observer = new ResizeObserver(updatePosition);
|
|
291
|
+
observer.observe(ref.current);
|
|
292
|
+
|
|
293
|
+
updatePosition();
|
|
294
|
+
return () => observer.disconnect();
|
|
295
|
+
}
|
|
296
|
+
}, [heightChange]);
|
|
297
|
+
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
return () => {
|
|
300
|
+
heightChange?.(0);
|
|
301
|
+
};
|
|
302
|
+
}, [heightChange]);
|
|
303
|
+
return (
|
|
304
|
+
<div ref={ref} className={Styles.header}>
|
|
305
|
+
{children}
|
|
306
|
+
</div>
|
|
307
|
+
);
|
|
308
|
+
};
|
|
309
|
+
|
|
260
310
|
export interface TitanLayoutContentProps {
|
|
261
311
|
children: ReactNode;
|
|
262
312
|
}
|
|
263
|
-
const TitanLayoutContent: FC<TitanLayoutContentProps> = ({ children }) =>
|
|
264
|
-
|
|
265
|
-
|
|
313
|
+
const TitanLayoutContent: FC<TitanLayoutContentProps> = ({ children }) => children;
|
|
314
|
+
|
|
315
|
+
const LayoutContent: FC<{
|
|
316
|
+
children: ReactNode;
|
|
317
|
+
header?: ReactNode;
|
|
318
|
+
anvil1: boolean;
|
|
319
|
+
anvil2: boolean;
|
|
320
|
+
minWidth: number | undefined;
|
|
321
|
+
}> = ({ anvil1, anvil2, children, header }) => {
|
|
322
|
+
const [anvil2Styles, setAnvil2Styles] = useState<object>({});
|
|
323
|
+
const updateIndicatorsHeight = useCallback((offset: number) => {
|
|
324
|
+
setAnvil2Styles({ '--offset': `calc(var(--nav-offset-top) + ${offset}px)` });
|
|
325
|
+
}, []);
|
|
326
|
+
|
|
327
|
+
return (
|
|
328
|
+
<Fragment>
|
|
329
|
+
{!!header &&
|
|
330
|
+
(anvil2 ? (
|
|
331
|
+
<TitanLayoutHeaderObserved heightChange={updateIndicatorsHeight}>
|
|
332
|
+
{header}
|
|
333
|
+
</TitanLayoutHeaderObserved>
|
|
334
|
+
) : (
|
|
335
|
+
<div className={Styles.header}>{header}</div>
|
|
336
|
+
))}
|
|
337
|
+
<div className={Styles.content} style={anvil2Styles} data-cy="layout-content">
|
|
338
|
+
{anvil1 ? (
|
|
339
|
+
<div className="position-relative d-f flex-grow-1 flex-basis-0 of-hidden">
|
|
340
|
+
{children}
|
|
341
|
+
</div>
|
|
342
|
+
) : (
|
|
343
|
+
children
|
|
344
|
+
)}
|
|
345
|
+
</div>
|
|
346
|
+
</Fragment>
|
|
347
|
+
);
|
|
348
|
+
};
|
|
266
349
|
|
|
267
350
|
export const TitanLayout = Object.assign(TitanLayoutComponent, {
|
|
268
351
|
Content: TitanLayoutContent,
|
|
269
352
|
Logo: TitanLayoutLogo,
|
|
270
|
-
|
|
271
|
-
|
|
353
|
+
Link: TitanLayoutSidebarLink,
|
|
354
|
+
Trigger: TitanLayoutSidebarTrigger,
|
|
272
355
|
});
|