@hashicorp/react-components 0.0.0-canary.23632af → 0.0.0-canary.32599ff
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.
- package/package.json +6 -5
- package/src/components/actions/index.tsx +5 -5
- package/src/components/call-to-action/index.tsx +12 -10
- package/src/components/call-to-action/styles/variant-centered.module.css +5 -4
- package/src/components/call-to-action/styles/variant-compact-grid.module.css +6 -4
- package/src/components/call-to-action/styles/variant-compact.module.css +6 -4
- package/src/components/call-to-action/styles/variant-links.module.css +6 -11
- package/src/components/card/index.test.tsx +1 -1
- package/src/components/card/newsroom-card/index.test.tsx +1 -1
- package/src/components/card/newsroom-card/style.module.css +1 -1
- package/src/components/card/partner-card/index.tsx +5 -5
- package/src/components/card/person-card/index.tsx +3 -3
- package/src/components/card/primitives.tsx +20 -19
- package/src/components/card/resource-card/index.test.tsx +1 -1
- package/src/components/card/resource-card/index.tsx +3 -0
- package/src/components/card/style.module.css +2 -2
- package/src/components/card/types.ts +2 -2
- package/src/components/card/unified-card/index.spec.tsx +40 -0
- package/src/components/card/unified-card/index.tsx +5 -11
- package/src/components/inline-video/index.tsx +104 -0
- package/src/components/inline-video/style.module.css +99 -0
- package/src/components/intro/style.module.css +2 -2
- package/src/components/marketo-form/contexts/FormMetadata.ts +2 -0
- package/src/components/marketo-form/form/index.tsx +12 -7
- package/src/components/marketo-form/partials/fields/checkbox-field/index.tsx +1 -1
- package/src/components/marketo-form/partials/fields/email-field/index.tsx +1 -1
- package/src/components/marketo-form/partials/fields/form-page-url-field/index.tsx +12 -1
- package/src/components/marketo-form/partials/fields/hidden-field/index.tsx +1 -0
- package/src/components/marketo-form/partials/fields/htmltext-field/style.module.css +2 -2
- package/src/components/marketo-form/partials/fields/radio-buttons-field/index.tsx +1 -1
- package/src/components/marketo-form/partials/fields/select-field/index.tsx +1 -1
- package/src/components/marketo-form/partials/fields/telephone-field/index.tsx +1 -1
- package/src/components/marketo-form/partials/fields/text-field/index.tsx +1 -1
- package/src/components/marketo-form/partials/fields/textarea-field/index.tsx +1 -1
- package/src/components/marketo-form/types.ts +10 -12
- package/src/components/marketo-form/utils.ts +1 -1
- package/src/components/nav-panel/components/link-list/index.tsx +15 -9
- package/src/components/nav-panel/components/link-list/style.module.css +10 -10
- package/src/components/nav-panel/components/panel/column/style.module.css +3 -3
- package/src/components/nav-panel/components/panel/root/style.module.css +6 -6
- package/src/components/nav-panel/components/promo/index.tsx +15 -9
- package/src/components/nav-panel/components/promo/style.module.css +23 -13
- package/src/components/nav-panel/product-panel/index.tsx +36 -25
- package/src/components/nav-panel/product-panel/style.module.css +45 -41
- package/src/components/nav-panel/standard-panel/index.tsx +3 -0
- package/src/components/nav-panel/standard-panel/style.module.css +2 -2
- package/src/components/next-steps/index.tsx +3 -2
- package/src/components/next-steps/style.module.css +18 -18
- package/src/components/product-badge/index.tsx +1 -1
- package/src/components/product-badge/style.module.css +2 -2
- package/src/components/products-used/style.module.css +7 -7
- package/src/components/related-content/index.tsx +28 -29
- package/src/components/related-content/style.module.css +58 -60
- package/src/components/related-content/types.ts +2 -2
- package/src/components/subnav/index.tsx +12 -3
- package/src/components/subnav/partials/CtaLinks/github-stars-link/style.module.css +8 -12
- package/src/components/subnav/partials/CtaLinks/index.tsx +9 -8
- package/src/components/subnav/partials/CtaLinks/style.module.css +6 -6
- package/src/components/subnav/partials/DropdownTrigger/index.tsx +2 -2
- package/src/components/subnav/partials/DropdownTrigger/style.module.css +11 -8
- package/src/components/subnav/partials/MenuItemsDefault/index.tsx +24 -8
- package/src/components/subnav/partials/MenuItemsDefault/style.module.css +44 -31
- package/src/components/subnav/partials/MenuItemsOverflow/index.tsx +17 -4
- package/src/components/subnav/partials/MenuItemsOverflow/style.module.css +24 -18
- package/src/components/subnav/partials/TitleLink/index.tsx +6 -4
- package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-dark.ts +2 -1
- package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-light.ts +2 -1
- package/src/components/subnav/partials/TitleLink/style.module.css +3 -3
- package/src/components/subnav/partials/nav-item-text/style.module.css +2 -4
- package/src/components/subnav/style.module.css +5 -7
- package/src/lib/get-localized-link-props/index.test.ts +30 -0
- package/src/lib/get-localized-link-props/index.ts +45 -0
- package/src/lib/parse-url/index.test.ts +40 -1
- package/src/lib/parse-url/index.ts +75 -9
- package/src/lib/supported-locales/index.ts +1 -0
- package/src/lib/track-nav-click-event/index.ts +4 -4
- package/src/lib/v/index.ts +4 -5
- package/src/components/consent-manager/README.md +0 -73
- package/src/components/consent-manager/components/banner/banner.module.css +0 -23
- package/src/components/consent-manager/components/banner/banner.test.tsx +0 -31
- package/src/components/consent-manager/components/banner/banner.tsx +0 -73
- package/src/components/consent-manager/components/dialog/dialog.module.css +0 -145
- package/src/components/consent-manager/components/dialog/dialog.test.tsx +0 -194
- package/src/components/consent-manager/components/dialog/dialog.tsx +0 -339
- package/src/components/consent-manager/img/icn_close.tsx +0 -19
- package/src/components/consent-manager/index.test.tsx +0 -334
- package/src/components/consent-manager/index.tsx +0 -186
- package/src/components/consent-manager/loader/README.md +0 -29
- package/src/components/consent-manager/loader/categories.ts +0 -22
- package/src/components/consent-manager/loader/index.tsx +0 -94
- package/src/components/consent-manager/loader/presets/enterprise.ts +0 -12
- package/src/components/consent-manager/loader/presets/oss.ts +0 -10
- package/src/components/consent-manager/loader/services.ts +0 -45
- package/src/components/consent-manager/scripts/custom.tsx +0 -59
- package/src/components/consent-manager/scripts/segment.tsx +0 -87
- package/src/components/consent-manager/style.module.css +0 -9
- package/src/components/consent-manager/types.ts +0 -55
- package/src/components/consent-manager/util/cookies.test.ts +0 -75
- package/src/components/consent-manager/util/cookies.ts +0 -70
- package/src/components/consent-manager/util/integrations.test.ts +0 -115
- package/src/components/consent-manager/util/integrations.ts +0 -110
- package/src/components/subnav/theme.module.css +0 -50
|
@@ -9,22 +9,30 @@ import NavItemText from '../nav-item-text'
|
|
|
9
9
|
import DropdownTrigger from '../DropdownTrigger'
|
|
10
10
|
import * as NavigationMenu from '@radix-ui/react-navigation-menu'
|
|
11
11
|
import s from './style.module.css'
|
|
12
|
+
import FlightIcon from '@hashicorp/react-mds/src/hds/components/flight-icon'
|
|
13
|
+
import { getLocalizedLinkProps } from '../../../../lib/get-localized-link-props'
|
|
12
14
|
|
|
13
15
|
interface MenuItemsDefaultProps {
|
|
14
16
|
menuItems: (
|
|
15
17
|
| {
|
|
16
18
|
text: string
|
|
17
19
|
url: string
|
|
18
|
-
submenu: {
|
|
20
|
+
submenu: {
|
|
21
|
+
icon: string
|
|
22
|
+
text: string
|
|
23
|
+
url: string
|
|
24
|
+
_isActiveUrl: string
|
|
25
|
+
}[]
|
|
19
26
|
_isActiveUrl: boolean
|
|
20
27
|
}
|
|
21
28
|
| 'divider'
|
|
22
29
|
)[]
|
|
23
30
|
activatePanel: (panel: string) => void
|
|
31
|
+
locale?: string
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
function MenuItemsDefault(props: MenuItemsDefaultProps) {
|
|
27
|
-
const { menuItems, activatePanel } = props
|
|
35
|
+
const { menuItems, activatePanel, locale } = props
|
|
28
36
|
return (
|
|
29
37
|
<NavigationMenu.List className={s.root}>
|
|
30
38
|
{menuItems.map((menuItem, stableIdx) => {
|
|
@@ -41,6 +49,7 @@ function MenuItemsDefault(props: MenuItemsDefaultProps) {
|
|
|
41
49
|
text={text}
|
|
42
50
|
submenu={submenu}
|
|
43
51
|
activatePanel={activatePanel}
|
|
52
|
+
locale={locale}
|
|
44
53
|
/>
|
|
45
54
|
) : (
|
|
46
55
|
<NavLink
|
|
@@ -50,6 +59,7 @@ function MenuItemsDefault(props: MenuItemsDefaultProps) {
|
|
|
50
59
|
text={text}
|
|
51
60
|
url={url}
|
|
52
61
|
isActive={_isActiveUrl}
|
|
62
|
+
locale={locale}
|
|
53
63
|
/>
|
|
54
64
|
)
|
|
55
65
|
})}
|
|
@@ -69,14 +79,15 @@ interface NavLinkProps {
|
|
|
69
79
|
text: string
|
|
70
80
|
url: string
|
|
71
81
|
isActive: boolean
|
|
82
|
+
locale?: string
|
|
72
83
|
}
|
|
73
84
|
|
|
74
85
|
function NavLink(props: NavLinkProps) {
|
|
75
|
-
const { text, url, isActive } = props
|
|
86
|
+
const { text, url, isActive, locale } = props
|
|
76
87
|
return (
|
|
77
88
|
<NavigationMenu.Item className={s.listItem}>
|
|
78
89
|
<NavigationMenu.Link asChild>
|
|
79
|
-
<Link className={s.navLink}
|
|
90
|
+
<Link className={s.navLink} {...getLocalizedLinkProps(url, locale)}>
|
|
80
91
|
<NavItemText isActive={isActive} text={text} />
|
|
81
92
|
</Link>
|
|
82
93
|
</NavigationMenu.Link>
|
|
@@ -86,8 +97,9 @@ function NavLink(props: NavLinkProps) {
|
|
|
86
97
|
|
|
87
98
|
interface NavLinkWithDropdownProps {
|
|
88
99
|
text: string
|
|
89
|
-
submenu: { text: string; url: string; _isActiveUrl: string }[]
|
|
100
|
+
submenu: { icon: string; text: string; url: string; _isActiveUrl: string }[]
|
|
90
101
|
activatePanel: (panel: string) => void
|
|
102
|
+
locale?: string
|
|
91
103
|
}
|
|
92
104
|
|
|
93
105
|
interface NavLinkWithDropdownState {
|
|
@@ -99,7 +111,7 @@ class NavLinkWithDropdown extends React.Component<
|
|
|
99
111
|
NavLinkWithDropdownState
|
|
100
112
|
> {
|
|
101
113
|
render() {
|
|
102
|
-
const { text, submenu, activatePanel } = this.props
|
|
114
|
+
const { text, submenu, activatePanel, locale } = this.props
|
|
103
115
|
const hasActiveChild = submenu.some((s) => s._isActiveUrl)
|
|
104
116
|
|
|
105
117
|
const handleFocusOutside = () => {
|
|
@@ -128,12 +140,16 @@ class NavLinkWithDropdown extends React.Component<
|
|
|
128
140
|
<NavigationMenu.Sub>
|
|
129
141
|
<NavigationMenu.List className={s.dropdownList}>
|
|
130
142
|
{submenu.map((submenuItem, stableIdx) => {
|
|
131
|
-
const { text, url } = submenuItem
|
|
143
|
+
const { icon, text, url } = submenuItem
|
|
132
144
|
return (
|
|
133
145
|
// eslint-disable-next-line react/no-array-index-key
|
|
134
146
|
<NavigationMenu.Item key={stableIdx}>
|
|
135
147
|
<NavigationMenu.Link asChild>
|
|
136
|
-
<Link
|
|
148
|
+
<Link
|
|
149
|
+
className={s.submenuItem}
|
|
150
|
+
{...getLocalizedLinkProps(url, locale)}
|
|
151
|
+
>
|
|
152
|
+
{icon ? <FlightIcon name={icon} /> : null}
|
|
137
153
|
{text}
|
|
138
154
|
</Link>
|
|
139
155
|
</NavigationMenu.Link>
|
|
@@ -3,11 +3,9 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MPL-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
/* Note: consumes from theme.module.css, as marked */
|
|
7
|
-
|
|
8
6
|
.root {
|
|
9
7
|
display: flex;
|
|
10
|
-
padding: 0 0 0 var(--
|
|
8
|
+
padding: 0 0 0 var(--mds-spacing-08);
|
|
11
9
|
margin: 0;
|
|
12
10
|
align-items: center;
|
|
13
11
|
justify-content: flex-end;
|
|
@@ -16,23 +14,22 @@
|
|
|
16
14
|
|
|
17
15
|
.listItem {
|
|
18
16
|
position: relative;
|
|
19
|
-
white-space: nowrap;
|
|
20
17
|
margin: 0;
|
|
21
18
|
padding: 0;
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
.navLink {
|
|
25
|
-
composes:
|
|
26
|
-
composes:
|
|
22
|
+
composes: token-typography-body-200 from global;
|
|
23
|
+
composes: mds-typography-font-weight-medium from global;
|
|
27
24
|
position: relative;
|
|
28
|
-
padding: var(--
|
|
25
|
+
padding: var(--mds-spacing-04);
|
|
29
26
|
display: flex;
|
|
30
27
|
align-items: center;
|
|
31
28
|
white-space: nowrap;
|
|
32
29
|
|
|
33
30
|
&:hover {
|
|
34
|
-
background-color: var(--
|
|
35
|
-
border-radius: var(--
|
|
31
|
+
background-color: var(--token-color-surface-interactive-hover);
|
|
32
|
+
border-radius: var(--mds-spacing-01);
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
&:focus {
|
|
@@ -42,43 +39,58 @@
|
|
|
42
39
|
}
|
|
43
40
|
|
|
44
41
|
.submenuItem {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
--submenu-item-background-color: transparent;
|
|
43
|
+
|
|
44
|
+
position: relative;
|
|
45
|
+
composes: token-typography-body-200 from global;
|
|
46
|
+
composes: mds-typography-font-weight-medium from global;
|
|
47
|
+
color: var(--token-color-foreground-primary);
|
|
48
|
+
display: flex;
|
|
49
|
+
gap: var(--mds-spacing-04);
|
|
50
|
+
padding: var(--mds-spacing-03);
|
|
51
|
+
min-width: 190px;
|
|
52
|
+
align-items: center;
|
|
53
|
+
|
|
54
|
+
&::before {
|
|
55
|
+
content: "";
|
|
56
|
+
position: absolute;
|
|
57
|
+
z-index: -1;
|
|
58
|
+
inset: 2px 0;
|
|
59
|
+
border-radius: var(--mds-spacing-01);
|
|
60
|
+
background-color: var(--submenu-item-background-color);
|
|
61
|
+
}
|
|
49
62
|
|
|
50
63
|
&:hover {
|
|
51
|
-
|
|
64
|
+
--submenu-item-background-color: var(--token-color-surface-interactive-hover);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@media (--large) {
|
|
68
|
+
max-width: 416px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&:focus {
|
|
72
|
+
outline: 2px solid var(--token-color-focus-action-internal);
|
|
73
|
+
outline-style: auto;
|
|
52
74
|
}
|
|
53
75
|
}
|
|
54
76
|
|
|
55
77
|
.submenuModal {
|
|
56
|
-
border-radius:
|
|
57
|
-
|
|
58
|
-
|
|
78
|
+
border-radius: var(--mds-spacing-03);
|
|
79
|
+
border: 1px solid var(--token-color-border-primary);
|
|
80
|
+
box-shadow: var(--token-elevation-high-box-shadow);
|
|
81
|
+
background: var(--token-color-surface-primary);
|
|
59
82
|
z-index: 1;
|
|
60
|
-
display: block;
|
|
61
83
|
position: absolute;
|
|
62
84
|
top: 100%;
|
|
63
|
-
margin:
|
|
64
|
-
padding:
|
|
85
|
+
margin: var(--mds-spacing-03) 0 0 0;
|
|
86
|
+
padding: var(--mds-spacing-04);
|
|
65
87
|
left: 100%;
|
|
66
88
|
transform: translateX(-100%);
|
|
67
89
|
list-style: none;
|
|
68
|
-
|
|
69
|
-
& li {
|
|
70
|
-
& a:hover .text {
|
|
71
|
-
text-decoration: underline;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
& + li {
|
|
75
|
-
margin-top: 6px;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
90
|
}
|
|
79
91
|
|
|
80
92
|
.verticalDivider {
|
|
81
|
-
background: var(--border-
|
|
93
|
+
background: var(--token-color-border-primary);
|
|
82
94
|
height: 1.75rem;
|
|
83
95
|
width: 1px;
|
|
84
96
|
margin: 0 8px;
|
|
@@ -86,6 +98,7 @@
|
|
|
86
98
|
}
|
|
87
99
|
|
|
88
100
|
.dropdownList {
|
|
101
|
+
min-width: max-content;
|
|
89
102
|
list-style: none;
|
|
90
103
|
padding: 0;
|
|
91
104
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from 'react'
|
|
7
|
-
import {
|
|
7
|
+
import { vercelSplit } from '../../../../lib/v'
|
|
8
8
|
import Link from 'next/link'
|
|
9
9
|
import type { Products } from '@hashicorp/platform-product-meta'
|
|
10
10
|
import CtaLinks, { type CtaLinkProps } from '../CtaLinks'
|
|
@@ -12,6 +12,8 @@ import DropdownTrigger from '../DropdownTrigger'
|
|
|
12
12
|
import * as NavigationMenu from '@radix-ui/react-navigation-menu'
|
|
13
13
|
import classNames from 'classnames'
|
|
14
14
|
import s from './style.module.css'
|
|
15
|
+
import FlightIcon from '@hashicorp/react-mds/src/hds/components/flight-icon'
|
|
16
|
+
import { getLocalizedLinkProps } from '../../../../lib/get-localized-link-props'
|
|
15
17
|
|
|
16
18
|
interface MenuItemsOverflowProps {
|
|
17
19
|
menuItems: (
|
|
@@ -19,7 +21,7 @@ interface MenuItemsOverflowProps {
|
|
|
19
21
|
| {
|
|
20
22
|
text: string
|
|
21
23
|
url: string
|
|
22
|
-
submenu: { url: string; text: string }[]
|
|
24
|
+
submenu: { icon: string; url: string; text: string }[]
|
|
23
25
|
}
|
|
24
26
|
)[]
|
|
25
27
|
ctaLinks: CtaLinkProps
|
|
@@ -28,6 +30,7 @@ interface MenuItemsOverflowProps {
|
|
|
28
30
|
menuText: string
|
|
29
31
|
constrainWidth?: boolean
|
|
30
32
|
activatePanel: (panel: string) => void
|
|
33
|
+
locale?: string
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
interface MenuItemsOverflowState {
|
|
@@ -47,6 +50,7 @@ class MenuItemsOverflow extends React.Component<
|
|
|
47
50
|
menuText,
|
|
48
51
|
constrainWidth,
|
|
49
52
|
activatePanel,
|
|
53
|
+
locale,
|
|
50
54
|
} = this.props
|
|
51
55
|
|
|
52
56
|
const handleFocusOutside = () => {
|
|
@@ -89,6 +93,8 @@ class MenuItemsOverflow extends React.Component<
|
|
|
89
93
|
key={subStableIdx}
|
|
90
94
|
url={subItem.url}
|
|
91
95
|
text={subItem.text}
|
|
96
|
+
icon={subItem.icon}
|
|
97
|
+
locale={locale}
|
|
92
98
|
/>
|
|
93
99
|
))}
|
|
94
100
|
<hr className={s.divider} />
|
|
@@ -120,15 +126,22 @@ class MenuItemsOverflow extends React.Component<
|
|
|
120
126
|
}
|
|
121
127
|
|
|
122
128
|
interface SubmenuItemProps {
|
|
129
|
+
icon?: string
|
|
123
130
|
url: string
|
|
124
131
|
text: string
|
|
132
|
+
locale?: string
|
|
125
133
|
}
|
|
126
134
|
|
|
127
|
-
function SubmenuItem({ url, text }: SubmenuItemProps) {
|
|
135
|
+
function SubmenuItem({ icon, url, text, locale }: SubmenuItemProps) {
|
|
128
136
|
return (
|
|
129
137
|
<li>
|
|
130
138
|
<NavigationMenu.Link asChild>
|
|
131
|
-
<Link
|
|
139
|
+
<Link
|
|
140
|
+
className={s.submenuItem}
|
|
141
|
+
title={vercelSplit(text)}
|
|
142
|
+
{...getLocalizedLinkProps(url, locale)}
|
|
143
|
+
>
|
|
144
|
+
{icon ? <FlightIcon name={icon} /> : null}
|
|
132
145
|
{text}
|
|
133
146
|
</Link>
|
|
134
147
|
</NavigationMenu.Link>
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MPL-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
/* Note: consumes from theme.module.css, as marked */
|
|
7
|
-
|
|
8
6
|
.root {
|
|
9
7
|
position: relative;
|
|
10
8
|
display: flex;
|
|
@@ -12,18 +10,18 @@
|
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
.dropdown {
|
|
15
|
-
background: var(--
|
|
16
|
-
border-radius:
|
|
13
|
+
background: var(--token-color-surface-primary);
|
|
14
|
+
border-radius: var(--mds-spacing-03);
|
|
17
15
|
box-shadow: var(--token-elevation-high-box-shadow);
|
|
18
|
-
border: 1px solid var(--border-
|
|
16
|
+
border: 1px solid var(--token-color-border-primary);
|
|
19
17
|
margin-top: 8px;
|
|
20
18
|
max-height: calc(100vh - 300%);
|
|
21
19
|
overflow-y: auto;
|
|
22
|
-
padding: var(--
|
|
20
|
+
padding: var(--mds-spacing-04);
|
|
23
21
|
position: absolute;
|
|
24
22
|
right: 0;
|
|
25
23
|
top: 100%;
|
|
26
|
-
width: calc(100vw - var(--
|
|
24
|
+
width: calc(100vw - var(--mds-spacing-08));
|
|
27
25
|
z-index: 1;
|
|
28
26
|
|
|
29
27
|
@nest :global(.hashidaysConference) & {
|
|
@@ -32,7 +30,7 @@
|
|
|
32
30
|
|
|
33
31
|
&.constrained {
|
|
34
32
|
max-width: 568px;
|
|
35
|
-
width: calc(100vw - var(--
|
|
33
|
+
width: calc(100vw - var(--mds-spacing-10));
|
|
36
34
|
|
|
37
35
|
@media (--medium-up) {
|
|
38
36
|
width: max-content;
|
|
@@ -52,27 +50,35 @@
|
|
|
52
50
|
|
|
53
51
|
.submenuTitle {
|
|
54
52
|
composes: g-type-label from global;
|
|
55
|
-
margin:
|
|
56
|
-
color: var(--
|
|
53
|
+
margin: var(--mds-spacing-04) var(--mds-spacing-03) 8px;
|
|
54
|
+
color: var(--token-color-foreground-faint);
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
.divider {
|
|
60
|
-
margin:
|
|
58
|
+
margin: var(--mds-spacing-04) var(--mds-spacing-03);
|
|
61
59
|
border: 0;
|
|
62
60
|
padding: 0;
|
|
63
61
|
height: 1px;
|
|
64
|
-
background: var(--border-
|
|
62
|
+
background: var(--token-color-border-primary);
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
.submenuItem {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
composes: token-typography-body-300 from global;
|
|
67
|
+
composes: mds-typography-font-weight-semibold from global;
|
|
68
|
+
display: flex;
|
|
69
|
+
gap: var(--mds-spacing-04);
|
|
70
|
+
padding: var(--mds-spacing-02) var(--mds-spacing-03);
|
|
71
|
+
color: var(--token-color-foreground-primary);
|
|
72
|
+
border-radius: var(--mds-spacing-01);
|
|
73
|
+
align-items: center;
|
|
73
74
|
|
|
74
75
|
&:hover {
|
|
75
|
-
|
|
76
|
+
background-color: var(--token-color-surface-interactive-hover);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&:focus {
|
|
80
|
+
outline: 2px solid var(--token-color-focus-action-internal);
|
|
81
|
+
outline-style: auto;
|
|
76
82
|
}
|
|
77
83
|
}
|
|
78
84
|
|
|
@@ -7,7 +7,7 @@ import { forwardRef } from 'react'
|
|
|
7
7
|
import { camelCase } from 'camel-case'
|
|
8
8
|
import Link from 'next/link'
|
|
9
9
|
import Image from 'next/image'
|
|
10
|
-
import {
|
|
10
|
+
import { vercelSplit } from '../../../../lib/v'
|
|
11
11
|
import classNames from 'classnames'
|
|
12
12
|
import * as CommunityProductLogosOnDark from './mktg-logos/all-community-product-logos_on-dark'
|
|
13
13
|
import * as CommunityProductLogosOnLight from './mktg-logos/all-community-product-logos_on-light'
|
|
@@ -22,6 +22,7 @@ import WaypointLogoAttrOnDark from '@hashicorp/web-mktg-logos/src/waypoint/hashi
|
|
|
22
22
|
import HCPTerraformLogoOnLight from '@hashicorp/web-mktg-logos/src/terraform/hcp-terraform/hcp-terraform_on-light.svg'
|
|
23
23
|
import HCPTerraformLogoOnDark from '@hashicorp/web-mktg-logos/src/terraform/hcp-terraform/hcp-terraform_on-dark.svg'
|
|
24
24
|
import s from './style.module.css'
|
|
25
|
+
import { getLocalizedLinkProps } from '../../../../lib/get-localized-link-props'
|
|
25
26
|
|
|
26
27
|
const logoDict = {
|
|
27
28
|
light: {
|
|
@@ -41,6 +42,7 @@ const logoDict = {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
interface TitleLinkProps {
|
|
45
|
+
locale?: string
|
|
44
46
|
text: string
|
|
45
47
|
url: string
|
|
46
48
|
product?: string
|
|
@@ -80,8 +82,8 @@ function getLogo(
|
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
const TitleLink = forwardRef<HTMLAnchorElement, TitleLinkProps>(
|
|
83
|
-
({ text, url, product, theme }, ref) => {
|
|
84
|
-
const parsedText =
|
|
85
|
+
({ text, url, product, theme, locale }, ref) => {
|
|
86
|
+
const parsedText = vercelSplit(text)
|
|
85
87
|
const Logo = getLogo(parsedText, theme)
|
|
86
88
|
|
|
87
89
|
return (
|
|
@@ -91,9 +93,9 @@ const TitleLink = forwardRef<HTMLAnchorElement, TitleLinkProps>(
|
|
|
91
93
|
s[`brand-${product}`],
|
|
92
94
|
s[camelCase(parsedText)]
|
|
93
95
|
)}
|
|
94
|
-
href={url}
|
|
95
96
|
title={parsedText}
|
|
96
97
|
ref={ref}
|
|
98
|
+
{...getLocalizedLinkProps(url, locale)}
|
|
97
99
|
>
|
|
98
100
|
{Logo ? (
|
|
99
101
|
<Image
|
package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-dark.ts
CHANGED
|
@@ -5,5 +5,6 @@ import packer from '@hashicorp/web-mktg-logos/src/packer/packer-community/packer
|
|
|
5
5
|
import terraform from '@hashicorp/web-mktg-logos/src/terraform/terraform-community/terraform-community_on-dark.svg'
|
|
6
6
|
import vagrant from '@hashicorp/web-mktg-logos/src/vagrant/vagrant-community/vagrant-community_on-dark.svg'
|
|
7
7
|
import vault from '@hashicorp/web-mktg-logos/src/vault/vault-community/vault-community_on-dark.svg'
|
|
8
|
+
import waypoint from '@hashicorp/web-mktg-logos/src/waypoint/hashicorp-waypoint-attributed/hashicorp-waypoint_on-dark.svg'
|
|
8
9
|
|
|
9
|
-
export { boundary, consul, nomad, packer, terraform, vagrant, vault }
|
|
10
|
+
export { boundary, consul, nomad, packer, terraform, vagrant, vault, waypoint }
|
package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-light.ts
CHANGED
|
@@ -5,5 +5,6 @@ import packer from '@hashicorp/web-mktg-logos/src/packer/packer-community/packer
|
|
|
5
5
|
import terraform from '@hashicorp/web-mktg-logos/src/terraform/terraform-community/terraform-community_on-light.svg'
|
|
6
6
|
import vagrant from '@hashicorp/web-mktg-logos/src/vagrant/vagrant-community/vagrant-community_on-light.svg'
|
|
7
7
|
import vault from '@hashicorp/web-mktg-logos/src/vault/vault-community/vault-community_on-light.svg'
|
|
8
|
+
import waypoint from '@hashicorp/web-mktg-logos/src/waypoint/hashicorp-waypoint-attributed/hashicorp-waypoint_on-light.svg'
|
|
8
9
|
|
|
9
|
-
export { boundary, consul, nomad, packer, terraform, vagrant, vault }
|
|
10
|
+
export { boundary, consul, nomad, packer, terraform, vagrant, vault, waypoint }
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
.root {
|
|
9
9
|
position: relative;
|
|
10
10
|
display: inline-flex;
|
|
11
|
-
padding-block: var(--
|
|
12
|
-
font-weight: var(--font-weight-bold);
|
|
13
|
-
color: var(--
|
|
11
|
+
padding-block: var(--mds-spacing-04);
|
|
12
|
+
font-weight: var(--mds-typography-font-weight-bold);
|
|
13
|
+
color: var(--token-color-foreground-primary); /* from theme.module.css */
|
|
14
14
|
font-size: 1.25rem;
|
|
15
15
|
line-height: 1.35rem;
|
|
16
16
|
|
|
@@ -3,13 +3,11 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MPL-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
/* Note: consumes from theme.module.css, as marked */
|
|
7
|
-
|
|
8
6
|
.root {
|
|
9
|
-
color: var(--
|
|
7
|
+
color: var(--token-color-foreground-primary);
|
|
10
8
|
position: relative;
|
|
11
9
|
|
|
12
10
|
&.isActive {
|
|
13
|
-
color: var(--
|
|
11
|
+
color: var(--token-color-foreground-strong);
|
|
14
12
|
}
|
|
15
13
|
}
|
|
@@ -3,19 +3,17 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MPL-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
/* Note: consumes from theme.module.css, as marked */
|
|
7
|
-
|
|
8
6
|
.root {
|
|
9
7
|
position: sticky;
|
|
10
8
|
top: -1px;
|
|
11
9
|
z-index: 900;
|
|
12
|
-
background: var(--
|
|
13
|
-
border-top: 1px solid var(--border-
|
|
10
|
+
background: var(--token-color-surface-primary);
|
|
11
|
+
border-top: 1px solid var(--token-color-border-faint);
|
|
14
12
|
border-bottom: 1px solid transparent;
|
|
15
13
|
transition: border-bottom-color 0.8s;
|
|
16
14
|
|
|
17
15
|
&.isSticky {
|
|
18
|
-
border-bottom-color: var(--border-
|
|
16
|
+
border-bottom-color: var(--token-color-border-faint);
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
/*
|
|
@@ -46,7 +44,7 @@
|
|
|
46
44
|
|
|
47
45
|
.subnavInner {
|
|
48
46
|
display: grid;
|
|
49
|
-
grid-template-columns:
|
|
47
|
+
grid-template-columns: max-content min-content;
|
|
50
48
|
align-items: center;
|
|
51
49
|
justify-content: space-between;
|
|
52
50
|
min-height: 62px;
|
|
@@ -58,7 +56,7 @@
|
|
|
58
56
|
|
|
59
57
|
&.notConstrained {
|
|
60
58
|
/* This padding should always match the horizontal padding of the main nav */
|
|
61
|
-
padding: 0 var(--
|
|
59
|
+
padding: 0 var(--mds-spacing-05);
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
|
|
@@ -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
|
})
|