@hashicorp/react-components 0.0.0-nightly.91abcef → 0.0.0-nightly.928c674

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 (140) hide show
  1. package/.eslintrc.js +1 -2
  2. package/.stylelintrc.js +1 -1
  3. package/README.md +1 -1
  4. package/package.json +3 -8
  5. package/postcss.config.js +1 -1
  6. package/src/components/nav-panel/components/flight-icon/index.tsx +51 -0
  7. package/src/components/nav-panel/components/flight-icon/style.module.css +3 -0
  8. package/src/components/nav-panel/components/link/index.tsx +127 -0
  9. package/src/components/nav-panel/components/link/style.module.css +64 -0
  10. package/src/components/nav-panel/components/link-list/index.tsx +7 -64
  11. package/src/components/nav-panel/components/link-list/style.module.css +1 -50
  12. package/src/components/nav-panel/components/panel/column/style.module.css +2 -2
  13. package/src/components/nav-panel/components/panel/root/style.module.css +5 -5
  14. package/src/components/nav-panel/components/promo/index.tsx +26 -9
  15. package/src/components/nav-panel/components/promo/style.module.css +33 -19
  16. package/src/components/nav-panel/components/text/index.tsx +34 -0
  17. package/src/components/nav-panel/product-panel/index.tsx +46 -14
  18. package/src/components/nav-panel/product-panel/style.module.css +133 -53
  19. package/src/components/nav-panel/standard-panel/style.module.css +2 -2
  20. package/src/lib/get-localized-link-props/index.ts +2 -3
  21. package/src/lib/parse-url/index.ts +2 -9
  22. package/src/lib/send-posthog-event/index.ts +22 -0
  23. package/src/lib/supported-locales/index.ts +10 -1
  24. package/src/lib/track-nav-click-event/index.ts +4 -4
  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 -177
  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 -40
  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.spec.tsx +0 -40
  53. package/src/components/card/unified-card/index.tsx +0 -58
  54. package/src/components/intro/index.tsx +0 -82
  55. package/src/components/intro/style.module.css +0 -67
  56. package/src/components/intro/types.ts +0 -44
  57. package/src/components/marketo-form/CHANGELOG.md +0 -122
  58. package/src/components/marketo-form/README.md +0 -1
  59. package/src/components/marketo-form/contexts/FormMetadata.ts +0 -13
  60. package/src/components/marketo-form/docs.mdx +0 -197
  61. package/src/components/marketo-form/fixtures/index.ts +0 -185
  62. package/src/components/marketo-form/form/index.tsx +0 -371
  63. package/src/components/marketo-form/index.test.tsx +0 -320
  64. package/src/components/marketo-form/index.ts +0 -11
  65. package/src/components/marketo-form/package.original.json +0 -30
  66. package/src/components/marketo-form/partials/error-message/index.tsx +0 -12
  67. package/src/components/marketo-form/partials/error-message/style.module.css +0 -13
  68. package/src/components/marketo-form/partials/field/index.tsx +0 -90
  69. package/src/components/marketo-form/partials/field-wrapper/index.tsx +0 -26
  70. package/src/components/marketo-form/partials/fields/checkbox-field/index.tsx +0 -32
  71. package/src/components/marketo-form/partials/fields/email-field/index.tsx +0 -35
  72. package/src/components/marketo-form/partials/fields/form-page-url-field/index.tsx +0 -32
  73. package/src/components/marketo-form/partials/fields/hidden-field/index.tsx +0 -38
  74. package/src/components/marketo-form/partials/fields/htmltext-field/index.tsx +0 -21
  75. package/src/components/marketo-form/partials/fields/htmltext-field/style.module.css +0 -18
  76. package/src/components/marketo-form/partials/fields/name-field/index.tsx +0 -19
  77. package/src/components/marketo-form/partials/fields/name-field/style.module.css +0 -13
  78. package/src/components/marketo-form/partials/fields/radio-buttons-field/index.tsx +0 -48
  79. package/src/components/marketo-form/partials/fields/select-field/index.tsx +0 -39
  80. package/src/components/marketo-form/partials/fields/select-field/style.module.css +0 -5
  81. package/src/components/marketo-form/partials/fields/telephone-field/index.tsx +0 -30
  82. package/src/components/marketo-form/partials/fields/text-field/index.tsx +0 -30
  83. package/src/components/marketo-form/partials/fields/textarea-field/index.tsx +0 -29
  84. package/src/components/marketo-form/partials/label/index.tsx +0 -24
  85. package/src/components/marketo-form/partials/label/style.module.css +0 -12
  86. package/src/components/marketo-form/partials/visibility-rule/index.tsx +0 -84
  87. package/src/components/marketo-form/props.js +0 -66
  88. package/src/components/marketo-form/server/api-routes.ts +0 -109
  89. package/src/components/marketo-form/server/client.ts +0 -98
  90. package/src/components/marketo-form/server/index.ts +0 -8
  91. package/src/components/marketo-form/types.ts +0 -262
  92. package/src/components/marketo-form/utils.test.tsx +0 -103
  93. package/src/components/marketo-form/utils.ts +0 -449
  94. package/src/components/next-steps/index.tsx +0 -138
  95. package/src/components/next-steps/style.module.css +0 -270
  96. package/src/components/next-steps/types.ts +0 -63
  97. package/src/components/product-badge/index.test.tsx +0 -11
  98. package/src/components/product-badge/index.tsx +0 -42
  99. package/src/components/product-badge/style.module.css +0 -76
  100. package/src/components/products-used/index.tsx +0 -84
  101. package/src/components/products-used/style.module.css +0 -87
  102. package/src/components/products-used/types.ts +0 -31
  103. package/src/components/related-content/index.test.tsx +0 -74
  104. package/src/components/related-content/index.tsx +0 -56
  105. package/src/components/related-content/style.module.css +0 -89
  106. package/src/components/related-content/types.ts +0 -21
  107. package/src/components/subnav/helpers/areBasePathsMatching.ts +0 -13
  108. package/src/components/subnav/helpers/traverse/index.ts +0 -42
  109. package/src/components/subnav/helpers/useHeightRef.ts +0 -42
  110. package/src/components/subnav/helpers/useNavRef.ts +0 -30
  111. package/src/components/subnav/helpers/useOverflowRef.ts +0 -85
  112. package/src/components/subnav/helpers/useStuckRef.ts +0 -51
  113. package/src/components/subnav/index.tsx +0 -209
  114. package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.test.ts +0 -26
  115. package/src/components/subnav/partials/CtaLinks/github-stars-link/formatStarCount/index.ts +0 -22
  116. package/src/components/subnav/partials/CtaLinks/github-stars-link/index.tsx +0 -87
  117. package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.test.ts +0 -29
  118. package/src/components/subnav/partials/CtaLinks/github-stars-link/parseGithubUrl/index.ts +0 -32
  119. package/src/components/subnav/partials/CtaLinks/github-stars-link/style.module.css +0 -81
  120. package/src/components/subnav/partials/CtaLinks/icons/github-logo.js +0 -20
  121. package/src/components/subnav/partials/CtaLinks/icons/github.svg.js +0 -7
  122. package/src/components/subnav/partials/CtaLinks/icons/star.js +0 -20
  123. package/src/components/subnav/partials/CtaLinks/index.tsx +0 -131
  124. package/src/components/subnav/partials/CtaLinks/style.module.css +0 -45
  125. package/src/components/subnav/partials/DropdownTrigger/index.tsx +0 -35
  126. package/src/components/subnav/partials/DropdownTrigger/style.module.css +0 -39
  127. package/src/components/subnav/partials/MenuItemsDefault/index.tsx +0 -173
  128. package/src/components/subnav/partials/MenuItemsDefault/style.module.css +0 -104
  129. package/src/components/subnav/partials/MenuItemsOverflow/index.tsx +0 -155
  130. package/src/components/subnav/partials/MenuItemsOverflow/style.module.css +0 -88
  131. package/src/components/subnav/partials/TitleLink/index.tsx +0 -115
  132. package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-dark.ts +0 -10
  133. package/src/components/subnav/partials/TitleLink/mktg-logos/all-community-product-logos_on-light.ts +0 -10
  134. package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-dark.ts +0 -23
  135. package/src/components/subnav/partials/TitleLink/mktg-logos/all-primary-logos_on-light.ts +0 -23
  136. package/src/components/subnav/partials/TitleLink/style.module.css +0 -43
  137. package/src/components/subnav/partials/nav-item-text/index.tsx +0 -37
  138. package/src/components/subnav/partials/nav-item-text/style.module.css +0 -13
  139. package/src/components/subnav/style.module.css +0 -66
  140. package/src/components/subnav/subnav-consts.ts +0 -1
@@ -1,209 +0,0 @@
1
- 'use client'
2
-
3
- /**
4
- * Copyright (c) HashiCorp, Inc.
5
- * SPDX-License-Identifier: MPL-2.0
6
- */
7
- import { useState } from 'react'
8
- import classNames from 'classnames'
9
- import useProductMeta, { Products } from '@hashicorp/platform-product-meta'
10
- import { THEMES } from './subnav-consts'
11
- import useNavRef from './helpers/useNavRef'
12
-
13
- import MenuItemsOverflow from './partials/MenuItemsOverflow'
14
- import TitleLink from './partials/TitleLink'
15
- import MenuItemsDefault from './partials/MenuItemsDefault'
16
- import CtaLinks, { type CtaLinkProps } from './partials/CtaLinks'
17
- import traverse, { isObject } from './helpers/traverse'
18
- import { areBasePathsMatching } from './helpers/areBasePathsMatching'
19
- import * as NavigationMenu from '@radix-ui/react-navigation-menu'
20
- import s from './style.module.css'
21
-
22
- const productAllowList = {
23
- consul: 'consul',
24
- hcp: 'hcp',
25
- nomad: 'nomad',
26
- packer: 'packer',
27
- terraform: 'terraform',
28
- tfc: 'terraform',
29
- vagrant: 'vagrant',
30
- vault: 'vault',
31
- boundary: 'boundary',
32
- waypoint: 'waypoint',
33
- }
34
-
35
- type SubnavLink = {
36
- text: string
37
- url: string
38
- _isActiveUrl?: boolean
39
- }
40
-
41
- type SubnavDropdown = {
42
- text: string
43
- submenu: Array<SubnavLink>
44
- }
45
-
46
- type MenuItem = SubnavLink | SubnavDropdown | 'divider'
47
-
48
- export interface SubnavInnerProps {
49
- locale?: string
50
- hasOverflow?: boolean
51
- titleLink: { text: string; url: string }
52
- product?: Products
53
- ctaLinks?: CtaLinkProps
54
- hideGithubStars?: boolean
55
- menuItems: Array<MenuItem>
56
- constrainWidth?: boolean
57
- currentPath: string
58
- matchOnBasePath?: boolean
59
- theme?: (typeof THEMES)[number]
60
- menuText?: string
61
- activatePanel: (panel: string) => void
62
- }
63
-
64
- function SubnavInner({
65
- locale,
66
- hasOverflow,
67
- titleLink,
68
- product,
69
- ctaLinks = [],
70
- hideGithubStars,
71
- menuItems,
72
- constrainWidth,
73
- currentPath,
74
- matchOnBasePath = false,
75
- theme = 'light',
76
- menuText = 'Menu',
77
- activatePanel,
78
- }: SubnavInnerProps) {
79
- // Add _isActiveUrl to menuItems so we can highlight them appropriately
80
- const menuItemsWithActive = traverse(menuItems, (_key, value: any) => {
81
- const hasUrl = isObject(value) && value.url
82
- if (hasUrl) {
83
- value._isActiveUrl = matchOnBasePath
84
- ? areBasePathsMatching(value.url, currentPath)
85
- : value.url === currentPath
86
- }
87
- return value
88
- })
89
-
90
- const { themeClass } = useProductMeta(product)
91
-
92
- /**
93
- * Note on constrainWidth & g-grid-container
94
- *
95
- * TEMPORARY: this is a temporary patch
96
- * to constrain the width of the subnav.
97
- * We want to settle on fully consistent subnav
98
- * max-width and alignment behavior at some point
99
- * Related Asana task:
100
- * https://app.asana.com/0/1126477231080283/1162972875950505/f
101
- */
102
- return (
103
- <div className={s.subnavInnerRoot}>
104
- <div
105
- className={classNames(s.subnavInner, themeClass, {
106
- 'g-grid-container': constrainWidth,
107
- [s.notConstrained]: !constrainWidth,
108
- [s.hasOverflow]: hasOverflow,
109
- })}
110
- data-overflow-target
111
- >
112
- <NavigationMenu.Link asChild>
113
- <TitleLink
114
- locale={locale}
115
- text={titleLink.text}
116
- url={titleLink.url}
117
- product={product}
118
- theme={theme}
119
- />
120
- </NavigationMenu.Link>
121
-
122
- {!hasOverflow && (
123
- <div className={s.subNavRight}>
124
- <MenuItemsDefault
125
- menuItems={menuItemsWithActive}
126
- activatePanel={activatePanel}
127
- locale={locale}
128
- product={product}
129
- />
130
- {ctaLinks?.length > 0 && (
131
- <CtaLinks
132
- links={ctaLinks}
133
- product={product}
134
- hideGithubStars={hideGithubStars}
135
- />
136
- )}
137
- </div>
138
- )}
139
- {hasOverflow && (
140
- <MenuItemsOverflow
141
- menuItems={menuItemsWithActive}
142
- ctaLinks={ctaLinks}
143
- hideGithubStars={hideGithubStars}
144
- product={product}
145
- menuText={menuText}
146
- constrainWidth={constrainWidth}
147
- activatePanel={activatePanel}
148
- />
149
- )}
150
- </div>
151
- </div>
152
- )
153
- }
154
-
155
- export interface SubnavProps extends Omit<SubnavInnerProps, 'activatePanel'> {
156
- className?: string
157
- }
158
-
159
- function Subnav({ className, theme = 'light', ...restProps }: SubnavProps) {
160
- const [activePanel, setActivePanel] = useState('')
161
- const [isSticky, hasOverflow, height, wrapperRef] = useNavRef()
162
- // Set the brand theme automatically based on the nav's title
163
- const product =
164
- (restProps.product &&
165
- restProps.product in productAllowList &&
166
- productAllowList[restProps.product]) ||
167
- 'hashicorp'
168
-
169
- const activatePanel = (panel) => {
170
- setActivePanel(panel)
171
- }
172
-
173
- const ariaLabel = restProps?.titleLink?.text
174
- ? `${restProps.titleLink.text} pages`
175
- : 'Subnav pages'
176
-
177
- return (
178
- <>
179
- {/**
180
- * Injecting a :root css var for subnav-height so the `scroll-margin-top`
181
- * property on all page anchors can be dynamic based on the height of
182
- * the subnav.
183
- */}
184
- <style>{`:root{--subnav-height:${height}px}`}</style>
185
- <NavigationMenu.Root
186
- ref={wrapperRef}
187
- className={classNames(s.root, className, {
188
- [s.isSticky]: isSticky,
189
- [s.hasOverflow]: hasOverflow,
190
- 'hdsplus-dark-mode': theme === 'dark',
191
- })}
192
- aria-label={ariaLabel}
193
- onValueChange={activatePanel}
194
- value={activePanel}
195
- delayDuration={0}
196
- >
197
- <SubnavInner
198
- {...restProps}
199
- product={product}
200
- hasOverflow={hasOverflow}
201
- theme={theme}
202
- activatePanel={activatePanel}
203
- />
204
- </NavigationMenu.Root>
205
- </>
206
- )
207
- }
208
-
209
- export default Subnav
@@ -1,26 +0,0 @@
1
- import formatStarCount from './'
2
-
3
- describe('<Subnav /> - formatStarCount', () => {
4
- it('should return zero for an undefined, null, or zero count', () => {
5
- expect(formatStarCount(undefined)).toBe(false)
6
- //@ts-expect-error purposefully testing invalid input
7
- expect(formatStarCount(null)).toBe(false)
8
- expect(formatStarCount(0)).toBe(false)
9
- })
10
-
11
- it('should return numbers 1 to 999 without formatting', () => {
12
- expect(formatStarCount(1)).toBe('1')
13
- expect(formatStarCount(999)).toBe('999')
14
- })
15
-
16
- it('should abbreviate numbers in the tens of thousands with "k" and a single decimal point', () => {
17
- expect(formatStarCount(1003)).toBe('1.0k')
18
- expect(formatStarCount(1280)).toBe('1.2k')
19
- expect(formatStarCount(15630)).toBe('15.6k')
20
- })
21
-
22
- it('should abbreviate numbers in the hundreds of thousands with "k" and no decimal point', () => {
23
- expect(formatStarCount(100000)).toBe('100k')
24
- expect(formatStarCount(156783)).toBe('156k')
25
- })
26
- })
@@ -1,22 +0,0 @@
1
- /**
2
- * Copyright (c) HashiCorp, Inc.
3
- * SPDX-License-Identifier: MPL-2.0
4
- */
5
-
6
- /*
7
- * Given:
8
- * starCount (int)
9
- * Return:
10
- * Formatted string, to match GitHub's typical display of star counts,
11
- * that is, expressed as thousands of stars
12
- * Or returns false for falsy starCount values
13
- */
14
- function formatStarCount(starCount?: number) {
15
- if (!starCount || starCount <= 0) return false
16
- if (starCount < 1000) return `${starCount}`
17
- const thousands = Math.floor(starCount / 100.0) / 10.0
18
- if (starCount < 100000) return `${thousands.toFixed(1)}k`
19
- return `${Math.floor(thousands)}k`
20
- }
21
-
22
- export default formatStarCount
@@ -1,87 +0,0 @@
1
- /**
2
- * Copyright (c) HashiCorp, Inc.
3
- * SPDX-License-Identifier: MPL-2.0
4
- */
5
-
6
- import React, { useEffect, useState } from 'react'
7
- import fetch from 'isomorphic-unfetch'
8
- import formatStarCount from './formatStarCount'
9
- import parseGithubUrl from './parseGithubUrl'
10
- import StarIcon from '../icons/star'
11
- import GithubIcon from '../icons/github-logo'
12
- import { VisuallyHidden } from '@radix-ui/react-visually-hidden'
13
- import s from './style.module.css'
14
-
15
- interface GithubStarsButtonProps {
16
- url: string
17
- hideGithubStars?: boolean
18
- }
19
-
20
- function GithubStarsButton(props: GithubStarsButtonProps) {
21
- const { url, hideGithubStars } = props
22
- const [starCount, setStarCount] = useState(-1)
23
-
24
- useEffect(() => {
25
- if (hideGithubStars) return setStarCount(0)
26
- const parsedGithubUrl = parseGithubUrl(url)
27
- if (!parsedGithubUrl || !parsedGithubUrl.org || !parsedGithubUrl.repo)
28
- return setStarCount(0)
29
- const { org, repo } = parsedGithubUrl
30
- if (!org || !repo) return setStarCount(0)
31
- const githubApiUrl = `https://api.github.com/repos/${org}/${repo}`
32
- fetch(githubApiUrl)
33
- .then((response) => {
34
- response.json().then((data) => {
35
- // Github's rate limit for unauthenticated requests is 60 per hour
36
- // When the limit is hit, data.stargazers_count is undefined,
37
- // and setStarCount falls back to not showing the star count
38
- setStarCount(data.stargazers_count)
39
- // Warn if this limit is hit, to avoid otherwise confusing behavior
40
- // We're still using the response to provide a documentation link
41
- if (!data.stargazers_count) {
42
- const { headers } = response
43
- if (headers.get('x-ratelimit-remaining') === '0') {
44
- const resetAtSeconds = parseInt(headers.get('x-ratelimit-reset')!)
45
- const resetDate = new Date(resetAtSeconds * 1000)
46
- const rateLimit = headers.get('x-ratelimit-limit')
47
- console.warn(
48
- `⭐ Stargazers count could not be fetched. Rate limit exceeded for unauthenticated GitHub API. Limit will be reset to ${rateLimit} at ${resetDate}. See ${data.documentation_url} for more details.`
49
- )
50
- } else {
51
- console.warn(
52
- `Request for stargazers was successful, but the returned value was undefined or falsy. This might be because the repo has no stars, or it might be a different issue.`
53
- )
54
- }
55
- }
56
- })
57
- })
58
- .catch((err) => {
59
- setStarCount(0)
60
- console.warn(JSON.stringify(err, null, 2))
61
- })
62
- }, [hideGithubStars, url])
63
-
64
- const isLoadingStarCount = starCount === -1
65
- const isFailedStarCount = formatStarCount(starCount) === false
66
- const showStarCount =
67
- !hideGithubStars && (isLoadingStarCount || !isFailedStarCount)
68
- return (
69
- <a href={url} className={s.root}>
70
- <span className={s.github}>
71
- <GithubIcon />
72
- <VisuallyHidden>GitHub</VisuallyHidden>
73
- </span>
74
- {showStarCount && (
75
- <span className={s.stars}>
76
- <StarIcon />
77
- <span className="g-type-body-small-strong" data-testid="github-stars">
78
- {formatStarCount(starCount) || <span>&mdash;</span>}
79
- </span>
80
- <VisuallyHidden>Stars on GitHub</VisuallyHidden>
81
- </span>
82
- )}
83
- </a>
84
- )
85
- }
86
-
87
- export default GithubStarsButton
@@ -1,29 +0,0 @@
1
- import parseGithubUrl from './'
2
-
3
- describe('<Subnav /> - parseGithubUrl', () => {
4
- it('should gracefully handle an invalid URL', () => {
5
- // Suppress console.warn for this test, we expect warnings
6
- vi.stubGlobal('console', {
7
- warn() {
8
- return
9
- },
10
- })
11
- //@ts-expect-error purposefully testing invalid input
12
- expect(parseGithubUrl(undefined)).toBe(false)
13
- expect(parseGithubUrl('blah-blah')).toBe(false)
14
- })
15
-
16
- it('should handle a non-GitHub URL', () => {
17
- expect(parseGithubUrl('https://www.example.com/hashicorp/terraform')).toBe(
18
- false
19
- )
20
- })
21
-
22
- it('should parse the org and repo from a GitHub URL', () => {
23
- const testInput = 'https://www.github.com/hashicorp/terraform'
24
- //@ts-expect-error purposefully testing invalid input
25
- const { repo, org } = parseGithubUrl(testInput)
26
- expect(repo).toBe('terraform')
27
- expect(org).toBe('hashicorp')
28
- })
29
- })
@@ -1,32 +0,0 @@
1
- /**
2
- * Copyright (c) HashiCorp, Inc.
3
- * SPDX-License-Identifier: MPL-2.0
4
- */
5
-
6
- /*
7
- * Given:
8
- * urlString (string) valid URL string
9
- * Return:
10
- * { org, repo }, where the url is ~= www.github.com/{org}/{repo}
11
- * or false otherwise (eg if not a valid URL, or if not a GitHub url)
12
- */
13
- function parseGithubUrl(
14
- urlString: string
15
- ): { org: string; repo: string } | false {
16
- try {
17
- const urlObj = new URL(urlString)
18
- if (urlObj.hostname !== 'www.github.com') return false
19
- const parts = urlObj.pathname.split('/').filter(Boolean)
20
- const org = parts[0]
21
- const repo = parts[1]
22
- return { org, repo }
23
- } catch (err) {
24
- console.warn(
25
- 'Warning! An invalid URL has probably been supplied to the GitHub ctaLink in <Subnav />. The corresponding error:'
26
- )
27
- console.warn(err)
28
- return false
29
- }
30
- }
31
-
32
- export default parseGithubUrl
@@ -1,81 +0,0 @@
1
- /**
2
- * Copyright (c) HashiCorp, Inc.
3
- * SPDX-License-Identifier: MPL-2.0
4
- */
5
-
6
- .root {
7
- --local-scrim-opacity: 0;
8
- --local-divider-color: var(--token-color-border-primary);
9
-
10
- position: relative;
11
- color: var(--token-color-foreground-primary);
12
- border: 1px solid var(--local-divider-color);
13
- border-radius: 5px;
14
- background: none;
15
- transition: background 0.2s, border-color 0.2s;
16
- display: flex;
17
- align-items: center;
18
-
19
- /* Scrim used in most hover effects */
20
- &::before {
21
- content: '';
22
- position: absolute;
23
- top: -1px;
24
- left: -1px;
25
- right: -1px;
26
- bottom: -1px;
27
- border-radius: 5px;
28
- transition: opacity 0.25s ease;
29
- opacity: var(--local-scrim-opacity);
30
- z-index: 0;
31
- background-color: var(--token-color-foreground-primary);
32
- }
33
-
34
- &:hover,
35
- &:active {
36
- --local-scrim-opacity: 0.12;
37
- }
38
- }
39
-
40
- .github {
41
- display: flex;
42
- align-items: center;
43
- padding: 8px 10px;
44
- & > svg {
45
- width: 20px;
46
- height: 20px;
47
-
48
- & [fill] {
49
- fill: currentColor;
50
- }
51
-
52
- & [stroke] {
53
- stroke: currentColor;
54
- }
55
- }
56
- }
57
-
58
- .stars {
59
- display: flex;
60
- align-items: center;
61
- height: 100%;
62
- border-left: 1px solid;
63
- border-color: var(--local-divider-color);
64
- padding: 6px 12px 7px 10px;
65
- transition: border-color 0.2s;
66
- z-index: 1;
67
- & > svg {
68
- width: 16px;
69
- height: 16px;
70
- margin-right: 4px;
71
- margin-top: 1px;
72
-
73
- & [fill] {
74
- fill: currentColor;
75
- }
76
-
77
- & [stroke] {
78
- stroke: currentColor;
79
- }
80
- }
81
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * Copyright (c) HashiCorp, Inc.
3
- * SPDX-License-Identifier: MPL-2.0
4
- */
5
-
6
- import React from 'react'
7
-
8
- function GithubIcon(props) {
9
- return (
10
- <svg width={16} height={16} viewBox="0 0 16 16" {...props}>
11
- <path
12
- fillRule="evenodd"
13
- fill="#000000"
14
- d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
15
- />
16
- </svg>
17
- )
18
- }
19
-
20
- export default GithubIcon
@@ -1,7 +0,0 @@
1
- /**
2
- * Copyright (c) HashiCorp, Inc.
3
- * SPDX-License-Identifier: MPL-2.0
4
- */
5
-
6
- export default `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M11.9633 0.325439C5.3578 0.325439 0 5.68324 0 12.2887C0 17.5731 3.44954 22.0502 8.14679 23.6649C8.73394 23.7383 8.95413 23.3713 8.95413 23.0777C8.95413 22.7842 8.95413 22.0502 8.95413 21.0227C5.65138 21.7566 4.91743 19.408 4.91743 19.408C4.40367 18.0135 3.59633 17.6465 3.59633 17.6465C2.49541 16.9126 3.66972 16.9126 3.66972 16.9126C4.84404 16.986 5.50459 18.1603 5.50459 18.1603C6.6055 19.9952 8.29358 19.4814 8.95413 19.1878C9.02752 18.3805 9.3945 17.8667 9.68807 17.5731C7.04587 17.2796 4.25688 16.252 4.25688 11.6282C4.25688 10.3071 4.69725 9.27957 5.50459 8.39883C5.43119 8.17865 4.99083 6.93094 5.65138 5.31627C5.65138 5.31627 6.6789 5.02269 8.95413 6.56397C9.90826 6.27039 10.9358 6.197 11.9633 6.197C12.9908 6.197 14.0183 6.34379 14.9725 6.56397C17.2477 5.02269 18.2752 5.31627 18.2752 5.31627C18.9358 6.93094 18.4954 8.17865 18.422 8.47223C19.156 9.27957 19.6697 10.3805 19.6697 11.7016C19.6697 16.3254 16.8807 17.2796 14.2385 17.5731C14.6789 17.9401 15.0459 18.6741 15.0459 19.775C15.0459 21.3897 15.0459 22.6374 15.0459 23.0777C15.0459 23.3713 15.2661 23.7383 15.8532 23.6649C20.6239 22.0502 24 17.5731 24 12.2887C23.9266 5.68324 18.5688 0.325439 11.9633 0.325439Z" fill="#252937"/>
7
- </svg>`
@@ -1,20 +0,0 @@
1
- /**
2
- * Copyright (c) HashiCorp, Inc.
3
- * SPDX-License-Identifier: MPL-2.0
4
- */
5
-
6
- import React from 'react'
7
-
8
- function StarIcon(props) {
9
- return (
10
- <svg width={14} height={16} viewBox="0 0 14 16" {...props}>
11
- <path
12
- fillRule="evenodd"
13
- fill="#000000"
14
- d="M14 6l-4.9-.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14 7 11.67 11.33 14l-.93-4.74L14 6z"
15
- />
16
- </svg>
17
- )
18
- }
19
-
20
- export default StarIcon
@@ -1,131 +0,0 @@
1
- /**
2
- * Copyright (c) HashiCorp, Inc.
3
- * SPDX-License-Identifier: MPL-2.0
4
- */
5
-
6
- import {
7
- HDSPlusButton,
8
- type HDSPlusButtonProps,
9
- } from '@hashicorp/react-mds/src/hds-plus/button'
10
- import FlightIcon from '@hashicorp/react-hds/src/components/flight-icon'
11
- import type { Products } from '@hashicorp/platform-product-meta'
12
- import type { ToggleButtonProps } from '@hashicorp/react-hds/src/components/dropdown/toggle/button'
13
- import * as Dropdown from '@hashicorp/react-hds/src/components/dropdown'
14
- import GithubStarsLink from './github-stars-link'
15
- import classNames from 'classnames'
16
- import * as NavigationMenu from '@radix-ui/react-navigation-menu'
17
- import s from './style.module.css'
18
-
19
- type CtaLink = HDSPlusButtonProps & { href: string; __typename?: string }
20
-
21
- type CtaDropdown = {
22
- __typename?: string
23
- submenu: { text: string; url: string }[]
24
- buttonControls: ToggleButtonProps
25
- }
26
-
27
- export type CtaLinkProps = Array<CtaLink | CtaDropdown>
28
-
29
- interface CtaLinksProps {
30
- links: Array<CtaLink | CtaDropdown>
31
- product?: Products
32
- isInDropdown?: boolean
33
- hideGithubStars?: boolean
34
- }
35
-
36
- function CtaLinks({
37
- links,
38
- product = 'hashicorp',
39
- isInDropdown,
40
- hideGithubStars,
41
- }: CtaLinksProps) {
42
- return (
43
- <NavigationMenu.List
44
- className={classNames(s.root, { [s.isInDropdown]: isInDropdown })}
45
- >
46
- {links.map((cta, stableIdx) => {
47
- if (isDropdown(cta)) {
48
- const { buttonControls, submenu } = cta
49
-
50
- return (
51
- // eslint-disable-next-line react/no-array-index-key
52
- <Dropdown.Root key={`dropdownRoot${stableIdx}`}>
53
- <Dropdown.Toggle.Button {...buttonControls} />
54
- <Dropdown.Content width="100%">
55
- <Dropdown.List>
56
- {submenu.map((item, index) => (
57
- <Dropdown.ListItem.Interactive
58
- text={item.text}
59
- // eslint-disable-next-line react/no-array-index-key
60
- key={`dropdownItem${index}`}
61
- href={item.url}
62
- />
63
- ))}
64
- </Dropdown.List>
65
- </Dropdown.Content>
66
- </Dropdown.Root>
67
- )
68
- } else {
69
- {
70
- const { text, href, icon, color, size, __typename, ...rest } = cta
71
-
72
- const textKey = text?.toLowerCase()
73
- const isDownload = textKey === 'download'
74
- const isGithub = textKey === 'github'
75
-
76
- if (isGithub && !isInDropdown)
77
- return (
78
- <GithubStarsLink
79
- key={href}
80
- url={href}
81
- hideGithubStars={hideGithubStars}
82
- />
83
- )
84
- const isLastButton = stableIdx === links.length - 1
85
-
86
- return (
87
- <HDSPlusButton
88
- key={href}
89
- text={text}
90
- href={href}
91
- size={size}
92
- isFullWidth={isInDropdown}
93
- color={color ?? (isLastButton ? product : 'secondary')}
94
- isIconOnly={!text}
95
- icon={
96
- icon ? (
97
- icon
98
- ) : isDownload ? (
99
- <FlightIcon
100
- name="download"
101
- size={16}
102
- style={{ display: 'block' }}
103
- />
104
- ) : isGithub ? (
105
- <FlightIcon
106
- name="github"
107
- size={16}
108
- style={{ display: 'block' }}
109
- />
110
- ) : undefined
111
- }
112
- {...rest}
113
- />
114
- )
115
- }
116
- }
117
- })}
118
- </NavigationMenu.List>
119
- )
120
- }
121
-
122
- export default CtaLinks
123
-
124
- /**
125
- * Type guard to properly type incoming subnav CTAs as Dropdown if needed
126
- * @param cta CTA to guard
127
- * @returns CTA re-typed according to whether it has a submenu property
128
- */
129
- function isDropdown(cta: CtaDropdown | CtaLink): cta is CtaDropdown {
130
- return 'submenu' in cta
131
- }