@hashicorp/react-components 0.0.0-nightly.10f9286 → 0.0.0-nightly.1679700
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/.eslintrc.js +1 -2
- package/.stylelintrc.js +1 -1
- package/README.md +1 -1
- package/package.json +1 -1
- package/postcss.config.js +1 -1
- package/src/components/nav-panel/components/flight-icon/style.module.css +1 -1
- package/src/components/nav-panel/components/link/index.tsx +107 -0
- package/src/components/nav-panel/components/link/style.module.css +64 -0
- package/src/components/nav-panel/components/link-list/index.tsx +7 -64
- package/src/components/nav-panel/components/link-list/style.module.css +0 -49
- package/src/components/nav-panel/components/promo/index.tsx +22 -8
- package/src/components/nav-panel/product-panel/index.tsx +21 -4
- package/src/components/nav-panel/product-panel/style.module.css +39 -0
package/.eslintrc.js
CHANGED
package/.stylelintrc.js
CHANGED
package/README.md
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# `@hashicorp/react-components`
|
|
2
2
|
|
|
3
|
-
This package contains React components that are built using HDS guidelines that don't align with existing HDS components.
|
|
3
|
+
This package contains React components that are built using HDS guidelines that don't align with existing HDS components.
|
package/package.json
CHANGED
package/postcss.config.js
CHANGED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import Link from 'next/link'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import { vercelSplit } from '../../../../lib/v'
|
|
4
|
+
import { getLocalizedLinkProps } from '../../../../lib/get-localized-link-props'
|
|
5
|
+
import FlightIcon from '../flight-icon'
|
|
6
|
+
import * as NavigationMenu from '@radix-ui/react-navigation-menu'
|
|
7
|
+
import s from './style.module.css'
|
|
8
|
+
|
|
9
|
+
interface NavLinkProps {
|
|
10
|
+
title: string
|
|
11
|
+
url: string
|
|
12
|
+
icon?: string
|
|
13
|
+
description?: string
|
|
14
|
+
iconGradient?: string
|
|
15
|
+
iconAppearance?: 'light' | 'dark'
|
|
16
|
+
linkClickHandler?: (title: string, url: string) => void
|
|
17
|
+
locale?: string
|
|
18
|
+
className?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const GRADIENT_VALUE_MAP = new Map([
|
|
22
|
+
[
|
|
23
|
+
'ILM',
|
|
24
|
+
{
|
|
25
|
+
iconGradient: {
|
|
26
|
+
light: 'var(--icon-gradient-infrastructure-lifecycle-management)',
|
|
27
|
+
dark: 'var(--icon-gradient-infrastructure-lifecycle-management-dark)',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
'SLM',
|
|
33
|
+
{
|
|
34
|
+
iconGradient: {
|
|
35
|
+
light: 'var(--icon-gradient-security-lifecycle-management)',
|
|
36
|
+
dark: 'var(--icon-gradient-security-lifecycle-management-dark)',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
[
|
|
41
|
+
'Cloud',
|
|
42
|
+
{
|
|
43
|
+
iconGradient: {
|
|
44
|
+
light: 'var(--icon-gradient-infrastructure-cloud)',
|
|
45
|
+
dark: 'var(--icon-gradient-infrastructure-cloud-dark)',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
])
|
|
50
|
+
|
|
51
|
+
export default function NavLink({
|
|
52
|
+
url,
|
|
53
|
+
title,
|
|
54
|
+
description,
|
|
55
|
+
icon,
|
|
56
|
+
iconGradient,
|
|
57
|
+
iconAppearance = 'light',
|
|
58
|
+
linkClickHandler,
|
|
59
|
+
locale,
|
|
60
|
+
className,
|
|
61
|
+
}: NavLinkProps) {
|
|
62
|
+
const style = iconGradient
|
|
63
|
+
? {
|
|
64
|
+
['--iconGradient' as string]: GRADIENT_VALUE_MAP.get(
|
|
65
|
+
vercelSplit(iconGradient)
|
|
66
|
+
)?.iconGradient[vercelSplit(iconAppearance)],
|
|
67
|
+
}
|
|
68
|
+
: undefined
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<NavigationMenu.Link asChild>
|
|
72
|
+
<Link
|
|
73
|
+
className={classNames(s.link, className)}
|
|
74
|
+
{...getLocalizedLinkProps(url, locale)}
|
|
75
|
+
onClickCapture={() => {
|
|
76
|
+
linkClickHandler && linkClickHandler(title, url)
|
|
77
|
+
}}
|
|
78
|
+
>
|
|
79
|
+
{iconGradient && icon ? (
|
|
80
|
+
<div
|
|
81
|
+
className={s.iconBackground}
|
|
82
|
+
style={style}
|
|
83
|
+
data-theme={iconAppearance}
|
|
84
|
+
>
|
|
85
|
+
<FlightIcon
|
|
86
|
+
name={vercelSplit(icon)}
|
|
87
|
+
color="var(--token-color-foreground-strong)"
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
) : (
|
|
91
|
+
icon && (
|
|
92
|
+
<div className={s.iconWrapper}>
|
|
93
|
+
<FlightIcon
|
|
94
|
+
name={vercelSplit(icon)}
|
|
95
|
+
color="var(--token-color-foreground-faint)"
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
)
|
|
99
|
+
)}
|
|
100
|
+
<div>
|
|
101
|
+
<div className={iconGradient && s.boldTitle}>{title}</div>
|
|
102
|
+
{description && <div className={s.description}>{description}</div>}
|
|
103
|
+
</div>
|
|
104
|
+
</Link>
|
|
105
|
+
</NavigationMenu.Link>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
.linkList {
|
|
2
|
+
display: flex;
|
|
3
|
+
list-style: none;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: var(--mds-spacing-03);
|
|
6
|
+
margin: 0;
|
|
7
|
+
padding: 0;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.link {
|
|
11
|
+
color: var(--token-color-foreground-primary);
|
|
12
|
+
display: flex;
|
|
13
|
+
gap: var(--mds-spacing-04);
|
|
14
|
+
padding: var(--mds-spacing-03) var(--mds-spacing-05);
|
|
15
|
+
min-width: 190px;
|
|
16
|
+
align-items: flex-start;
|
|
17
|
+
height: 100%;
|
|
18
|
+
|
|
19
|
+
&:hover {
|
|
20
|
+
background-color: var(--token-color-surface-interactive-hover);
|
|
21
|
+
border-radius: var(--mds-spacing-01);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&:has(.iconBackground) {
|
|
25
|
+
align-items: flex-start;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@media (--large) {
|
|
29
|
+
max-width: 416px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&:focus {
|
|
33
|
+
outline: 2px solid var(--token-color-focus-action-internal);
|
|
34
|
+
outline-style: auto;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.description {
|
|
39
|
+
font-size: var(--mds-typography-body-200-font-size);
|
|
40
|
+
font-weight: var(--mds-typography-font-weight-regular);
|
|
41
|
+
margin-top: var(--mds-spacing-02);
|
|
42
|
+
color: var(--token-color-foreground-faint);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.iconBackground {
|
|
46
|
+
background: var(--iconGradient);
|
|
47
|
+
height: var(--mds-spacing-08);
|
|
48
|
+
width: var(--mds-spacing-08);
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
justify-content: center;
|
|
52
|
+
border-radius: 3px;
|
|
53
|
+
flex: none;
|
|
54
|
+
margin-top: 3px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.boldTitle {
|
|
58
|
+
font-weight: var(--mds-typography-font-weight-semibold);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.iconWrapper {
|
|
62
|
+
margin-top: 3px;
|
|
63
|
+
height: fit-content;
|
|
64
|
+
}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { vercelSplit } from '../../../../lib/v'
|
|
3
|
-
import { getLocalizedLinkProps } from '../../../../lib/get-localized-link-props'
|
|
4
|
-
import FlightIcon from '../flight-icon'
|
|
5
|
-
import * as NavigationMenu from '@radix-ui/react-navigation-menu'
|
|
1
|
+
import NavLink from '../link'
|
|
6
2
|
import s from './style.module.css'
|
|
7
3
|
|
|
8
4
|
export interface LinkListProps {
|
|
@@ -13,31 +9,11 @@ export interface LinkListProps {
|
|
|
13
9
|
icon?: string
|
|
14
10
|
description?: string
|
|
15
11
|
iconGradient?: string
|
|
12
|
+
iconAppearance?: 'light' | 'dark'
|
|
16
13
|
}[]
|
|
17
14
|
linkClickHandler?: (title: string, url: string) => void
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
const GRADIENT_VALUE_MAP = new Map([
|
|
21
|
-
[
|
|
22
|
-
'ILM',
|
|
23
|
-
{
|
|
24
|
-
iconGradient: 'var(--icon-gradient-infrastructure-lifecycle-management)',
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
[
|
|
28
|
-
'SLM',
|
|
29
|
-
{
|
|
30
|
-
iconGradient: 'var(--icon-gradient-security-lifecycle-management)',
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
[
|
|
34
|
-
'Cloud',
|
|
35
|
-
{
|
|
36
|
-
iconGradient: 'var(--icon-gradient-infrastructure-cloud)',
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
])
|
|
40
|
-
|
|
41
17
|
export default function LinkList({
|
|
42
18
|
locale,
|
|
43
19
|
links,
|
|
@@ -46,46 +22,13 @@ export default function LinkList({
|
|
|
46
22
|
return (
|
|
47
23
|
<ul className={s.linkList}>
|
|
48
24
|
{links.map((link) => {
|
|
49
|
-
let style
|
|
50
|
-
link.iconGradient
|
|
51
|
-
? (style = {
|
|
52
|
-
'--iconGradient': GRADIENT_VALUE_MAP.get(
|
|
53
|
-
vercelSplit(link.iconGradient)
|
|
54
|
-
)?.iconGradient,
|
|
55
|
-
} as React.CSSProperties)
|
|
56
|
-
: (style = null)
|
|
57
25
|
return (
|
|
58
26
|
<li key={link.title}>
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
linkClickHandler && linkClickHandler(link.title, link.url)
|
|
65
|
-
}}
|
|
66
|
-
>
|
|
67
|
-
{link.iconGradient && link.icon ? (
|
|
68
|
-
<div className={s.iconBackground} style={style}>
|
|
69
|
-
<FlightIcon name={vercelSplit(link.icon)} />
|
|
70
|
-
</div>
|
|
71
|
-
) : (
|
|
72
|
-
link.icon && (
|
|
73
|
-
<FlightIcon
|
|
74
|
-
name={vercelSplit(link.icon)}
|
|
75
|
-
color="var(--token-color-foreground-faint)"
|
|
76
|
-
/>
|
|
77
|
-
)
|
|
78
|
-
)}
|
|
79
|
-
<div>
|
|
80
|
-
<div className={link.iconGradient && s.boldTitle}>
|
|
81
|
-
{link.title}
|
|
82
|
-
</div>
|
|
83
|
-
{link.description && (
|
|
84
|
-
<div className={s.description}>{link.description}</div>
|
|
85
|
-
)}
|
|
86
|
-
</div>
|
|
87
|
-
</Link>
|
|
88
|
-
</NavigationMenu.Link>
|
|
27
|
+
<NavLink
|
|
28
|
+
{...link}
|
|
29
|
+
linkClickHandler={linkClickHandler}
|
|
30
|
+
locale={locale}
|
|
31
|
+
/>
|
|
89
32
|
</li>
|
|
90
33
|
)
|
|
91
34
|
})}
|
|
@@ -6,52 +6,3 @@
|
|
|
6
6
|
margin: 0;
|
|
7
7
|
padding: 0;
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
.link {
|
|
11
|
-
color: var(--token-color-foreground-primary);
|
|
12
|
-
display: flex;
|
|
13
|
-
gap: var(--mds-spacing-04);
|
|
14
|
-
padding: var(--mds-spacing-03) var(--mds-spacing-04);
|
|
15
|
-
min-width: 190px;
|
|
16
|
-
align-items: center;
|
|
17
|
-
|
|
18
|
-
&:hover {
|
|
19
|
-
background-color: var(--token-color-surface-interactive-hover);
|
|
20
|
-
border-radius: var(--mds-spacing-01);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
&:has(.iconBackground) {
|
|
24
|
-
align-items: flex-start;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@media (--large) {
|
|
28
|
-
max-width: 416px;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
&:focus {
|
|
32
|
-
outline: 2px solid var(--token-color-focus-action-internal);
|
|
33
|
-
outline-style: auto;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.description {
|
|
38
|
-
font-size: var(--mds-typography-body-200-font-size);
|
|
39
|
-
font-weight: var(--mds-typography-font-weight-regular);
|
|
40
|
-
margin-top: var(--mds-spacing-02);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.iconBackground {
|
|
44
|
-
background: var(--iconGradient);
|
|
45
|
-
height: var(--mds-spacing-08);
|
|
46
|
-
width: var(--mds-spacing-08);
|
|
47
|
-
display: flex;
|
|
48
|
-
align-items: center;
|
|
49
|
-
justify-content: center;
|
|
50
|
-
border-radius: 3px;
|
|
51
|
-
flex: none;
|
|
52
|
-
margin-top: 3px;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.boldTitle {
|
|
56
|
-
font-weight: var(--mds-typography-font-weight-semibold);
|
|
57
|
-
}
|
|
@@ -11,6 +11,7 @@ import s from './style.module.css'
|
|
|
11
11
|
export interface PromoProps {
|
|
12
12
|
locale?: string
|
|
13
13
|
title: string
|
|
14
|
+
titleLinkUrl?: string
|
|
14
15
|
description: string
|
|
15
16
|
linkUrl: string
|
|
16
17
|
linkTitle: string
|
|
@@ -24,6 +25,7 @@ export interface PromoProps {
|
|
|
24
25
|
export default function Promo({
|
|
25
26
|
locale,
|
|
26
27
|
title,
|
|
28
|
+
titleLinkUrl,
|
|
27
29
|
description,
|
|
28
30
|
linkUrl,
|
|
29
31
|
linkTitle,
|
|
@@ -65,14 +67,26 @@ export default function Promo({
|
|
|
65
67
|
)}
|
|
66
68
|
<div className={s.rightContent}>
|
|
67
69
|
<div>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
{titleLinkUrl ? (
|
|
71
|
+
<a
|
|
72
|
+
className={classNames(s.title, s.link, {
|
|
73
|
+
[s.hashidays]: vercelSplit(theme) === 'hashidays',
|
|
74
|
+
[s.hashiconf]: vercelSplit(theme) === 'hashiconf',
|
|
75
|
+
})}
|
|
76
|
+
href={titleLinkUrl}
|
|
77
|
+
>
|
|
78
|
+
{title}
|
|
79
|
+
</a>
|
|
80
|
+
) : (
|
|
81
|
+
<div
|
|
82
|
+
className={classNames(s.title, {
|
|
83
|
+
[s.hashidays]: vercelSplit(theme) === 'hashidays',
|
|
84
|
+
[s.hashiconf]: vercelSplit(theme) === 'hashiconf',
|
|
85
|
+
})}
|
|
86
|
+
>
|
|
87
|
+
{title}
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
76
90
|
<div className={s.description}>{description}</div>
|
|
77
91
|
</div>
|
|
78
92
|
<NavigationMenu.Link asChild>
|
|
@@ -8,6 +8,8 @@ import FlightIcon from '../components/flight-icon'
|
|
|
8
8
|
import { Text } from '../components/text'
|
|
9
9
|
import { trackNavClickEvent } from '../../../lib/track-nav-click-event'
|
|
10
10
|
import * as NavigationMenu from '@radix-ui/react-navigation-menu'
|
|
11
|
+
import { LinkListProps } from '../components/link-list'
|
|
12
|
+
import NavLink from '../components/link'
|
|
11
13
|
import s from './style.module.css'
|
|
12
14
|
|
|
13
15
|
const PRODUCT_LOGO_MAP = new Map([
|
|
@@ -29,9 +31,15 @@ const PRODUCT_LOGO_EXCEPTION_CLASSNAMES = {
|
|
|
29
31
|
'HCP Vault Radar': 'hcpVaultRadar',
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
export type ProductCategoriesProps = Array<{
|
|
35
|
+
title: string
|
|
36
|
+
group?: LinkListProps['links'][0]
|
|
37
|
+
products: NavProductProps[]
|
|
38
|
+
}>
|
|
39
|
+
|
|
32
40
|
export interface ProductsPanelProps {
|
|
33
41
|
locale?: string
|
|
34
|
-
productCategories:
|
|
42
|
+
productCategories: ProductCategoriesProps
|
|
35
43
|
promo?: PromoProps
|
|
36
44
|
sidePanel?: {
|
|
37
45
|
label: string
|
|
@@ -71,10 +79,19 @@ const ProductPanel = ({
|
|
|
71
79
|
) : null}
|
|
72
80
|
<NavPanel.Column hasSidePanel={Boolean(sidePanel)}>
|
|
73
81
|
<ul className={s.productCategories}>
|
|
74
|
-
{productCategories.map(({ title, products }) => {
|
|
82
|
+
{productCategories.map(({ group, title, products }) => {
|
|
75
83
|
return (
|
|
76
|
-
<li
|
|
77
|
-
|
|
84
|
+
<li
|
|
85
|
+
key={title}
|
|
86
|
+
className={classNames(s.productCategory, {
|
|
87
|
+
[s.productCategoryHasGroup]: group,
|
|
88
|
+
})}
|
|
89
|
+
>
|
|
90
|
+
{group ? (
|
|
91
|
+
<NavLink {...group} className={s.productGroupLink} />
|
|
92
|
+
) : (
|
|
93
|
+
<Text className={s.eyebrow}>{title}</Text>
|
|
94
|
+
)}
|
|
78
95
|
<ul className={s.productList}>
|
|
79
96
|
{products.map((product) => {
|
|
80
97
|
return (
|
|
@@ -354,3 +354,42 @@ packages/react-components/src/components/nav-panel/components/link-list/style.mo
|
|
|
354
354
|
.sidePanelText {
|
|
355
355
|
font-weight: var(--mds-typography-font-weight-semibold);
|
|
356
356
|
}
|
|
357
|
+
|
|
358
|
+
.productCategoryHasGroup {
|
|
359
|
+
& .productList {
|
|
360
|
+
padding-left: 0;
|
|
361
|
+
padding-right: 0;
|
|
362
|
+
padding-top: 0;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
& .productWrapper {
|
|
366
|
+
gap: var(--mds-spacing-04);
|
|
367
|
+
|
|
368
|
+
@media (--small) {
|
|
369
|
+
padding: var(--mds-spacing-03) var(--mds-spacing-05);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
& .productLogo {
|
|
374
|
+
margin-top: 3px;
|
|
375
|
+
height: 32px;
|
|
376
|
+
width: 32px;
|
|
377
|
+
min-width: 32px;
|
|
378
|
+
|
|
379
|
+
& svg {
|
|
380
|
+
width: 100%;
|
|
381
|
+
height: 100%;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
& .terraform {
|
|
386
|
+
width: 100%;
|
|
387
|
+
height: 100%;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.productGroupLink {
|
|
392
|
+
min-width: 100%;
|
|
393
|
+
max-width: 100%;
|
|
394
|
+
margin-bottom: var(--mds-spacing-03);
|
|
395
|
+
}
|