@hashicorp/react-components 0.0.0-canary.88aaf8d → 0.0.0-canary.8d655fa

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/package.json +5 -9
  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 +15 -9
  5. package/src/components/nav-panel/components/link-list/style.module.css +10 -10
  6. package/src/components/nav-panel/components/panel/column/index.tsx +15 -2
  7. package/src/components/nav-panel/components/panel/column/style.module.css +13 -3
  8. package/src/components/nav-panel/components/panel/root/index.tsx +11 -2
  9. package/src/components/nav-panel/components/panel/root/style.module.css +20 -6
  10. package/src/components/nav-panel/components/promo/index.tsx +23 -10
  11. package/src/components/nav-panel/components/promo/style.module.css +52 -16
  12. package/src/components/nav-panel/components/text/index.tsx +34 -0
  13. package/src/components/nav-panel/product-panel/index.tsx +49 -23
  14. package/src/components/nav-panel/product-panel/style.module.css +178 -42
  15. package/src/components/nav-panel/standard-panel/index.tsx +3 -0
  16. package/src/components/nav-panel/standard-panel/style.module.css +2 -2
  17. package/src/lib/get-localized-link-props/index.test.ts +30 -0
  18. package/src/lib/get-localized-link-props/index.ts +45 -0
  19. package/src/lib/parse-url/index.test.ts +40 -1
  20. package/src/lib/parse-url/index.ts +77 -9
  21. package/src/lib/send-posthog-event/index.ts +22 -0
  22. package/src/lib/supported-locales/index.ts +1 -0
  23. package/src/lib/track-nav-click-event/index.ts +4 -4
  24. package/src/lib/v/index.ts +4 -5
  25. package/src/components/actions/index.tsx +0 -107
  26. package/src/components/actions/style.module.css +0 -28
  27. package/src/components/actions/types.ts +0 -73
  28. package/src/components/call-to-action/index.tsx +0 -205
  29. package/src/components/call-to-action/styles/variant-centered.module.css +0 -93
  30. package/src/components/call-to-action/styles/variant-compact-grid.module.css +0 -88
  31. package/src/components/call-to-action/styles/variant-compact.module.css +0 -91
  32. package/src/components/call-to-action/styles/variant-links.module.css +0 -85
  33. package/src/components/card/README.md +0 -11
  34. package/src/components/card/card.tsx +0 -45
  35. package/src/components/card/index.test.tsx +0 -69
  36. package/src/components/card/index.tsx +0 -14
  37. package/src/components/card/newsroom-card/index.test.tsx +0 -39
  38. package/src/components/card/newsroom-card/index.tsx +0 -37
  39. package/src/components/card/newsroom-card/style.module.css +0 -12
  40. package/src/components/card/partner-card/index.test.tsx +0 -57
  41. package/src/components/card/partner-card/index.tsx +0 -69
  42. package/src/components/card/partner-card/style.module.css +0 -24
  43. package/src/components/card/person-card/index.test.tsx +0 -71
  44. package/src/components/card/person-card/index.tsx +0 -93
  45. package/src/components/card/person-card/style.module.css +0 -33
  46. package/src/components/card/primitives.tsx +0 -176
  47. package/src/components/card/promo-card/index.tsx +0 -51
  48. package/src/components/card/resource-card/index.test.tsx +0 -48
  49. package/src/components/card/resource-card/index.tsx +0 -37
  50. package/src/components/card/style.module.css +0 -145
  51. package/src/components/card/types.ts +0 -66
  52. package/src/components/card/unified-card/index.tsx +0 -64
  53. package/src/components/consent-manager/README.md +0 -73
  54. package/src/components/consent-manager/components/banner/banner.module.css +0 -23
  55. package/src/components/consent-manager/components/banner/banner.test.tsx +0 -31
  56. package/src/components/consent-manager/components/banner/banner.tsx +0 -73
  57. package/src/components/consent-manager/components/dialog/dialog.module.css +0 -145
  58. package/src/components/consent-manager/components/dialog/dialog.test.tsx +0 -194
  59. package/src/components/consent-manager/components/dialog/dialog.tsx +0 -339
  60. package/src/components/consent-manager/img/icn_close.tsx +0 -19
  61. package/src/components/consent-manager/index.test.tsx +0 -334
  62. package/src/components/consent-manager/index.tsx +0 -186
  63. package/src/components/consent-manager/loader/README.md +0 -29
  64. package/src/components/consent-manager/loader/categories.ts +0 -22
  65. package/src/components/consent-manager/loader/index.tsx +0 -94
  66. package/src/components/consent-manager/loader/presets/enterprise.ts +0 -12
  67. package/src/components/consent-manager/loader/presets/oss.ts +0 -10
  68. package/src/components/consent-manager/loader/services.ts +0 -45
  69. package/src/components/consent-manager/scripts/custom.tsx +0 -59
  70. package/src/components/consent-manager/scripts/segment.tsx +0 -87
  71. package/src/components/consent-manager/style.module.css +0 -9
  72. package/src/components/consent-manager/types.ts +0 -55
  73. package/src/components/consent-manager/util/cookies.test.ts +0 -75
  74. package/src/components/consent-manager/util/cookies.ts +0 -70
  75. package/src/components/consent-manager/util/integrations.test.ts +0 -115
  76. package/src/components/consent-manager/util/integrations.ts +0 -110
  77. package/src/components/intro/index.tsx +0 -82
  78. package/src/components/intro/style.module.css +0 -67
  79. package/src/components/intro/types.ts +0 -44
  80. package/src/components/marketo-form/CHANGELOG.md +0 -122
  81. package/src/components/marketo-form/README.md +0 -1
  82. package/src/components/marketo-form/contexts/FormMetadata.ts +0 -11
  83. package/src/components/marketo-form/docs.mdx +0 -197
  84. package/src/components/marketo-form/fixtures/index.ts +0 -185
  85. package/src/components/marketo-form/form/index.tsx +0 -369
  86. package/src/components/marketo-form/index.test.tsx +0 -320
  87. package/src/components/marketo-form/index.ts +0 -11
  88. package/src/components/marketo-form/package.original.json +0 -30
  89. package/src/components/marketo-form/partials/error-message/index.tsx +0 -12
  90. package/src/components/marketo-form/partials/error-message/style.module.css +0 -13
  91. package/src/components/marketo-form/partials/field/index.tsx +0 -90
  92. package/src/components/marketo-form/partials/field-wrapper/index.tsx +0 -26
  93. package/src/components/marketo-form/partials/fields/checkbox-field/index.tsx +0 -32
  94. package/src/components/marketo-form/partials/fields/email-field/index.tsx +0 -35
  95. package/src/components/marketo-form/partials/fields/form-page-url-field/index.tsx +0 -21
  96. package/src/components/marketo-form/partials/fields/hidden-field/index.tsx +0 -37
  97. package/src/components/marketo-form/partials/fields/htmltext-field/index.tsx +0 -21
  98. package/src/components/marketo-form/partials/fields/htmltext-field/style.module.css +0 -18
  99. package/src/components/marketo-form/partials/fields/name-field/index.tsx +0 -19
  100. package/src/components/marketo-form/partials/fields/name-field/style.module.css +0 -13
  101. package/src/components/marketo-form/partials/fields/radio-buttons-field/index.tsx +0 -48
  102. package/src/components/marketo-form/partials/fields/select-field/index.tsx +0 -39
  103. package/src/components/marketo-form/partials/fields/select-field/style.module.css +0 -5
  104. package/src/components/marketo-form/partials/fields/telephone-field/index.tsx +0 -30
  105. package/src/components/marketo-form/partials/fields/text-field/index.tsx +0 -30
  106. package/src/components/marketo-form/partials/fields/textarea-field/index.tsx +0 -29
  107. package/src/components/marketo-form/partials/label/index.tsx +0 -24
  108. package/src/components/marketo-form/partials/label/style.module.css +0 -12
  109. package/src/components/marketo-form/partials/visibility-rule/index.tsx +0 -84
  110. package/src/components/marketo-form/props.js +0 -66
  111. package/src/components/marketo-form/server/api-routes.ts +0 -109
  112. package/src/components/marketo-form/server/client.ts +0 -98
  113. package/src/components/marketo-form/server/index.ts +0 -8
  114. package/src/components/marketo-form/types.ts +0 -268
  115. package/src/components/marketo-form/utils.test.tsx +0 -103
  116. package/src/components/marketo-form/utils.ts +0 -449
  117. package/src/components/next-steps/index.tsx +0 -137
  118. package/src/components/next-steps/style.module.css +0 -270
  119. package/src/components/next-steps/types.ts +0 -63
  120. package/src/components/product-badge/index.test.tsx +0 -11
  121. package/src/components/product-badge/index.tsx +0 -42
  122. package/src/components/product-badge/style.module.css +0 -76
  123. package/src/components/products-used/index.tsx +0 -84
  124. package/src/components/products-used/style.module.css +0 -87
  125. package/src/components/products-used/types.ts +0 -31
  126. package/src/components/related-content/index.test.tsx +0 -74
  127. package/src/components/related-content/index.tsx +0 -56
  128. package/src/components/related-content/style.module.css +0 -89
  129. package/src/components/related-content/types.ts +0 -21
  130. package/src/components/subnav/helpers/areBasePathsMatching.ts +0 -13
  131. package/src/components/subnav/helpers/traverse/index.ts +0 -42
  132. package/src/components/subnav/helpers/useHeightRef.ts +0 -42
  133. package/src/components/subnav/helpers/useNavRef.ts +0 -30
  134. package/src/components/subnav/helpers/useOverflowRef.ts +0 -85
  135. package/src/components/subnav/helpers/useStuckRef.ts +0 -51
  136. package/src/components/subnav/index.tsx +0 -199
  137. package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.test.ts +0 -26
  138. package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.ts +0 -22
  139. package/src/components/subnav/partials/CtaLinks/github-stars-link/index.tsx +0 -87
  140. package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.test.ts +0 -29
  141. package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.ts +0 -32
  142. package/src/components/subnav/partials/CtaLinks/github-stars-link/style.module.css +0 -85
  143. package/src/components/subnav/partials/CtaLinks/icons/github-logo.js +0 -20
  144. package/src/components/subnav/partials/CtaLinks/icons/github.svg.js +0 -7
  145. package/src/components/subnav/partials/CtaLinks/icons/star.js +0 -20
  146. package/src/components/subnav/partials/CtaLinks/index.tsx +0 -130
  147. package/src/components/subnav/partials/CtaLinks/style.module.css +0 -45
  148. package/src/components/subnav/partials/DropdownTrigger/index.tsx +0 -35
  149. package/src/components/subnav/partials/DropdownTrigger/style.module.css +0 -36
  150. package/src/components/subnav/partials/MenuItemsDefault/index.tsx +0 -151
  151. package/src/components/subnav/partials/MenuItemsDefault/style.module.css +0 -91
  152. package/src/components/subnav/partials/MenuItemsOverflow/index.tsx +0 -139
  153. package/src/components/subnav/partials/MenuItemsOverflow/style.module.css +0 -82
  154. package/src/components/subnav/partials/TitleLink/index.tsx +0 -113
  155. package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-dark.ts +0 -9
  156. package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-light.ts +0 -9
  157. package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-dark.ts +0 -23
  158. package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-light.ts +0 -23
  159. package/src/components/subnav/partials/TitleLink/style.module.css +0 -43
  160. package/src/components/subnav/partials/nav-item-text/index.tsx +0 -37
  161. package/src/components/subnav/partials/nav-item-text/style.module.css +0 -15
  162. package/src/components/subnav/style.module.css +0 -68
  163. package/src/components/subnav/subnav-consts.ts +0 -1
  164. package/src/components/subnav/theme.module.css +0 -50
@@ -1,16 +1,17 @@
1
+ import classNames from 'classnames'
1
2
  import Link from 'next/link'
2
3
  import * as NavPanel from '../components/panel'
3
4
  import Promo, { type PromoProps } from '../components/promo'
5
+ import { getLocalizedLinkProps } from '../../../lib/get-localized-link-props'
4
6
  import { Products } from '@hashicorp/platform-product-meta'
5
- import FlightIcon from '@hashicorp/react-design-system-components/src/components/flight-icon'
6
- import { TextPlus } from '@hashicorp/react-design-system-components/src/components/text'
7
- import { parseUrl } from '../../../lib/parse-url'
7
+ import FlightIcon from '../components/flight-icon'
8
+ import { Text } from '../components/text'
8
9
  import { trackNavClickEvent } from '../../../lib/track-nav-click-event'
9
10
  import * as NavigationMenu from '@radix-ui/react-navigation-menu'
10
11
  import s from './style.module.css'
11
12
 
12
13
  const PRODUCT_LOGO_MAP = new Map([
13
- ['Terraform', 'terraform-fill-color'],
14
+ ['Terraform', 'terraform-fill'],
14
15
  ['Packer', 'packer-fill-color'],
15
16
  ['Vault', 'vault-fill-color'],
16
17
  ['Boundary', 'boundary-fill-color'],
@@ -23,11 +24,13 @@ const PRODUCT_LOGO_MAP = new Map([
23
24
  ])
24
25
 
25
26
  const PRODUCT_LOGO_EXCEPTION_CLASSNAMES = {
27
+ Terraform: 'terraform',
26
28
  'HCP Vault Secrets': 'hcpVaultSecrets',
27
29
  'HCP Vault Radar': 'hcpVaultRadar',
28
30
  }
29
31
 
30
32
  export interface ProductsPanelProps {
33
+ locale?: string
31
34
  productCategories: any
32
35
  promo?: PromoProps
33
36
  sidePanel?: {
@@ -39,27 +42,44 @@ export interface ProductsPanelProps {
39
42
  url: string
40
43
  }[]
41
44
  }
45
+ isPromoOnTop?: boolean
42
46
  }
43
47
 
44
48
  const ProductPanel = ({
49
+ locale,
45
50
  productCategories,
46
51
  promo,
47
52
  sidePanel,
53
+ isPromoOnTop = false,
48
54
  }: ProductsPanelProps) => {
49
55
  return (
50
- <NavPanel.Root className={s.productPanel}>
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
+ >
51
64
  <div className={s.mainPanel}>
52
- <NavPanel.Column>
65
+ {promo && isPromoOnTop ? (
66
+ <Promo
67
+ {...promo}
68
+ hasSidePanel={Boolean(sidePanel)}
69
+ isPromoOnTop={isPromoOnTop}
70
+ />
71
+ ) : null}
72
+ <NavPanel.Column hasSidePanel={Boolean(sidePanel)}>
53
73
  <ul className={s.productCategories}>
54
74
  {productCategories.map(({ title, products }) => {
55
75
  return (
56
76
  <li key={title} className={s.productCategory}>
57
- <TextPlus.Body className={s.eyebrow}>{title}</TextPlus.Body>
77
+ <Text className={s.eyebrow}>{title}</Text>
58
78
  <ul className={s.productList}>
59
79
  {products.map((product) => {
60
80
  return (
61
81
  <li key={product.url}>
62
- <NavProduct {...product} />
82
+ <NavProduct locale={locale} {...product} />
63
83
  </li>
64
84
  )
65
85
  })}
@@ -69,14 +89,16 @@ const ProductPanel = ({
69
89
  })}
70
90
  </ul>
71
91
  </NavPanel.Column>
72
- {promo ? <Promo {...promo} /> : null}
92
+ {promo && !isPromoOnTop ? (
93
+ <Promo {...promo} hasSidePanel={Boolean(sidePanel)} />
94
+ ) : null}
73
95
  </div>
74
96
 
75
97
  {sidePanel ? (
76
98
  <NavPanel.Column className={s.sidePanel}>
77
- <TextPlus.Body size="200" weight="semibold">
99
+ <Text size="200" weight="semibold">
78
100
  {sidePanel.label}
79
- </TextPlus.Body>
101
+ </Text>
80
102
 
81
103
  {/* ! TODO Replace the below list with the <LinkList /> component,
82
104
  That component will require a refactor to support greater customization
@@ -87,18 +109,22 @@ const ProductPanel = ({
87
109
  {sidePanel.navItems.map(({ icon, title, description, url }) => {
88
110
  return (
89
111
  <li key={title}>
90
- <Link href={parseUrl(url).href} className={s.sidePanelItem}>
112
+ <Link
113
+ aria-label={`${title} - ${description}`}
114
+ {...getLocalizedLinkProps(url, locale)}
115
+ locale={locale ? locale : undefined}
116
+ className={classNames(s.sidePanelItem, s.focusIndicator)}
117
+ >
91
118
  <div className={s.iconBackground}>
92
119
  <FlightIcon
93
- size={16}
94
120
  name={icon}
95
121
  color="var(--token-color-foreground-faint)"
96
122
  />
97
123
  </div>
98
124
  <div className={s.sidePanelItemContent}>
99
- <TextPlus.Body size="200" weight="semibold" tag="span">
125
+ <Text size="200" weight="semibold">
100
126
  {title}
101
- </TextPlus.Body>
127
+ </Text>
102
128
  <span className={s.sidePanelItemDesc}>{description}</span>
103
129
  </div>
104
130
  </Link>
@@ -113,16 +139,19 @@ const ProductPanel = ({
113
139
  }
114
140
 
115
141
  export interface NavProductProps {
142
+ locale?: string
116
143
  url: string
117
144
  product: Products | string
118
145
  description: string
119
146
  }
120
147
 
121
- function NavProduct({ url, product, description }: NavProductProps) {
148
+ function NavProduct({ locale, url, product, description }: NavProductProps) {
122
149
  return (
123
150
  <NavigationMenu.Link asChild>
124
151
  <Link
125
- href={parseUrl(url).href}
152
+ aria-label={`${product} - ${description}`}
153
+ {...getLocalizedLinkProps(url, locale)}
154
+ locale={locale ? locale : undefined}
126
155
  onClickCapture={() => {
127
156
  trackNavClickEvent(product, url, 'products')
128
157
  }}
@@ -131,13 +160,10 @@ function NavProduct({ url, product, description }: NavProductProps) {
131
160
  <div className={s.productWrapper}>
132
161
  <div className={s.productLogo}>
133
162
  <FlightIcon
134
- name={
135
- PRODUCT_LOGO_MAP.get('HCP Vault Secrets') ??
136
- 'hashicorp-fill-color'
137
- }
163
+ name={PRODUCT_LOGO_MAP.get(product) ?? 'hashicorp-fill-color'}
138
164
  className={
139
- PRODUCT_LOGO_EXCEPTION_CLASSNAMES['HCP Vault Secrets']
140
- ? s[PRODUCT_LOGO_EXCEPTION_CLASSNAMES['HCP Vault Secrets']]
165
+ PRODUCT_LOGO_EXCEPTION_CLASSNAMES[product]
166
+ ? s[PRODUCT_LOGO_EXCEPTION_CLASSNAMES[product]]
141
167
  : undefined
142
168
  }
143
169
  />
@@ -1,11 +1,47 @@
1
+ @custom-media --dev-dot-viewport (min-width: 924px);
2
+
1
3
  .productPanel {
2
4
  height: 100%;
3
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
+
4
29
  @media (--large) {
5
- display: grid;
6
- grid-template-rows: 1fr;
7
- grid-template-columns: max-content max-content;
8
- padding: 0;
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
+ }
9
45
  }
10
46
  }
11
47
 
@@ -13,10 +49,22 @@
13
49
  list-style: none;
14
50
  padding: 0;
15
51
  display: grid;
16
- margin: var(--hdsplus-spacing-06) 0 0;
52
+ margin: var(--mds-spacing-07) 0 0;
53
+
54
+ @nest .topPromo & {
55
+ margin-bottom: var(--mds-spacing-07);
56
+ }
17
57
 
18
58
  @media (--large) {
19
- margin: 0;
59
+ @nest .noSide & {
60
+ margin: 0;
61
+ }
62
+ }
63
+
64
+ @media (--dev-dot-viewport) {
65
+ @nest .hasSide & {
66
+ margin: 0;
67
+ }
20
68
  }
21
69
  }
22
70
 
@@ -27,18 +75,28 @@
27
75
 
28
76
  &:first-child {
29
77
  border-bottom: 1px solid var(--token-color-border-primary);
30
- margin-bottom: var(--hdsplus-spacing-05);
31
- padding-bottom: var(--hdsplus-spacing-05);
78
+ margin-bottom: var(--mds-spacing-05);
79
+ padding-bottom: var(--mds-spacing-05);
32
80
  }
33
81
  }
34
82
 
35
83
  .eyebrow {
36
- padding-bottom: var(--hdsplus-spacing-04);
84
+ padding-bottom: var(--mds-spacing-04);
37
85
  color: var(--token-color-foreground-strong);
38
- font-weight: var(--font-weight-semi-bold);
86
+ font-weight: var(--mds-typography-font-weight-semibold);
39
87
 
40
88
  @media (--large) {
41
- padding: 0 0 var(--hdsplus-spacing-01) var(--hdsplus-spacing-04);
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
+ }
42
100
  }
43
101
  }
44
102
 
@@ -50,10 +108,31 @@
50
108
  padding: 0;
51
109
 
52
110
  @media (--large) {
53
- grid-auto-flow: row;
54
- grid-template-columns: repeat(2, 300px);
55
- grid-template-rows: repeat(2, max-content);
56
- gap: 0;
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
+ }
57
136
  }
58
137
  }
59
138
 
@@ -61,16 +140,30 @@
61
140
 
62
141
  .productWrapper {
63
142
  display: flex;
64
- margin-bottom: var(--hdsplus-spacing-05);
65
- gap: var(--hdsplus-spacing-05);
143
+ margin-bottom: var(--mds-spacing-05);
144
+ gap: var(--mds-spacing-05);
66
145
 
67
146
  @media (--large) {
68
- padding: var(--hdsplus-spacing-05);
69
- margin-bottom: 0;
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
+ }
70
157
 
71
- &:hover {
72
- background-color: var(--token-color-surface-interactive-hover);
73
- border-radius: var(--hdsplus-spacing-01);
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
+ }
74
167
  }
75
168
  }
76
169
  }
@@ -81,10 +174,23 @@
81
174
  & svg {
82
175
  height: 42px;
83
176
  width: 42px;
177
+ }
84
178
 
85
- @media (--large) {
86
- height: var(--hdsplus-spacing-08);
87
- width: var(--hdsplus-spacing-08);
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
+ }
88
194
  }
89
195
  }
90
196
  }
@@ -117,8 +223,25 @@
117
223
  flex-direction: column;
118
224
 
119
225
  @media (--large) {
120
- padding: var(--hdsplus-spacing-05) 0 var(--hdsplus-spacing-05)
121
- var(--hdsplus-spacing-04);
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
+ }
122
245
  }
123
246
  }
124
247
 
@@ -127,10 +250,10 @@
127
250
  background: var(--token-color-surface-faint);
128
251
  display: flex;
129
252
  flex-direction: column;
130
- gap: var(--hdsplus-spacing-05);
253
+ gap: var(--mds-spacing-05);
131
254
  margin: 0;
132
- padding: var(--hdsplus-spacing-05) var(--hdsplus-spacing-07)
133
- var(--hdsplus-spacing-09) var(--hdsplus-spacing-07);
255
+ padding: var(--mds-spacing-07) var(--mds-spacing-04)
256
+ var(--mds-spacing-09) var(--mds-spacing-07);
134
257
  }
135
258
 
136
259
  .sidePanelItems {
@@ -139,26 +262,24 @@
139
262
  padding: 0;
140
263
  display: grid;
141
264
  grid-template-columns: 1fr;
142
- gap: var(--hdsplus-spacing-07);
265
+ gap: var(--mds-spacing-07);
143
266
 
144
- @media (--large) {
145
- gap: var(--hdsplus-spacing-05);
267
+ @media (--dev-dot-viewport) {
268
+ gap: var(--mds-spacing-05);
146
269
  }
147
270
  }
148
271
 
149
272
  /* Lifted from .productWrapper */
150
273
  .sidePanelItem {
151
274
  display: flex;
152
- margin-bottom: var(--hdsplus-spacing-05);
153
- gap: var(--hdsplus-spacing-05);
275
+ gap: var(--mds-spacing-05);
154
276
 
155
- @media (--large) {
156
- padding: var(--hdsplus-spacing-03) var(--hdsplus-spacing-05);
157
- margin-bottom: 0;
277
+ @media (--dev-dot-viewport) {
278
+ padding: var(--mds-spacing-03) var(--mds-spacing-05);
158
279
 
159
280
  &:hover {
160
281
  background-color: var(--token-color-surface-interactive-hover);
161
- border-radius: var(--hdsplus-spacing-01);
282
+ border-radius: var(--mds-spacing-01);
162
283
  }
163
284
  }
164
285
  }
@@ -167,8 +288,8 @@
167
288
  packages/react-components/src/components/nav-panel/components/link-list/style.module.css */
168
289
  .iconBackground {
169
290
  background: var(--token-color-foreground-high-contrast);
170
- height: var(--hdsplus-spacing-08);
171
- width: var(--hdsplus-spacing-08);
291
+ height: var(--mds-spacing-08);
292
+ width: var(--mds-spacing-08);
172
293
  display: flex;
173
294
  align-items: center;
174
295
  justify-content: center;
@@ -194,13 +315,28 @@ packages/react-components/src/components/nav-panel/components/link-list/style.mo
194
315
 
195
316
  /* Branding exception classnames */
196
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
+
197
333
  /* Styles for HCP Vault mimic the spec for `product-square` icons,
198
334
  while allowing the symbol inside the icon border to change color
199
335
  based on the site's theme
200
336
  */
201
337
  .hcpVaultSecrets,
202
338
  .hcpVaultRadar {
203
- padding: var(--hdsplus-spacing-01);
339
+ padding: var(--mds-spacing-01);
204
340
  border: 2px solid var(--token-color-vault-brand);
205
341
  border-radius: 3px;
206
342
 
@@ -12,12 +12,14 @@ interface StandardPanelProps {
12
12
  navData: NavItem[]
13
13
  promo?: PromoProps
14
14
  sectionName?: string
15
+ locale?: any
15
16
  }
16
17
 
17
18
  const StandardPanel = ({
18
19
  navData,
19
20
  promo,
20
21
  sectionName = '',
22
+ locale,
21
23
  }: StandardPanelProps) => {
22
24
  return (
23
25
  <NavPanel.Root>
@@ -26,6 +28,7 @@ const StandardPanel = ({
26
28
  return (
27
29
  <NavPanel.Column key={stableIdx}>
28
30
  <LinkList
31
+ locale={locale}
29
32
  links={navItems}
30
33
  linkClickHandler={(text, href) => {
31
34
  trackNavClickEvent(text, href, sectionName)
@@ -1,8 +1,8 @@
1
1
  .columns {
2
2
  display: flex;
3
- gap: var(--hdsplus-spacing-03);
3
+ gap: var(--mds-spacing-03);
4
4
  flex-direction: column;
5
- margin-top: var(--hdsplus-spacing-06);
5
+ margin-top: var(--mds-spacing-07);
6
6
 
7
7
  @media (--large) {
8
8
  flex-direction: row;
@@ -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
+ }
@@ -1,4 +1,4 @@
1
- import { parseUrl } from '.'
1
+ import { parseUrl, hasHashiCorpDestination } from '.'
2
2
 
3
3
  describe('parseUrl', () => {
4
4
  it('detects hashicorp.com URLs as internal', () => {
@@ -7,6 +7,12 @@ describe('parseUrl', () => {
7
7
  expect(url.linkType).toBe('inbound')
8
8
  })
9
9
 
10
+ it('detects www.hashicorp.com URLs as internal', () => {
11
+ const url = parseUrl('https://hashicorp.com/foo')
12
+ expect(url.href).toBe('/foo')
13
+ expect(url.linkType).toBe('inbound')
14
+ })
15
+
10
16
  it('detects URLs not containing hashicorp.com as external', () => {
11
17
  const externalUrl = 'https://google.com/example'
12
18
  const url = parseUrl(externalUrl)
@@ -27,4 +33,37 @@ describe('parseUrl', () => {
27
33
  )
28
34
  expect(url.href).toBe('/resources?type=case-study&products=terraform')
29
35
  })
36
+
37
+ it('leaves URL hash intact', () => {
38
+ const url = parseUrl('https://hashicorp.com/about#leadership')
39
+ expect(url.href).toBe('/about#leadership')
40
+ })
41
+
42
+ it('leaves HashiCorp subdomain URLs intact', () => {
43
+ const url = parseUrl('https://developer.hashicorp.com/terraform')
44
+ expect(url.href).toBe('https://developer.hashicorp.com/terraform')
45
+ })
46
+ })
47
+
48
+ describe('hasHashiCorpDestination', () => {
49
+ it('returns true for supported hashicorp domains', () => {
50
+ const isHashiCorpDestination = hasHashiCorpDestination(
51
+ 'https://portal.cloud.hashicorp.com/foo'
52
+ )
53
+ expect(isHashiCorpDestination).toBe(true)
54
+ })
55
+ it('returns false for external domains', () => {
56
+ const isHashiCorpDestination = hasHashiCorpDestination(
57
+ 'https://foo.com/bar'
58
+ )
59
+ expect(isHashiCorpDestination).toBe(false)
60
+ })
61
+ it('returns true for relative links', () => {
62
+ const isHashiCorpDestination = hasHashiCorpDestination('/bar')
63
+ expect(isHashiCorpDestination).toBe(true)
64
+ })
65
+ it('returns true for hashes', () => {
66
+ const isHashiCorpDestination = hasHashiCorpDestination('#someHash')
67
+ expect(isHashiCorpDestination).toBe(true)
68
+ })
30
69
  })