@hashicorp/react-components 0.0.0-canary.3a0af3d → 0.0.0-canary.3cd4069

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 (166) hide show
  1. package/package.json +9 -10
  2. package/src/components/nav-panel/components/flight-icon/index.tsx +51 -0
  3. package/src/components/nav-panel/components/flight-icon/style.module.css +3 -0
  4. package/src/components/nav-panel/components/link-list/index.tsx +94 -0
  5. package/src/components/nav-panel/components/link-list/style.module.css +57 -0
  6. package/src/components/nav-panel/components/panel/column/index.tsx +24 -0
  7. package/src/components/nav-panel/components/panel/column/style.module.css +24 -0
  8. package/src/components/nav-panel/components/panel/index.tsx +4 -0
  9. package/src/components/nav-panel/components/panel/root/index.tsx +20 -0
  10. package/src/components/nav-panel/components/panel/root/style.module.css +30 -0
  11. package/src/components/nav-panel/components/promo/index.tsx +92 -0
  12. package/src/components/nav-panel/components/promo/style.module.css +128 -0
  13. package/src/components/nav-panel/components/text/index.tsx +34 -0
  14. package/src/components/nav-panel/index.tsx +6 -0
  15. package/src/components/nav-panel/product-panel/index.tsx +181 -0
  16. package/src/components/nav-panel/product-panel/style.module.css +350 -0
  17. package/src/components/nav-panel/standard-panel/index.tsx +47 -0
  18. package/src/components/nav-panel/standard-panel/style.module.css +11 -0
  19. package/src/lib/get-localized-link-props/index.test.ts +30 -0
  20. package/src/lib/get-localized-link-props/index.ts +45 -0
  21. package/src/lib/parse-url/index.test.ts +69 -0
  22. package/src/lib/parse-url/index.ts +98 -0
  23. package/src/lib/send-posthog-event/index.ts +22 -0
  24. package/src/lib/supported-locales/index.ts +1 -0
  25. package/src/lib/track-nav-click-event/index.ts +22 -0
  26. package/src/lib/v/index.ts +10 -0
  27. package/src/components/actions/index.tsx +0 -107
  28. package/src/components/actions/style.module.css +0 -28
  29. package/src/components/actions/types.ts +0 -73
  30. package/src/components/call-to-action/index.tsx +0 -205
  31. package/src/components/call-to-action/styles/variant-centered.module.css +0 -93
  32. package/src/components/call-to-action/styles/variant-compact-grid.module.css +0 -88
  33. package/src/components/call-to-action/styles/variant-compact.module.css +0 -91
  34. package/src/components/call-to-action/styles/variant-links.module.css +0 -85
  35. package/src/components/card/README.md +0 -11
  36. package/src/components/card/card.tsx +0 -45
  37. package/src/components/card/index.test.tsx +0 -69
  38. package/src/components/card/index.tsx +0 -14
  39. package/src/components/card/newsroom-card/index.test.tsx +0 -39
  40. package/src/components/card/newsroom-card/index.tsx +0 -37
  41. package/src/components/card/newsroom-card/style.module.css +0 -12
  42. package/src/components/card/partner-card/index.test.tsx +0 -57
  43. package/src/components/card/partner-card/index.tsx +0 -69
  44. package/src/components/card/partner-card/style.module.css +0 -24
  45. package/src/components/card/person-card/index.test.tsx +0 -71
  46. package/src/components/card/person-card/index.tsx +0 -93
  47. package/src/components/card/person-card/style.module.css +0 -33
  48. package/src/components/card/primitives.tsx +0 -176
  49. package/src/components/card/promo-card/index.tsx +0 -51
  50. package/src/components/card/resource-card/index.test.tsx +0 -48
  51. package/src/components/card/resource-card/index.tsx +0 -37
  52. package/src/components/card/style.module.css +0 -145
  53. package/src/components/card/types.ts +0 -66
  54. package/src/components/card/unified-card/index.tsx +0 -64
  55. package/src/components/consent-manager/README.md +0 -73
  56. package/src/components/consent-manager/components/banner/banner.module.css +0 -23
  57. package/src/components/consent-manager/components/banner/banner.test.tsx +0 -31
  58. package/src/components/consent-manager/components/banner/banner.tsx +0 -73
  59. package/src/components/consent-manager/components/dialog/dialog.module.css +0 -145
  60. package/src/components/consent-manager/components/dialog/dialog.test.tsx +0 -194
  61. package/src/components/consent-manager/components/dialog/dialog.tsx +0 -339
  62. package/src/components/consent-manager/img/icn_close.tsx +0 -19
  63. package/src/components/consent-manager/index.test.tsx +0 -334
  64. package/src/components/consent-manager/index.tsx +0 -186
  65. package/src/components/consent-manager/loader/README.md +0 -29
  66. package/src/components/consent-manager/loader/categories.ts +0 -22
  67. package/src/components/consent-manager/loader/index.tsx +0 -94
  68. package/src/components/consent-manager/loader/presets/enterprise.ts +0 -12
  69. package/src/components/consent-manager/loader/presets/oss.ts +0 -10
  70. package/src/components/consent-manager/loader/services.ts +0 -45
  71. package/src/components/consent-manager/scripts/custom.tsx +0 -59
  72. package/src/components/consent-manager/scripts/segment.tsx +0 -87
  73. package/src/components/consent-manager/style.module.css +0 -9
  74. package/src/components/consent-manager/types.ts +0 -55
  75. package/src/components/consent-manager/util/cookies.test.ts +0 -75
  76. package/src/components/consent-manager/util/cookies.ts +0 -70
  77. package/src/components/consent-manager/util/integrations.test.ts +0 -115
  78. package/src/components/consent-manager/util/integrations.ts +0 -110
  79. package/src/components/intro/index.tsx +0 -82
  80. package/src/components/intro/style.module.css +0 -67
  81. package/src/components/intro/types.ts +0 -44
  82. package/src/components/marketo-form/CHANGELOG.md +0 -122
  83. package/src/components/marketo-form/README.md +0 -1
  84. package/src/components/marketo-form/contexts/FormMetadata.ts +0 -11
  85. package/src/components/marketo-form/docs.mdx +0 -197
  86. package/src/components/marketo-form/fixtures/index.ts +0 -185
  87. package/src/components/marketo-form/form/index.tsx +0 -369
  88. package/src/components/marketo-form/index.test.tsx +0 -320
  89. package/src/components/marketo-form/index.ts +0 -11
  90. package/src/components/marketo-form/package.original.json +0 -30
  91. package/src/components/marketo-form/partials/error-message/index.tsx +0 -12
  92. package/src/components/marketo-form/partials/error-message/style.module.css +0 -13
  93. package/src/components/marketo-form/partials/field/index.tsx +0 -90
  94. package/src/components/marketo-form/partials/field-wrapper/index.tsx +0 -26
  95. package/src/components/marketo-form/partials/fields/checkbox-field/index.tsx +0 -32
  96. package/src/components/marketo-form/partials/fields/email-field/index.tsx +0 -35
  97. package/src/components/marketo-form/partials/fields/form-page-url-field/index.tsx +0 -21
  98. package/src/components/marketo-form/partials/fields/hidden-field/index.tsx +0 -37
  99. package/src/components/marketo-form/partials/fields/htmltext-field/index.tsx +0 -21
  100. package/src/components/marketo-form/partials/fields/htmltext-field/style.module.css +0 -6
  101. package/src/components/marketo-form/partials/fields/name-field/index.tsx +0 -19
  102. package/src/components/marketo-form/partials/fields/name-field/style.module.css +0 -13
  103. package/src/components/marketo-form/partials/fields/radio-buttons-field/index.tsx +0 -48
  104. package/src/components/marketo-form/partials/fields/select-field/index.tsx +0 -39
  105. package/src/components/marketo-form/partials/fields/select-field/style.module.css +0 -5
  106. package/src/components/marketo-form/partials/fields/telephone-field/index.tsx +0 -30
  107. package/src/components/marketo-form/partials/fields/text-field/index.tsx +0 -30
  108. package/src/components/marketo-form/partials/fields/textarea-field/index.tsx +0 -29
  109. package/src/components/marketo-form/partials/label/index.tsx +0 -24
  110. package/src/components/marketo-form/partials/label/style.module.css +0 -12
  111. package/src/components/marketo-form/partials/visibility-rule/index.tsx +0 -84
  112. package/src/components/marketo-form/props.js +0 -66
  113. package/src/components/marketo-form/server/api-routes.ts +0 -109
  114. package/src/components/marketo-form/server/client.ts +0 -98
  115. package/src/components/marketo-form/server/index.ts +0 -8
  116. package/src/components/marketo-form/types.ts +0 -268
  117. package/src/components/marketo-form/utils.test.tsx +0 -103
  118. package/src/components/marketo-form/utils.ts +0 -445
  119. package/src/components/next-steps/index.tsx +0 -143
  120. package/src/components/next-steps/style.module.css +0 -270
  121. package/src/components/next-steps/types.ts +0 -63
  122. package/src/components/product-badge/index.test.tsx +0 -11
  123. package/src/components/product-badge/index.tsx +0 -42
  124. package/src/components/product-badge/style.module.css +0 -76
  125. package/src/components/products-used/index.tsx +0 -84
  126. package/src/components/products-used/style.module.css +0 -87
  127. package/src/components/products-used/types.ts +0 -31
  128. package/src/components/related-content/index.test.tsx +0 -74
  129. package/src/components/related-content/index.tsx +0 -56
  130. package/src/components/related-content/style.module.css +0 -89
  131. package/src/components/related-content/types.ts +0 -21
  132. package/src/components/subnav/helpers/areBasePathsMatching.ts +0 -13
  133. package/src/components/subnav/helpers/traverse/index.ts +0 -42
  134. package/src/components/subnav/helpers/useHeightRef.ts +0 -42
  135. package/src/components/subnav/helpers/useNavRef.ts +0 -30
  136. package/src/components/subnav/helpers/useOverflowRef.ts +0 -85
  137. package/src/components/subnav/helpers/useStuckRef.ts +0 -51
  138. package/src/components/subnav/index.tsx +0 -199
  139. package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.test.ts +0 -26
  140. package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.ts +0 -22
  141. package/src/components/subnav/partials/CtaLinks/github-stars-link/index.tsx +0 -87
  142. package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.test.ts +0 -29
  143. package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.ts +0 -32
  144. package/src/components/subnav/partials/CtaLinks/github-stars-link/style.module.css +0 -85
  145. package/src/components/subnav/partials/CtaLinks/icons/github-logo.js +0 -20
  146. package/src/components/subnav/partials/CtaLinks/icons/github.svg.js +0 -7
  147. package/src/components/subnav/partials/CtaLinks/icons/star.js +0 -20
  148. package/src/components/subnav/partials/CtaLinks/index.tsx +0 -130
  149. package/src/components/subnav/partials/CtaLinks/style.module.css +0 -45
  150. package/src/components/subnav/partials/DropdownTrigger/index.tsx +0 -35
  151. package/src/components/subnav/partials/DropdownTrigger/style.module.css +0 -36
  152. package/src/components/subnav/partials/MenuItemsDefault/index.tsx +0 -151
  153. package/src/components/subnav/partials/MenuItemsDefault/style.module.css +0 -91
  154. package/src/components/subnav/partials/MenuItemsOverflow/index.tsx +0 -139
  155. package/src/components/subnav/partials/MenuItemsOverflow/style.module.css +0 -82
  156. package/src/components/subnav/partials/TitleLink/index.tsx +0 -113
  157. package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-dark.ts +0 -9
  158. package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-light.ts +0 -9
  159. package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-dark.ts +0 -23
  160. package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-light.ts +0 -23
  161. package/src/components/subnav/partials/TitleLink/style.module.css +0 -43
  162. package/src/components/subnav/partials/nav-item-text/index.tsx +0 -37
  163. package/src/components/subnav/partials/nav-item-text/style.module.css +0 -15
  164. package/src/components/subnav/style.module.css +0 -68
  165. package/src/components/subnav/subnav-consts.ts +0 -1
  166. package/src/components/subnav/theme.module.css +0 -50
@@ -0,0 +1,181 @@
1
+ import classNames from 'classnames'
2
+ import Link from 'next/link'
3
+ import * as NavPanel from '../components/panel'
4
+ import Promo, { type PromoProps } from '../components/promo'
5
+ import { getLocalizedLinkProps } from '../../../lib/get-localized-link-props'
6
+ import { Products } from '@hashicorp/platform-product-meta'
7
+ import FlightIcon from '../components/flight-icon'
8
+ import { Text } from '../components/text'
9
+ import { trackNavClickEvent } from '../../../lib/track-nav-click-event'
10
+ import * as NavigationMenu from '@radix-ui/react-navigation-menu'
11
+ import s from './style.module.css'
12
+
13
+ const PRODUCT_LOGO_MAP = new Map([
14
+ ['Terraform', 'terraform-fill'],
15
+ ['Packer', 'packer-fill-color'],
16
+ ['Vault', 'vault-fill-color'],
17
+ ['Boundary', 'boundary-fill-color'],
18
+ ['Consul', 'consul-fill-color'],
19
+ ['Nomad', 'nomad-fill-color'],
20
+ ['Waypoint', 'waypoint-fill-color'],
21
+ ['Vagrant', 'vagrant-fill-color'],
22
+ ['HCP Vault Secrets', 'vault-secrets'],
23
+ ['HCP Vault Radar', 'vault-radar'],
24
+ ])
25
+
26
+ const PRODUCT_LOGO_EXCEPTION_CLASSNAMES = {
27
+ Terraform: 'terraform',
28
+ 'HCP Vault Secrets': 'hcpVaultSecrets',
29
+ 'HCP Vault Radar': 'hcpVaultRadar',
30
+ }
31
+
32
+ export interface ProductsPanelProps {
33
+ locale?: string
34
+ productCategories: any
35
+ promo?: PromoProps
36
+ sidePanel?: {
37
+ label: string
38
+ navItems: {
39
+ icon: string
40
+ title: string
41
+ description: string
42
+ url: string
43
+ }[]
44
+ }
45
+ isPromoOnTop?: boolean
46
+ }
47
+
48
+ const ProductPanel = ({
49
+ locale,
50
+ productCategories,
51
+ promo,
52
+ sidePanel,
53
+ isPromoOnTop = false,
54
+ }: ProductsPanelProps) => {
55
+ return (
56
+ <NavPanel.Root
57
+ className={classNames(s.productPanel, {
58
+ [s.hasSide]: sidePanel,
59
+ [s.noSide]: !sidePanel,
60
+ [s.topPromo]: isPromoOnTop,
61
+ })}
62
+ hasSidePanel={Boolean(sidePanel)}
63
+ >
64
+ <div className={s.mainPanel}>
65
+ {promo && isPromoOnTop ? (
66
+ <Promo
67
+ {...promo}
68
+ hasSidePanel={Boolean(sidePanel)}
69
+ isPromoOnTop={isPromoOnTop}
70
+ />
71
+ ) : null}
72
+ <NavPanel.Column hasSidePanel={Boolean(sidePanel)}>
73
+ <ul className={s.productCategories}>
74
+ {productCategories.map(({ title, products }) => {
75
+ return (
76
+ <li key={title} className={s.productCategory}>
77
+ <Text className={s.eyebrow}>{title}</Text>
78
+ <ul className={s.productList}>
79
+ {products.map((product) => {
80
+ return (
81
+ <li key={product.url}>
82
+ <NavProduct locale={locale} {...product} />
83
+ </li>
84
+ )
85
+ })}
86
+ </ul>
87
+ </li>
88
+ )
89
+ })}
90
+ </ul>
91
+ </NavPanel.Column>
92
+ {promo && !isPromoOnTop ? (
93
+ <Promo {...promo} hasSidePanel={Boolean(sidePanel)} />
94
+ ) : null}
95
+ </div>
96
+
97
+ {sidePanel ? (
98
+ <NavPanel.Column className={s.sidePanel}>
99
+ <Text size="200" weight="semibold">
100
+ {sidePanel.label}
101
+ </Text>
102
+
103
+ {/* ! TODO Replace the below list with the <LinkList /> component,
104
+ That component will require a refactor to support greater customization
105
+ Ticket:
106
+ https://app.asana.com/0/1206176289707208/1208162145034615/f
107
+ */}
108
+ <ul className={s.sidePanelItems}>
109
+ {sidePanel.navItems.map(({ icon, title, description, url }) => {
110
+ return (
111
+ <li key={title}>
112
+ <Link
113
+ aria-label={`${title} - ${description}`}
114
+ {...getLocalizedLinkProps(url, locale)}
115
+ locale={locale ? locale : undefined}
116
+ className={classNames(s.sidePanelItem, s.focusIndicator)}
117
+ >
118
+ <div className={s.iconBackground}>
119
+ <FlightIcon
120
+ name={icon}
121
+ color="var(--token-color-foreground-faint)"
122
+ />
123
+ </div>
124
+ <div className={s.sidePanelItemContent}>
125
+ <Text size="200" weight="semibold">
126
+ {title}
127
+ </Text>
128
+ <span className={s.sidePanelItemDesc}>{description}</span>
129
+ </div>
130
+ </Link>
131
+ </li>
132
+ )
133
+ })}
134
+ </ul>
135
+ </NavPanel.Column>
136
+ ) : null}
137
+ </NavPanel.Root>
138
+ )
139
+ }
140
+
141
+ export interface NavProductProps {
142
+ locale?: string
143
+ url: string
144
+ product: Products | string
145
+ description: string
146
+ }
147
+
148
+ function NavProduct({ locale, url, product, description }: NavProductProps) {
149
+ return (
150
+ <NavigationMenu.Link asChild>
151
+ <Link
152
+ aria-label={`${product} - ${description}`}
153
+ {...getLocalizedLinkProps(url, locale)}
154
+ locale={locale ? locale : undefined}
155
+ onClickCapture={() => {
156
+ trackNavClickEvent(product, url, 'products')
157
+ }}
158
+ className={s.focusIndicator}
159
+ >
160
+ <div className={s.productWrapper}>
161
+ <div className={s.productLogo}>
162
+ <FlightIcon
163
+ name={PRODUCT_LOGO_MAP.get(product) ?? 'hashicorp-fill-color'}
164
+ className={
165
+ PRODUCT_LOGO_EXCEPTION_CLASSNAMES[product]
166
+ ? s[PRODUCT_LOGO_EXCEPTION_CLASSNAMES[product]]
167
+ : undefined
168
+ }
169
+ />
170
+ </div>
171
+ <div className={s.productTextContent}>
172
+ <span>{product}</span>
173
+ <span className={s.productDesc}>{description}</span>
174
+ </div>
175
+ </div>
176
+ </Link>
177
+ </NavigationMenu.Link>
178
+ )
179
+ }
180
+
181
+ export default ProductPanel
@@ -0,0 +1,350 @@
1
+ @custom-media --dev-dot-viewport (min-width: 924px);
2
+
3
+ .productPanel {
4
+ height: 100%;
5
+
6
+ /* Temporarily included for devdot compatability
7
+ https://app.asana.com/1/90955849329269/project/1209320521286316/task/1210514680913728?focus=true */
8
+ --mds-spacing-01: 0.25rem;
9
+ --mds-spacing-02: 0.375rem;
10
+ --mds-spacing-03: 0.5rem;
11
+ --mds-spacing-04: 0.75rem;
12
+ --mds-spacing-05: 1rem;
13
+ --mds-spacing-06: 1.25rem;
14
+ --mds-spacing-07: 1.5rem;
15
+ --mds-spacing-08: 2rem;
16
+ --mds-spacing-09: 2.5rem;
17
+ --mds-spacing-10: 3rem;
18
+ --mds-spacing-11: 3.5rem;
19
+ --mds-spacing-12: 4rem;
20
+ --mds-spacing-13: 4.5rem;
21
+ --mds-spacing-14: 5.5rem;
22
+ --mds-spacing-15: 6rem;
23
+ --mds-spacing-16: 8rem;
24
+ --mds-spacing-17: 8.5rem;
25
+ --mds-typography-body-200-font-size: 0.875rem;
26
+ --mds-typography-font-weight-regular: 400;
27
+ --mds-typography-font-weight-semibold: 600;
28
+
29
+ @media (--large) {
30
+ &.noSide {
31
+ display: grid;
32
+ grid-template-rows: 1fr;
33
+ grid-template-columns: max-content max-content;
34
+ padding: 0;
35
+ }
36
+ }
37
+
38
+ @media (--dev-dot-viewport) {
39
+ &.hasSide {
40
+ display: grid;
41
+ grid-template-rows: 1fr;
42
+ grid-template-columns: max-content max-content;
43
+ padding: 0;
44
+ }
45
+ }
46
+ }
47
+
48
+ .productCategories {
49
+ list-style: none;
50
+ padding: 0;
51
+ display: grid;
52
+ margin: var(--mds-spacing-07) 0 0;
53
+
54
+ @nest .topPromo & {
55
+ margin-bottom: var(--mds-spacing-07);
56
+ }
57
+
58
+ @media (--large) {
59
+ @nest .noSide & {
60
+ margin: 0;
61
+ }
62
+ }
63
+
64
+ @media (--dev-dot-viewport) {
65
+ @nest .hasSide & {
66
+ margin: 0;
67
+ }
68
+ }
69
+ }
70
+
71
+ .productCategory {
72
+ display: flex;
73
+ flex-direction: column;
74
+ min-width: 160px;
75
+
76
+ &:first-child {
77
+ border-bottom: 1px solid var(--token-color-border-primary);
78
+ margin-bottom: var(--mds-spacing-05);
79
+ padding-bottom: var(--mds-spacing-05);
80
+ }
81
+ }
82
+
83
+ .eyebrow {
84
+ padding-bottom: var(--mds-spacing-04);
85
+ color: var(--token-color-foreground-strong);
86
+ font-weight: var(--mds-typography-font-weight-semibold);
87
+
88
+ @media (--large) {
89
+ @nest .noSide & {
90
+ padding-bottom: 0;
91
+ padding-left: var(--mds-spacing-06);
92
+ }
93
+ }
94
+
95
+ @media (--dev-dot-viewport) {
96
+ @nest .hasSide & {
97
+ padding-bottom: 0;
98
+ padding-left: var(--mds-spacing-06);
99
+ }
100
+ }
101
+ }
102
+
103
+ .productList {
104
+ display: grid;
105
+ grid-template-columns: 1fr;
106
+ list-style: none;
107
+ margin: 0;
108
+ padding: 0;
109
+
110
+ @media (--large) {
111
+ @nest .noSide & {
112
+ padding: var(--mds-spacing-06) var(--mds-spacing-05)
113
+ var(--mds-spacing-04);
114
+ grid-auto-flow: row;
115
+ grid-template-columns: repeat(2, 300px);
116
+ grid-template-rows: repeat(2, max-content);
117
+ gap: 0;
118
+ }
119
+ }
120
+
121
+ @media (--dev-dot-viewport) {
122
+ @nest .hasSide & {
123
+ padding: var(--mds-spacing-06) var(--mds-spacing-05)
124
+ var(--mds-spacing-04);
125
+ grid-auto-flow: row;
126
+ grid-template-columns: repeat(2, 300px);
127
+ grid-template-rows: repeat(2, max-content);
128
+ gap: 0;
129
+ }
130
+ }
131
+
132
+ & li:last-child {
133
+ & .productWrapper {
134
+ margin-bottom: 0;
135
+ }
136
+ }
137
+ }
138
+
139
+ /* NavProduct styles */
140
+
141
+ .productWrapper {
142
+ display: flex;
143
+ margin-bottom: var(--mds-spacing-05);
144
+ gap: var(--mds-spacing-05);
145
+
146
+ @media (--large) {
147
+ @nest .noSide & {
148
+ padding: var(--mds-spacing-03) var(--mds-spacing-05);
149
+ margin-bottom: 0;
150
+
151
+ &:hover {
152
+ background-color: var(--token-color-surface-interactive-hover);
153
+ border-radius: var(--mds-spacing-01);
154
+ }
155
+ }
156
+ }
157
+
158
+ @media (--dev-dot-viewport) {
159
+ @nest .hasSide & {
160
+ padding: var(--mds-spacing-03) var(--mds-spacing-05);
161
+ margin-bottom: 0;
162
+
163
+ &:hover {
164
+ background-color: var(--token-color-surface-interactive-hover);
165
+ border-radius: var(--mds-spacing-01);
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ .productLogo {
172
+ margin-top: 3px;
173
+
174
+ & svg {
175
+ height: 42px;
176
+ width: 42px;
177
+ }
178
+
179
+ @nest .noSide & {
180
+ & svg {
181
+ @media (--large) {
182
+ height: var(--mds-spacing-08);
183
+ width: var(--mds-spacing-08);
184
+ }
185
+ }
186
+ }
187
+
188
+ @nest .hasSide & {
189
+ & svg {
190
+ @media (--dev-dot-viewport) {
191
+ height: var(--mds-spacing-08);
192
+ width: var(--mds-spacing-08);
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ .productTextContent {
199
+ display: flex;
200
+ flex-direction: column;
201
+ color: var(--token-color-foreground-strong);
202
+ }
203
+
204
+ .productDesc {
205
+ font-weight: 400;
206
+ font-size: 14px;
207
+ line-height: 20px;
208
+ letter-spacing: 0.0125em;
209
+ color: var(--token-color-foreground-faint);
210
+ }
211
+
212
+ .focusIndicator {
213
+ &:focus {
214
+ outline: 2px solid var(--token-color-focus-action-internal);
215
+ outline-style: auto;
216
+ }
217
+ }
218
+
219
+ .mainPanel {
220
+ height: 100%;
221
+ display: flex;
222
+ justify-content: space-between;
223
+ flex-direction: column;
224
+
225
+ @media (--large) {
226
+ @nest .noSide & {
227
+ padding: var(--mds-spacing-07) 0 var(--mds-spacing-09)
228
+ var(--mds-spacing-04);
229
+ }
230
+
231
+ @nest .topPromo & {
232
+ padding-bottom: var(--mds-spacing-04);
233
+ }
234
+ }
235
+
236
+ @media (--dev-dot-viewport) {
237
+ @nest .hasSide & {
238
+ padding: var(--mds-spacing-07) 0 var(--mds-spacing-09)
239
+ var(--mds-spacing-04);
240
+ }
241
+
242
+ @nest .topPromo & {
243
+ padding-bottom: var(--mds-spacing-04);
244
+ }
245
+ }
246
+ }
247
+
248
+ .sidePanel {
249
+ height: 100%;
250
+ background: var(--token-color-surface-faint);
251
+ display: flex;
252
+ flex-direction: column;
253
+ gap: var(--mds-spacing-05);
254
+ margin: 0;
255
+ padding: var(--mds-spacing-07) var(--mds-spacing-04)
256
+ var(--mds-spacing-09) var(--mds-spacing-07);
257
+ }
258
+
259
+ .sidePanelItems {
260
+ list-style: none;
261
+ margin: 0;
262
+ padding: 0;
263
+ display: grid;
264
+ grid-template-columns: 1fr;
265
+ gap: var(--mds-spacing-07);
266
+
267
+ @media (--dev-dot-viewport) {
268
+ gap: var(--mds-spacing-05);
269
+ }
270
+ }
271
+
272
+ /* Lifted from .productWrapper */
273
+ .sidePanelItem {
274
+ display: flex;
275
+ gap: var(--mds-spacing-05);
276
+
277
+ @media (--dev-dot-viewport) {
278
+ padding: var(--mds-spacing-03) var(--mds-spacing-05);
279
+
280
+ &:hover {
281
+ background-color: var(--token-color-surface-interactive-hover);
282
+ border-radius: var(--mds-spacing-01);
283
+ }
284
+ }
285
+ }
286
+
287
+ /* Lifted from:
288
+ packages/react-components/src/components/nav-panel/components/link-list/style.module.css */
289
+ .iconBackground {
290
+ background: var(--token-color-foreground-high-contrast);
291
+ height: var(--mds-spacing-08);
292
+ width: var(--mds-spacing-08);
293
+ display: flex;
294
+ align-items: center;
295
+ justify-content: center;
296
+ border-radius: 3px;
297
+ flex: none;
298
+ margin-top: 3px;
299
+ border: 1px solid var(--token-color-border-primary);
300
+ }
301
+
302
+ /* Lifted from .productTextContent */
303
+ .sidePanelItemContent {
304
+ display: flex;
305
+ flex-direction: column;
306
+ color: var(--token-color-foreground-strong);
307
+ }
308
+
309
+ .sidePanelItemDesc {
310
+ font-weight: 400;
311
+ font-size: 13px;
312
+ line-height: 18px;
313
+ color: var(--token-color-foreground-primary);
314
+ }
315
+
316
+ /* Branding exception classnames */
317
+
318
+ /* Allows switching to a dark-mode-specific color for Terraform */
319
+ .terraform {
320
+ & use {
321
+ fill: var(--token-color-terraform-brand);
322
+
323
+ @nest [data-theme='dark'] & {
324
+ fill: var(--token-color-terraform-foreground);
325
+ }
326
+ }
327
+
328
+ & path {
329
+ fill: inherit;
330
+ }
331
+ }
332
+
333
+ /* Styles for HCP Vault mimic the spec for `product-square` icons,
334
+ while allowing the symbol inside the icon border to change color
335
+ based on the site's theme
336
+ */
337
+ .hcpVaultSecrets,
338
+ .hcpVaultRadar {
339
+ padding: var(--mds-spacing-01);
340
+ border: 2px solid var(--token-color-vault-brand);
341
+ border-radius: 3px;
342
+
343
+ & use {
344
+ fill: var(--token-color-foreground-strong);
345
+ }
346
+
347
+ & path {
348
+ fill: inherit;
349
+ }
350
+ }
@@ -0,0 +1,47 @@
1
+ import { trackNavClickEvent } from '../../../lib/track-nav-click-event'
2
+ import * as NavPanel from '../components/panel'
3
+ import LinkList, { type LinkListProps } from '../components/link-list'
4
+ import Promo, { type PromoProps } from '../components/promo'
5
+ import s from './style.module.css'
6
+
7
+ export interface NavItem {
8
+ navItems: LinkListProps['links']
9
+ }
10
+
11
+ interface StandardPanelProps {
12
+ navData: NavItem[]
13
+ promo?: PromoProps
14
+ sectionName?: string
15
+ locale?: any
16
+ }
17
+
18
+ const StandardPanel = ({
19
+ navData,
20
+ promo,
21
+ sectionName = '',
22
+ locale,
23
+ }: StandardPanelProps) => {
24
+ return (
25
+ <NavPanel.Root>
26
+ <div className={s.columns}>
27
+ {navData.map(({ navItems }, stableIdx) => {
28
+ return (
29
+ <NavPanel.Column key={stableIdx}>
30
+ <LinkList
31
+ locale={locale}
32
+ links={navItems}
33
+ linkClickHandler={(text, href) => {
34
+ trackNavClickEvent(text, href, sectionName)
35
+ }}
36
+ />
37
+ </NavPanel.Column>
38
+ )
39
+ })}
40
+ </div>
41
+
42
+ {promo ? <Promo {...promo} /> : null}
43
+ </NavPanel.Root>
44
+ )
45
+ }
46
+
47
+ export default StandardPanel
@@ -0,0 +1,11 @@
1
+ .columns {
2
+ display: flex;
3
+ gap: var(--mds-spacing-03);
4
+ flex-direction: column;
5
+ margin-top: var(--mds-spacing-07);
6
+
7
+ @media (--large) {
8
+ flex-direction: row;
9
+ margin-top: 0;
10
+ }
11
+ }
@@ -0,0 +1,30 @@
1
+ import { getLocalizedLinkProps } from '.'
2
+
3
+ describe('getLocalizedLinkProps', () => {
4
+ it('does not format localized homepage', () => {
5
+ const localizedLinkProps = getLocalizedLinkProps('/en', 'ja')
6
+ expect(localizedLinkProps.href).toBe('/en')
7
+ expect(localizedLinkProps.hrefLang).toBe('en')
8
+ })
9
+
10
+ it('does not format localized path hrefs', () => {
11
+ const localizedLinkProps = getLocalizedLinkProps('/ja/solutions', 'de')
12
+ expect(localizedLinkProps.href).toBe('/ja/solutions')
13
+ expect(localizedLinkProps.hrefLang).toBe('ja')
14
+ })
15
+
16
+ it('does format paths that start with a locale string', () => {
17
+ const localizedLinkProps = getLocalizedLinkProps(
18
+ '/deconstructing-cloud',
19
+ 'en'
20
+ )
21
+ expect(localizedLinkProps.href).toBe('/en/deconstructing-cloud')
22
+ expect(localizedLinkProps.hrefLang).toBe('en')
23
+ })
24
+
25
+ it('does not format external paths', () => {
26
+ const localizedLinkProps = getLocalizedLinkProps('https://google.com', 'ja')
27
+ expect(localizedLinkProps.href).toBe('https://google.com')
28
+ expect(localizedLinkProps.hrefLang).toBe(undefined)
29
+ })
30
+ })
@@ -0,0 +1,45 @@
1
+ import { parseUrl } from '../parse-url'
2
+ import { allSupportedLocales } from '../supported-locales'
3
+
4
+ export const getLocalizedLinkProps = (
5
+ url: string,
6
+ locale?: string
7
+ ): {
8
+ href: string
9
+ hrefLang: string | undefined
10
+ } => {
11
+ const parsedHref = parseUrl(url).href
12
+
13
+ // example: /en
14
+ const hrefIsLocalizedHomepage = allSupportedLocales.includes(
15
+ parsedHref.substring(1)
16
+ )
17
+
18
+ // true example: /en/solutions
19
+ // false example: /entry-point
20
+ const hrefIsLocalized =
21
+ allSupportedLocales.includes(parsedHref.substring(1, 3)) &&
22
+ parsedHref[3] === '/'
23
+
24
+ // If the href is already localized:
25
+ // - do not format the href
26
+ // - use the locale from the href for the hrefLang
27
+ if (hrefIsLocalizedHomepage || hrefIsLocalized) {
28
+ return {
29
+ href: parsedHref,
30
+ hrefLang: parsedHref.substring(1, 3),
31
+ }
32
+ }
33
+
34
+ if (parsedHref.startsWith('/') && locale) {
35
+ return {
36
+ href: `/${locale}${parsedHref}`,
37
+ hrefLang: locale,
38
+ }
39
+ }
40
+
41
+ return {
42
+ href: parsedHref,
43
+ hrefLang: undefined,
44
+ }
45
+ }