@servicetitan/navigation 10.6.1 → 11.0.0-canary.237.0ce6038.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.
Files changed (164) hide show
  1. package/dist/components/header-navigation/header-navigation-extra.stories.d.ts.map +1 -1
  2. package/dist/components/header-navigation/header-navigation-extra.stories.js +5 -5
  3. package/dist/components/header-navigation/header-navigation-extra.stories.js.map +1 -1
  4. package/dist/components/header-navigation/header-navigation-links.d.ts.map +1 -1
  5. package/dist/components/header-navigation/header-navigation-links.js +2 -2
  6. package/dist/components/header-navigation/header-navigation-links.js.map +1 -1
  7. package/dist/components/header-navigation/header-navigation-stacked.stories.d.ts.map +1 -1
  8. package/dist/components/header-navigation/header-navigation-stacked.stories.js +1 -1
  9. package/dist/components/header-navigation/header-navigation-stacked.stories.js.map +1 -1
  10. package/dist/components/header-navigation/header-navigation.stories.d.ts.map +1 -1
  11. package/dist/components/header-navigation/header-navigation.stories.js +2 -2
  12. package/dist/components/header-navigation/header-navigation.stories.js.map +1 -1
  13. package/dist/components/header-navigation/with-tooltip.d.ts +1 -1
  14. package/dist/components/header-navigation/with-tooltip.d.ts.map +1 -1
  15. package/dist/components/left-navigation/header-navigation-tiny.stories.d.ts.map +1 -1
  16. package/dist/components/left-navigation/header-navigation-tiny.stories.js +2 -2
  17. package/dist/components/left-navigation/header-navigation-tiny.stories.js.map +1 -1
  18. package/dist/components/left-navigation/interface.d.ts +1 -1
  19. package/dist/components/left-navigation/interface.d.ts.map +1 -1
  20. package/dist/components/left-navigation/side-navigation-links-internal.d.ts +3 -1
  21. package/dist/components/left-navigation/side-navigation-links-internal.d.ts.map +1 -1
  22. package/dist/components/left-navigation/side-navigation-links-internal.js +3 -3
  23. package/dist/components/left-navigation/side-navigation-links-internal.js.map +1 -1
  24. package/dist/components/left-navigation/side-navigation.d.ts.map +1 -1
  25. package/dist/components/left-navigation/side-navigation.js +8 -7
  26. package/dist/components/left-navigation/side-navigation.js.map +1 -1
  27. package/dist/components/left-navigation/side-navigation.module.less +21 -19
  28. package/dist/components/links.d.ts.map +1 -1
  29. package/dist/components/links.js +7 -7
  30. package/dist/components/links.js.map +1 -1
  31. package/dist/components/logo/logo-company-title.d.ts +1 -0
  32. package/dist/components/logo/logo-company-title.d.ts.map +1 -1
  33. package/dist/components/logo/logo-company-title.js +2 -2
  34. package/dist/components/logo/logo-company-title.js.map +1 -1
  35. package/dist/components/profile-dropdown/profile-dropdown.d.ts +6 -3
  36. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
  37. package/dist/components/profile-dropdown/profile-dropdown.js +7 -8
  38. package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
  39. package/dist/components/profile-dropdown/profile-dropdown.module.less +4 -0
  40. package/dist/components/profile-dropdown/profile-dropdown.stories.js +2 -2
  41. package/dist/components/profile-dropdown/profile-dropdown.stories.js.map +1 -1
  42. package/dist/components/titan-layout/index.d.ts +6 -0
  43. package/dist/components/titan-layout/index.d.ts.map +1 -0
  44. package/dist/components/titan-layout/index.js +6 -0
  45. package/dist/components/titan-layout/index.js.map +1 -0
  46. package/dist/components/titan-layout/interface-internal.d.ts +6 -0
  47. package/dist/components/titan-layout/interface-internal.d.ts.map +1 -0
  48. package/dist/components/titan-layout/interface-internal.js +2 -0
  49. package/dist/components/titan-layout/interface-internal.js.map +1 -0
  50. package/dist/components/titan-layout/interface.d.ts +21 -0
  51. package/dist/components/titan-layout/interface.d.ts.map +1 -0
  52. package/dist/components/titan-layout/interface.js +2 -0
  53. package/dist/components/titan-layout/interface.js.map +1 -0
  54. package/dist/components/titan-layout/layout-context.d.ts +20 -0
  55. package/dist/components/titan-layout/layout-context.d.ts.map +1 -0
  56. package/dist/components/titan-layout/layout-context.js +12 -0
  57. package/dist/components/titan-layout/layout-context.js.map +1 -0
  58. package/dist/components/titan-layout/layout-header-links.d.ts +7 -0
  59. package/dist/components/titan-layout/layout-header-links.d.ts.map +1 -0
  60. package/dist/components/titan-layout/layout-header-links.js +32 -0
  61. package/dist/components/titan-layout/layout-header-links.js.map +1 -0
  62. package/dist/components/titan-layout/layout-header.d.ts +20 -0
  63. package/dist/components/titan-layout/layout-header.d.ts.map +1 -0
  64. package/dist/components/titan-layout/layout-header.js +11 -0
  65. package/dist/components/titan-layout/layout-header.js.map +1 -0
  66. package/dist/components/titan-layout/layout-header.module.less +154 -0
  67. package/dist/components/titan-layout/layout-logo.d.ts +12 -0
  68. package/dist/components/titan-layout/layout-logo.d.ts.map +1 -0
  69. package/dist/components/titan-layout/layout-logo.js +15 -0
  70. package/dist/components/titan-layout/layout-logo.js.map +1 -0
  71. package/dist/components/titan-layout/layout-logo.stories.d.ts +13 -0
  72. package/dist/components/titan-layout/layout-logo.stories.d.ts.map +1 -0
  73. package/dist/components/titan-layout/layout-logo.stories.js +17 -0
  74. package/dist/components/titan-layout/layout-logo.stories.js.map +1 -0
  75. package/dist/components/titan-layout/layout-profile.d.ts +9 -0
  76. package/dist/components/titan-layout/layout-profile.d.ts.map +1 -0
  77. package/dist/components/titan-layout/layout-profile.js +44 -0
  78. package/dist/components/titan-layout/layout-profile.js.map +1 -0
  79. package/dist/components/titan-layout/layout-profile.stories.d.ts +13 -0
  80. package/dist/components/titan-layout/layout-profile.stories.d.ts.map +1 -0
  81. package/dist/components/titan-layout/layout-profile.stories.js +13 -0
  82. package/dist/components/titan-layout/layout-profile.stories.js.map +1 -0
  83. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +46 -0
  84. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -0
  85. package/dist/components/titan-layout/layout-sidebar-links-internal.js +61 -0
  86. package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -0
  87. package/dist/components/titan-layout/layout-sidebar-links.d.ts +6 -0
  88. package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -0
  89. package/dist/components/titan-layout/layout-sidebar-links.js +21 -0
  90. package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -0
  91. package/dist/components/titan-layout/layout-sidebar.d.ts +17 -0
  92. package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -0
  93. package/dist/components/titan-layout/layout-sidebar.js +65 -0
  94. package/dist/components/titan-layout/layout-sidebar.js.map +1 -0
  95. package/dist/components/titan-layout/layout-sidebar.module.less +513 -0
  96. package/dist/components/titan-layout/titan-layout.d.ts +36 -0
  97. package/dist/components/titan-layout/titan-layout.d.ts.map +1 -0
  98. package/dist/components/titan-layout/titan-layout.js +109 -0
  99. package/dist/components/titan-layout/titan-layout.js.map +1 -0
  100. package/dist/components/titan-layout/titan-layout.module.less +76 -0
  101. package/dist/components/titan-layout/titan-layout.stories.d.ts +18 -0
  102. package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -0
  103. package/dist/components/titan-layout/titan-layout.stories.js +62 -0
  104. package/dist/components/titan-layout/titan-layout.stories.js.map +1 -0
  105. package/dist/components/titan-layout/with-tooltip.d.ts +4 -0
  106. package/dist/components/titan-layout/with-tooltip.d.ts.map +1 -0
  107. package/dist/components/titan-layout/with-tooltip.js +4 -0
  108. package/dist/components/titan-layout/with-tooltip.js.map +1 -0
  109. package/dist/index.d.ts +2 -1
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +2 -1
  112. package/dist/index.js.map +1 -1
  113. package/dist/test/data.d.ts.map +1 -1
  114. package/dist/test/data.js +3 -3
  115. package/dist/test/data.js.map +1 -1
  116. package/dist/utils/navigation-legacy.d.ts +3 -1
  117. package/dist/utils/navigation-legacy.d.ts.map +1 -1
  118. package/dist/utils/use-breakpoint.d.ts +7 -0
  119. package/dist/utils/use-breakpoint.d.ts.map +1 -0
  120. package/dist/utils/use-breakpoint.js +13 -0
  121. package/dist/utils/use-breakpoint.js.map +1 -0
  122. package/package.json +5 -6
  123. package/src/components/header-navigation/header-navigation-extra.stories.tsx +7 -0
  124. package/src/components/header-navigation/header-navigation-links.tsx +2 -0
  125. package/src/components/header-navigation/header-navigation-stacked.stories.tsx +4 -0
  126. package/src/components/header-navigation/header-navigation.stories.tsx +5 -0
  127. package/src/components/left-navigation/header-navigation-tiny.stories.tsx +6 -0
  128. package/src/components/left-navigation/interface.ts +2 -2
  129. package/src/components/left-navigation/side-navigation-links-internal.tsx +21 -6
  130. package/src/components/left-navigation/side-navigation-links.tsx +1 -1
  131. package/src/components/left-navigation/side-navigation.module.less +21 -19
  132. package/src/components/left-navigation/side-navigation.module.less.d.ts +2 -1
  133. package/src/components/left-navigation/side-navigation.tsx +15 -8
  134. package/src/components/links.tsx +33 -13
  135. package/src/components/logo/logo-company-title.tsx +8 -6
  136. package/src/components/profile-dropdown/profile-dropdown.module.less +4 -0
  137. package/src/components/profile-dropdown/profile-dropdown.stories.tsx +4 -4
  138. package/src/components/profile-dropdown/profile-dropdown.tsx +43 -46
  139. package/src/components/titan-layout/index.ts +5 -0
  140. package/src/components/titan-layout/interface-internal.ts +6 -0
  141. package/src/components/titan-layout/interface.ts +26 -0
  142. package/src/components/titan-layout/layout-context.tsx +30 -0
  143. package/src/components/titan-layout/layout-header-links.tsx +144 -0
  144. package/src/components/titan-layout/layout-header.module.less +154 -0
  145. package/src/components/titan-layout/layout-header.module.less.d.ts +16 -0
  146. package/src/components/titan-layout/layout-header.tsx +86 -0
  147. package/src/components/titan-layout/layout-logo.stories.tsx +31 -0
  148. package/src/components/titan-layout/layout-logo.tsx +57 -0
  149. package/src/components/titan-layout/layout-profile.stories.tsx +37 -0
  150. package/src/components/titan-layout/layout-profile.tsx +116 -0
  151. package/src/components/titan-layout/layout-sidebar-links-internal.tsx +265 -0
  152. package/src/components/titan-layout/layout-sidebar-links.tsx +56 -0
  153. package/src/components/titan-layout/layout-sidebar.module.less +513 -0
  154. package/src/components/titan-layout/layout-sidebar.module.less.d.ts +48 -0
  155. package/src/components/titan-layout/layout-sidebar.tsx +295 -0
  156. package/src/components/titan-layout/titan-layout.module.less +76 -0
  157. package/src/components/titan-layout/titan-layout.module.less.d.ts +13 -0
  158. package/src/components/titan-layout/titan-layout.stories.tsx +194 -0
  159. package/src/components/titan-layout/titan-layout.tsx +272 -0
  160. package/src/components/titan-layout/with-tooltip.tsx +16 -0
  161. package/src/index.ts +2 -1
  162. package/src/test/data.tsx +3 -2
  163. package/src/utils/navigation-legacy.ts +3 -1
  164. package/src/utils/use-breakpoint.ts +19 -0
@@ -0,0 +1,295 @@
1
+ import { Icon, Popover, Text, ThemeProvider } from '@servicetitan/anvil2';
2
+ import SvgClose from '@servicetitan/anvil2/assets/icons/material/round/close.svg';
3
+ import SvgCollapse from '@servicetitan/anvil2/assets/icons/st/gnav_menu_collapse.svg';
4
+ import SvgExpand from '@servicetitan/anvil2/assets/icons/st/gnav_menu_expand.svg';
5
+ import classNames from 'classnames';
6
+ import {
7
+ Children,
8
+ FC,
9
+ Fragment,
10
+ MouseEvent,
11
+ ReactElement,
12
+ isValidElement,
13
+ useCallback,
14
+ } from 'react';
15
+ import { NavigationItemData, NavigationSubmenuData } from '../../utils/navigation';
16
+ import { NavLinkComponentProps } from '../../utils/navigation-context';
17
+ import { getCounterTag, getSubmenuGroupTag } from '../../utils/side-nav';
18
+ import { NavigationComponentProps } from './interface-internal';
19
+ import { LayoutPlacementContext, useTitanLayoutContext } from './layout-context';
20
+ import {
21
+ InternalSideNavigationGroup,
22
+ InternalSideNavigationGroupLink,
23
+ InternalSideNavigationLink,
24
+ } from './layout-sidebar-links-internal';
25
+ import * as Styles from './layout-sidebar.module.less';
26
+
27
+ import { withTooltip } from './with-tooltip';
28
+
29
+ export interface LayoutSidebarProps {
30
+ className?: string;
31
+ top?: ReactElement[];
32
+ bottom?: ReactElement;
33
+ mainItems?: NavigationItemData[];
34
+ barExpanded: boolean;
35
+ submenuExpanded: string | undefined;
36
+ mobile: boolean;
37
+ navigationComponent: FC<NavLinkComponentProps>;
38
+ onBarExpandChange(expanded: boolean): void;
39
+ onSubmenuExpandChange(id: string, expanded: boolean): void;
40
+ }
41
+
42
+ export const LayoutSidebar: FC<LayoutSidebarProps> = ({
43
+ className,
44
+ mobile,
45
+ barExpanded,
46
+ submenuExpanded,
47
+ onBarExpandChange,
48
+ onSubmenuExpandChange,
49
+ mainItems,
50
+ top,
51
+ bottom,
52
+ navigationComponent,
53
+ }) => {
54
+ const handleClick = (e: MouseEvent<never>) => {
55
+ e.stopPropagation();
56
+ };
57
+
58
+ return (
59
+ <LayoutPlacementContext.Provider value="side">
60
+ <div
61
+ className={classNames(
62
+ Styles.nav,
63
+ mobile && Styles.navDrawer,
64
+ mobile && barExpanded && Styles.navDrawerOpened,
65
+ !mobile && (barExpanded ? Styles.navWide : Styles.navSlim),
66
+ className
67
+ )}
68
+ data-cy="side-navigation"
69
+ onClick={handleClick}
70
+ >
71
+ <ThemeProvider mode="dark" className={Styles.navMain}>
72
+ {mobile && (
73
+ <div className={Styles.navCloseWrapper}>
74
+ <div
75
+ className={Styles.navClose}
76
+ onClick={() => onBarExpandChange(false)}
77
+ >
78
+ <Icon svg={SvgClose} size="large" />
79
+ </div>
80
+ </div>
81
+ )}
82
+ {!!top?.length && <SidebarTop>{top}</SidebarTop>}
83
+
84
+ <div data-cy="navigation-items">
85
+ {mainItems?.map(item =>
86
+ item.submenu ? (
87
+ <SideNavigationGroupItem
88
+ key={item.id}
89
+ barExpanded={barExpanded}
90
+ submenuExpanded={!!item.id && submenuExpanded === item.id}
91
+ onSubmenuExpand={onSubmenuExpandChange}
92
+ navigationComponent={navigationComponent}
93
+ {...item}
94
+ />
95
+ ) : (
96
+ <InternalSideNavigationLink
97
+ key={item.id}
98
+ submenuExpanded={undefined}
99
+ navigationComponent={navigationComponent}
100
+ {...item}
101
+ tag={getSubmenuGroupTag(
102
+ item.submenu,
103
+ getCounterTag(item.counter, item.tag)
104
+ )}
105
+ />
106
+ )
107
+ )}
108
+ </div>
109
+
110
+ {!!bottom && <SidebarBottom>{bottom}</SidebarBottom>}
111
+ </ThemeProvider>
112
+
113
+ {!mobile && (
114
+ <div className={Styles.navFooter}>
115
+ <div className={Styles.divider} />
116
+ <div className={Styles.toggleWrapper}>
117
+ <SideNavigationOptionsToggle
118
+ appearance={barExpanded ? 'collapse-button' : 'expand'}
119
+ onExpandedChange={() => onBarExpandChange(!barExpanded)}
120
+ />
121
+ </div>
122
+ </div>
123
+ )}
124
+ </div>
125
+ </LayoutPlacementContext.Provider>
126
+ );
127
+ };
128
+ LayoutSidebar.displayName = 'LayoutSidebar';
129
+
130
+ /** Side Navigation options toggle */
131
+ const SideNavigationOptionsToggle: FC<{
132
+ appearance: 'expand' | 'collapse' | 'collapse-button';
133
+ onExpandedChange?(expanded: boolean): void;
134
+ }> = ({ appearance, onExpandedChange }) =>
135
+ withTooltip(
136
+ <div
137
+ data-cy="navigation-left-options"
138
+ data-pendo="navigation-left-options"
139
+ className={classNames(Styles.toggle)}
140
+ onClick={() => onExpandedChange?.(appearance === 'expand')}
141
+ >
142
+ <div className={Styles.toggleContent}>
143
+ <div className={Styles.toggleIconWrapper}>
144
+ <Icon
145
+ className={Styles.toggleIcon}
146
+ svg={appearance === 'expand' ? SvgExpand : SvgCollapse}
147
+ />
148
+ </div>
149
+
150
+ {appearance === 'collapse-button' && (
151
+ <span className={Styles.toggleText}>Collapse Menu</span>
152
+ )}
153
+ </div>
154
+ </div>,
155
+ appearance === 'expand'
156
+ ? 'Expand Menu'
157
+ : appearance === 'collapse'
158
+ ? 'Collapse Menu'
159
+ : undefined,
160
+ 'right'
161
+ );
162
+
163
+ /** Side Navigation menu item */
164
+ const SideNavigationGroupItem: FC<
165
+ NavigationItemData & {
166
+ navigationComponent: FC<NavLinkComponentProps>;
167
+ barExpanded: boolean;
168
+ submenuExpanded: boolean;
169
+ onSubmenuExpand: undefined | ((id: string, expanded: boolean) => void);
170
+ }
171
+ > = ({ onSubmenuExpand, barExpanded, submenuExpanded, ...props }) => {
172
+ const onExpandToggle = useCallback(
173
+ (e: MouseEvent<never>) => {
174
+ e.preventDefault();
175
+ e.stopPropagation();
176
+
177
+ if (props.id) {
178
+ onSubmenuExpand?.(props.id, !submenuExpanded);
179
+ }
180
+ },
181
+ [props.id, submenuExpanded, onSubmenuExpand]
182
+ );
183
+ const {
184
+ sidebar: {
185
+ styles: { popoverContent },
186
+ },
187
+ } = useTitanLayoutContext();
188
+
189
+ const tag = getSubmenuGroupTag(props.submenu, getCounterTag(props.counter, props.tag));
190
+
191
+ return barExpanded ? (
192
+ <InternalSideNavigationGroup
193
+ {...props}
194
+ submenuExpanded={submenuExpanded}
195
+ onExpandToggle={onExpandToggle}
196
+ tag={tag}
197
+ >
198
+ <SideNavigationGroupContent
199
+ groups={props.submenu?.groups ?? []}
200
+ navigationComponent={props.navigationComponent}
201
+ />
202
+ </InternalSideNavigationGroup>
203
+ ) : (
204
+ <Popover placement="right-start" openOnHover delay={500}>
205
+ <Popover.Trigger>
206
+ {(triggerProps: any) => (
207
+ <div {...triggerProps}>
208
+ <InternalSideNavigationLink
209
+ {...props}
210
+ submenuExpanded={undefined}
211
+ tag={tag}
212
+ />
213
+ </div>
214
+ )}
215
+ </Popover.Trigger>
216
+ <Popover.Content style={popoverContent} className="z-global-nav-i">
217
+ <div className={Styles.submenuPopover}>
218
+ <Text
219
+ variant="headline"
220
+ el="h4"
221
+ size="small"
222
+ className="c-white m-b-half-i m-t-1"
223
+ >
224
+ {props.title}
225
+ </Text>
226
+ <SideNavigationGroupContent
227
+ groups={props.submenu?.groups ?? []}
228
+ navigationComponent={props.navigationComponent}
229
+ />
230
+ </div>
231
+ </Popover.Content>
232
+ </Popover>
233
+ );
234
+ };
235
+ const SideNavigationGroupContent: FC<NavigationSubmenuData & NavigationComponentProps> = ({
236
+ groups,
237
+ navigationComponent,
238
+ }) => {
239
+ return (
240
+ <Fragment>
241
+ {groups.reduce((out, group, index) => {
242
+ if (!group.links.length) {
243
+ return out;
244
+ }
245
+
246
+ const title = group.title?.trim() ?? '';
247
+ /* eslint-disable react/no-array-index-key */
248
+ out.push(
249
+ <Text
250
+ key={`:group:${index}:title`}
251
+ variant="eyebrow"
252
+ className={classNames(Styles.submenuGroupHeader, {
253
+ [Styles.submenuGroupHeaderEmpty]: !title,
254
+ })}
255
+ >
256
+ {title}
257
+ </Text>
258
+ );
259
+ out.push(
260
+ ...group.links.map((link, index) => (
261
+ <InternalSideNavigationGroupLink
262
+ key={`:${link.id}:${index}`}
263
+ {...link}
264
+ navigationComponent={navigationComponent}
265
+ />
266
+ ))
267
+ );
268
+ /* eslint-enable react/no-array-index-key */
269
+
270
+ return out;
271
+ }, [] as ReactElement[])}
272
+ </Fragment>
273
+ );
274
+ };
275
+
276
+ function SidebarTop({ children }: any) {
277
+ const list = Children.map(children, child => {
278
+ return child && isValidElement(child) ? child : null;
279
+ });
280
+ return list?.length ? (
281
+ <ThemeProvider mode="dark" className={Styles.navTop} data-cy="navigation-items-top">
282
+ {list}
283
+ <div className={Styles.divider} />
284
+ </ThemeProvider>
285
+ ) : null;
286
+ }
287
+
288
+ function SidebarBottom({ children }: any) {
289
+ return (
290
+ <ThemeProvider mode="dark" className={Styles.navBottom} data-cy="navigation-items-bottom">
291
+ <div className={Styles.divider} />
292
+ {children}
293
+ </ThemeProvider>
294
+ );
295
+ }
@@ -0,0 +1,76 @@
1
+ /* stylelint-disable no-descending-specificity */
2
+ @import (reference) '@servicetitan/tokens/core/tokens.less';
3
+
4
+ @text-color: var(--colorsTextInverted, @color-white);
5
+ @text-color-active: var(--colorsTextPrimarySubdued, @color-blue-300);
6
+ @border-color: var(--colorsTextOnGrey, @color-neutral-200);
7
+ @bg-color: #0f1d26;
8
+ @bg-color-hover: rgba(255, 255, 255, 0.08);
9
+ @bg-color-active: rgba(120, 187, 250, 0.2);
10
+
11
+ .layout-anvil1 {
12
+ height: calc(100vh - var(--nav-offset-top));
13
+ margin-top: var(--nav-offset-top);
14
+
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
+ }
31
+ }
32
+
33
+ .layout-legacy,
34
+ .layout-anvil2 {
35
+ padding-left: var(--nav-offset-left);
36
+
37
+ .top-placeholder {
38
+ height: var(--nav-offset-top);
39
+ }
40
+
41
+ &:not(.layout-mobile) {
42
+ .side {
43
+ position: fixed;
44
+ top: var(--nav-offset-top);
45
+ bottom: 0;
46
+ left: 0;
47
+ right: 0;
48
+ z-index: @z-index-global-nav;
49
+ }
50
+ }
51
+ }
52
+
53
+ .layout {
54
+ --nav-offset-top: 49px;
55
+
56
+ &.layout-mobile {
57
+ --nav-offset-top: 61px;
58
+ --nav-offset-left: 0;
59
+ }
60
+
61
+ &.layout-nav-slim {
62
+ --nav-offset-left: 64px;
63
+ }
64
+
65
+ &.layout-nav-wide {
66
+ --nav-offset-left: 212px;
67
+ }
68
+
69
+ .top {
70
+ position: fixed;
71
+ top: 0;
72
+ left: 0;
73
+ right: 0;
74
+ z-index: 991;
75
+ }
76
+ }
@@ -0,0 +1,13 @@
1
+ export const __esModule: true;
2
+ export const content: string;
3
+ export const layout: string;
4
+ export const layoutAnvil1: string;
5
+ export const layoutAnvil2: string;
6
+ export const layoutLegacy: string;
7
+ export const layoutMobile: string;
8
+ export const layoutNavSlim: string;
9
+ export const layoutNavWide: string;
10
+ export const side: string;
11
+ export const top: string;
12
+ export const topPlaceholder: string;
13
+
@@ -0,0 +1,194 @@
1
+ import { Page as Anvil2Page, Popover } from '@servicetitan/anvil2';
2
+ import SvgSearch from '@servicetitan/anvil2/assets/icons/material/round/search.svg';
3
+ import SvgAtlas from '@servicetitan/anvil2/assets/icons/st/atlas_logo.svg';
4
+ import SvgSettingsActive from '@servicetitan/anvil2/assets/icons/st/gnav_settings_active.svg';
5
+ import SvgSettings from '@servicetitan/anvil2/assets/icons/st/gnav_settings_inactive.svg';
6
+ import SvgRocketActive from '@servicetitan/anvil2/assets/icons/st/gnav_titan_advisor_active.svg';
7
+ import SvgRocket from '@servicetitan/anvil2/assets/icons/st/gnav_titan_advisor_inactive.svg';
8
+ import { Page as Anvil1Page } from '@servicetitan/design-system';
9
+ import { FC, Fragment, useState } from 'react';
10
+ import {
11
+ CallsNavigationTrigger,
12
+ LocationInfo,
13
+ NavLinkMock,
14
+ items,
15
+ withAnvil,
16
+ withDefaultRedirects,
17
+ withMemoryRouter,
18
+ } from '../../test/data';
19
+ import { SideNavigationLinkWrapperProps } from '../left-navigation';
20
+ import { HeaderNavigationLink, HeaderNavigationTrigger } from '../links';
21
+ import { ProfileDropdown, TitanLayout, TitanLayoutProps, TitanLayoutState } from './';
22
+
23
+ export default {
24
+ title: 'Navigation/TitanLayout',
25
+ component: TitanLayout,
26
+ decorators: [withDefaultRedirects, withMemoryRouter, withAnvil],
27
+ parameters: {},
28
+ };
29
+
30
+ const mainNavItems = [
31
+ items.dashboard,
32
+ items.calendar,
33
+ items.calls,
34
+ items.accountingWithSubmenu,
35
+ items.dispatch,
36
+
37
+ items.fleet,
38
+ items.followUps,
39
+ items.inventory,
40
+
41
+ items.marketing,
42
+ items.priceBook,
43
+ items.pointOfSale,
44
+ items.reports,
45
+ ];
46
+
47
+ const profile = (
48
+ <ProfileDropdown>
49
+ <ProfileDropdown.Link
50
+ id="first"
51
+ to="https://google.com"
52
+ tooltip="Google it"
53
+ target="_blank"
54
+ >
55
+ first link
56
+ </ProfileDropdown.Link>
57
+ <ProfileDropdown.Section
58
+ id="second"
59
+ onClick={() => alert('second click')}
60
+ tooltip="Second hint"
61
+ >
62
+ second link
63
+ </ProfileDropdown.Section>
64
+ <ProfileDropdown.Divider />
65
+ <ProfileDropdown.Section id="content">some content</ProfileDropdown.Section>
66
+ <ProfileDropdown.Divider />
67
+ <ProfileDropdown.Divider />
68
+ <ProfileDropdown.Divider />
69
+ <ProfileDropdown.Link id="third" to="/third">
70
+ third link
71
+ </ProfileDropdown.Link>
72
+ <ProfileDropdown.Divider />
73
+ </ProfileDropdown>
74
+ );
75
+
76
+ const extraLinks = (
77
+ <Fragment>
78
+ <HeaderNavigationLink
79
+ id="search"
80
+ to="https://google.com"
81
+ target="_blank"
82
+ title="Search"
83
+ hint="Search: for all the questions"
84
+ tooltip="Search"
85
+ icon={SvgSearch}
86
+ iconActive={SvgSearch}
87
+ />
88
+
89
+ <CallsNavigationTrigger />
90
+
91
+ <HeaderNavigationLink
92
+ id="titanAdvisor"
93
+ to="/titanAdvisor"
94
+ title="Titan Advisor"
95
+ icon={SvgRocket}
96
+ iconActive={SvgRocketActive}
97
+ />
98
+
99
+ <HeaderNavigationLink
100
+ id="settings"
101
+ to="/settings"
102
+ title="Settings"
103
+ target="_blank"
104
+ aria-label="search"
105
+ hint="Settings"
106
+ icon={SvgSettings}
107
+ iconActive={SvgSettingsActive}
108
+ />
109
+ </Fragment>
110
+ );
111
+
112
+ const extraLinksTop = (
113
+ <HeaderNavigationTrigger
114
+ id="atlas"
115
+ title="Atlas"
116
+ icon={SvgAtlas}
117
+ iconActive={SvgAtlas}
118
+ data-pendo="atlas-chat-button"
119
+ data-cy="atlas-chat-button"
120
+ data-atlas-chat-button
121
+ />
122
+ );
123
+
124
+ const SideLinkPopoverWrapper: FC<SideNavigationLinkWrapperProps> = ({ children, context }) => {
125
+ return (
126
+ <Popover placement="right" openOnHover>
127
+ <Popover.Trigger>{(props: any) => <div {...props}>{children}</div>}</Popover.Trigger>
128
+ <Popover.Content style={context.styles.popoverContent}>popover content</Popover.Content>
129
+ </Popover>
130
+ );
131
+ };
132
+
133
+ const sidebarTop = () => [
134
+ <TitanLayout.SidebarLink key="tasks" {...items.tasks} />,
135
+ <TitanLayout.SidebarLink key="calls" {...items.calls} />,
136
+ <TitanLayout.SidebarTrigger
137
+ key="marketing"
138
+ {...items.marketing}
139
+ isActive={false}
140
+ wrapper={SideLinkPopoverWrapper}
141
+ onMobileClick={() => alert('clicked')}
142
+ counter={50}
143
+ />,
144
+ ];
145
+ const useLayoutProps = (): TitanLayoutProps => {
146
+ const [state, setState] = useState<TitanLayoutState | undefined>(undefined);
147
+
148
+ return {
149
+ state,
150
+ onStateChange: setState,
151
+
152
+ navigationMainItems: mainNavItems,
153
+ profile,
154
+ extraLinks,
155
+ extraLinksTop,
156
+
157
+ sidebarTop: sidebarTop(),
158
+ navigationComponent: NavLinkMock,
159
+ extraText: 'EST (-8 hrs)',
160
+ };
161
+ };
162
+
163
+ export const TitanLayoutLegacy = () => (
164
+ <TitanLayout {...useLayoutProps()} appearance="legacy">
165
+ <TitanLayout.Logo title />
166
+ <TitanLayout.Content>
167
+ <LocationInfo />
168
+ </TitanLayout.Content>
169
+ </TitanLayout>
170
+ );
171
+
172
+ export const TitanLayoutAnvil1 = () => (
173
+ <TitanLayout {...useLayoutProps()} appearance="anvil1">
174
+ <TitanLayout.Logo title />
175
+ <TitanLayout.Content>
176
+ <Anvil1Page>
177
+ <LocationInfo />
178
+ </Anvil1Page>
179
+ </TitanLayout.Content>
180
+ </TitanLayout>
181
+ );
182
+
183
+ export const TitanLayoutAnvil2 = () => (
184
+ <TitanLayout {...useLayoutProps()} appearance="anvil2">
185
+ <TitanLayout.Logo title />
186
+ <TitanLayout.Content>
187
+ <Anvil2Page>
188
+ <Anvil2Page.Content>
189
+ <LocationInfo />
190
+ </Anvil2Page.Content>
191
+ </Anvil2Page>
192
+ </TitanLayout.Content>
193
+ </TitanLayout>
194
+ );