@servicetitan/navigation 11.0.0-canary.237.4d902dc.0 → 11.0.0-canary.237.6ce8e81.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 +9 -7
- package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
- 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 +37 -16
- package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-profile.js +13 -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.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.d.ts +0 -1
- package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.js +2 -2
- package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.module.less +4 -16
- package/dist/components/titan-layout/titan-layout.d.ts +4 -3
- package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.js +39 -11
- package/dist/components/titan-layout/titan-layout.js.map +1 -1
- package/dist/components/titan-layout/titan-layout.module.less +47 -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 +9 -6
- package/src/components/titan-layout/layout-header.module.less +37 -16
- package/src/components/titan-layout/layout-header.tsx +5 -1
- package/src/components/titan-layout/layout-profile.stories.tsx +9 -0
- package/src/components/titan-layout/layout-profile.tsx +18 -6
- package/src/components/titan-layout/layout-sidebar-links.tsx +5 -2
- package/src/components/titan-layout/layout-sidebar.module.less +4 -16
- package/src/components/titan-layout/layout-sidebar.module.less.d.ts +0 -2
- package/src/components/titan-layout/layout-sidebar.tsx +1 -4
- package/src/components/titan-layout/titan-layout.module.less +47 -16
- package/src/components/titan-layout/titan-layout.module.less.d.ts +4 -0
- package/src/components/titan-layout/titan-layout.stories.tsx +156 -18
- package/src/components/titan-layout/titan-layout.tsx +89 -17
|
@@ -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 */
|
|
@@ -15,21 +15,6 @@
|
|
|
15
15
|
align-items: stretch;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
// desktop version positioned with flex
|
|
19
|
-
.nav-flex {
|
|
20
|
-
flex-basis: var(--nav-offset-left);
|
|
21
|
-
flex-grow: 0;
|
|
22
|
-
flex-shrink: 0;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// desktop version positioned with fixed
|
|
26
|
-
.nav-fixed {
|
|
27
|
-
position: fixed;
|
|
28
|
-
top: var(--nav-offset-top);
|
|
29
|
-
bottom: 0;
|
|
30
|
-
left: 0;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
18
|
// mobile version
|
|
34
19
|
.nav-drawer {
|
|
35
20
|
display: none;
|
|
@@ -156,7 +141,6 @@
|
|
|
156
141
|
// desktop version expanded
|
|
157
142
|
.nav-wide {
|
|
158
143
|
width: var(--nav-offset-left);
|
|
159
|
-
padding-top: @spacing-2;
|
|
160
144
|
|
|
161
145
|
.toggle {
|
|
162
146
|
.toggle-content {
|
|
@@ -177,6 +161,10 @@
|
|
|
177
161
|
margin-top: @spacing-1;
|
|
178
162
|
margin-bottom: @spacing-1;
|
|
179
163
|
}
|
|
164
|
+
|
|
165
|
+
.nav-main {
|
|
166
|
+
padding-top: @spacing-1;
|
|
167
|
+
}
|
|
180
168
|
}
|
|
181
169
|
|
|
182
170
|
.nav-drawer,
|
|
@@ -6,8 +6,6 @@ export const navClose: string;
|
|
|
6
6
|
export const navCloseWrapper: string;
|
|
7
7
|
export const navDrawer: string;
|
|
8
8
|
export const navDrawerOpened: string;
|
|
9
|
-
export const navFixed: string;
|
|
10
|
-
export const navFlex: string;
|
|
11
9
|
export const navFooter: string;
|
|
12
10
|
export const navGroupItem: string;
|
|
13
11
|
export const navGroupWrapper: string;
|
|
@@ -31,7 +31,6 @@ export interface LayoutSidebarProps {
|
|
|
31
31
|
top?: ReactElement[];
|
|
32
32
|
bottom?: ReactElement;
|
|
33
33
|
mainItems?: NavigationItemData[];
|
|
34
|
-
flex: boolean;
|
|
35
34
|
barExpanded: boolean;
|
|
36
35
|
submenuExpanded: string | undefined;
|
|
37
36
|
mobile: boolean;
|
|
@@ -42,7 +41,6 @@ export interface LayoutSidebarProps {
|
|
|
42
41
|
|
|
43
42
|
export const LayoutSidebar: FC<LayoutSidebarProps> = ({
|
|
44
43
|
className,
|
|
45
|
-
flex,
|
|
46
44
|
mobile,
|
|
47
45
|
barExpanded,
|
|
48
46
|
submenuExpanded,
|
|
@@ -65,7 +63,6 @@ export const LayoutSidebar: FC<LayoutSidebarProps> = ({
|
|
|
65
63
|
mobile && Styles.navDrawer,
|
|
66
64
|
mobile && barExpanded && Styles.navDrawerOpened,
|
|
67
65
|
!mobile && (barExpanded ? Styles.navWide : Styles.navSlim),
|
|
68
|
-
!mobile && (flex ? Styles.navFlex : Styles.navFixed),
|
|
69
66
|
className
|
|
70
67
|
)}
|
|
71
68
|
data-cy="side-navigation"
|
|
@@ -82,7 +79,7 @@ export const LayoutSidebar: FC<LayoutSidebarProps> = ({
|
|
|
82
79
|
</div>
|
|
83
80
|
</div>
|
|
84
81
|
)}
|
|
85
|
-
{top?.length && <SidebarTop>{top}</SidebarTop>}
|
|
82
|
+
{!!top?.length && <SidebarTop>{top}</SidebarTop>}
|
|
86
83
|
|
|
87
84
|
<div data-cy="navigation-items">
|
|
88
85
|
{mainItems?.map(item =>
|
|
@@ -8,30 +8,53 @@
|
|
|
8
8
|
@bg-color-hover: rgba(255, 255, 255, 0.08);
|
|
9
9
|
@bg-color-active: rgba(120, 187, 250, 0.2);
|
|
10
10
|
|
|
11
|
-
.layout-legacy {
|
|
12
|
-
padding-left: var(--nav-offset-left);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
11
|
.layout-anvil1 {
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
height: calc(100vh - var(--nav-offset-top));
|
|
13
|
+
margin-top: var(--nav-offset-top);
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: row;
|
|
17
|
+
|
|
18
|
+
.side {
|
|
19
|
+
flex-basis: var(--nav-offset-left);
|
|
20
|
+
flex-grow: 0;
|
|
21
|
+
flex-shrink: 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.content {
|
|
25
|
+
flex-grow: 1;
|
|
26
|
+
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
}
|
|
21
31
|
}
|
|
22
32
|
|
|
23
|
-
.layout-legacy,
|
|
24
33
|
.layout-anvil2 {
|
|
25
|
-
.
|
|
26
|
-
|
|
34
|
+
.header {
|
|
35
|
+
position: sticky;
|
|
36
|
+
top: var(--nav-offset-top);
|
|
37
|
+
z-index: 989;
|
|
27
38
|
}
|
|
39
|
+
}
|
|
28
40
|
|
|
29
|
-
|
|
41
|
+
.layout-desktop {
|
|
42
|
+
padding-left: var(--nav-offset-left);
|
|
43
|
+
|
|
44
|
+
.side {
|
|
30
45
|
position: fixed;
|
|
31
|
-
top:
|
|
46
|
+
top: var(--nav-offset-top);
|
|
47
|
+
bottom: 0;
|
|
32
48
|
left: 0;
|
|
33
49
|
right: 0;
|
|
34
|
-
z-index:
|
|
50
|
+
z-index: @z-index-global-nav;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.layout-legacy,
|
|
55
|
+
.layout-anvil2 {
|
|
56
|
+
.top-placeholder {
|
|
57
|
+
height: var(--nav-offset-top);
|
|
35
58
|
}
|
|
36
59
|
}
|
|
37
60
|
|
|
@@ -43,11 +66,19 @@
|
|
|
43
66
|
--nav-offset-left: 0;
|
|
44
67
|
}
|
|
45
68
|
|
|
46
|
-
&.layout-nav-slim {
|
|
69
|
+
&.layout-desktop.layout-nav-slim {
|
|
47
70
|
--nav-offset-left: 64px;
|
|
48
71
|
}
|
|
49
72
|
|
|
50
|
-
&.layout-nav-wide {
|
|
73
|
+
&.layout-desktop.layout-nav-wide {
|
|
51
74
|
--nav-offset-left: 212px;
|
|
52
75
|
}
|
|
76
|
+
|
|
77
|
+
.top {
|
|
78
|
+
position: fixed;
|
|
79
|
+
top: 0;
|
|
80
|
+
left: 0;
|
|
81
|
+
right: 0;
|
|
82
|
+
z-index: 991;
|
|
83
|
+
}
|
|
53
84
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
export const __esModule: true;
|
|
2
|
+
export const content: string;
|
|
3
|
+
export const header: string;
|
|
2
4
|
export const layout: string;
|
|
3
5
|
export const layoutAnvil1: string;
|
|
4
6
|
export const layoutAnvil2: string;
|
|
7
|
+
export const layoutDesktop: string;
|
|
5
8
|
export const layoutLegacy: string;
|
|
6
9
|
export const layoutMobile: string;
|
|
7
10
|
export const layoutNavSlim: string;
|
|
8
11
|
export const layoutNavWide: string;
|
|
12
|
+
export const side: string;
|
|
9
13
|
export const top: string;
|
|
10
14
|
export const topPlaceholder: string;
|
|
11
15
|
|
|
@@ -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,12 @@ 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
|
-
sidebarTop?: ReactElement[];
|
|
58
60
|
};
|
|
59
61
|
|
|
60
62
|
const defaultSidebarContext: TitanLayoutSidebarContextType = {
|
|
@@ -76,7 +78,7 @@ const useVariant = (appearance: TitanLayoutProps['appearance']) =>
|
|
|
76
78
|
isLegacy,
|
|
77
79
|
isAnvil1,
|
|
78
80
|
isAnvil2,
|
|
79
|
-
isSequent: isLegacy ||
|
|
81
|
+
isSequent: isLegacy || isAnvil2,
|
|
80
82
|
};
|
|
81
83
|
}, [appearance]);
|
|
82
84
|
|
|
@@ -115,6 +117,7 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
115
117
|
children,
|
|
116
118
|
navigationComponent,
|
|
117
119
|
header,
|
|
120
|
+
top,
|
|
118
121
|
profile,
|
|
119
122
|
state,
|
|
120
123
|
onStateChange,
|
|
@@ -122,7 +125,7 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
122
125
|
extraLinks,
|
|
123
126
|
extraLinksTop,
|
|
124
127
|
extraText,
|
|
125
|
-
|
|
128
|
+
sideTop,
|
|
126
129
|
}) => {
|
|
127
130
|
const breakpoint = useTitanBreakpoint();
|
|
128
131
|
const isMobile = breakpoint.isMobile;
|
|
@@ -179,8 +182,6 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
179
182
|
[state, onStateChange]
|
|
180
183
|
);
|
|
181
184
|
|
|
182
|
-
const [layoutStyles] = useState<object>({});
|
|
183
|
-
|
|
184
185
|
const layoutClass = variant.isLegacy
|
|
185
186
|
? Styles.layoutLegacy
|
|
186
187
|
: variant.isAnvil1
|
|
@@ -194,21 +195,19 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
194
195
|
id={id}
|
|
195
196
|
className={classNames(
|
|
196
197
|
Styles.layout,
|
|
197
|
-
isMobile
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
: Styles.layoutNavWide,
|
|
198
|
+
isMobile ? Styles.layoutMobile : Styles.layoutDesktop,
|
|
199
|
+
!isMobile && state?.navCollapsed
|
|
200
|
+
? Styles.layoutNavSlim
|
|
201
|
+
: Styles.layoutNavWide,
|
|
202
202
|
layoutClass
|
|
203
203
|
)}
|
|
204
|
-
style={layoutStyles}
|
|
205
204
|
>
|
|
206
205
|
{variant.isSequent && <div className={Styles.topPlaceholder} />}
|
|
207
206
|
<LayoutHeader
|
|
208
207
|
className={Styles.top}
|
|
209
208
|
logo={logo}
|
|
210
209
|
profile={isMobile ? undefined : profile}
|
|
211
|
-
center={
|
|
210
|
+
center={top}
|
|
212
211
|
rightText={isMobile ? undefined : extraText}
|
|
213
212
|
right={
|
|
214
213
|
<Fragment>
|
|
@@ -220,13 +219,13 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
220
219
|
/>
|
|
221
220
|
|
|
222
221
|
<LayoutSidebar
|
|
223
|
-
|
|
222
|
+
className={Styles.side}
|
|
224
223
|
mobile={breakpoint.isMobile}
|
|
225
224
|
barExpanded={isMobile ? mobileDrawerOpened : !state?.navCollapsed}
|
|
226
225
|
submenuExpanded={state?.submenuExpanded}
|
|
227
226
|
onBarExpandChange={onBarExpandChange}
|
|
228
227
|
onSubmenuExpandChange={onSubmenuExpandChange}
|
|
229
|
-
top={
|
|
228
|
+
top={sideTop}
|
|
230
229
|
mainItems={navigationMainItems}
|
|
231
230
|
navigationComponent={context.NavigationComponent}
|
|
232
231
|
bottom={
|
|
@@ -250,21 +249,94 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
250
249
|
}
|
|
251
250
|
/>
|
|
252
251
|
|
|
253
|
-
|
|
252
|
+
<LayoutContent
|
|
253
|
+
header={header}
|
|
254
|
+
anvil2={variant.isAnvil2}
|
|
255
|
+
anvil1={variant.isAnvil1}
|
|
256
|
+
>
|
|
257
|
+
{content}
|
|
258
|
+
</LayoutContent>
|
|
254
259
|
</div>
|
|
255
260
|
</LayoutPlacementContext.Provider>
|
|
256
261
|
</LayoutContext.Provider>
|
|
257
262
|
);
|
|
258
263
|
};
|
|
259
264
|
|
|
265
|
+
const TitanLayoutHeaderObserved: FC<{
|
|
266
|
+
children: ReactNode;
|
|
267
|
+
heightChange?(value: number): void;
|
|
268
|
+
}> = ({ children, heightChange }) => {
|
|
269
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
270
|
+
|
|
271
|
+
useEffect(() => {
|
|
272
|
+
if (ref.current) {
|
|
273
|
+
const updatePosition = () => {
|
|
274
|
+
if (ref.current && heightChange) {
|
|
275
|
+
const pos = ref.current.getBoundingClientRect();
|
|
276
|
+
heightChange(pos.height);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const observer = new ResizeObserver(updatePosition);
|
|
281
|
+
observer.observe(ref.current);
|
|
282
|
+
|
|
283
|
+
updatePosition();
|
|
284
|
+
return () => observer.disconnect();
|
|
285
|
+
}
|
|
286
|
+
}, [heightChange]);
|
|
287
|
+
|
|
288
|
+
useEffect(() => {
|
|
289
|
+
return () => {
|
|
290
|
+
heightChange?.(0);
|
|
291
|
+
};
|
|
292
|
+
}, [heightChange]);
|
|
293
|
+
return (
|
|
294
|
+
<div ref={ref} className={Styles.header}>
|
|
295
|
+
{children}
|
|
296
|
+
</div>
|
|
297
|
+
);
|
|
298
|
+
};
|
|
299
|
+
|
|
260
300
|
export interface TitanLayoutContentProps {
|
|
261
301
|
children: ReactNode;
|
|
262
302
|
}
|
|
263
303
|
const TitanLayoutContent: FC<TitanLayoutContentProps> = ({ children }) => children;
|
|
264
304
|
|
|
305
|
+
const LayoutContent: FC<{
|
|
306
|
+
children: ReactNode;
|
|
307
|
+
header?: ReactNode;
|
|
308
|
+
anvil1: boolean;
|
|
309
|
+
anvil2: boolean;
|
|
310
|
+
}> = ({ anvil1, anvil2, children, header }) => {
|
|
311
|
+
const [anvil2Styles, setAnvil2Styles] = useState<object>({});
|
|
312
|
+
const updateIndicatorsHeight = useCallback((offset: number) => {
|
|
313
|
+
setAnvil2Styles({ '--offset': `calc(var(--nav-offset-top) + ${offset}px)` });
|
|
314
|
+
}, []);
|
|
315
|
+
|
|
316
|
+
return (
|
|
317
|
+
<div className={Styles.content} style={anvil2Styles}>
|
|
318
|
+
{!!header &&
|
|
319
|
+
(anvil2 ? (
|
|
320
|
+
<TitanLayoutHeaderObserved heightChange={updateIndicatorsHeight}>
|
|
321
|
+
{header}
|
|
322
|
+
</TitanLayoutHeaderObserved>
|
|
323
|
+
) : (
|
|
324
|
+
header
|
|
325
|
+
))}
|
|
326
|
+
{anvil1 ? (
|
|
327
|
+
<div className="position-relative d-f flex-grow-1 flex-basis-0 of-hidden">
|
|
328
|
+
{children}
|
|
329
|
+
</div>
|
|
330
|
+
) : (
|
|
331
|
+
children
|
|
332
|
+
)}
|
|
333
|
+
</div>
|
|
334
|
+
);
|
|
335
|
+
};
|
|
336
|
+
|
|
265
337
|
export const TitanLayout = Object.assign(TitanLayoutComponent, {
|
|
266
338
|
Content: TitanLayoutContent,
|
|
267
339
|
Logo: TitanLayoutLogo,
|
|
268
|
-
|
|
269
|
-
|
|
340
|
+
Link: TitanLayoutSidebarLink,
|
|
341
|
+
Trigger: TitanLayoutSidebarTrigger,
|
|
270
342
|
});
|