diff --git a/website/components/downloader/cards/index.jsx b/website/components/downloader/cards/index.jsx deleted file mode 100644 index d2c6de175..000000000 --- a/website/components/downloader/cards/index.jsx +++ /dev/null @@ -1,136 +0,0 @@ -import Tabs from '@hashicorp/react-tabs' -import { - prettyOs, - prettyArch, - trackDownload, -} from 'components/downloader/utils/downloader' -import styles from './style.module.css' - -export default function DownloadTabs({ - defaultTabIdx, - tabData, - downloads, - version, - merchandisingSlot, - brand, - logo, - tutorialLink, -}) { - return ( - ({ - heading: prettyOs(os), - tabChildren: function TabChildren() { - return ( -
- - {merchandisingSlot} -
- ) - }, - }))} - /> - ) -} - -function Cards({ - os, - downloads, - packageManagers, - version, - theme, - logo, - tutorialLink, -}) { - const arches = downloads[os] - const hasPackageManager = Boolean(packageManagers) - const hasMultiplePackageManagers = Array.isArray(packageManagers) - - function handleArchClick(arch) { - return () => trackDownload('boundary', version, os, arch) - } - - return ( - <> -
- {hasPackageManager && ( -
- Package Manager - {Array.isArray(packageManagers) ? ( - ({ - heading: label, - tabChildren: function TabChildren() { - return ( -
- {commands.map((command) => ( -
{command}
- ))} -
- ) - }, - }))} - /> - ) : ( -
- {packageManagers.commands.map((command) => ( -
{command}
- ))} -
- )} - {tutorialLink && ( -
- {tutorialLink.label} -
- )} -
- )} -
- Binary Download -
-
- {logo} - {version} -
- {Object.entries(arches).map(([arch, url]) => ( - - {prettyArch(arch)} - - ))} -
-
- Bandwidth courtesy of - Fastly -
-
-
- - ) -} diff --git a/website/components/downloader/cards/style.module.css b/website/components/downloader/cards/style.module.css deleted file mode 100644 index 3983457ff..000000000 --- a/website/components/downloader/cards/style.module.css +++ /dev/null @@ -1,156 +0,0 @@ -.cards { - max-width: 880px; - margin: 0 auto; -} - -.logoWrapper { - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 10px; -} - -.logoDownloadWrapper { - width: 100%; -} - -.version { - margin-left: 8px; -} - -.downloadCards { - justify-content: center; - margin: 54px 0 24px; - - & a { - color: var(--gray-2); - } - - @media (--medium-up) { - margin: 64px 0; - display: grid; - grid-template-columns: 1fr 1fr; - grid-column-gap: 48px; - justify-items: center; - } - - & .downloadLink { - color: var(--brand); - margin-right: 16px; - } -} - -.downloadCardsSingle { - composes: downloadCards; - - & .card { - max-width: unset; - } - - @media (--medium-up) { - grid-template-columns: 1fr; - - & .card:first-child { - margin-bottom: 48px; - } - } -} - -.card { - width: 100%; - min-height: 278px; - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - justify-content: space-between; - padding: 40px 32px; - color: var(--gray-2); - border: 1px solid var(--gray-6); - - &:first-child { - border-bottom: none; - - @media (--medium-up) { - border-bottom: 1px solid var(--gray-6); - } - } -} - -.packageManagers { - composes: card; - - & a { - color: var(--brand); - } - - & :global { - & .g-tabs { - width: 100%; - - @media (--medium-up) { - width: initial; - } - } - } -} - -.soloCard { - composes: card; - grid-column: span 2; - - &:first-child { - border-bottom: 1px solid var(--gray-6); - } -} - -.install { - color: var(--white); - background-color: var(--black); - padding: 16px 24px; - border-radius: 3px; - text-align: left; - margin: 32px 0; - - & pre { - margin: 0; - padding: 0; - background-color: inherit; - white-space: normal; - - &::before { - color: #e93471; - content: '$'; - margin-right: 8px; - } - - @media (--medium-up) { - white-space: pre; - } - } -} - -.cardTitle { - font-family: var(--font-display); - font-size: 12px; - line-height: 18px; - letter-spacing: 0.06em; - text-transform: uppercase; - color: var(--gray-4); - font-weight: bold; -} - -.fastly { - display: flex; - align-items: center; - flex-direction: column; - - & svg path { - fill: var(--black); - } - - & img { - margin-top: 12px; - width: 48px; - } -} diff --git a/website/components/downloader/dropdown/index.jsx b/website/components/downloader/dropdown/index.jsx deleted file mode 100644 index 11d202db3..000000000 --- a/website/components/downloader/dropdown/index.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { useState, useRef, useEffect } from 'react' -import Button from '@hashicorp/react-button' -import styles from './style.module.css' - -export default function Dropdown({ options, onChange, title, brand }) { - const [open, setOpen] = useState(false) - const buttonRef = useRef() - - useEffect(() => { - function handleClickOutside(event) { - if (buttonRef.current.contains(event.target)) return - - setOpen(false) - } - document.addEventListener('mousedown', handleClickOutside) - - return () => { - document.removeEventListener('mousedown', handleClickOutside) - } - }, []) - - return ( -
-
- ) -} diff --git a/website/components/downloader/dropdown/style.module.css b/website/components/downloader/dropdown/style.module.css deleted file mode 100644 index f7e381898..000000000 --- a/website/components/downloader/dropdown/style.module.css +++ /dev/null @@ -1,28 +0,0 @@ -.root { - display: inline-block; - position: relative; -} - -.menu { - position: absolute; - list-style: none; - max-height: 250px; - overflow-y: auto; - top: 35px; - width: 100%; - padding: 0; - background-color: var(--white); - box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), - 0 1px 3px 0 rgba(0, 0, 0, 0.12); -} - -.option { - padding: 8px 16px; - cursor: pointer; - background-color: var(--brand); - color: var(--white); - - &:hover { - background-color: var(--brand-d1); - } -} diff --git a/website/components/downloader/logos/fastly.svg b/website/components/downloader/logos/fastly.svg deleted file mode 100644 index cfe7b7e96..000000000 --- a/website/components/downloader/logos/fastly.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - \ No newline at end of file diff --git a/website/components/downloader/release-information/index.jsx b/website/components/downloader/release-information/index.jsx deleted file mode 100644 index 2e2562cb7..000000000 --- a/website/components/downloader/release-information/index.jsx +++ /dev/null @@ -1,165 +0,0 @@ -import { useState, Fragment, useEffect } from 'react' - -import Dropdown from 'components/downloader/dropdown' -import { - prettyArch, - prettyOs, - trackDownload, - sortPlatforms, - getVersionLabel, - sortAndFilterReleases, -} from 'components/downloader/utils/downloader' -import styles from './style.module.css' - -export default function ReleaseInformation({ - productId, - productName, - latestVersion, - packageManagers, - containers, - tutorials, - changelog, - brand, -}) { - const [selectedVersionId, setSelectedVersionId] = useState(latestVersion) - const [releases, setReleases] = useState([]) - const { version, ...selectedVersion } = - releases.find((release) => release.version === selectedVersionId) || {} - - useEffect(() => { - // lazy load all release versions to populate dropdown & releases section - fetch(`https://releases.hashicorp.com/${productId}/index.json`) - .then((res) => res.json()) - .then((data) => { - const latestReleases = sortAndFilterReleases(Object.keys(data.versions)) - - const releases = latestReleases.map((releaseVersion) => ({ - ...sortPlatforms(data.versions[releaseVersion]), - version: releaseVersion, - })) - setReleases(releases) - }) - }, []) - - return ( -
-
-

Release Information

-
- {releases.length > 0 && ( - <> -
Releases:
-
- ({ - label: `${productName} ${getVersionLabel( - releaseData.version, - latestVersion - )}`, - value: releaseData.version, - }))} - onChange={(release) => setSelectedVersionId(release)} - /> - - Changelog - -
- - )} -
Latest Downloads:
-
- Package downloads for {productName} {version} -
- {Object.entries(selectedVersion).map(([os, release]) => ( - -
{prettyOs(os)}
-
- {Object.entries(release).map(([arch, file]) => ( - - trackDownload('boundary', version, os, arch) - } - > - {prettyArch(arch)} - - ))} -
-
- ))} -
-

- You can find the{' '} - - SHA256 checksums for {productName} {version} - {' '} - online and you can{' '} - - verify the checksums signature file - {' '} - which has been signed using{' '} - - HashiCorp's GPG key. - -

-
- - {packageManagers?.length > 0 && ( - <> -
Package Managers
-
- {packageManagers.map((packageManager) => ( -
- Install with{' '} - {packageManager.label} -
- ))} -
- - )} - {containers?.length > 0 && ( - <> -
Containers
-
- {containers.map((container) => ( -
- Run with {container.label} -
- ))} -
- - )} - - {containers?.length > 0 && ( - <> -
Tutorials
-
- {tutorials.map((tutorial) => ( - - ))} -
- - )} -
-
-
- ) -} diff --git a/website/components/downloader/release-information/style.module.css b/website/components/downloader/release-information/style.module.css deleted file mode 100644 index 3f91d6ec0..000000000 --- a/website/components/downloader/release-information/style.module.css +++ /dev/null @@ -1,101 +0,0 @@ -.root { - background-color: var(--gray-7); - padding: 42px 0; - margin-top: 42px; - color: var(--gray-2); - - & p { - color: var(--gray-2); - } - - & a { - color: var(--gray-2); - } - - & :global(.g-container) { - max-width: 825px; - } - - & h2 { - text-align: center; - color: var(--black); - margin-bottom: 54px; - - @media (--medium-up) { - margin-bottom: 64px; - } - } -} - -.heading { - margin: 24px 0; - font-weight: bold; - color: var(--black); - - @media (--medium-up) { - text-align: right; - margin: 0; - } -} - -.changelog { - display: block; - margin: 24px 0 0; - color: var(--black); - - @media (--medium-up) { - display: inline-block; - margin: 0 0 0 24px; - } -} - -.grid { - margin: 48px auto; - - @media (--medium-up) { - display: grid; - grid-column-gap: 32px; - grid-row-gap: 48px; - grid-template-columns: auto 1fr; - } -} - -.latestDownloads { - composes: heading; - margin-top: 40px; - - @media (--medium-up) { - margin-top: 0; - } -} - -.downloads { - display: grid; - width: 100%; - grid-template-columns: auto 1fr; - margin: 17px 0 40px; - grid-column-gap: 28px; - grid-row-gap: 16px; - - & a { - margin: 0 6px; - } - - & .os { - font-weight: bold; - color: var(--black); - } - - @media (--medium-up) { - margin: 20px 0 64px; - } -} - -.releases { - align-self: center; - composes: heading; -} - -.links > div:not(:first-child) { - margin: 15px 0; -} diff --git a/website/components/downloader/utils/downloader.js b/website/components/downloader/utils/downloader.js deleted file mode 100644 index f9dd60a3f..000000000 --- a/website/components/downloader/utils/downloader.js +++ /dev/null @@ -1,139 +0,0 @@ -import semverRSort from 'semver/functions/rsort' -import semverPrerelease from 'semver/functions/prerelease' -import semverValid from 'semver/functions/valid' - -export function getVersionLabel(version, latestVersion) { - if (version === latestVersion) { - return `${version} (latest)` - } - - return version -} - -export function sortAndFilterReleases(releases) { - const validReleases = releases.filter(semverValid) - // descending sort on releases, while filtering out pre-releases - return semverRSort(validReleases).filter( - (version) => !semverPrerelease(version) - ) -} - -/** TODO: Below utils directly from Product-Downloader component. - * Should either be exported, or migrated back to web-components */ - -export function prettyArch(arch) { - switch (arch) { - case 'all': - return 'Universal (32 and 64-bit)' - case 'i686': - case 'i386': - case '686': - case '386': - return '32-bit' - case 'x86_64': - case '86_64': - case 'amd64': - return '64-bit' - default: - if (/-/.test(arch)) { - const parts = arch.split(/-(.+)/) - return `${prettyArch(parts[0])} (${parts[1]})` - } else { - const parts = arch.split('_') - if (parts.length > 0) { - return ( - parts[parts.length - 1].charAt(0).toUpperCase() + - parts[parts.length - 1].slice(1) - ) - } - } - } -} - -export function detectOs(platform) { - for (let key in platformMap) { - if (platform.indexOf(key) !== -1) { - return platformMap[key] - } - } - - return null -} - -export function prettyOs(os) { - switch (os) { - case 'darwin': - return 'Mac OS X' - case 'freebsd': - return 'FreeBSD' - case 'openbsd': - return 'OpenBSD' - case 'netbsd': - return 'NetBSD' - case 'archlinux': - return 'Arch Linux' - case 'linux': - return 'Linux' - case 'windows': - return 'Windows' - default: - return os.charAt(0).toUpperCase() + os.slice(1) - } -} - -const platformMap = { - Mac: 'darwin', - Win: 'windows', - Linux: 'linux', -} - -export function sortPlatforms(releaseData) { - // first we pull the platforms out of the release data object and format it the way we want - const platforms = releaseData.builds.reduce((acc, build) => { - if (!acc[build.os]) acc[build.os] = {} - acc[build.os][build.arch] = build.url - return acc - }, {}) - - const platformKeys = Object.keys(platforms) - - // create array of sorted values to base the order on - const sortedValues = Object.keys(platformMap) - .map((e) => platformMap[e]) - // join the lists together to make sure - // all items are accounted for when sorting - .concat(platformKeys) - // filter our any duplicates and unneeded items - .filter((elem, pos, arr) => { - return arr.indexOf(elem) == pos && platformKeys.indexOf(elem) > -1 - }) - - return ( - platformKeys - // sort items based on platformMap order - .sort((a, b) => { - return sortedValues.indexOf(a) - sortedValues.indexOf(b) - }) - // create new sorted object to return - .reduce((result, key) => { - result[key] = platforms[key] - return result - }, {}) - ) -} - -export function trackDownload(product, version, _os, _arch) { - const os = prettyOs(_os) - const arch = prettyArch(_arch) - - if (window.analytics) { - window.analytics.track('Download', { - category: 'Button', - label: `${product} | v${version} | ${os} | ${arch}`, - version, - os, - architecture: arch, - product, - }) - } -} diff --git a/website/package-lock.json b/website/package-lock.json index a1175aaef..0407aa1b7 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -1728,11 +1728,13 @@ } }, "@hashicorp/react-product-downloader": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@hashicorp/react-product-downloader/-/react-product-downloader-4.1.5.tgz", - "integrity": "sha512-ytmQi0ZfGmhSboRujDtXJGIhJE13ZSd0MsEpyAEoiWwZqv190qSXnYgl3HcT7iM4nENJEmPcHA4MnvCcKQaODA==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@hashicorp/react-product-downloader/-/react-product-downloader-6.1.1.tgz", + "integrity": "sha512-jvWQiMmrJkkAAhNa13fL9ogaMDD4WhLR319ozlKySVT7g8a03vwum0GG8FyIFf0LyKXBQJzSsuXpSX4vC6eKzQ==", "requires": { - "@hashicorp/react-button": "^2.2.8" + "@hashicorp/react-button": "^2.2.8", + "@hashicorp/react-tabs": "^1.0.0", + "semver": "^7.3.2" }, "dependencies": { "@hashicorp/react-button": { diff --git a/website/package.json b/website/package.json index 6b882c9ab..fd1806b16 100644 --- a/website/package.json +++ b/website/package.json @@ -16,7 +16,7 @@ "@hashicorp/react-head": "1.1.4", "@hashicorp/react-hero": "^3.1.9", "@hashicorp/react-image": "3.0.1", - "@hashicorp/react-product-downloader": "4.1.5", + "@hashicorp/react-product-downloader": "^6.1.1", "@hashicorp/react-product-features-list": "^2.1.2", "@hashicorp/react-section-header": "3.0.0", "@hashicorp/react-subnav": "5.0.0", diff --git a/website/pages/downloads/index.jsx b/website/pages/downloads/index.jsx index 78122fa8e..5222d526d 100644 --- a/website/pages/downloads/index.jsx +++ b/website/pages/downloads/index.jsx @@ -1,84 +1,114 @@ -import { useMemo, useState, useEffect } from 'react' import VERSION from 'data/version.js' import Head from 'next/head' import HashiHead from '@hashicorp/react-head' - import { productName, productSlug } from 'data/metadata' -import { packageManagersByOs, getStartedLinks } from 'data/downloads' -import ReleaseInformation from 'components/downloader/release-information' -import { sortPlatforms, detectOs } from 'components/downloader/utils/downloader' -import DownloadCards from 'components/downloader/cards' +import ProductDownloader from '@hashicorp/react-product-downloader' import styles from './style.module.css' -export default function DownloadsPage({ releaseData, previousVersions }) { - const sortedDownloads = useMemo(() => sortPlatforms(releaseData), [ - releaseData, - ]) - const osKeys = Object.keys(sortedDownloads) - const [osIndex, setSelectedOsIndex] = useState() - - const tabData = Object.keys(sortedDownloads).map((osKey) => ({ - os: osKey, - packageManagers: packageManagersByOs[osKey] || null, - })) - - useEffect(() => { - // if we're on the client side, detect the default platform only on initial render - const index = osKeys.indexOf(detectOs(window.navigator.platform)) - setSelectedOsIndex(index) - }, []) - +export default function DownloadsPage({ releases }) { return (
-

Download {productName}

- } + brand="red" tutorialLink={{ label: 'View Tutorial on HashiCorp Learn', href: 'https://learn.hashicorp.com/tutorials/boundary/getting-started-install', }} /> - -
-
-

Getting Started

-
- {getStartedLinks.map((link) => ( - - {link.label} - - ))} -
-
-
- -
) } export async function getStaticProps() { - return fetch(`https://releases.hashicorp.com/boundary/${VERSION}/index.json`) - .then((r) => r.json()) - .then((releaseData) => ({ props: { releaseData } })) + return fetch(`https://releases.hashicorp.com/boundary/index.json`, { + headers: { + 'Cache-Control': 'no-cache', + }, + }) + .then((res) => res.json()) + .then((result) => { + return { + props: { + releases: result, + }, + } + }) .catch(() => { throw new Error( `-------------------------------------------------------- diff --git a/website/pages/downloads/style.module.css b/website/pages/downloads/style.module.css index 448aa3cb3..82da36376 100644 --- a/website/pages/downloads/style.module.css +++ b/website/pages/downloads/style.module.css @@ -1,61 +1,7 @@ .root { - margin-top: 72px; - - & a { - text-decoration: underline; - } - - & h1 { - text-align: center; - } - - --brand: var(--red); - --brand-d1: #c03e43; + --red-d1: #c03e43; } .logo { max-width: 140px; } - -.hosting { - border: 1px solid var(--gray-6); - padding: 16px; - text-align: center; - color: var(--gray-2); -} - -.gettingStarted { - max-width: 680px; - margin: 40px auto 64px; - text-align: center; - - & p { - color: var(--gray-3); - } - - & a { - color: var(--black); - } - - & h2 { - text-align: center; - margin: 16px 0; - } - - @media (--medium-up) { - margin: 88px auto 128px; - } -} - -.links { - margin-top: 32px; - & a { - text-align: center; - display: block; - margin: 8px 0; - } -} - -.signUpButton { - margin-left: 26px; -} diff --git a/website/pages/style.css b/website/pages/style.css index b80fe9667..90af34bd5 100644 --- a/website/pages/style.css +++ b/website/pages/style.css @@ -11,7 +11,6 @@ @import '~@hashicorp/react-consent-manager/dist/style.css'; @import '~@hashicorp/react-toggle/dist/style.css'; @import '~@hashicorp/react-section-header/style.css'; -@import '~@hashicorp/react-product-downloader/dist/style.css'; @import '~@hashicorp/react-vertical-text-block-list/style.css'; @import '~@hashicorp/react-docs-sidenav/style.css'; @import '~@hashicorp/react-content/style.css';