@servicetitan/navigation 10.6.1 → 11.0.0-canary.237.4cefc6a.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 (219) hide show
  1. package/package.json +4 -4
  2. package/src/components/header-navigation/header-navigation-extra.stories.tsx +7 -0
  3. package/src/components/header-navigation/header-navigation-links.tsx +2 -0
  4. package/src/components/header-navigation/header-navigation-stacked.stories.tsx +4 -0
  5. package/src/components/header-navigation/header-navigation.stories.tsx +5 -0
  6. package/src/components/left-navigation/header-navigation-tiny.stories.tsx +6 -0
  7. package/src/components/left-navigation/interface.ts +2 -2
  8. package/src/components/left-navigation/side-navigation-links-internal.tsx +21 -6
  9. package/src/components/left-navigation/side-navigation.module.less +21 -19
  10. package/src/components/left-navigation/side-navigation.tsx +15 -8
  11. package/src/components/links.tsx +33 -13
  12. package/src/components/logo/logo-company-title.tsx +8 -6
  13. package/src/components/profile-dropdown/profile-dropdown.module.less +4 -0
  14. package/src/components/profile-dropdown/profile-dropdown.stories.tsx +4 -4
  15. package/src/components/profile-dropdown/profile-dropdown.tsx +43 -46
  16. package/src/components/titan-layout/index.ts +5 -0
  17. package/src/components/titan-layout/interface-internal.ts +6 -0
  18. package/src/components/titan-layout/interface.ts +26 -0
  19. package/src/components/titan-layout/layout-context.tsx +30 -0
  20. package/src/components/titan-layout/layout-header-links.tsx +144 -0
  21. package/{dist/components/left-navigation/header-navigation-tiny.module.less → src/components/titan-layout/layout-header.module.less} +41 -5
  22. package/src/components/titan-layout/layout-header.tsx +86 -0
  23. package/src/components/titan-layout/layout-logo.stories.tsx +31 -0
  24. package/src/components/titan-layout/layout-logo.tsx +57 -0
  25. package/src/components/titan-layout/layout-profile.stories.tsx +37 -0
  26. package/src/components/titan-layout/layout-profile.tsx +116 -0
  27. package/src/components/titan-layout/layout-sidebar-links-internal.tsx +265 -0
  28. package/src/components/titan-layout/layout-sidebar-links.tsx +56 -0
  29. package/src/components/titan-layout/layout-sidebar.module.less +528 -0
  30. package/src/components/titan-layout/layout-sidebar.tsx +298 -0
  31. package/src/components/titan-layout/titan-layout.module.less +53 -0
  32. package/src/components/titan-layout/titan-layout.stories.tsx +194 -0
  33. package/src/components/titan-layout/titan-layout.tsx +270 -0
  34. package/src/components/titan-layout/with-tooltip.tsx +16 -0
  35. package/src/index.ts +2 -1
  36. package/src/test/data.tsx +3 -2
  37. package/src/utils/navigation-legacy.ts +3 -1
  38. package/src/utils/use-breakpoint.ts +19 -0
  39. package/dist/components/badge-tag.d.ts +0 -12
  40. package/dist/components/badge-tag.d.ts.map +0 -1
  41. package/dist/components/badge-tag.js +0 -8
  42. package/dist/components/badge-tag.js.map +0 -1
  43. package/dist/components/counter-tag.d.ts +0 -12
  44. package/dist/components/counter-tag.d.ts.map +0 -1
  45. package/dist/components/counter-tag.js +0 -8
  46. package/dist/components/counter-tag.js.map +0 -1
  47. package/dist/components/header-navigation/header-navigation-content.d.ts +0 -30
  48. package/dist/components/header-navigation/header-navigation-content.d.ts.map +0 -1
  49. package/dist/components/header-navigation/header-navigation-content.js +0 -22
  50. package/dist/components/header-navigation/header-navigation-content.js.map +0 -1
  51. package/dist/components/header-navigation/header-navigation-extra-stacked.stories.d.ts +0 -9
  52. package/dist/components/header-navigation/header-navigation-extra-stacked.stories.d.ts.map +0 -1
  53. package/dist/components/header-navigation/header-navigation-extra-stacked.stories.js +0 -13
  54. package/dist/components/header-navigation/header-navigation-extra-stacked.stories.js.map +0 -1
  55. package/dist/components/header-navigation/header-navigation-extra.stories.d.ts +0 -12
  56. package/dist/components/header-navigation/header-navigation-extra.stories.d.ts.map +0 -1
  57. package/dist/components/header-navigation/header-navigation-extra.stories.js +0 -29
  58. package/dist/components/header-navigation/header-navigation-extra.stories.js.map +0 -1
  59. package/dist/components/header-navigation/header-navigation-links.d.ts +0 -11
  60. package/dist/components/header-navigation/header-navigation-links.d.ts.map +0 -1
  61. package/dist/components/header-navigation/header-navigation-links.js +0 -26
  62. package/dist/components/header-navigation/header-navigation-links.js.map +0 -1
  63. package/dist/components/header-navigation/header-navigation-stacked.stories.d.ts +0 -12
  64. package/dist/components/header-navigation/header-navigation-stacked.stories.d.ts.map +0 -1
  65. package/dist/components/header-navigation/header-navigation-stacked.stories.js +0 -50
  66. package/dist/components/header-navigation/header-navigation-stacked.stories.js.map +0 -1
  67. package/dist/components/header-navigation/header-navigation-stories.module.less +0 -6
  68. package/dist/components/header-navigation/header-navigation.d.ts +0 -59
  69. package/dist/components/header-navigation/header-navigation.d.ts.map +0 -1
  70. package/dist/components/header-navigation/header-navigation.js +0 -96
  71. package/dist/components/header-navigation/header-navigation.js.map +0 -1
  72. package/dist/components/header-navigation/header-navigation.module.less +0 -260
  73. package/dist/components/header-navigation/header-navigation.stories.d.ts +0 -12
  74. package/dist/components/header-navigation/header-navigation.stories.d.ts.map +0 -1
  75. package/dist/components/header-navigation/header-navigation.stories.js +0 -54
  76. package/dist/components/header-navigation/header-navigation.stories.js.map +0 -1
  77. package/dist/components/header-navigation/index.d.ts +0 -2
  78. package/dist/components/header-navigation/index.d.ts.map +0 -1
  79. package/dist/components/header-navigation/index.js +0 -2
  80. package/dist/components/header-navigation/index.js.map +0 -1
  81. package/dist/components/header-navigation/with-tooltip.d.ts +0 -4
  82. package/dist/components/header-navigation/with-tooltip.d.ts.map +0 -1
  83. package/dist/components/header-navigation/with-tooltip.js +0 -4
  84. package/dist/components/header-navigation/with-tooltip.js.map +0 -1
  85. package/dist/components/layout.stories.d.ts +0 -13
  86. package/dist/components/layout.stories.d.ts.map +0 -1
  87. package/dist/components/layout.stories.js +0 -29
  88. package/dist/components/layout.stories.js.map +0 -1
  89. package/dist/components/left-navigation/header-navigation-extra-tiny.stories.d.ts +0 -9
  90. package/dist/components/left-navigation/header-navigation-extra-tiny.stories.d.ts.map +0 -1
  91. package/dist/components/left-navigation/header-navigation-extra-tiny.stories.js +0 -13
  92. package/dist/components/left-navigation/header-navigation-extra-tiny.stories.js.map +0 -1
  93. package/dist/components/left-navigation/header-navigation-tiny-links.d.ts +0 -18
  94. package/dist/components/left-navigation/header-navigation-tiny-links.d.ts.map +0 -1
  95. package/dist/components/left-navigation/header-navigation-tiny-links.js +0 -32
  96. package/dist/components/left-navigation/header-navigation-tiny-links.js.map +0 -1
  97. package/dist/components/left-navigation/header-navigation-tiny.d.ts +0 -23
  98. package/dist/components/left-navigation/header-navigation-tiny.d.ts.map +0 -1
  99. package/dist/components/left-navigation/header-navigation-tiny.js +0 -7
  100. package/dist/components/left-navigation/header-navigation-tiny.js.map +0 -1
  101. package/dist/components/left-navigation/header-navigation-tiny.stories.d.ts +0 -12
  102. package/dist/components/left-navigation/header-navigation-tiny.stories.d.ts.map +0 -1
  103. package/dist/components/left-navigation/header-navigation-tiny.stories.js +0 -30
  104. package/dist/components/left-navigation/header-navigation-tiny.stories.js.map +0 -1
  105. package/dist/components/left-navigation/index.d.ts +0 -5
  106. package/dist/components/left-navigation/index.d.ts.map +0 -1
  107. package/dist/components/left-navigation/index.js +0 -5
  108. package/dist/components/left-navigation/index.js.map +0 -1
  109. package/dist/components/left-navigation/interface-internal.d.ts +0 -10
  110. package/dist/components/left-navigation/interface-internal.d.ts.map +0 -1
  111. package/dist/components/left-navigation/interface-internal.js +0 -2
  112. package/dist/components/left-navigation/interface-internal.js.map +0 -1
  113. package/dist/components/left-navigation/interface.d.ts +0 -20
  114. package/dist/components/left-navigation/interface.d.ts.map +0 -1
  115. package/dist/components/left-navigation/interface.js +0 -2
  116. package/dist/components/left-navigation/interface.js.map +0 -1
  117. package/dist/components/left-navigation/side-navigation-context.d.ts +0 -8
  118. package/dist/components/left-navigation/side-navigation-context.d.ts.map +0 -1
  119. package/dist/components/left-navigation/side-navigation-context.js +0 -7
  120. package/dist/components/left-navigation/side-navigation-context.js.map +0 -1
  121. package/dist/components/left-navigation/side-navigation-links-internal.d.ts +0 -26
  122. package/dist/components/left-navigation/side-navigation-links-internal.d.ts.map +0 -1
  123. package/dist/components/left-navigation/side-navigation-links-internal.js +0 -29
  124. package/dist/components/left-navigation/side-navigation-links-internal.js.map +0 -1
  125. package/dist/components/left-navigation/side-navigation-links.d.ts +0 -6
  126. package/dist/components/left-navigation/side-navigation-links.d.ts.map +0 -1
  127. package/dist/components/left-navigation/side-navigation-links.js +0 -27
  128. package/dist/components/left-navigation/side-navigation-links.js.map +0 -1
  129. package/dist/components/left-navigation/side-navigation.d.ts +0 -29
  130. package/dist/components/left-navigation/side-navigation.d.ts.map +0 -1
  131. package/dist/components/left-navigation/side-navigation.js +0 -181
  132. package/dist/components/left-navigation/side-navigation.js.map +0 -1
  133. package/dist/components/left-navigation/side-navigation.module.less +0 -528
  134. package/dist/components/left-navigation/side-navigation.stories.d.ts +0 -17
  135. package/dist/components/left-navigation/side-navigation.stories.d.ts.map +0 -1
  136. package/dist/components/left-navigation/side-navigation.stories.js +0 -115
  137. package/dist/components/left-navigation/side-navigation.stories.js.map +0 -1
  138. package/dist/components/left-navigation/with-tooltip.d.ts +0 -4
  139. package/dist/components/left-navigation/with-tooltip.d.ts.map +0 -1
  140. package/dist/components/left-navigation/with-tooltip.js +0 -4
  141. package/dist/components/left-navigation/with-tooltip.js.map +0 -1
  142. package/dist/components/links.d.ts +0 -5
  143. package/dist/components/links.d.ts.map +0 -1
  144. package/dist/components/links.js +0 -14
  145. package/dist/components/links.js.map +0 -1
  146. package/dist/components/logo/logo-company-title.d.ts +0 -7
  147. package/dist/components/logo/logo-company-title.d.ts.map +0 -1
  148. package/dist/components/logo/logo-company-title.js +0 -6
  149. package/dist/components/logo/logo-company-title.js.map +0 -1
  150. package/dist/components/logo/logo-titan-text.d.ts +0 -29
  151. package/dist/components/logo/logo-titan-text.d.ts.map +0 -1
  152. package/dist/components/logo/logo-titan-text.js +0 -13
  153. package/dist/components/logo/logo-titan-text.js.map +0 -1
  154. package/dist/components/logo/logo-titan-text.module.less +0 -31
  155. package/dist/components/logo/logo-titan.d.ts +0 -9
  156. package/dist/components/logo/logo-titan.d.ts.map +0 -1
  157. package/dist/components/logo/logo-titan.js +0 -13
  158. package/dist/components/logo/logo-titan.js.map +0 -1
  159. package/dist/components/logo/logo.stories.d.ts +0 -14
  160. package/dist/components/logo/logo.stories.d.ts.map +0 -1
  161. package/dist/components/logo/logo.stories.js +0 -20
  162. package/dist/components/logo/logo.stories.js.map +0 -1
  163. package/dist/components/profile-dropdown/profile-dropdown-stacked.stories.d.ts +0 -9
  164. package/dist/components/profile-dropdown/profile-dropdown-stacked.stories.d.ts.map +0 -1
  165. package/dist/components/profile-dropdown/profile-dropdown-stacked.stories.js +0 -13
  166. package/dist/components/profile-dropdown/profile-dropdown-stacked.stories.js.map +0 -1
  167. package/dist/components/profile-dropdown/profile-dropdown-tiny.stories.d.ts +0 -9
  168. package/dist/components/profile-dropdown/profile-dropdown-tiny.stories.d.ts.map +0 -1
  169. package/dist/components/profile-dropdown/profile-dropdown-tiny.stories.js +0 -13
  170. package/dist/components/profile-dropdown/profile-dropdown-tiny.stories.js.map +0 -1
  171. package/dist/components/profile-dropdown/profile-dropdown.d.ts +0 -74
  172. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +0 -1
  173. package/dist/components/profile-dropdown/profile-dropdown.js +0 -86
  174. package/dist/components/profile-dropdown/profile-dropdown.js.map +0 -1
  175. package/dist/components/profile-dropdown/profile-dropdown.module.less +0 -167
  176. package/dist/components/profile-dropdown/profile-dropdown.stories.d.ts +0 -16
  177. package/dist/components/profile-dropdown/profile-dropdown.stories.d.ts.map +0 -1
  178. package/dist/components/profile-dropdown/profile-dropdown.stories.js +0 -51
  179. package/dist/components/profile-dropdown/profile-dropdown.stories.js.map +0 -1
  180. package/dist/components/profile-dropdown/profile-icon.d.ts +0 -3
  181. package/dist/components/profile-dropdown/profile-icon.d.ts.map +0 -1
  182. package/dist/components/profile-dropdown/profile-icon.js +0 -5
  183. package/dist/components/profile-dropdown/profile-icon.js.map +0 -1
  184. package/dist/index.d.ts +0 -12
  185. package/dist/index.d.ts.map +0 -1
  186. package/dist/index.js +0 -12
  187. package/dist/index.js.map +0 -1
  188. package/dist/test/data-stories.module.less +0 -8
  189. package/dist/test/data.d.ts +0 -32
  190. package/dist/test/data.d.ts.map +0 -1
  191. package/dist/test/data.js +0 -244
  192. package/dist/test/data.js.map +0 -1
  193. package/dist/utils/counter-tag.d.ts +0 -5
  194. package/dist/utils/counter-tag.d.ts.map +0 -1
  195. package/dist/utils/counter-tag.js +0 -2
  196. package/dist/utils/counter-tag.js.map +0 -1
  197. package/dist/utils/navigation-context.d.ts +0 -27
  198. package/dist/utils/navigation-context.d.ts.map +0 -1
  199. package/dist/utils/navigation-context.js +0 -10
  200. package/dist/utils/navigation-context.js.map +0 -1
  201. package/dist/utils/navigation-legacy.d.ts +0 -86
  202. package/dist/utils/navigation-legacy.d.ts.map +0 -1
  203. package/dist/utils/navigation-legacy.js +0 -2
  204. package/dist/utils/navigation-legacy.js.map +0 -1
  205. package/dist/utils/navigation.d.ts +0 -48
  206. package/dist/utils/navigation.d.ts.map +0 -1
  207. package/dist/utils/navigation.js +0 -2
  208. package/dist/utils/navigation.js.map +0 -1
  209. package/dist/utils/side-nav.d.ts +0 -6
  210. package/dist/utils/side-nav.d.ts.map +0 -1
  211. package/dist/utils/side-nav.js +0 -28
  212. package/dist/utils/side-nav.js.map +0 -1
  213. package/src/components/header-navigation/header-navigation-stories.module.less.d.ts +0 -3
  214. package/src/components/header-navigation/header-navigation.module.less.d.ts +0 -22
  215. package/src/components/left-navigation/header-navigation-tiny.module.less.d.ts +0 -15
  216. package/src/components/left-navigation/side-navigation.module.less.d.ts +0 -47
  217. package/src/components/logo/logo-titan-text.module.less.d.ts +0 -6
  218. package/src/components/profile-dropdown/profile-dropdown.module.less.d.ts +0 -21
  219. package/src/test/data-stories.module.less.d.ts +0 -3
@@ -0,0 +1,298 @@
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
+ flex: boolean;
35
+ barExpanded: boolean;
36
+ submenuExpanded: string | undefined;
37
+ mobile: boolean;
38
+ navigationComponent: FC<NavLinkComponentProps>;
39
+ onBarExpandChange(expanded: boolean): void;
40
+ onSubmenuExpandChange(id: string, expanded: boolean): void;
41
+ }
42
+
43
+ export const LayoutSidebar: FC<LayoutSidebarProps> = ({
44
+ className,
45
+ flex,
46
+ mobile,
47
+ barExpanded,
48
+ submenuExpanded,
49
+ onBarExpandChange,
50
+ onSubmenuExpandChange,
51
+ mainItems,
52
+ top,
53
+ bottom,
54
+ navigationComponent,
55
+ }) => {
56
+ const handleClick = (e: MouseEvent<never>) => {
57
+ e.stopPropagation();
58
+ };
59
+
60
+ return (
61
+ <LayoutPlacementContext.Provider value="side">
62
+ <div
63
+ className={classNames(
64
+ Styles.nav,
65
+ mobile && Styles.navDrawer,
66
+ mobile && barExpanded && Styles.navDrawerOpened,
67
+ !mobile && (barExpanded ? Styles.navWide : Styles.navSlim),
68
+ !mobile && (flex ? Styles.navFlex : Styles.navFixed),
69
+ className
70
+ )}
71
+ data-cy="side-navigation"
72
+ onClick={handleClick}
73
+ >
74
+ <ThemeProvider mode="dark" className={Styles.navMain}>
75
+ {mobile && (
76
+ <div className={Styles.navCloseWrapper}>
77
+ <div
78
+ className={Styles.navClose}
79
+ onClick={() => onBarExpandChange(false)}
80
+ >
81
+ <Icon svg={SvgClose} size="large" />
82
+ </div>
83
+ </div>
84
+ )}
85
+ {top?.length && <SidebarTop>{top}</SidebarTop>}
86
+
87
+ <div data-cy="navigation-items">
88
+ {mainItems?.map(item =>
89
+ item.submenu ? (
90
+ <SideNavigationGroupItem
91
+ key={item.id}
92
+ barExpanded={barExpanded}
93
+ submenuExpanded={!!item.id && submenuExpanded === item.id}
94
+ onSubmenuExpand={onSubmenuExpandChange}
95
+ navigationComponent={navigationComponent}
96
+ {...item}
97
+ />
98
+ ) : (
99
+ <InternalSideNavigationLink
100
+ key={item.id}
101
+ submenuExpanded={undefined}
102
+ navigationComponent={navigationComponent}
103
+ {...item}
104
+ tag={getSubmenuGroupTag(
105
+ item.submenu,
106
+ getCounterTag(item.counter, item.tag)
107
+ )}
108
+ />
109
+ )
110
+ )}
111
+ </div>
112
+
113
+ {!!bottom && <SidebarBottom>{bottom}</SidebarBottom>}
114
+ </ThemeProvider>
115
+
116
+ {!mobile && (
117
+ <div className={Styles.navFooter}>
118
+ <div className={Styles.divider} />
119
+ <div className={Styles.toggleWrapper}>
120
+ <SideNavigationOptionsToggle
121
+ appearance={barExpanded ? 'collapse-button' : 'expand'}
122
+ onExpandedChange={() => onBarExpandChange(!barExpanded)}
123
+ />
124
+ </div>
125
+ </div>
126
+ )}
127
+ </div>
128
+ </LayoutPlacementContext.Provider>
129
+ );
130
+ };
131
+ LayoutSidebar.displayName = 'LayoutSidebar';
132
+
133
+ /** Side Navigation options toggle */
134
+ const SideNavigationOptionsToggle: FC<{
135
+ appearance: 'expand' | 'collapse' | 'collapse-button';
136
+ onExpandedChange?(expanded: boolean): void;
137
+ }> = ({ appearance, onExpandedChange }) =>
138
+ withTooltip(
139
+ <div
140
+ data-cy="navigation-left-options"
141
+ data-pendo="navigation-left-options"
142
+ className={classNames(Styles.toggle)}
143
+ onClick={() => onExpandedChange?.(appearance === 'expand')}
144
+ >
145
+ <div className={Styles.toggleContent}>
146
+ <div className={Styles.toggleIconWrapper}>
147
+ <Icon
148
+ className={Styles.toggleIcon}
149
+ svg={appearance === 'expand' ? SvgExpand : SvgCollapse}
150
+ />
151
+ </div>
152
+
153
+ {appearance === 'collapse-button' && (
154
+ <span className={Styles.toggleText}>Collapse Menu</span>
155
+ )}
156
+ </div>
157
+ </div>,
158
+ appearance === 'expand'
159
+ ? 'Expand Menu'
160
+ : appearance === 'collapse'
161
+ ? 'Collapse Menu'
162
+ : undefined,
163
+ 'right'
164
+ );
165
+
166
+ /** Side Navigation menu item */
167
+ const SideNavigationGroupItem: FC<
168
+ NavigationItemData & {
169
+ navigationComponent: FC<NavLinkComponentProps>;
170
+ barExpanded: boolean;
171
+ submenuExpanded: boolean;
172
+ onSubmenuExpand: undefined | ((id: string, expanded: boolean) => void);
173
+ }
174
+ > = ({ onSubmenuExpand, barExpanded, submenuExpanded, ...props }) => {
175
+ const onExpandToggle = useCallback(
176
+ (e: MouseEvent<never>) => {
177
+ e.preventDefault();
178
+ e.stopPropagation();
179
+
180
+ if (props.id) {
181
+ onSubmenuExpand?.(props.id, !submenuExpanded);
182
+ }
183
+ },
184
+ [props.id, submenuExpanded, onSubmenuExpand]
185
+ );
186
+ const {
187
+ sidebar: {
188
+ styles: { popoverContent },
189
+ },
190
+ } = useTitanLayoutContext();
191
+
192
+ const tag = getSubmenuGroupTag(props.submenu, getCounterTag(props.counter, props.tag));
193
+
194
+ return barExpanded ? (
195
+ <InternalSideNavigationGroup
196
+ {...props}
197
+ submenuExpanded={submenuExpanded}
198
+ onExpandToggle={onExpandToggle}
199
+ tag={tag}
200
+ >
201
+ <SideNavigationGroupContent
202
+ groups={props.submenu?.groups ?? []}
203
+ navigationComponent={props.navigationComponent}
204
+ />
205
+ </InternalSideNavigationGroup>
206
+ ) : (
207
+ <Popover placement="right-start" openOnHover delay={500}>
208
+ <Popover.Trigger>
209
+ {(triggerProps: any) => (
210
+ <div {...triggerProps}>
211
+ <InternalSideNavigationLink
212
+ {...props}
213
+ submenuExpanded={undefined}
214
+ tag={tag}
215
+ />
216
+ </div>
217
+ )}
218
+ </Popover.Trigger>
219
+ <Popover.Content style={popoverContent} className="z-global-nav-i">
220
+ <div className={Styles.submenuPopover}>
221
+ <Text
222
+ variant="headline"
223
+ el="h4"
224
+ size="small"
225
+ className="c-white m-b-half-i m-t-1"
226
+ >
227
+ {props.title}
228
+ </Text>
229
+ <SideNavigationGroupContent
230
+ groups={props.submenu?.groups ?? []}
231
+ navigationComponent={props.navigationComponent}
232
+ />
233
+ </div>
234
+ </Popover.Content>
235
+ </Popover>
236
+ );
237
+ };
238
+ const SideNavigationGroupContent: FC<NavigationSubmenuData & NavigationComponentProps> = ({
239
+ groups,
240
+ navigationComponent,
241
+ }) => {
242
+ return (
243
+ <Fragment>
244
+ {groups.reduce((out, group, index) => {
245
+ if (!group.links.length) {
246
+ return out;
247
+ }
248
+
249
+ const title = group.title?.trim() ?? '';
250
+ /* eslint-disable react/no-array-index-key */
251
+ out.push(
252
+ <Text
253
+ key={`:group:${index}:title`}
254
+ variant="eyebrow"
255
+ className={classNames(Styles.submenuGroupHeader, {
256
+ [Styles.submenuGroupHeaderEmpty]: !title,
257
+ })}
258
+ >
259
+ {title}
260
+ </Text>
261
+ );
262
+ out.push(
263
+ ...group.links.map((link, index) => (
264
+ <InternalSideNavigationGroupLink
265
+ key={`:${link.id}:${index}`}
266
+ {...link}
267
+ navigationComponent={navigationComponent}
268
+ />
269
+ ))
270
+ );
271
+ /* eslint-enable react/no-array-index-key */
272
+
273
+ return out;
274
+ }, [] as ReactElement[])}
275
+ </Fragment>
276
+ );
277
+ };
278
+
279
+ function SidebarTop({ children }: any) {
280
+ const list = Children.map(children, child => {
281
+ return child && isValidElement(child) ? child : null;
282
+ });
283
+ return list?.length ? (
284
+ <ThemeProvider mode="dark" className={Styles.navTop} data-cy="navigation-items-top">
285
+ {list}
286
+ <div className={Styles.divider} />
287
+ </ThemeProvider>
288
+ ) : null;
289
+ }
290
+
291
+ function SidebarBottom({ children }: any) {
292
+ return (
293
+ <ThemeProvider mode="dark" className={Styles.navBottom} data-cy="navigation-items-bottom">
294
+ <div className={Styles.divider} />
295
+ {children}
296
+ </ThemeProvider>
297
+ );
298
+ }
@@ -0,0 +1,53 @@
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-legacy {
12
+ padding-left: var(--nav-offset-left);
13
+ }
14
+
15
+ .layout-anvil1 {
16
+ display: block;
17
+ }
18
+
19
+ .layout-anvil2 {
20
+ display: block;
21
+ }
22
+
23
+ .layout-legacy,
24
+ .layout-anvil2 {
25
+ .top-placeholder {
26
+ height: var(--nav-offset-top);
27
+ }
28
+
29
+ .top {
30
+ position: fixed;
31
+ top: 0;
32
+ left: 0;
33
+ right: 0;
34
+ z-index: 991;
35
+ }
36
+ }
37
+
38
+ .layout {
39
+ --nav-offset-top: 49px;
40
+
41
+ &.layout-mobile {
42
+ --nav-offset-top: 61px;
43
+ --nav-offset-left: 0;
44
+ }
45
+
46
+ &.layout-nav-slim {
47
+ --nav-offset-left: 64px;
48
+ }
49
+
50
+ &.layout-nav-wide {
51
+ --nav-offset-left: 212px;
52
+ }
53
+ }
@@ -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
+ );