@smartbooks-ai/layout 0.0.3

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 (54) hide show
  1. package/package/tsconfig.layout.tsbuildinfo +1 -0
  2. package/package.json +48 -0
  3. package/src/components/PageHeader/PageHeader.tsx +15 -0
  4. package/src/components/PageHeader/index.ts +1 -0
  5. package/src/components/PageHeader/styles.ts +34 -0
  6. package/src/components/PageWithMenuLayout/AppSelect/index.tsx +66 -0
  7. package/src/components/PageWithMenuLayout/AppSelect/styles.ts +33 -0
  8. package/src/components/PageWithMenuLayout/LogoHeaderImage.tsx +44 -0
  9. package/src/components/PageWithMenuLayout/LogoHeaderText.tsx +48 -0
  10. package/src/components/PageWithMenuLayout/MenuItemWithChildren/MenuItemWithChildren.tsx +149 -0
  11. package/src/components/PageWithMenuLayout/MenuItemWithChildren/styles.ts +179 -0
  12. package/src/components/PageWithMenuLayout/MenuSelect/index.tsx +78 -0
  13. package/src/components/PageWithMenuLayout/MenuSelect/styles.ts +97 -0
  14. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/ConsolidationIcon.tsx +6 -0
  15. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/MultiSubscriptionsMenuItems.tsx +120 -0
  16. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/consolidation.svg +8 -0
  17. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/index.ts +1 -0
  18. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/styles.ts +10 -0
  19. package/src/components/PageWithMenuLayout/PageWithMenuLayout.tsx +106 -0
  20. package/src/components/PageWithMenuLayout/UserProfileSelect/index.tsx +64 -0
  21. package/src/components/PageWithMenuLayout/UserProfileSelect/styles.ts +8 -0
  22. package/src/components/PageWithMenuLayout/index.ts +8 -0
  23. package/src/components/PageWithMenuLayout/styles.ts +110 -0
  24. package/src/components/PageWithMenuLayout/types.ts +7 -0
  25. package/src/components/index.ts +3 -0
  26. package/src/emotion.d.ts +76 -0
  27. package/src/hooks/index.ts +2 -0
  28. package/src/hooks/useIsAuthorized.ts +35 -0
  29. package/src/hooks/useToggle.ts +27 -0
  30. package/src/index.ts +7 -0
  31. package/src/package-isolation.test.ts +60 -0
  32. package/src/security/AuthorizedContent/index.tsx +77 -0
  33. package/src/security/AuthorizedContent/state.ts +8 -0
  34. package/src/security/AuthorizedContent/useAuthorizationState.ts +42 -0
  35. package/src/security/ProfileContext/ProfileContext.tsx +37 -0
  36. package/src/security/ProfileContext/index.ts +4 -0
  37. package/src/security/ProfileContext/types.ts +7 -0
  38. package/src/security/ProfileContext/useProfile.tsx +7 -0
  39. package/src/security/UserProfile.ts +48 -0
  40. package/src/security/index.ts +2 -0
  41. package/src/theme/colorPrimitives.ts +107 -0
  42. package/src/theme/colors.ts +78 -0
  43. package/src/theme/font.ts +27 -0
  44. package/src/theme/globalStyles.tsx +55 -0
  45. package/src/theme/index.tsx +228 -0
  46. package/src/theme/radius.ts +12 -0
  47. package/src/theme/spacing.ts +12 -0
  48. package/src/theme/typography.ts +40 -0
  49. package/src/utils/assertNever.ts +14 -0
  50. package/src/utils/index.ts +2 -0
  51. package/src/utils/shouldNotForwardPropsWithKeys.ts +7 -0
  52. package/tsconfig.json +34 -0
  53. package/tsconfig.layout.tsbuildinfo +1 -0
  54. package/vitest.config.ts +10 -0
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@smartbooks-ai/layout",
3
+ "version": "0.0.3",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.ts",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.ts",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "test": "vitest",
18
+ "lint:ts": "tsc --noEmit"
19
+ },
20
+ "peerDependencies": {
21
+ "@emotion/react": "^11.14.0",
22
+ "@emotion/styled": "^11.14.1",
23
+ "@mui/icons-material": "7.3.6",
24
+ "@mui/material": "^7.3.6",
25
+ "@mui/x-date-pickers": "8.22.0",
26
+ "polished": "^4.3.1",
27
+ "react-router": "^7.10.1",
28
+ "react": "^18.3.1",
29
+ "@auth0/auth0-react": "2.8.0",
30
+ "react-dom": "^18.3.1"
31
+ },
32
+ "devDependencies": {
33
+ "@emotion/react": "^11.14.0",
34
+ "@emotion/styled": "^11.14.1",
35
+ "@mui/material": "^7.3.6",
36
+ "@testing-library/react": "^16.3.1",
37
+ "@tsconfig/vite-react": "^7.0.2",
38
+ "@types/react": "^18.3.27",
39
+ "jsdom": "^27.3.0",
40
+ "react": "^18.3.1",
41
+ "typescript": "^5.9.3",
42
+ "vitest": "^4.0.16"
43
+ },
44
+ "dependencies": {
45
+ "@smartbooks-ai/api-client": "0.0.1",
46
+ "use-resize-observer": "^9.1.0"
47
+ }
48
+ }
@@ -0,0 +1,15 @@
1
+ import Typography from '@mui/material/Typography';
2
+
3
+ import * as Styled from './styles';
4
+
5
+ export type PageHeaderProps = {
6
+ title: React.ReactNode;
7
+ actions?: React.ReactNode;
8
+ };
9
+
10
+ export const PageHeader: React.FC<PageHeaderProps> = ({ title, actions }) => (
11
+ <Styled.Container>
12
+ {typeof title === 'string' ? <Typography variant="h1">{title}</Typography> : title}
13
+ {actions && <Styled.CtaButtons>{actions}</Styled.CtaButtons>}
14
+ </Styled.Container>
15
+ );
@@ -0,0 +1 @@
1
+ export { PageHeader } from './PageHeader';
@@ -0,0 +1,34 @@
1
+ import { css } from '@emotion/react';
2
+ import styled from '@emotion/styled';
3
+
4
+ export const Container = styled.section(
5
+ ({ theme }) => css`
6
+ display: flex;
7
+
8
+ align-items: center;
9
+ justify-content: space-between;
10
+
11
+ width: 100%;
12
+
13
+ ${theme.breakpoints?.down?.('md')} {
14
+ flex-direction: column;
15
+
16
+ align-items: flex-start;
17
+ }
18
+ `,
19
+ );
20
+
21
+ export const CtaButtons = styled.section(
22
+ ({ theme }) => css`
23
+ display: flex;
24
+
25
+ flex: none;
26
+
27
+ column-gap: 0.5rem;
28
+ align-items: center;
29
+
30
+ ${theme.breakpoints?.down?.('md')} {
31
+ align-self: flex-end;
32
+ }
33
+ `,
34
+ );
@@ -0,0 +1,66 @@
1
+ import { useMemo } from 'react';
2
+
3
+ import { AvailableCompany } from '@smartbooks-ai/api-client';
4
+
5
+ import * as Styled from './styles';
6
+
7
+ import { UserProfile } from '../../../security/UserProfile';
8
+ import { MenuSelect } from '../MenuSelect';
9
+ import { MultiSubscriptionsMenuItems } from '../MultiSubscriptionsMenuItems';
10
+
11
+ type Props = {
12
+ companyCode?: string;
13
+ tenantCode?: string;
14
+ isExpanded: boolean;
15
+ profile: UserProfile | null;
16
+ onCompanyClicked: (company: AvailableCompany) => Promise<void>;
17
+ };
18
+
19
+ export const AppSelect: React.FC<Props> = ({ companyCode, isExpanded, tenantCode, profile, onCompanyClicked }) => {
20
+ const tenants = profile?.allowedTenants;
21
+
22
+ const tenantsWithCompanies = useMemo(() => tenants?.filter(({ companies }) => companies.length > 0) ?? [], [tenants]);
23
+
24
+ const currentCompany = companyCode ? profile?.allowedCompanies.find(({ code }) => code === companyCode) : undefined;
25
+
26
+ const tenant = tenants?.find((t) =>
27
+ currentCompany ? t.companies.some(({ code }) => code === currentCompany.code) : t.code === tenantCode,
28
+ );
29
+
30
+ const onCompanySelected = (closeMenu: () => void) => (company: AvailableCompany) => {
31
+ closeMenu();
32
+
33
+ onCompanyClicked(company);
34
+ };
35
+
36
+ const avatarContent = currentCompany?.description
37
+ .split(' ')
38
+ .slice(0, 2)
39
+ .map((word) => word[0])
40
+ .join('');
41
+
42
+ return (
43
+ <MenuSelect
44
+ isExpanded={isExpanded}
45
+ startIcon={
46
+ <Styled.SelectorAvatar variant="rounded" isMenuExpanded={isExpanded}>
47
+ {avatarContent}
48
+ </Styled.SelectorAvatar>
49
+ }
50
+ selectedOptionText={currentCompany?.description}
51
+ renderMenuItems={({ closeMenu }) => [
52
+ ...(tenantsWithCompanies.length > 0
53
+ ? [
54
+ <MultiSubscriptionsMenuItems
55
+ key="multi-subscriptions-menu-items"
56
+ selectedTenant={tenant}
57
+ tenants={tenantsWithCompanies}
58
+ selectedCompanyCode={companyCode}
59
+ onCompanySelected={onCompanySelected(closeMenu)}
60
+ />,
61
+ ]
62
+ : []),
63
+ ]}
64
+ />
65
+ );
66
+ };
@@ -0,0 +1,33 @@
1
+ import { css } from '@emotion/react';
2
+ import styled from '@emotion/styled';
3
+ import Avatar from '@mui/material/Avatar';
4
+
5
+ import { shouldNotForwardPropsWithKeys } from '../../../utils/shouldNotForwardPropsWithKeys';
6
+
7
+ type Props = {
8
+ isMenuExpanded: boolean;
9
+ };
10
+ export const SelectorAvatar = styled(Avatar, shouldNotForwardPropsWithKeys<Props>(['isMenuExpanded']))<Props>`
11
+ width: 1.75rem;
12
+ height: 1.75rem;
13
+
14
+ color: ${({ theme }) => theme.my.colors.text.main};
15
+
16
+ background-color: ${({ theme }) => theme.my.colors.background.light};
17
+ border-radius: ${({ theme }) => theme.my.radius.sm};
18
+
19
+ && {
20
+ font: ${({ theme }) => theme.my.font.body2};
21
+ }
22
+
23
+ transition:
24
+ width 0.3s,
25
+ height 0.3s;
26
+
27
+ ${({ isMenuExpanded }) =>
28
+ isMenuExpanded &&
29
+ css`
30
+ width: 2rem;
31
+ height: 2rem;
32
+ `}
33
+ `;
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+
3
+ const LogoHeaderImage = (props: React.SVGProps<SVGSVGElement>) => (
4
+ <svg viewBox="0 0 56.0617 56.0627" xmlns="http://www.w3.org/2000/svg" fill="#fff" {...props}>
5
+ <g transform="matrix(1, 0, 0, 1, -3.2658579349517822, -5.714171886444092)">
6
+ <g transform="matrix(1, 0, 0, 1, 65.689034, -123.853729)">
7
+ <g transform="matrix(0.35277777,0,0,-0.35277777,-228.38369,383.37697)">
8
+ <path transform="translate(496.3657,612.2275)" d="m 0,0 v -1.998 c -0.271,0.472 -0.53,0.948 -0.779,1.431 z" />
9
+ <path
10
+ transform="translate(555.2109,567.0908)"
11
+ d="m 0,0 c -1.76,-0.12 -3.53,-0.189 -5.32,-0.189 -3.51,0 -6.96,0.25 -10.34,0.729 V 68.681 L 0,80.07 Z M 0,87.94 -15.66,76.541 -22.02,71.92 V -4.779 c 2.09,-0.45 4.21,-0.821 6.36,-1.091 3.38,-0.449 6.84,-0.68 10.34,-0.68 1.79,0 3.56,0.061 5.32,0.18 2.15,0.141 4.27,0.37 6.36,0.681 v 98.25 z"
12
+ />
13
+ <path
14
+ transform="translate(612.5273,688.8418)"
15
+ d="m 0,0 c -1.309,1.68 -2.687,3.307 -4.124,4.871 -14.537,15.819 -35.386,25.746 -58.509,25.746 -43.814,0 -79.455,-35.641 -79.455,-79.455 0,-14.214 3.752,-27.569 10.318,-39.129 1.05,-1.854 2.173,-3.656 3.371,-5.411 3.514,-5.178 7.627,-9.921 12.237,-14.135 2.025,-1.849 4.15,-3.598 6.36,-5.23 4.834,-3.583 10.086,-6.625 15.672,-9.047 2.072,-0.896 4.197,-1.712 6.359,-2.433 v 68.257 l -6.359,-4.627 -15.672,-11.394 -6.36,-4.627 v -1.998 c -0.27,0.471 -0.53,0.948 -0.779,1.43 -4.446,8.48 -6.958,18.126 -6.958,28.344 0,33.781 27.484,61.266 61.266,61.266 7.043,0 13.811,-1.193 20.112,-3.397 4.012,-1.389 7.833,-3.196 11.417,-5.353 3.21,-1.936 6.225,-4.159 9.018,-6.631 l 0.635,0.463 4.61,3.354 c -3.807,3.513 -8.012,6.603 -12.552,9.174 -9.82,5.57 -21.168,8.75 -33.24,8.75 -37.29,0 -67.626,-30.342 -67.626,-67.626 0,-11.617 2.946,-22.561 8.124,-32.122 1.018,-1.876 2.12,-3.694 3.302,-5.459 0.848,-1.262 1.739,-2.496 2.671,-3.699 1.951,-2.528 4.076,-4.913 6.36,-7.139 v 17.404 l 15.672,11.4 V -114.8 c -5.666,2.719 -10.929,6.143 -15.672,10.16 -2.242,1.898 -4.362,3.922 -6.36,6.069 -2.591,2.787 -4.965,5.776 -7.096,8.935 -1.187,1.759 -2.3,3.572 -3.334,5.438 -5.819,10.482 -9.137,22.54 -9.137,35.36 0,40.305 32.791,73.095 73.096,73.095 16.18,0 31.147,-5.284 43.273,-14.219 1.807,-1.33 3.556,-2.746 5.231,-4.229 0.609,-0.543 1.2,-1.106 1.791,-1.668 L -9.89,5.923 V 1.707 c 0.194,-0.202 0.397,-0.395 0.589,-0.6 1.452,-1.552 2.841,-3.169 4.16,-4.843 9.773,-12.429 15.608,-28.095 15.608,-45.102 0,-21.714 -9.513,-41.249 -24.596,-54.652 -2.025,-1.796 -4.145,-3.482 -6.36,-5.051 -3.587,-2.535 -7.412,-4.757 -11.432,-6.627 v -6.955 c 3.986,1.677 7.807,3.668 11.432,5.945 2.194,1.378 4.314,2.863 6.36,4.442 18.814,14.543 30.956,37.332 30.956,62.898 C 16.827,-30.442 10.542,-13.483 0,0"
16
+ />
17
+ <path
18
+ transform="translate(598.3979,592.9258)"
19
+ d="m 0,0 c 11.829,12.184 19.122,28.794 19.122,47.078 0,15.799 -5.449,30.352 -14.569,41.879 -0.102,0.128 -0.211,0.25 -0.313,0.377 V 78.215 C 9.653,69.085 12.762,58.437 12.762,47.078 12.762,35.719 9.653,25.067 4.24,15.936 V 8.245 L 3.359,7.101 C 1.314,4.445 -0.974,1.911 -3.441,-0.431 L -6.36,-3.201 V -5.777 C -4.118,-3.986 -1.993,-2.057 0,0"
20
+ />
21
+ <path
22
+ transform="translate(602.6377,690.5483)"
23
+ d="M 0,0 V 4.216 L -2.448,2.435 C -1.613,1.642 -0.797,0.831 0,0"
24
+ />
25
+ <path
26
+ transform="translate(576.3667,571.8584)"
27
+ d="m 0,0 v -6.783 c 1.433,0.508 2.846,1.056 4.24,1.643 V 1.815 C 2.849,1.168 1.436,0.562 0,0"
28
+ />
29
+ <path transform="translate(597.8096,678.1411)" d="M 0,0 C 0.202,-0.249 0.397,-0.498 0.588,-0.752 V 0.43 Z" />
30
+ <path
31
+ transform="translate(601.7573,600.0264)"
32
+ d="m 0,0 0.88,1.145 v 7.69 C -0.407,6.663 -1.822,4.576 -3.359,2.587 -5.294,0.075 -7.424,-2.278 -9.719,-4.456 v -5.846 L -6.8,-7.531 C -4.333,-5.189 -2.045,-2.655 0,0"
33
+ />
34
+ <path
35
+ transform="translate(598.4009,678.5713)"
36
+ d="m 0,0 -0.59,-0.43 c 0.2,-0.25 0.4,-0.5 0.59,-0.75 v -74.78 c -1.94,-2.51 -4.07,-4.86 -6.36,-7.04 v 78.37 l -15.67,-11.4 v -97.47 c -2.09,-0.73 -4.21,-1.38 -6.36,-1.95 v 102.67 l 6.36,4.62 15.67,11.4 1.53,1.11 L 0,7.86 Z"
37
+ />
38
+ </g>
39
+ </g>
40
+ </g>
41
+ </svg>
42
+ );
43
+
44
+ export default LogoHeaderImage;
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+
3
+ const LogoHeaderText = (props: React.SVGProps<SVGSVGElement>) => (
4
+ <svg viewBox="0 0 277.5198 28.2999" xmlns="http://www.w3.org/2000/svg" fill="#fff" {...props}>
5
+ <path
6
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 21.501811905092836, 16.848698628076818)"
7
+ d="m 0,0 c -1.02,2.42 -2.35,4.47 -4.01,6.119 -1.65,1.651 -3.53,3.01 -5.64,4.061 -2.11,1.06 -4.24,1.9 -6.39,2.54 -2.15,0.63 -4.22,1.119 -6.23,1.469 -2,0.361 -3.74,0.71 -5.22,1.061 -1.97,0.49 -4.01,0.979 -6.12,1.479 -2.12,0.491 -4.05,1.091 -5.81,1.791 -1.76,0.7 -3.2,1.58 -4.33,2.64 -1.12,1.06 -1.69,2.36 -1.69,3.91 0,1.539 0.48,2.86 1.43,3.95 0.95,1.089 2.14,1.99 3.59,2.7 1.44,0.699 2.97,1.21 4.59,1.53 1.62,0.31 3.06,0.47 4.33,0.47 3.73,0 7.28,-0.67 10.66,-2 3.38,-1.341 6.89,-3.281 10.55,-5.81 l 8.24,11.61 c -2.4,1.689 -4.63,3.149 -6.71,4.379 -2.07,1.23 -4.2,2.25 -6.38,3.06 -2.18,0.811 -4.54,1.431 -7.07,1.851 -2.54,0.419 -5.42,0.629 -8.66,0.629 -3.24,0 -6.6,-0.35 -10.08,-1.049 -3.48,-0.71 -6.65,-1.92 -9.5,-3.64 -2.85,-1.73 -5.19,-4.09 -7.02,-7.081 -1.83,-2.989 -2.74,-6.739 -2.74,-11.239 0,-3.091 0.51,-5.79 1.53,-8.071 1.02,-2.289 2.37,-4.259 4.06,-5.909 1.69,-1.66 3.59,-3.031 5.7,-4.121 2.11,-1.09 4.26,-1.97 6.44,-2.64 2.18,-0.669 4.29,-1.2 6.33,-1.58 2.04,-0.389 3.84,-0.719 5.39,-1 2.32,-0.429 4.55,-0.889 6.7,-1.38 2.14,-0.49 4.01,-1.089 5.59,-1.79 1.59,-0.71 2.85,-1.599 3.8,-2.689 0.95,-1.091 1.43,-2.41 1.43,-3.96 0,-1.2 -0.32,-2.41 -0.95,-3.641 -0.64,-1.229 -1.59,-2.32 -2.85,-3.269 -1.27,-0.95 -2.82,-1.731 -4.65,-2.33 -1.83,-0.601 -3.94,-0.891 -6.33,-0.891 -4.5,0 -8.81,0.96 -12.93,2.901 -4.12,1.929 -8.11,4.24 -11.98,6.91 l -8.02,-11.821 c 2.39,-1.689 4.71,-3.24 6.96,-4.639 2.26,-1.41 4.65,-2.63 7.18,-3.641 2.54,-1.029 5.33,-1.84 8.39,-2.43 3.06,-0.599 6.6,-0.899 10.61,-0.899 4.36,0 8.34,0.489 11.93,1.48 3.59,0.98 6.68,2.44 9.29,4.379 2.6,1.93 4.61,4.38 6.01,7.33 1.41,2.96 2.11,6.441 2.11,10.451 C 1.53,-5.37 1.02,-2.431 0,0"
8
+ />
9
+ <path
10
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 54.25382881612312, 0.5575740958811508)"
11
+ d="M 0,0 -38,-44.55 -75.9,0 h -0.95 v -77.16 h 14.78 v 39.05 L -38,-67.13 -13.83,-38.11 V -77.16 H 0.95 V 0 Z"
12
+ />
13
+ <path
14
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 68.36493998021616, 18.955030016193632)"
15
+ d="M 0,0 11.08,23.33 22.06,0 Z m 11.82,52.15 h -1.47 l -39.48,-77.16 h 16.04 l 5.91,12.14 h 36.42 l 6.02,-12.14 H 51.3 Z"
16
+ />
17
+ <path
18
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 102.79950923521027, 14.206504166930245)"
19
+ d="m 0,0 c -1.44,-0.53 -2.82,-0.79 -4.16,-0.79 h -20.3 V 25.7 h 20.3 c 2.6,0 4.67,-0.49 6.21,-1.47 1.54,-0.99 2.74,-2.19 3.58,-3.59 0.84,-1.41 1.4,-2.89 1.68,-4.44 0.28,-1.54 0.42,-2.88 0.42,-4.01 0,-2.18 -0.37,-4.08 -1.1,-5.7 C 5.89,4.87 4.96,3.52 3.84,2.43 2.72,1.34 1.44,0.53 0,0 m 6.44,-12.51 c 4.86,1.9 8.75,5.03 11.68,9.4 2.93,4.36 4.39,9.46 4.39,15.3 0,3.87 -0.65,7.44 -1.96,10.72 -1.3,3.27 -3.12,6.08 -5.44,8.44 -2.33,2.36 -5.13,4.19 -8.41,5.49 -3.28,1.3 -6.89,1.95 -10.84,1.95 h -35.1 v -77.26 h 14.78 v 24.59 h 14.62 c 2.95,-4.22 5.9,-8.37 8.84,-12.451 2.95,-4.089 5.96,-8.129 9.05,-12.139 h 17.63 c -6.34,8.72 -12.75,17.38 -19.24,25.96"
20
+ />
21
+ <path
22
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 113.71805040033725, 0.5222618670159136)"
23
+ d="m 0,0 v -13.09 h 22.17 v -64.17 h 14.78 v 64.17 H 59.01 V 0 Z"
24
+ />
25
+ <path
26
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 154.45664918610782, 20.796476624127536)"
27
+ d="M 0,0 C -0.5,-1.23 -1.17,-2.36 -2.01,-3.38 -2.85,-4.4 -3.84,-5.21 -4.97,-5.81 -6.09,-6.41 -7.29,-6.7 -8.55,-6.7 h -20.899 v 19.63 h 19.309 c 3.38,0 6.04,-0.88 7.97,-2.64 C -0.229,8.53 0.73,6.35 0.73,3.75 0.73,2.48 0.49,1.23 0,0 m -29.449,44.38 h 19.21 c 1.05,0 2.059,-0.25 3.01,-0.74 0.95,-0.5 1.769,-1.13 2.479,-1.91 0.7,-0.78 1.261,-1.7 1.681,-2.76 0.429,-1.06 0.639,-2.16 0.639,-3.29 0,-1.13 -0.2,-2.28 -0.58,-3.45 -0.389,-1.17 -0.95,-2.21 -1.689,-3.13 -0.74,-0.92 -1.66,-1.67 -2.75,-2.23 C -8.54,26.3 -9.819,26.02 -11.3,26.02 H -29.449 Z M 14.091,9.69 c -0.95,2.1 -2.171,3.96 -3.651,5.57 -1.469,1.62 -3.139,2.9 -5.009,3.85 -1.861,0.94 -3.75,1.49 -5.651,1.63 1.83,0.07 3.521,0.62 5.071,1.64 1.549,1.02 2.87,2.28 3.96,3.76 1.089,1.48 1.95,3.1 2.589,4.87 0.63,1.76 0.941,3.42 0.941,4.97 0,4.38 -0.591,7.96 -1.79,10.75 -1.2,2.78 -2.811,4.97 -4.851,6.56 -2.05,1.59 -4.439,2.68 -7.179,3.28 -2.75,0.6 -5.67,0.9 -8.76,0.9 h -33.99 V -19.79 H -8.55 c 3.3,0 6.42,0.38 9.34,1.16 2.92,0.77 5.471,2.05 7.65,3.84 2.18,1.79 3.901,4.14 5.17,7.05 1.27,2.91 1.901,6.48 1.901,10.69 0,2.38 -0.471,4.63 -1.42,6.74"
28
+ />
29
+ <path
30
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 186.44298285655168, 17.68863444259115)"
31
+ d="m 0,0 c -1.34,-3.159 -3.14,-5.96 -5.43,-8.39 -2.28,-2.429 -4.95,-4.36 -8,-5.799 -3.059,-1.451 -6.34,-2.17 -9.849,-2.17 -3.511,0 -6.8,0.719 -9.851,2.17 -3.05,1.439 -5.72,3.37 -8.01,5.799 -2.28,2.43 -4.089,5.231 -5.42,8.39 -1.33,3.171 -2,6.511 -2,10.03 0,3.45 0.67,6.77 2,9.97 1.331,3.21 3.14,6 5.42,8.4 2.29,2.391 4.96,4.31 8.01,5.75 3.051,1.44 6.34,2.161 9.851,2.161 3.509,0 6.79,-0.721 9.849,-2.161 3.05,-1.44 5.72,-3.359 8,-5.75 C -3.14,26 -1.34,23.21 0,20 1.33,16.8 2,13.48 2,10.03 2,6.511 1.33,3.171 0,0 M 13.61,25.601 C 11.5,30.49 8.631,34.75 5.011,38.371 1.381,41.99 -2.859,44.86 -7.71,46.97 c -4.859,2.111 -10.069,3.171 -15.619,3.171 -5.49,0 -10.66,-1.06 -15.521,-3.171 -4.849,-2.11 -9.089,-4.98 -12.719,-8.599 -3.62,-3.621 -6.491,-7.881 -8.601,-12.77 -2.109,-4.891 -3.17,-10.08 -3.17,-15.571 0,-5.559 1.061,-10.769 3.17,-15.62 2.11,-4.859 4.981,-9.099 8.601,-12.72 3.63,-3.629 7.87,-6.49 12.719,-8.599 4.861,-2.111 10.031,-3.17 15.521,-3.17 5.55,0 10.76,1.059 15.619,3.17 4.851,2.109 9.091,4.97 12.721,8.599 3.62,3.621 6.489,7.861 8.599,12.72 2.111,4.851 3.17,10.061 3.17,15.62 0,5.491 -1.059,10.68 -3.17,15.571"
32
+ />
33
+ <path
34
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 218.68700967032424, 17.68863444259115)"
35
+ d="m 0,0 c -1.33,-3.159 -3.14,-5.96 -5.42,-8.39 -2.28,-2.429 -4.95,-4.36 -8.01,-5.799 -3.049,-1.451 -6.33,-2.17 -9.84,-2.17 -3.51,0 -6.8,0.719 -9.85,2.17 -3.06,1.439 -5.73,3.37 -8.01,5.799 -2.28,2.43 -4.09,5.231 -5.42,8.39 -1.34,3.171 -2,6.511 -2,10.03 0,3.45 0.66,6.77 2,9.97 1.33,3.21 3.14,6 5.42,8.4 2.28,2.391 4.95,4.31 8.01,5.75 3.05,1.44 6.34,2.161 9.85,2.161 3.51,0 6.791,-0.721 9.84,-2.161 3.06,-1.44 5.73,-3.359 8.01,-5.75 C -3.14,26 -1.33,23.21 0,20 1.34,16.8 2.01,13.48 2.01,10.03 2.01,6.511 1.34,3.171 0,0 M 13.62,25.601 C 11.51,30.49 8.64,34.75 5.01,38.371 1.39,41.99 -2.85,44.86 -7.7,46.97 c -4.86,2.111 -10.07,3.171 -15.63,3.171 -5.48,0 -10.66,-1.06 -15.51,-3.171 -4.86,-2.11 -9.1,-4.98 -12.72,-8.599 -3.63,-3.621 -6.49,-7.881 -8.6,-12.77 -2.11,-4.891 -3.17,-10.08 -3.17,-15.571 0,-5.559 1.06,-10.769 3.17,-15.62 2.11,-4.859 4.97,-9.099 8.6,-12.72 3.62,-3.629 7.86,-6.49 12.72,-8.599 4.85,-2.111 10.03,-3.17 15.51,-3.17 5.56,0 10.77,1.059 15.63,3.17 4.85,2.109 9.09,4.97 12.71,8.599 3.63,3.621 6.5,7.861 8.61,12.72 2.11,4.851 3.16,10.061 3.16,15.62 0,5.491 -1.05,10.68 -3.16,15.571"
36
+ />
37
+ <path
38
+ d="M 0,0 31.77,39.9 H 13.62 L -17.101,0.74 V 40 H -31.88 v -77.26 h 14.779 V -2.109 L 15.3,-37.26 h 19.53 z"
39
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 241.21554419908352, 14.633502222190145)"
40
+ />
41
+ <path
42
+ transform="matrix(0.35277777910232544, 0, 0, -0.35277777910232544, 276.9801141033313, 16.848698628076818)"
43
+ d="m 0,0 c -1.021,2.42 -2.36,4.47 -4.01,6.119 -1.65,1.651 -3.54,3.01 -5.65,4.061 -2.111,1.06 -4.24,1.9 -6.38,2.54 -2.15,0.63 -4.22,1.119 -6.231,1.469 -2.009,0.361 -3.75,0.71 -5.219,1.061 -1.98,0.49 -4.02,0.979 -6.13,1.479 -2.11,0.491 -4.04,1.091 -5.8,1.791 -1.761,0.7 -3.2,1.58 -4.33,2.64 -1.13,1.06 -1.69,2.36 -1.69,3.91 0,1.539 0.48,2.86 1.43,3.95 0.949,1.089 2.14,1.99 3.579,2.7 1.451,0.699 2.981,1.21 4.601,1.53 1.61,0.31 3.059,0.47 4.32,0.47 3.73,0 7.29,-0.67 10.659,-2 3.381,-1.341 6.901,-3.281 10.561,-5.81 l 8.229,11.61 c -2.389,1.689 -4.62,3.149 -6.699,4.379 -2.08,1.23 -4.2,2.25 -6.39,3.06 -2.18,0.811 -4.531,1.431 -7.07,1.851 -2.53,0.419 -5.421,0.629 -8.65,0.629 -3.24,0 -6.6,-0.35 -10.08,-1.049 -3.49,-0.71 -6.651,-1.92 -9.5,-3.64 -2.85,-1.73 -5.191,-4.09 -7.02,-7.081 -1.83,-2.989 -2.75,-6.739 -2.75,-11.239 0,-3.091 0.51,-5.79 1.53,-8.071 1.02,-2.289 2.379,-4.259 4.07,-5.909 1.689,-1.66 3.59,-3.031 5.7,-4.121 2.109,-1.09 4.26,-1.97 6.44,-2.64 2.18,-0.669 4.29,-1.2 6.33,-1.58 2.04,-0.389 3.83,-0.719 5.379,-1 2.331,-0.429 4.561,-0.889 6.71,-1.38 2.141,-0.49 4.011,-1.089 5.591,-1.79 1.579,-0.71 2.85,-1.599 3.8,-2.689 0.95,-1.091 1.42,-2.41 1.42,-3.96 0,-1.2 -0.311,-2.41 -0.95,-3.641 -0.63,-1.229 -1.58,-2.32 -2.85,-3.269 -1.261,-0.95 -2.81,-1.731 -4.64,-2.33 -1.831,-0.601 -3.94,-0.891 -6.331,-0.891 -4.509,0 -8.819,0.96 -12.929,2.901 -4.12,1.929 -8.111,4.24 -11.981,6.91 l -8.019,-11.821 c 2.389,-1.689 4.71,-3.24 6.96,-4.639 2.25,-1.41 4.65,-2.63 7.179,-3.641 2.531,-1.029 5.331,-1.84 8.391,-2.43 3.06,-0.599 6.6,-0.899 10.609,-0.899 4.361,0 8.341,0.489 11.931,1.48 3.58,0.98 6.68,2.44 9.279,4.379 2.611,1.93 4.611,4.38 6.021,7.33 1.41,2.96 2.11,6.441 2.11,10.451 C 1.53,-5.37 1.02,-2.431 0,0"
44
+ />
45
+ </svg>
46
+ );
47
+
48
+ export default LogoHeaderText;
@@ -0,0 +1,149 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+
3
+ import { useEventCallback } from '@mui/material';
4
+ import Collapse from '@mui/material/Collapse';
5
+ import Fade from '@mui/material/Fade';
6
+ import { NavLink, useMatches } from 'react-router';
7
+
8
+ import * as Styled from './styles';
9
+
10
+ import { assertNever } from '../../../utils/assertNever';
11
+ import { MenuItem } from '../types';
12
+
13
+ const MenuItemLink = Styled.MenuItem.withComponent(NavLink);
14
+
15
+ const isAbsoluteUrl = (url: string) => /^(?:[a-z+]+:)?\/\//i.test(url);
16
+
17
+ const hasActiveChildren = (menuItem: MenuItem, pathnames: string[]): boolean =>
18
+ ('href' in menuItem && pathnames.includes(decodeURIComponent(menuItem.href))) ||
19
+ ('children' in menuItem && menuItem.children.some((child) => hasActiveChildren(child, pathnames)));
20
+
21
+ type Props = {
22
+ menuItem: MenuItem;
23
+ elevation?: number;
24
+ isMenuOpen: boolean;
25
+ isExpanded?: boolean;
26
+ onExpand?: (menuItem: MenuItem) => void;
27
+ onCollapse?: () => void;
28
+ openMenu: () => void;
29
+ };
30
+
31
+ export const MenuItemWithChildren: React.FC<Props> = ({
32
+ menuItem,
33
+ elevation = 0,
34
+ isMenuOpen,
35
+ isExpanded = true,
36
+ onCollapse,
37
+ onExpand,
38
+ openMenu,
39
+ }) => {
40
+ const [expandedChild, setExpandedChild] = useState<MenuItem>();
41
+ const onCollapseChild = useCallback(() => setExpandedChild(undefined), []);
42
+
43
+ const matches = useMatches();
44
+ const containsActiveChildren = useMemo(
45
+ () =>
46
+ hasActiveChildren(
47
+ menuItem,
48
+ matches.map(({ pathname }) => pathname),
49
+ ),
50
+ [menuItem, matches],
51
+ );
52
+
53
+ useEffect(() => {
54
+ if (containsActiveChildren && 'children' in menuItem) onExpand?.(menuItem);
55
+ }, [containsActiveChildren, onExpand, menuItem]);
56
+
57
+ const isTitle = 'children' in menuItem && !('href' in menuItem) && !('onClick' in menuItem) && elevation === 0;
58
+
59
+ const onMenuItemClick = useEventCallback(() => {
60
+ openMenu();
61
+
62
+ if (isTitle || 'href' in menuItem) return;
63
+
64
+ if ('children' in menuItem) {
65
+ if (isExpanded) {
66
+ onCollapse?.();
67
+ } else {
68
+ onExpand?.(menuItem);
69
+ }
70
+ } else if ('onClick' in menuItem) {
71
+ menuItem.onClick();
72
+ } else if ('disabled' in menuItem) {
73
+ // Do nothing
74
+ } else {
75
+ assertNever(menuItem);
76
+ }
77
+ });
78
+
79
+ const isHighlighted = containsActiveChildren && (!isExpanded || !isMenuOpen);
80
+
81
+ const menuItemContent = (
82
+ <>
83
+ {!isTitle && elevation > 0 && (
84
+ <Styled.ActiveMenuItemIndicator isMenuOpen={isMenuOpen} visible={containsActiveChildren && 'href' in menuItem}>
85
+ &nbsp;
86
+ </Styled.ActiveMenuItemIndicator>
87
+ )}
88
+
89
+ {menuItem.icon && <Styled.ListItemIcon>{menuItem.icon}</Styled.ListItemIcon>}
90
+
91
+ <Fade in={isMenuOpen || (isTitle && isExpanded)}>
92
+ <Styled.ListItem>
93
+ <Styled.ListItemText
94
+ elevation={elevation}
95
+ title={menuItem.title}
96
+ isHighlighted={isHighlighted}
97
+ isTitle={isTitle}
98
+ >
99
+ {menuItem.title}
100
+ </Styled.ListItemText>
101
+ </Styled.ListItem>
102
+ </Fade>
103
+
104
+ {'children' in menuItem && elevation !== 0 && (
105
+ <Styled.ArrowDownIcon isVisible={isMenuOpen} isExpanded={isExpanded} fontSize="small" />
106
+ )}
107
+ </>
108
+ );
109
+
110
+ const MenuItemComponent = 'href' in menuItem ? MenuItemLink : Styled.MenuItem;
111
+
112
+ return (
113
+ <section>
114
+ {!menuItem.skipHeader && (
115
+ <MenuItemComponent
116
+ isMenuOpen={isMenuOpen}
117
+ disabled={isTitle}
118
+ onClick={onMenuItemClick}
119
+ isHighlighted={isHighlighted}
120
+ elevation={elevation}
121
+ isTitle={isTitle}
122
+ to={'href' in menuItem ? menuItem.href : {}}
123
+ target={'href' in menuItem && isAbsoluteUrl(menuItem.href) ? '_blank' : undefined}
124
+ >
125
+ {menuItemContent}
126
+ </MenuItemComponent>
127
+ )}
128
+
129
+ {'children' in menuItem && (
130
+ <Collapse in={isExpanded && (isMenuOpen || elevation !== 0)}>
131
+ <Styled.MenuList elevation={elevation}>
132
+ {menuItem.children.map((secondLevelItem) => (
133
+ <MenuItemWithChildren
134
+ onCollapse={onCollapseChild}
135
+ onExpand={setExpandedChild}
136
+ key={secondLevelItem.title}
137
+ menuItem={secondLevelItem}
138
+ elevation={elevation + 1}
139
+ isMenuOpen={isMenuOpen}
140
+ isExpanded={expandedChild?.title === secondLevelItem.title}
141
+ openMenu={openMenu}
142
+ />
143
+ ))}
144
+ </Styled.MenuList>
145
+ </Collapse>
146
+ )}
147
+ </section>
148
+ );
149
+ };
@@ -0,0 +1,179 @@
1
+ import { css } from '@emotion/react';
2
+ import styled from '@emotion/styled';
3
+ import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDownRounded';
4
+ import MuiListItemIcon from '@mui/material/ListItemIcon';
5
+ import MuiListItemText, { listItemTextClasses } from '@mui/material/ListItemText';
6
+ import MuiMenuItem, { menuItemClasses } from '@mui/material/MenuItem';
7
+ import MuiMenuList from '@mui/material/MenuList';
8
+ import { rem } from 'polished';
9
+
10
+ import { shouldNotForwardPropsWithKeys } from '../../../utils/shouldNotForwardPropsWithKeys';
11
+
12
+ const iconMargin = rem(-2);
13
+
14
+ type MenuItemProps = {
15
+ isHighlighted: boolean;
16
+ elevation?: number;
17
+ isMenuOpen: boolean;
18
+ isTitle: boolean;
19
+ };
20
+ export const MenuItem = styled(
21
+ MuiMenuItem,
22
+ shouldNotForwardPropsWithKeys<MenuItemProps>(['isHighlighted', 'elevation', 'isMenuOpen', 'isTitle']),
23
+ )<MenuItemProps>(
24
+ ({ theme, elevation = 0, isHighlighted, isMenuOpen, isTitle, disabled }) => css`
25
+ display: flex;
26
+
27
+ align-items: center;
28
+
29
+ padding: ${theme.my.spacing.xxs};
30
+ padding-left: 0;
31
+ margin-top: ${elevation === 0 && isMenuOpen && isTitle && theme.my.spacing.sm};
32
+ margin-left: ${!isMenuOpen ? `calc(${theme.my.spacing.xxs} - ${iconMargin})` : 0};
33
+
34
+ font: ${isHighlighted ? theme.my.font.nav2 : theme.my.font.nav1};
35
+
36
+ color: ${theme.my.colors.text.white};
37
+
38
+ transition:
39
+ font-weight 0.3s,
40
+ margin 0.3s;
41
+
42
+ &:hover {
43
+ background-color: ${theme.my.colors.background.hover};
44
+ }
45
+
46
+ ${disabled &&
47
+ css`
48
+ &.${menuItemClasses.disabled} {
49
+ text-transform: uppercase;
50
+
51
+ pointer-events: initial;
52
+
53
+ background-color: initial;
54
+
55
+ opacity: 1;
56
+ }
57
+ `};
58
+ `,
59
+ );
60
+
61
+ export const ListItemIcon = styled(MuiListItemIcon)`
62
+ /* Icons from MUI have small paddings, so we need to artificially move them 2px ⬅︎ */
63
+ margin-left: ${iconMargin};
64
+
65
+ /* Increasing specificity */
66
+ &&& {
67
+ min-width: 1.75rem;
68
+ }
69
+
70
+ color: ${({ theme }) => theme.my.colors.text.white};
71
+ `;
72
+
73
+ type ListItemTextProps = {
74
+ isHighlighted: boolean;
75
+ isTitle: boolean;
76
+ elevation: number;
77
+ };
78
+ export const ListItemText = styled(
79
+ MuiListItemText,
80
+ shouldNotForwardPropsWithKeys<ListItemTextProps>(['isHighlighted', 'elevation', 'isTitle']),
81
+ )<ListItemTextProps>(
82
+ ({ theme, isHighlighted, elevation, isTitle }) => css`
83
+ margin-top: 0;
84
+ margin-bottom: 0;
85
+
86
+ white-space: nowrap;
87
+
88
+ .${listItemTextClasses.primary} {
89
+ padding-left: calc(${Math.max(elevation - 1, 0)} * ${theme.my.spacing.xxs});
90
+
91
+ overflow: hidden;
92
+ text-overflow: ellipsis;
93
+
94
+ font: ${isHighlighted ? theme.my.font.nav2 : theme.my.font.nav1};
95
+
96
+ transition: font 0.3s;
97
+
98
+ ${isTitle &&
99
+ css`
100
+ font-weight: 800;
101
+ `};
102
+ }
103
+ `,
104
+ );
105
+
106
+ export const ListItem = styled.section`
107
+ display: flex;
108
+
109
+ width: 100%;
110
+
111
+ overflow: hidden;
112
+ `;
113
+
114
+ type ArrowDownIconProps = {
115
+ isExpanded: boolean;
116
+ isVisible: boolean;
117
+ };
118
+ export const ArrowDownIcon = styled(
119
+ ArrowDropDownIcon,
120
+ shouldNotForwardPropsWithKeys<ArrowDownIconProps>(['isExpanded', 'isVisible']),
121
+ )<ArrowDownIconProps>(
122
+ ({ isExpanded, isVisible, theme }) => css`
123
+ color: ${isExpanded ? theme.my.colors.primitives.common.white : theme.my.colors.primitives.darkNavy[300]};
124
+
125
+ opacity: ${isVisible ? 1 : 0};
126
+
127
+ transform: rotate(${isExpanded ? 180 : 0}deg);
128
+
129
+ transition:
130
+ transform 0.3s,
131
+ color 0.3s,
132
+ opacity 0.3s;
133
+ `,
134
+ );
135
+
136
+ type MenuListProps = {
137
+ elevation: number;
138
+ };
139
+ export const MenuList = styled(MuiMenuList, shouldNotForwardPropsWithKeys<MenuListProps>(['elevation']))<MenuListProps>`
140
+ padding-top: 0;
141
+ padding-bottom: 0;
142
+
143
+ overflow: auto;
144
+
145
+ background-color: ${({ elevation, theme }) =>
146
+ [
147
+ theme.my.colors.primitives.darkNavy[900],
148
+ theme.my.colors.primitives.darkNavy[800],
149
+ theme.my.colors.primitives.darkNavy[700],
150
+ ][elevation]};
151
+ border-radius: ${({ elevation, theme }) => elevation === 1 && theme.my.radius.md};
152
+ `;
153
+
154
+ type ActiveMenuItemIndicatorProps = {
155
+ visible: boolean;
156
+ isMenuOpen: boolean;
157
+ };
158
+ export const ActiveMenuItemIndicator = styled(
159
+ 'div',
160
+ shouldNotForwardPropsWithKeys<ActiveMenuItemIndicatorProps>(['visible', 'isMenuOpen']),
161
+ )<ActiveMenuItemIndicatorProps>(
162
+ ({ theme, visible, isMenuOpen }) => css`
163
+ display: inline-block;
164
+
165
+ width: ${isMenuOpen ? theme.my.spacing.xxxs : 0};
166
+ height: 1rem;
167
+
168
+ margin-right: ${theme.my.spacing.xxs};
169
+
170
+ background-color: transparent;
171
+ border-radius: ${theme.my.radius.sm};
172
+
173
+ transition: 0.3s;
174
+ ${visible &&
175
+ css`
176
+ background-color: ${theme.my.colors.secondary.main};
177
+ `};
178
+ `,
179
+ );