website: remove source code (#15068)
* removes site source code * remove algolia index and docker image workflows * remove unneeded dependencies
This commit is contained in:
parent
e69f89c279
commit
2c4a619a8c
|
@ -148,22 +148,6 @@ jobs:
|
|||
- GO_VERSION: 1.17.9
|
||||
- GOFUMPT_VERSION: 0.2.1
|
||||
- GOTESTSUM_VERSION: 0.5.2
|
||||
algolia-index:
|
||||
docker:
|
||||
- image: node:14
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
if [ "$CIRCLE_REPOSITORY_URL" != "git@github.com:hashicorp/vault.git" ]; then
|
||||
echo "Not Vault OSS Repo, not indexing Algolia"
|
||||
exit 0
|
||||
fi
|
||||
cd website/
|
||||
npm install -g npm@latest
|
||||
npm install
|
||||
node scripts/index_search_content.js
|
||||
name: Push content to Algolia Index
|
||||
test-go-remote-docker:
|
||||
docker:
|
||||
- image: docker.mirror.hashicorp.services/cimg/go:1.17.9
|
||||
|
@ -588,29 +572,6 @@ jobs:
|
|||
environment:
|
||||
- CIRCLECI_CLI_VERSION: 0.1.5546
|
||||
- GO_TAGS: ''
|
||||
website-docker-image:
|
||||
docker:
|
||||
- image: circleci/buildpack-deps
|
||||
shell: /usr/bin/env bash -euo pipefail -c
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker
|
||||
- run:
|
||||
command: |
|
||||
IMAGE_TAG="$(git rev-list -n1 HEAD -- website/Dockerfile website/package-lock.json)"
|
||||
echo "Using $IMAGE_TAG"
|
||||
if [ "$CIRCLE_REPOSITORY_URL" != "git@github.com:hashicorp/vault.git" ]; then
|
||||
echo "Not Vault OSS Repo, not building website docker image"
|
||||
elif curl https://hub.docker.com/v2/repositories/hashicorp/vault-website/tags/$IMAGE_TAG -fsL > /dev/null; then
|
||||
echo "Dependencies have not changed, not building a new website docker image."
|
||||
else
|
||||
cd website/
|
||||
docker build -t hashicorp/vault-website:$IMAGE_TAG .
|
||||
docker tag hashicorp/vault-website:$IMAGE_TAG hashicorp/vault-website:latest
|
||||
docker login -u $WEBSITE_DOCKER_USER -p $WEBSITE_DOCKER_PASS
|
||||
docker push hashicorp/vault-website
|
||||
fi
|
||||
name: Build Docker Image if Necessary
|
||||
test-go:
|
||||
docker:
|
||||
- image: docker.mirror.hashicorp.services/cimg/go:1.17.9
|
||||
|
@ -1137,18 +1098,6 @@ workflows:
|
|||
- test-go-race-remote-docker:
|
||||
requires:
|
||||
- pre-flight-checks
|
||||
- website-docker-image:
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
context: vault-docs
|
||||
- algolia-index:
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- stable-website
|
||||
context: vault-docs
|
||||
- semgrep:
|
||||
requires:
|
||||
- pre-flight-checks
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
docker:
|
||||
- image: node:14
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Push content to Algolia Index
|
||||
command: |
|
||||
if [ "$CIRCLE_REPOSITORY_URL" != "git@github.com:hashicorp/vault.git" ]; then
|
||||
echo "Not Vault OSS Repo, not indexing Algolia"
|
||||
exit 0
|
||||
fi
|
||||
cd website/
|
||||
npm install -g npm@latest
|
||||
npm install
|
||||
node scripts/index_search_content.js
|
|
@ -1,22 +0,0 @@
|
|||
docker:
|
||||
- image: circleci/buildpack-deps
|
||||
shell: /usr/bin/env bash -euo pipefail -c
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker
|
||||
- run:
|
||||
name: Build Docker Image if Necessary
|
||||
command: |
|
||||
IMAGE_TAG="$(git rev-list -n1 HEAD -- website/Dockerfile website/package-lock.json)"
|
||||
echo "Using $IMAGE_TAG"
|
||||
if [ "$CIRCLE_REPOSITORY_URL" != "git@github.com:hashicorp/vault.git" ]; then
|
||||
echo "Not Vault OSS Repo, not building website docker image"
|
||||
elif curl https://hub.docker.com/v2/repositories/hashicorp/vault-website/tags/$IMAGE_TAG -fsL > /dev/null; then
|
||||
echo "Dependencies have not changed, not building a new website docker image."
|
||||
else
|
||||
cd website/
|
||||
docker build -t hashicorp/vault-website:$IMAGE_TAG .
|
||||
docker tag hashicorp/vault-website:$IMAGE_TAG hashicorp/vault-website:latest
|
||||
docker login -u $WEBSITE_DOCKER_USER -p $WEBSITE_DOCKER_PASS
|
||||
docker push hashicorp/vault-website
|
||||
fi
|
|
@ -38,18 +38,6 @@ jobs:
|
|||
- test-go-race-remote-docker:
|
||||
requires:
|
||||
- pre-flight-checks
|
||||
- website-docker-image:
|
||||
context: vault-docs
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
- algolia-index:
|
||||
context: vault-docs
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- stable-website
|
||||
- semgrep:
|
||||
requires:
|
||||
- pre-flight-checks
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Vault Website
|
||||
|
||||
This subdirectory contains the entire source for the [Vault Website](https://vaultproject.io/). This is a [NextJS](https://nextjs.org/) project, which builds a static site from these source files.
|
||||
This subdirectory contains the content for the [Vault Website](https://vaultproject.io/).
|
||||
|
||||
<!--
|
||||
This readme file contains several blocks of generated text, to make it easier to share common information
|
||||
|
@ -40,11 +40,10 @@ The website can be run locally through node.js or [Docker](https://www.docker.co
|
|||
|
||||
> **Note:** If you are using a text editor that uses a "safe write" save style such as **vim** or **goland**, this can cause issues with the live reload in development. If you turn off safe write, this should solve the problem. In vim, this can be done by running `:set backupcopy=yes`. In goland, search the settings for "safe write" and turn that setting off.
|
||||
|
||||
| :warning: WARNING :warning: |
|
||||
|:----------------------------|
|
||||
| :warning: WARNING :warning: |
|
||||
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| If you've previously run the website successfully using either the Docker or Node.js approach but are now facing some issue then try `docker rmi $(docker images -aq hashicorp-vault-website-local) && make build-image && make website-local` or `rm -rf node_modules`; failing that consider cloning this repository again and re-attempting the steps anew in a clean clone. |
|
||||
|
||||
|
||||
### With Docker
|
||||
|
||||
Running the site locally is simple. Provided you have Docker installed, clone this repo, run `make`, and then visit `http://localhost:3000`.
|
||||
|
@ -82,7 +81,6 @@ This file can be standard Markdown and also supports [YAML frontmatter](https://
|
|||
title: 'My Title'
|
||||
description: "A thorough, yet succinct description of the page's contents"
|
||||
---
|
||||
|
||||
```
|
||||
|
||||
The significant keys in the YAML frontmatter are:
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
fragment beforeAfterDiagramFields on SbcBeforeAfterDiagramRecord {
|
||||
theme
|
||||
beforeHeadline
|
||||
beforeContent
|
||||
beforeImage {
|
||||
...imageFields
|
||||
}
|
||||
afterHeadline
|
||||
afterContent
|
||||
afterImage {
|
||||
...imageFields
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
import Image from '@hashicorp/react-image'
|
||||
import InlineSvg from '@hashicorp/react-inline-svg'
|
||||
import alertIcon from 'public/img/icons/alert.svg?include'
|
||||
import checkIcon from 'public/img/icons/check.svg?include'
|
||||
import fragment from './fragment.graphql'
|
||||
import s from './style.module.css'
|
||||
function BeforeAfterDiagram(props) {
|
||||
const {
|
||||
theme,
|
||||
beforeHeadline,
|
||||
beforeContent,
|
||||
beforeImage,
|
||||
afterHeadline,
|
||||
afterContent,
|
||||
afterImage,
|
||||
} = props
|
||||
return (
|
||||
<div className={s.beforeAfterDiagram} data-theme={theme}>
|
||||
<div className={s.beforeSide}>
|
||||
<div className={s.image}>
|
||||
<div>
|
||||
<Image {...beforeImage} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={s.contentContainer}>
|
||||
<span className={s.iconLineContainer}>
|
||||
<InlineSvg className={s.beforeIcon} src={alertIcon} />
|
||||
<span className={s.lineSegment} />
|
||||
</span>
|
||||
<div>
|
||||
{beforeHeadline && (
|
||||
<h2
|
||||
className={s.contentHeadline}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: beforeHeadline,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{beforeContent && (
|
||||
<div
|
||||
className={s.beforeContent}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: beforeContent,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={s.afterSide}>
|
||||
<div className={s.image}>
|
||||
<div>
|
||||
<Image {...afterImage} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={s.contentContainer}>
|
||||
<span className={s.iconLineContainer}>
|
||||
<InlineSvg className={s.afterIcon} src={checkIcon} />
|
||||
</span>
|
||||
<div>
|
||||
{afterHeadline && (
|
||||
<h2
|
||||
className={s.contentHeadline}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: afterHeadline,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{afterContent && (
|
||||
<div
|
||||
className={s.afterContent}
|
||||
data-theme={theme}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: afterContent,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
BeforeAfterDiagram.fragmentSpec = { fragment, dependencies: [Image] }
|
||||
|
||||
export default BeforeAfterDiagram
|
|
@ -1,31 +0,0 @@
|
|||
import md from '@hashicorp/platform-markdown-utils/markdown-to-html'
|
||||
import mdInline from '@hashicorp/platform-markdown-utils/markdown-to-inline-html'
|
||||
|
||||
export default async function processBeforeAfterDiagramProps(props) {
|
||||
const { beforeHeadline, beforeContent, afterHeadline, afterContent } = props
|
||||
// Transform headline markdown to HTML, for inline bold / italic support
|
||||
props.beforeHeadline = await mdInline(beforeHeadline)
|
||||
props.afterHeadline = await mdInline(afterHeadline)
|
||||
// Transform content markdown to HTML, using custom type classes
|
||||
const contentOptions = {
|
||||
contentPlugins: {
|
||||
pluginOptions: {
|
||||
typography: {
|
||||
map: {
|
||||
h1: 'g-type-label',
|
||||
h2: 'g-type-label',
|
||||
h3: 'g-type-label',
|
||||
h4: 'g-type-label',
|
||||
h5: 'g-type-label',
|
||||
h6: 'g-type-label',
|
||||
p: 'g-type-body-small',
|
||||
li: 'g-type-body-small',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
props.beforeContent = await md(beforeContent, contentOptions)
|
||||
props.afterContent = await md(afterContent, contentOptions)
|
||||
return props
|
||||
}
|
|
@ -1,348 +0,0 @@
|
|||
/* Container */
|
||||
|
||||
.beforeAfterDiagram {
|
||||
/* CSS custom properties to control theming */
|
||||
--product-color: var(--black);
|
||||
--gray-6-transparent: rgba(210, 212, 219, 0);
|
||||
--after-bullet-background: url('/img/icons/check-square-vault.svg');
|
||||
--after-bullet-height: 18px;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -16px;
|
||||
position: relative;
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
margin-left: -12px;
|
||||
margin-right: -12px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
flex-direction: column;
|
||||
margin-left: 40px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Before and after columns */
|
||||
|
||||
.side {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 16px;
|
||||
position: relative;
|
||||
width: calc(50% - 32px);
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
margin: 0 12px;
|
||||
width: calc(50% - 24px);
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.beforeSide {
|
||||
composes: side;
|
||||
@media (max-width: 767px) {
|
||||
margin-bottom: 62px;
|
||||
}
|
||||
}
|
||||
|
||||
.afterSide {
|
||||
composes: side;
|
||||
}
|
||||
|
||||
/* Diagram images */
|
||||
|
||||
.image {
|
||||
align-items: flex-end;
|
||||
display: flex;
|
||||
height: 320px;
|
||||
justify-content: center;
|
||||
margin-bottom: 96px;
|
||||
|
||||
@media (max-width: 767px) {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
height: 284px;
|
||||
}
|
||||
|
||||
@media (max-width: 540px) {
|
||||
height: 238px;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
height: 211px;
|
||||
}
|
||||
|
||||
@media (max-width: 375px) {
|
||||
height: 163px;
|
||||
}
|
||||
|
||||
& div {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
& picture {
|
||||
height: 100%;
|
||||
}
|
||||
& img,
|
||||
& svg {
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
@media (--medium-up) {
|
||||
& div {
|
||||
height: unset;
|
||||
}
|
||||
|
||||
& picture {
|
||||
height: unset;
|
||||
}
|
||||
& img,
|
||||
& svg {
|
||||
height: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* icon / line container above content */
|
||||
|
||||
.iconLineContainer {
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -75px;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: 767px) {
|
||||
height: 100%;
|
||||
left: -28px;
|
||||
right: auto;
|
||||
top: 28px;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Line segment above content (before side only) */
|
||||
|
||||
.lineSegment {
|
||||
background: black;
|
||||
display: block;
|
||||
height: 2px;
|
||||
left: calc(50% + 30px);
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
width: calc(100% - 24px);
|
||||
|
||||
@media (max-width: 767px) {
|
||||
height: calc(100% + 375px);
|
||||
left: auto;
|
||||
top: 38px;
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
height: calc(100% + 339px);
|
||||
}
|
||||
|
||||
@media (max-width: 540px) {
|
||||
height: calc(100% + 293px);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
height: calc(100% + 266px);
|
||||
}
|
||||
|
||||
@media (max-width: 375px) {
|
||||
height: calc(100% + 218px);
|
||||
}
|
||||
|
||||
&::before {
|
||||
border-radius: 100%;
|
||||
border-style: solid;
|
||||
border-width: 5.5px 0 5.5px 8px;
|
||||
border-width: 2px;
|
||||
content: '';
|
||||
height: 8px;
|
||||
left: -8px;
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
width: 8px;
|
||||
|
||||
@media (max-width: 767px) {
|
||||
left: -3px;
|
||||
top: -8px;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-color: transparent transparent transparent var(--product-color);
|
||||
border-style: solid;
|
||||
border-width: 6px 0 6px 8px;
|
||||
content: '';
|
||||
height: 0;
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
top: -5px;
|
||||
width: 0;
|
||||
|
||||
@media (max-width: 767px) {
|
||||
bottom: -8px;
|
||||
right: -4px;
|
||||
top: auto;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Icon above each content container */
|
||||
|
||||
.contentIcon {
|
||||
& svg {
|
||||
left: 50%;
|
||||
margin: 0 0 0 -11px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.beforeIcon {
|
||||
composes: contentIcon;
|
||||
}
|
||||
|
||||
.afterIcon {
|
||||
composes: contentIcon;
|
||||
& svg path:first-child {
|
||||
fill: var(--product-color);
|
||||
stroke: var(--product-color);
|
||||
}
|
||||
}
|
||||
|
||||
/* Content container */
|
||||
|
||||
.contentContainer {
|
||||
border: 1px solid var(--gray-5);
|
||||
flex-grow: 1;
|
||||
padding: 24px 32px 20px;
|
||||
position: relative;
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
border: solid transparent;
|
||||
bottom: 100%;
|
||||
content: '';
|
||||
height: 0;
|
||||
left: 50%;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
&::before {
|
||||
border-color: rgba(229, 230, 235, 0);
|
||||
border-bottom-color: var(--gray-5);
|
||||
border-width: 18px;
|
||||
margin-left: -18px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-color: rgba(255, 255, 255, 0);
|
||||
border-bottom-color: var(--white);
|
||||
border-width: 17px;
|
||||
margin-left: -17px;
|
||||
}
|
||||
|
||||
& > div {
|
||||
height: 100%;
|
||||
|
||||
& > div {
|
||||
@media (min-width: 768px) {
|
||||
margin: 0 auto;
|
||||
max-width: 480px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Content headline */
|
||||
|
||||
.contentHeadline {
|
||||
border-bottom: 1px solid var(--gray-5);
|
||||
color: var(--black);
|
||||
composes: g-type-display-3 from global;
|
||||
margin: 0 0 24px;
|
||||
padding-bottom: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Content styles (for rendered markdown) */
|
||||
|
||||
.content {
|
||||
& :global(.__permalink-h) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& :global(.g-type-label) {
|
||||
margin: 24px 0 26px 0;
|
||||
}
|
||||
|
||||
& ul,
|
||||
& ol {
|
||||
list-style: none;
|
||||
padding-left: 32px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
& li {
|
||||
margin: 8px 0;
|
||||
|
||||
&::before {
|
||||
background-repeat: no-repeat;
|
||||
content: '';
|
||||
left: 0;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.beforeContent {
|
||||
composes: content;
|
||||
|
||||
& li::before {
|
||||
background: url('/img/icons/alert-check.svg');
|
||||
background-repeat: no-repeat;
|
||||
height: var(--after-bullet-height);
|
||||
margin-top: 3px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.afterContent {
|
||||
composes: content;
|
||||
|
||||
& li::before {
|
||||
background: var(--after-bullet-background);
|
||||
height: var(--after-bullet-height);
|
||||
margin-top: 4px;
|
||||
width: 18px;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
# Columns Component
|
||||
|
||||
An _experimental_ component currently used only on `/api-docs/plugins-directory` -- currently only works correctly when applied to `ul` elements.
|
|
@ -1,5 +0,0 @@
|
|||
import s from './style.module.css'
|
||||
|
||||
export default function Columns({ count = 1, children }) {
|
||||
return <div className={`${s.root} ${s['count-' + count]}`}>{children}</div>
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
.root {
|
||||
break-inside: avoid-column;
|
||||
page-break-inside: avoid;
|
||||
|
||||
&.count-1 ul {
|
||||
columns: 1;
|
||||
}
|
||||
&.count-2 ul {
|
||||
columns: 2;
|
||||
}
|
||||
&.count-3 ul {
|
||||
columns: 3;
|
||||
}
|
||||
&.count-4 ul {
|
||||
columns: 4;
|
||||
}
|
||||
|
||||
&[class] ul {
|
||||
@media (max-width: 500px) {
|
||||
columns: 1;
|
||||
}
|
||||
}
|
||||
|
||||
& > ul li {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="136" height="48" fill="none"><path fill-rule="evenodd" clip-rule="evenodd" d="M134.509 35.895c-.978.414-2.857.714-4.023.714-3.346 0-5.037-1.579-5.037-4.849V21.574h-2.744v-3.646h2.744v-4.549l4.586-.64v5.189h4.698l-.3 3.646h-4.398v9.585c0 .978.451 1.617 1.654 1.617.677 0 1.503-.15 2.293-.375l.527 3.495zm-18.269.338V10.446l4.586-.64v26.427h-4.586zm-14.773-18.306v12.78c0 .978.414 1.466 1.466 1.466 1.128 0 3.12-.676 4.774-1.54V17.926h4.586v18.306h-3.496l-.451-1.541c-2.293 1.128-5.187 1.917-7.33 1.917-3.044 0-4.135-2.143-4.135-5.413v-13.27h4.586zm-12.555 11.39H85.53c-1.503 0-1.917.414-1.917 1.805 0 1.278.414 1.84 1.841 1.84 1.354 0 2.595-.45 3.46-.939v-2.706zm4.586 6.916H89.74l-.338-1.24c-1.654 1.09-3.609 1.616-5.45 1.616-3.347 0-4.775-2.293-4.775-5.45 0-3.721 1.617-5.15 5.338-5.15h4.398V24.09c0-2.03-.564-2.744-3.496-2.744-1.654 0-3.458.226-5.074.564l-.564-3.496c1.728-.526 4.247-.865 6.277-.865 5.752 0 7.443 2.03 7.443 6.617v12.066zm-20.11-25.036h4.924l-7.48 25.036h-6.993l-7.48-25.036h4.924l6.052 20.864 6.053-20.864zm-45.96 9.567h2.782v-2.783h-2.782v2.783zm-.024-4.174h2.782v-2.783h-2.782v2.783zm-4.15-4.174h2.782V9.633h-2.783v2.783zm0 4.174h2.782v-2.783h-2.783v2.783zm0 4.174h2.782V17.98h-2.783v2.783zm0 4.174h2.782v-2.783h-2.783v2.782zM19.08 12.415h2.783V9.633H19.08v2.783zm0 4.174h2.783v-2.783H19.08v2.783zm0 4.174h2.783V17.98H19.08v2.783zm8.324-8.348h2.782V9.633h-2.782v2.783zM.645 0l23.913 48L48.645 0h-48z" fill="#000"/></svg>
|
Before Width: | Height: | Size: 1.5 KiB |
|
@ -1,76 +0,0 @@
|
|||
import Link from 'next/link'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import { VERSION, CHANGELOG_URL } from 'data/version'
|
||||
import s from '../../pages/downloads/style.module.css'
|
||||
|
||||
const changelogUrl = CHANGELOG_URL.length
|
||||
? CHANGELOG_URL
|
||||
: `https://github.com/hashicorp/vault/blob/v${VERSION}/CHANGELOG.md`
|
||||
|
||||
export default function DownloadsProps(preMerchandisingSlot) {
|
||||
return {
|
||||
changelog: changelogUrl,
|
||||
getStartedDescription:
|
||||
'Follow step-by-step tutorials on the essentials of Vault.',
|
||||
getStartedLinks: [
|
||||
{
|
||||
label: 'Getting Started with the CLI',
|
||||
href: 'http://learn.hashicorp.com/collections/vault/getting-started',
|
||||
},
|
||||
{
|
||||
label: 'Getting Started with Vault UI',
|
||||
href: 'http://learn.hashicorp.com/collections/vault/getting-started-ui',
|
||||
},
|
||||
{
|
||||
label: 'Vault on HCP',
|
||||
href: 'http://learn.hashicorp.com/collections/vault/getting-started-ui',
|
||||
},
|
||||
{
|
||||
label: 'View all Vault tutorials',
|
||||
href: 'https://learn.hashicorp.com/vault',
|
||||
},
|
||||
],
|
||||
logo: (
|
||||
<img
|
||||
className={s.logo}
|
||||
alt="Vault"
|
||||
src={require('./img/vault-logo.svg')}
|
||||
/>
|
||||
),
|
||||
tutorialLink: {
|
||||
href: 'https://learn.hashicorp.com/vault',
|
||||
label: 'View Tutorials at HashiCorp Learn',
|
||||
},
|
||||
merchandisingSlot: (
|
||||
<>
|
||||
{preMerchandisingSlot && preMerchandisingSlot}
|
||||
|
||||
<div className={s.merchandisingSlot}>
|
||||
<div className={s.centerWrapper}>
|
||||
<p>
|
||||
Want all of the power and security of Vault, without the
|
||||
complexity and overhead of managing it yourself?
|
||||
</p>
|
||||
<Button
|
||||
title="Sign up for HCP Vault"
|
||||
linkType="inbound"
|
||||
url="https://portal.cloud.hashicorp.com/sign-up?utm_source=vault_io&utm_content=download_cta"
|
||||
theme={{
|
||||
variant: 'tertiary',
|
||||
brand: 'vault',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className={s.releaseNote}>
|
||||
Release notes are available in our{' '}
|
||||
<Link href={`/docs/release-notes`}>
|
||||
<a>documentation</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
export default function Footer({ openConsentManager }) {
|
||||
return (
|
||||
<footer className="g-footer">
|
||||
<div className="g-grid-container">
|
||||
<div className="left">
|
||||
<Link href="/docs">
|
||||
<a>Docs</a>
|
||||
</Link>
|
||||
<Link href="/api">
|
||||
<a>API</a>
|
||||
</Link>
|
||||
<a href="https://learn.hashicorp.com/vault">Learn</a>
|
||||
<Link href="/community">
|
||||
<a>Community</a>
|
||||
</Link>
|
||||
<a href="https://hashicorp.com/privacy">Privacy</a>
|
||||
<Link href="/security">
|
||||
<a>Security</a>
|
||||
</Link>
|
||||
<Link href="/files/press-kit.zip">
|
||||
<a>Press Kit</a>
|
||||
</Link>
|
||||
<a onClick={openConsentManager}>Consent Manager</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
.g-footer {
|
||||
padding: 25px 0 17px 0;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
|
||||
& .g-grid-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
& a {
|
||||
color: var(--gray-3);
|
||||
transition: color 0.25s ease;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
|
||||
&:hover {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
& .left > a {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
.hcpCalloutSection {
|
||||
composes: g-grid-container from global;
|
||||
padding-top: 88px;
|
||||
padding-bottom: 88px;
|
||||
|
||||
& .header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 88px;
|
||||
@media (max-width: 1120px) {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
& h2 {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
max-width: 450px;
|
||||
}
|
||||
}
|
||||
|
||||
& .content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
@media (max-width: 1120px) {
|
||||
flex-direction: column-reverse;
|
||||
|
||||
& .info {
|
||||
margin-top: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
& .info {
|
||||
max-width: 488px;
|
||||
margin-right: 32px;
|
||||
|
||||
& h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
& .description {
|
||||
color: var(--gray-2);
|
||||
margin-top: 28px;
|
||||
margin-bottom: 0;
|
||||
|
||||
@media (max-width: 900px) {
|
||||
margin-top: 18px;
|
||||
}
|
||||
}
|
||||
& .links {
|
||||
margin-top: 32px;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
|
||||
& > * {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > img {
|
||||
align-self: center;
|
||||
margin-right: -48px;
|
||||
@media (max-width: 670px) {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chin {
|
||||
composes: g-type-label from global;
|
||||
}
|
||||
|
||||
.description {
|
||||
composes: g-type-long-body from global;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
import styles from './HCPCalloutSection.module.css'
|
||||
import Button from '@hashicorp/react-button'
|
||||
|
||||
export default function HcpCalloutSection({
|
||||
id,
|
||||
header,
|
||||
title,
|
||||
description,
|
||||
chin,
|
||||
image,
|
||||
links,
|
||||
}) {
|
||||
return (
|
||||
<div className={styles.hcpCalloutSection} id={id}>
|
||||
{header ? (
|
||||
<div className={styles.header}>
|
||||
<h2 className="g-type-display-2">{header}</h2>
|
||||
</div>
|
||||
) : null}
|
||||
<div className={styles.content}>
|
||||
<div className={styles.info}>
|
||||
<h1 className="g-type-display-1">{title}</h1>
|
||||
<span className={styles.chin}>{chin}</span>
|
||||
<p className={styles.description}>{description}</p>
|
||||
<div className={styles.links}>
|
||||
{links.map((link, index) => {
|
||||
const variant = index === 0 ? 'primary' : 'tertiary'
|
||||
return (
|
||||
<div key={link.text}>
|
||||
<Button
|
||||
title={link.text}
|
||||
label="Learn more — HCP Vault"
|
||||
linkType={link.type}
|
||||
url={link.url}
|
||||
theme={{ variant, brand: 'neutral', background: 'light' }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<img alt={title} src={image} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
.homepageHero {
|
||||
& .thirdLinkWrapper {
|
||||
position: relative;
|
||||
|
||||
& a {
|
||||
position: absolute;
|
||||
top: -200px;
|
||||
|
||||
@media (max-width: 1177px) {
|
||||
top: -150px;
|
||||
}
|
||||
|
||||
@media (max-width: 1120px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
import Hero from '@hashicorp/react-hero'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import styles from './HomepageHero.module.css'
|
||||
import classNames from 'classnames'
|
||||
|
||||
/* A simple Facade wrapper around the Hero component */
|
||||
export default function HomepageHero({
|
||||
title,
|
||||
description,
|
||||
buttons,
|
||||
uiVideo,
|
||||
cliVideo,
|
||||
}) {
|
||||
return (
|
||||
<div className={styles.homepageHero}>
|
||||
<Hero
|
||||
data={{
|
||||
backgroundTheme: 'light',
|
||||
buttons: buttons.slice(0, 2),
|
||||
centered: false,
|
||||
description: description,
|
||||
product: 'vault',
|
||||
title: title,
|
||||
videos: [
|
||||
{
|
||||
name: 'UI',
|
||||
playbackRate: 2,
|
||||
src: [
|
||||
{
|
||||
srcType: 'mp4',
|
||||
url: uiVideo,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'CLI',
|
||||
playbackRate: 2,
|
||||
src: [
|
||||
{
|
||||
srcType: 'mp4',
|
||||
url: cliVideo,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
{/* A hack to inject a third link styled in tertiary style
|
||||
this is very much a non-ideal way to handle this. */}
|
||||
<div className={classNames('g-grid-container', styles.thirdLinkWrapper)}>
|
||||
{buttons[2] && (
|
||||
<div className="third-link">
|
||||
<Button
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
linkType={buttons[2].type}
|
||||
theme={{
|
||||
variant: 'tertiary-neutral',
|
||||
brand: 'vault',
|
||||
background: 'light',
|
||||
}}
|
||||
title={buttons[2].title}
|
||||
url={buttons[2].url}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
# Inline Tag Component
|
||||
|
||||
An _experimental_ component, used only on the plugin directory page, to represent "tags" which are meant to be placed inline.
|
|
@ -1,5 +0,0 @@
|
|||
import s from './style.module.css'
|
||||
|
||||
export default function InlineTag({ title, color }) {
|
||||
return <span className={`${s.root} ${s[color]}`}>{title}</span>
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
.root {
|
||||
background: #333;
|
||||
color: white;
|
||||
padding: 5px 9px;
|
||||
border-radius: 999px;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-size: 0.8em;
|
||||
margin-left: 5px;
|
||||
|
||||
&.red {
|
||||
background: #c82525;
|
||||
}
|
||||
|
||||
&.orange {
|
||||
background: #ea721b;
|
||||
}
|
||||
|
||||
&.yellow {
|
||||
background: #fbb228;
|
||||
}
|
||||
|
||||
&.green {
|
||||
background: #63c863;
|
||||
}
|
||||
|
||||
&.blue {
|
||||
background: #358ce8;
|
||||
}
|
||||
|
||||
&.purple {
|
||||
background: #913799;
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import classNames from 'classnames'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import IoCard, { IoCardProps } from 'components/io-card'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoCardContaianerProps {
|
||||
theme?: 'light' | 'dark'
|
||||
heading?: string
|
||||
description?: string
|
||||
label?: string
|
||||
cta?: {
|
||||
url: string
|
||||
text: string
|
||||
}
|
||||
cardsPerRow: 3 | 4
|
||||
cards: Array<IoCardProps>
|
||||
}
|
||||
|
||||
export default function IoCardContaianer({
|
||||
theme = 'light',
|
||||
heading,
|
||||
description,
|
||||
label,
|
||||
cta,
|
||||
cardsPerRow = 3,
|
||||
cards,
|
||||
}: IoCardContaianerProps): React.ReactElement {
|
||||
return (
|
||||
<div className={classNames(s.cardContainer, s[theme])}>
|
||||
{heading || description ? (
|
||||
<header className={s.header}>
|
||||
{heading ? <h2 className={s.heading}>{heading}</h2> : null}
|
||||
{description ? <p className={s.description}>{description}</p> : null}
|
||||
</header>
|
||||
) : null}
|
||||
{cards.length ? (
|
||||
<>
|
||||
{label || cta ? (
|
||||
<header className={s.subHeader}>
|
||||
{label ? <h3 className={s.label}>{label}</h3> : null}
|
||||
{cta ? (
|
||||
<Button
|
||||
title={cta.text}
|
||||
url={cta.url}
|
||||
linkType="inbound"
|
||||
theme={{
|
||||
brand: 'neutral',
|
||||
variant: 'tertiary',
|
||||
background: theme,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</header>
|
||||
) : null}
|
||||
<ul
|
||||
className={classNames(
|
||||
s.cardList,
|
||||
cardsPerRow === 3 && s.threeUp,
|
||||
cardsPerRow === 4 && s.fourUp
|
||||
)}
|
||||
style={
|
||||
{
|
||||
'--length': cards.length,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
{cards.map((card, index) => {
|
||||
return (
|
||||
// Index is stable
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<li key={index}>
|
||||
<IoCard variant={theme} {...card} />
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
.cardContainer {
|
||||
position: relative;
|
||||
|
||||
& + .cardContainer {
|
||||
margin-top: 64px;
|
||||
|
||||
@media (--medium-up) {
|
||||
margin-top: 132px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
margin: 0 auto 64px;
|
||||
text-align: center;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 0;
|
||||
composes: g-type-display-2 from global;
|
||||
|
||||
@nest .dark & {
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 8px 0 0;
|
||||
composes: g-type-body-large from global;
|
||||
|
||||
@nest .dark & {
|
||||
color: var(--gray-5);
|
||||
}
|
||||
}
|
||||
|
||||
.subHeader {
|
||||
margin: 0 0 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
@nest .dark & {
|
||||
color: var(--gray-5);
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
margin: 0;
|
||||
composes: g-type-display-4 from global;
|
||||
}
|
||||
|
||||
.cardList {
|
||||
list-style: none;
|
||||
|
||||
--minCol: 250px;
|
||||
--columns: var(--length);
|
||||
|
||||
position: relative;
|
||||
gap: 32px;
|
||||
padding: 0;
|
||||
|
||||
@media (--small) {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
margin: 0;
|
||||
padding: 6px 24px;
|
||||
left: 50%;
|
||||
margin-left: -50vw;
|
||||
width: 100vw;
|
||||
|
||||
/* This is to ensure there is overflow padding right on mobile. */
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 1px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (--medium-up) {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(var(--minCol), 1fr));
|
||||
}
|
||||
|
||||
&.threeUp {
|
||||
@media (--medium-up) {
|
||||
--columns: 3;
|
||||
--minCol: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.fourUp {
|
||||
@media (--medium-up) {
|
||||
--columns: 3;
|
||||
--minCol: 0;
|
||||
}
|
||||
|
||||
@media (--large) {
|
||||
--columns: 4;
|
||||
}
|
||||
}
|
||||
|
||||
& > li {
|
||||
display: flex;
|
||||
|
||||
@media (--small) {
|
||||
flex-shrink: 0;
|
||||
width: 250px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import Link from 'next/link'
|
||||
import InlineSvg from '@hashicorp/react-inline-svg'
|
||||
import classNames from 'classnames'
|
||||
import { IconArrowRight24 } from '@hashicorp/flight-icons/svg-react/arrow-right-24'
|
||||
import { IconExternalLink24 } from '@hashicorp/flight-icons/svg-react/external-link-24'
|
||||
import { productLogos } from './product-logos'
|
||||
import s from './style.module.css'
|
||||
|
||||
export interface IoCardProps {
|
||||
variant?: 'light' | 'gray' | 'dark'
|
||||
products?: Array<{
|
||||
name: keyof typeof productLogos
|
||||
}>
|
||||
link: {
|
||||
url: string
|
||||
type: 'inbound' | 'outbound'
|
||||
}
|
||||
inset?: 'none' | 'sm' | 'md'
|
||||
eyebrow?: string
|
||||
heading?: string
|
||||
description?: string
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
function IoCard({
|
||||
variant = 'light',
|
||||
products,
|
||||
link,
|
||||
inset = 'md',
|
||||
eyebrow,
|
||||
heading,
|
||||
description,
|
||||
children,
|
||||
}: IoCardProps): React.ReactElement {
|
||||
const LinkWrapper = ({ className, children }) =>
|
||||
link.type === 'inbound' ? (
|
||||
<Link href={link.url}>
|
||||
<a className={className}>{children}</a>
|
||||
</Link>
|
||||
) : (
|
||||
<a
|
||||
className={className}
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
|
||||
return (
|
||||
<article className={classNames(s.card)}>
|
||||
<LinkWrapper className={classNames(s[variant], s[inset])}>
|
||||
{children ? (
|
||||
children
|
||||
) : (
|
||||
<>
|
||||
{eyebrow ? <Eyebrow>{eyebrow}</Eyebrow> : null}
|
||||
{heading ? <Heading>{heading}</Heading> : null}
|
||||
{description ? <Description>{description}</Description> : null}
|
||||
</>
|
||||
)}
|
||||
<footer className={s.footer}>
|
||||
{products && (
|
||||
<ul className={s.products}>
|
||||
{products.map(({ name }, index) => {
|
||||
const key = name.toLowerCase()
|
||||
const version = variant === 'dark' ? 'neutral' : 'color'
|
||||
return (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<li key={index}>
|
||||
<InlineSvg
|
||||
className={s.logo}
|
||||
src={productLogos[key][version]}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
<span className={s.linkType}>
|
||||
{link.type === 'inbound' ? (
|
||||
<IconArrowRight24 />
|
||||
) : (
|
||||
<IconExternalLink24 />
|
||||
)}
|
||||
</span>
|
||||
</footer>
|
||||
</LinkWrapper>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
|
||||
interface EyebrowProps {
|
||||
children: string
|
||||
}
|
||||
|
||||
function Eyebrow({ children }: EyebrowProps) {
|
||||
return <p className={s.eyebrow}>{children}</p>
|
||||
}
|
||||
|
||||
interface HeadingProps {
|
||||
as?: 'h2' | 'h3' | 'h4'
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
function Heading({ as: Component = 'h2', children }: HeadingProps) {
|
||||
return <Component className={s.heading}>{children}</Component>
|
||||
}
|
||||
|
||||
interface DescriptionProps {
|
||||
children: string
|
||||
}
|
||||
|
||||
function Description({ children }: DescriptionProps) {
|
||||
return <p className={s.description}>{children}</p>
|
||||
}
|
||||
|
||||
IoCard.Eyebrow = Eyebrow
|
||||
IoCard.Heading = Heading
|
||||
IoCard.Description = Description
|
||||
|
||||
export default IoCard
|
|
@ -1,34 +0,0 @@
|
|||
export const productLogos = {
|
||||
boundary: {
|
||||
color: require('@hashicorp/mktg-logos/product/boundary/logomark/color.svg?include'),
|
||||
neutral: require('@hashicorp/mktg-logos/product/boundary/logomark/white.svg?include'),
|
||||
},
|
||||
consul: {
|
||||
color: require('@hashicorp/mktg-logos/product/consul/logomark/color.svg?include'),
|
||||
neutral: require('@hashicorp/mktg-logos/product/consul/logomark/white.svg?include'),
|
||||
},
|
||||
nomad: {
|
||||
color: require('@hashicorp/mktg-logos/product/nomad/logomark/color.svg?include'),
|
||||
neutral: require('@hashicorp/mktg-logos/product/nomad/logomark/white.svg?include'),
|
||||
},
|
||||
packer: {
|
||||
color: require('@hashicorp/mktg-logos/product/packer/logomark/color.svg?include'),
|
||||
neutral: require('@hashicorp/mktg-logos/product/packer/logomark/white.svg?include'),
|
||||
},
|
||||
terraform: {
|
||||
color: require('@hashicorp/mktg-logos/product/terraform/logomark/color.svg?include'),
|
||||
neutral: require('@hashicorp/mktg-logos/product/terraform/logomark/white.svg?include'),
|
||||
},
|
||||
vagrant: {
|
||||
color: require('@hashicorp/mktg-logos/product/vagrant/logomark/color.svg?include'),
|
||||
neutral: require('@hashicorp/mktg-logos/product/vagrant/logomark/white.svg?include'),
|
||||
},
|
||||
vault: {
|
||||
color: require('@hashicorp/mktg-logos/product/vault/logomark/color.svg?include'),
|
||||
neutral: require('@hashicorp/mktg-logos/product/vault/logomark/white.svg?include'),
|
||||
},
|
||||
waypoint: {
|
||||
color: require('@hashicorp/mktg-logos/product/waypoint/logomark/color.svg?include'),
|
||||
neutral: require('@hashicorp/mktg-logos/product/waypoint/logomark/white.svg?include'),
|
||||
},
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
.card {
|
||||
/* Radii */
|
||||
--token-radius: 6px;
|
||||
|
||||
/* Spacing */
|
||||
--token-spacing-03: 8px;
|
||||
--token-spacing-04: 16px;
|
||||
--token-spacing-05: 24px;
|
||||
--token-spacing-06: 32px;
|
||||
|
||||
/* Elevations */
|
||||
--token-elevation-mid: 0 2px 3px rgba(101, 106, 118, 0.1),
|
||||
0 8px 16px -10px rgba(101, 106, 118, 0.2);
|
||||
--token-elevation-high: 0 2px 3px rgba(101, 106, 118, 0.15),
|
||||
0 16px 16px -10px rgba(101, 106, 118, 0.2);
|
||||
|
||||
/* Transition */
|
||||
--token-transition: ease-in-out 0.2s;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
min-height: 300px;
|
||||
|
||||
& a {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
border-radius: var(--token-radius);
|
||||
box-shadow: 0 0 0 1px rgba(38, 53, 61, 0.1), var(--token-elevation-mid);
|
||||
transition: var(--token-transition);
|
||||
transition-property: background-color, box-shadow;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 2px rgba(38, 53, 61, 0.15), var(--token-elevation-high);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Variants */
|
||||
&.dark {
|
||||
background-color: var(--gray-1);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--gray-2);
|
||||
}
|
||||
}
|
||||
|
||||
&.gray {
|
||||
background-color: #f9f9fa;
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-color: var(--white);
|
||||
}
|
||||
|
||||
/* Spacing */
|
||||
&.none {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&.sm {
|
||||
padding: var(--token-spacing-05);
|
||||
}
|
||||
|
||||
&.md {
|
||||
padding: var(--token-spacing-06);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0;
|
||||
composes: g-type-label-small from global;
|
||||
color: var(--gray-3);
|
||||
|
||||
@nest .dark & {
|
||||
color: var(--gray-5);
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 0;
|
||||
composes: g-type-display-5 from global;
|
||||
color: var(--black);
|
||||
|
||||
@nest * + & {
|
||||
margin-top: var(--token-spacing-05);
|
||||
}
|
||||
|
||||
@nest .dark & {
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 0;
|
||||
composes: g-type-body-small from global;
|
||||
color: var(--gray-3);
|
||||
|
||||
@nest * + & {
|
||||
margin-top: var(--token-spacing-03);
|
||||
}
|
||||
|
||||
@nest .dark & {
|
||||
color: var(--gray-5);
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
padding-top: 32px;
|
||||
}
|
||||
|
||||
.products {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
& > li {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
& .logo {
|
||||
display: flex;
|
||||
|
||||
& svg {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.linkType {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
color: var(--black);
|
||||
|
||||
@nest .dark & {
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import { DialogOverlay, DialogContent, DialogOverlayProps } from '@reach/dialog'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import s from './style.module.css'
|
||||
|
||||
export interface IoDialogProps extends DialogOverlayProps {
|
||||
label: string
|
||||
}
|
||||
|
||||
export default function IoDialog({
|
||||
isOpen,
|
||||
onDismiss,
|
||||
children,
|
||||
label,
|
||||
}: IoDialogProps): React.ReactElement {
|
||||
const AnimatedDialogOverlay = motion(DialogOverlay)
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<AnimatedDialogOverlay
|
||||
className={s.dialogOverlay}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
onDismiss={onDismiss}
|
||||
>
|
||||
<div className={s.dialogWrapper}>
|
||||
<motion.div
|
||||
initial={{ y: 50 }}
|
||||
animate={{ y: 0 }}
|
||||
exit={{ y: 50 }}
|
||||
transition={{ min: 0, max: 100, bounceDamping: 8 }}
|
||||
style={{ width: '100%', maxWidth: 800 }}
|
||||
>
|
||||
<DialogContent className={s.dialogContent} aria-label={label}>
|
||||
<button onClick={onDismiss} className={s.dialogClose}>
|
||||
Close
|
||||
</button>
|
||||
{children}
|
||||
</DialogContent>
|
||||
</motion.div>
|
||||
</div>
|
||||
</AnimatedDialogOverlay>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
)
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
.dialogOverlay {
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
height: 100%;
|
||||
left: 0;
|
||||
overflow-y: auto;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 666666667 /* higher than global nav */;
|
||||
}
|
||||
|
||||
.dialogWrapper {
|
||||
display: grid;
|
||||
min-height: 100vh;
|
||||
padding: 24px;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.dialogContent {
|
||||
background-color: var(--gray-1);
|
||||
color: var(--white);
|
||||
max-width: 800px;
|
||||
outline: none;
|
||||
overflow-y: auto;
|
||||
padding: 24px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
padding: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.dialogClose {
|
||||
appearance: none;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
composes: g-type-display-5 from global;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
color: var(--white);
|
||||
right: 24px;
|
||||
top: 24px;
|
||||
z-index: 1;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
right: 48px;
|
||||
top: 48px;
|
||||
}
|
||||
|
||||
@nest html[dir='rtl'] & {
|
||||
left: 24px;
|
||||
right: auto;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
left: 48px;
|
||||
right: auto;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
import ReactCallToAction from '@hashicorp/react-call-to-action'
|
||||
import { Products } from '@hashicorp/platform-product-meta'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoHomeCallToActionProps {
|
||||
brand: Products
|
||||
heading: string
|
||||
content: string
|
||||
links: Array<{
|
||||
text: string
|
||||
url: string
|
||||
}>
|
||||
}
|
||||
|
||||
export default function IoHomeCallToAction({
|
||||
brand,
|
||||
heading,
|
||||
content,
|
||||
links,
|
||||
}: IoHomeCallToActionProps) {
|
||||
return (
|
||||
<div className={s.callToAction}>
|
||||
<ReactCallToAction
|
||||
variant="compact"
|
||||
heading={heading}
|
||||
content={content}
|
||||
product={brand}
|
||||
theme="dark"
|
||||
links={links.map(({ text, url }, index) => {
|
||||
return {
|
||||
text,
|
||||
url,
|
||||
type: index === 1 ? 'inbound' : null,
|
||||
}
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
.callToAction {
|
||||
margin: 60px auto;
|
||||
background-image: linear-gradient(52.3deg, #2c2d2f 39.83%, #626264 96.92%);
|
||||
|
||||
@media (--medium-up) {
|
||||
margin: 120px auto;
|
||||
}
|
||||
|
||||
& > * {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import Image from 'next/image'
|
||||
import { isInternalLink } from 'lib/utils'
|
||||
import { IconExternalLink16 } from '@hashicorp/flight-icons/svg-react/external-link-16'
|
||||
import { IconArrowRight16 } from '@hashicorp/flight-icons/svg-react/arrow-right-16'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoHomeCaseStudiesProps {
|
||||
heading: string
|
||||
description: string
|
||||
primary: Array<{
|
||||
thumbnail: {
|
||||
url: string
|
||||
alt: string
|
||||
}
|
||||
link: string
|
||||
heading: string
|
||||
}>
|
||||
secondary: Array<{
|
||||
link: string
|
||||
heading: string
|
||||
}>
|
||||
}
|
||||
|
||||
export default function IoHomeCaseStudies({
|
||||
heading,
|
||||
description,
|
||||
primary,
|
||||
secondary,
|
||||
}: IoHomeCaseStudiesProps): React.ReactElement {
|
||||
return (
|
||||
<section className={s.root}>
|
||||
<div className={s.container}>
|
||||
<header className={s.header}>
|
||||
<h2 className={s.heading}>{heading}</h2>
|
||||
<p className={s.description}>{description}</p>
|
||||
</header>
|
||||
<div className={s.caseStudies}>
|
||||
<ul className={s.primary}>
|
||||
{primary.map((item, index) => {
|
||||
return (
|
||||
<li key={index} className={s.primaryItem}>
|
||||
<a className={s.card} href={item.link}>
|
||||
<h3 className={s.cardHeading}>{item.heading}</h3>
|
||||
<Image
|
||||
className={s.cardThumbnail}
|
||||
src={item.thumbnail.url}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
alt={item.thumbnail.alt}
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
|
||||
<ul className={s.secondary}>
|
||||
{secondary.map((item, index) => {
|
||||
return (
|
||||
<li key={index} className={s.secondaryItem}>
|
||||
<a className={s.link} href={item.link}>
|
||||
<span className={s.linkInner}>
|
||||
<h3 className={s.linkHeading}>{item.heading}</h3>
|
||||
{isInternalLink(item.link) ? (
|
||||
<IconArrowRight16 />
|
||||
) : (
|
||||
<IconExternalLink16 />
|
||||
)}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
.root {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
margin: 60px auto;
|
||||
max-width: 1600px;
|
||||
|
||||
@media (--medium-up) {
|
||||
margin: 120px auto;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
composes: g-grid-container from global;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
max-width: calc(100% * 5 / 12);
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 0;
|
||||
composes: g-type-display-3 from global;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 8px 0 0;
|
||||
composes: g-type-body from global;
|
||||
color: var(--gray-3);
|
||||
}
|
||||
|
||||
.caseStudies {
|
||||
--columns: 1;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
}
|
||||
}
|
||||
|
||||
.primary {
|
||||
--columns: 1;
|
||||
|
||||
grid-column: 1 / -1;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 2;
|
||||
}
|
||||
|
||||
@media (--large) {
|
||||
grid-column: 1 / 9;
|
||||
}
|
||||
}
|
||||
|
||||
.primaryItem {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
justify-content: flex-end;
|
||||
padding: 32px;
|
||||
box-shadow: 0 8px 16px -10px rgba(101, 106, 118, 0.2);
|
||||
background-color: #000;
|
||||
border-radius: 6px;
|
||||
color: var(--white);
|
||||
transition: ease-in-out 0.2s;
|
||||
transition-property: box-shadow;
|
||||
min-height: 300px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
border-radius: 6px;
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
rgba(0, 0, 0, 0),
|
||||
rgba(0, 0, 0, 0.45)
|
||||
);
|
||||
transition: opacity ease-in-out 0.2s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 3px rgba(101, 106, 118, 0.15),
|
||||
0 16px 16px -10px rgba(101, 106, 118, 0.2);
|
||||
|
||||
&::before {
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cardThumbnail {
|
||||
transition: transform 0.4s;
|
||||
|
||||
@nest .card:hover & {
|
||||
transform: scale(1.04);
|
||||
}
|
||||
}
|
||||
|
||||
.cardHeading {
|
||||
margin: 0;
|
||||
composes: g-type-display-4 from global;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
grid-column: 1 / -1;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
@media (--large) {
|
||||
margin-top: -32px;
|
||||
grid-column: 9 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.secondaryItem {
|
||||
border-bottom: 1px solid var(--gray-5);
|
||||
}
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
.linkInner {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
padding-top: 32px;
|
||||
padding-bottom: 32px;
|
||||
transition: transform ease-in-out 0.2s;
|
||||
|
||||
@nest .link:hover & {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
& svg {
|
||||
margin-top: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.linkHeading {
|
||||
margin: 0 32px 0 0;
|
||||
composes: g-type-display-6 from global;
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { isInternalLink } from 'lib/utils'
|
||||
import { IconArrowRight16 } from '@hashicorp/flight-icons/svg-react/arrow-right-16'
|
||||
import s from './style.module.css'
|
||||
|
||||
export interface IoHomeFeatureProps {
|
||||
link?: string
|
||||
image: {
|
||||
url: string
|
||||
alt: string
|
||||
}
|
||||
heading: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export default function IoHomeFeature({
|
||||
link,
|
||||
image,
|
||||
heading,
|
||||
description,
|
||||
}: IoHomeFeatureProps): React.ReactElement {
|
||||
return (
|
||||
<IoHomeFeatureWrap href={link}>
|
||||
<div className={s.featureMedia}>
|
||||
<Image
|
||||
src={image.url}
|
||||
width={400}
|
||||
height={200}
|
||||
layout="responsive"
|
||||
alt={image.alt}
|
||||
/>
|
||||
</div>
|
||||
<div className={s.featureContent}>
|
||||
<h3 className={s.featureHeading}>{heading}</h3>
|
||||
<p className={s.featureDescription}>{description}</p>
|
||||
{link ? (
|
||||
<span className={s.featureCta} aria-hidden={true}>
|
||||
Learn more{' '}
|
||||
<span>
|
||||
<IconArrowRight16 />
|
||||
</span>
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
</IoHomeFeatureWrap>
|
||||
)
|
||||
}
|
||||
|
||||
function IoHomeFeatureWrap({ href, children }) {
|
||||
if (!href) {
|
||||
return <div className={s.feature}>{children}</div>
|
||||
}
|
||||
|
||||
if (isInternalLink(href)) {
|
||||
return (
|
||||
<Link href={href}>
|
||||
<a className={s.feature}>{children}</a>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<a className={s.feature} href={href}>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
.feature {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: 32px;
|
||||
gap: 24px 64px;
|
||||
border-radius: 6px;
|
||||
background-color: #f9f9fa;
|
||||
color: var(--black);
|
||||
box-shadow: 0 2px 3px rgba(101, 106, 118, 0.1),
|
||||
0 8px 16px -10px rgba(101, 106, 118, 0.2);
|
||||
|
||||
@media (--medium-up) {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.featureLink {
|
||||
transition: box-shadow ease-in-out 0.2s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 3px rgba(101, 106, 118, 0.15),
|
||||
0 16px 16px -10px rgba(101, 106, 118, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.featureMedia {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--gray-5);
|
||||
|
||||
@media (--medium-up) {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
@media (--large) {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
& > * {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.featureContent {
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.featureHeading {
|
||||
margin: 0;
|
||||
composes: g-type-display-4 from global;
|
||||
}
|
||||
|
||||
.featureDescription {
|
||||
margin: 8px 0 24px;
|
||||
composes: g-type-body-small from global;
|
||||
color: var(--gray-3);
|
||||
}
|
||||
|
||||
.featureCta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
& > span {
|
||||
display: flex;
|
||||
margin-left: 12px;
|
||||
|
||||
& > svg {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
@nest .feature:hover & span svg {
|
||||
transform: translateX(2px);
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import { Products } from '@hashicorp/platform-product-meta'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import classNames from 'classnames'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoHomeHeroProps {
|
||||
pattern: string
|
||||
brand: Products | 'neutral'
|
||||
heading: string
|
||||
description: string
|
||||
ctas: Array<{
|
||||
title: string
|
||||
link: string
|
||||
}>
|
||||
cards: Array<IoHomeHeroCardProps>
|
||||
}
|
||||
|
||||
export default function IoHomeHero({
|
||||
pattern,
|
||||
brand,
|
||||
heading,
|
||||
description,
|
||||
ctas,
|
||||
cards,
|
||||
}: IoHomeHeroProps) {
|
||||
const [loaded, setLoaded] = React.useState(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setLoaded(true)
|
||||
}, 250)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<header
|
||||
className={classNames(s.hero, loaded && s.loaded)}
|
||||
style={
|
||||
{
|
||||
'--pattern': `url(${pattern})`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<span className={s.pattern} />
|
||||
<div className={s.container}>
|
||||
<div className={s.content}>
|
||||
<h1 className={s.heading}>{heading}</h1>
|
||||
<p className={s.description}>{description}</p>
|
||||
{ctas && (
|
||||
<div className={s.ctas}>
|
||||
{ctas.map((cta, index) => {
|
||||
return (
|
||||
<Button
|
||||
key={index}
|
||||
title={cta.title}
|
||||
url={cta.link}
|
||||
linkType="inbound"
|
||||
theme={{
|
||||
brand: 'neutral',
|
||||
variant: 'tertiary',
|
||||
background: 'light',
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{cards && (
|
||||
<div className={s.cards}>
|
||||
{cards.map((card, index) => {
|
||||
return (
|
||||
<IoHomeHeroCard
|
||||
key={index}
|
||||
index={index}
|
||||
heading={card.heading}
|
||||
description={card.description}
|
||||
cta={{
|
||||
brand: index === 0 ? 'neutral' : brand,
|
||||
title: card.cta.title,
|
||||
link: card.cta.link,
|
||||
}}
|
||||
subText={card.subText}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
interface IoHomeHeroCardProps {
|
||||
index?: number
|
||||
heading: string
|
||||
description: string
|
||||
cta: {
|
||||
title: string
|
||||
link: string
|
||||
brand?: 'neutral' | Products
|
||||
}
|
||||
subText: string
|
||||
}
|
||||
|
||||
function IoHomeHeroCard({
|
||||
index,
|
||||
heading,
|
||||
description,
|
||||
cta,
|
||||
subText,
|
||||
}: IoHomeHeroCardProps): React.ReactElement {
|
||||
return (
|
||||
<article
|
||||
className={s.card}
|
||||
style={
|
||||
{
|
||||
'--index': index,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<h2 className={s.cardHeading}>{heading}</h2>
|
||||
<p className={s.cardDescription}>{description}</p>
|
||||
<Button
|
||||
title={cta.title}
|
||||
url={cta.link}
|
||||
theme={{
|
||||
variant: 'primary',
|
||||
brand: cta.brand,
|
||||
}}
|
||||
/>
|
||||
<p className={s.cardSubText}>{subText}</p>
|
||||
</article>
|
||||
)
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
.hero {
|
||||
position: relative;
|
||||
padding-top: 64px;
|
||||
padding-bottom: 64px;
|
||||
background: linear-gradient(180deg, #f9f9fa 0%, #fff 28.22%, #fff 100%);
|
||||
|
||||
@media (--medium-up) {
|
||||
padding-top: 128px;
|
||||
padding-bottom: 128px;
|
||||
}
|
||||
}
|
||||
|
||||
.pattern {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
max-width: 1600px;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
|
||||
@media (--medium-up) {
|
||||
background-image: var(--pattern);
|
||||
background-repeat: no-repeat;
|
||||
background-position: top right;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
--columns: 1;
|
||||
|
||||
composes: g-grid-container from global;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 48px 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 1 / 6;
|
||||
}
|
||||
|
||||
& > * {
|
||||
max-width: 415px;
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 0;
|
||||
composes: g-type-display-1 from global;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 8px 0 0;
|
||||
composes: g-type-body-small from global;
|
||||
color: var(--gray-3);
|
||||
}
|
||||
|
||||
.ctas {
|
||||
margin-top: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.cards {
|
||||
--columns: 1;
|
||||
|
||||
grid-column: 1 / -1;
|
||||
align-self: start;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 32px;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
--columns: 2;
|
||||
}
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 1;
|
||||
|
||||
grid-column: 7 / -1;
|
||||
}
|
||||
|
||||
@media (--large) {
|
||||
--columns: 2;
|
||||
|
||||
grid-column: 6 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
--token-radius: 6px;
|
||||
--token-elevation-mid: 0 2px 3px rgba(101, 106, 118, 0.1),
|
||||
0 8px 16px -10px rgba(101, 106, 118, 0.2);
|
||||
|
||||
opacity: 0;
|
||||
padding: 40px 32px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
background-color: var(--white);
|
||||
border-radius: var(--token-radius);
|
||||
box-shadow: 0 0 0 1px rgba(38, 53, 61, 0.1), var(--token-elevation-mid);
|
||||
|
||||
@nest .loaded & {
|
||||
animation-name: slideIn;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: calc(var(--index) * 0.1s);
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
}
|
||||
|
||||
.cardHeading {
|
||||
margin: 0;
|
||||
composes: g-type-display-4 from global;
|
||||
}
|
||||
|
||||
.cardDescription {
|
||||
margin: 8px 0 16px;
|
||||
composes: g-type-display-6 from global;
|
||||
}
|
||||
|
||||
.cardSubText {
|
||||
margin: 32px 0 0;
|
||||
composes: g-type-body-small from global;
|
||||
color: var(--gray-3);
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(50px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import Image from 'next/image'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import { Products } from '@hashicorp/platform-product-meta'
|
||||
import { IoCardProps } from 'components/io-card'
|
||||
import IoCardContainer from 'components/io-card-container'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoHomeInPracticeProps {
|
||||
brand: Products
|
||||
pattern: string
|
||||
heading: string
|
||||
description: string
|
||||
cards: Array<IoCardProps>
|
||||
cta: {
|
||||
heading: string
|
||||
description: string
|
||||
link: string
|
||||
image: {
|
||||
url: string
|
||||
alt: string
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function IoHomeInPractice({
|
||||
brand,
|
||||
pattern,
|
||||
heading,
|
||||
description,
|
||||
cards,
|
||||
cta,
|
||||
}: IoHomeInPracticeProps) {
|
||||
return (
|
||||
<section
|
||||
className={s.inPractice}
|
||||
style={
|
||||
{
|
||||
'--pattern': `url(${pattern})`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<div className={s.container}>
|
||||
<IoCardContainer
|
||||
theme="dark"
|
||||
heading={heading}
|
||||
description={description}
|
||||
cardsPerRow={3}
|
||||
cards={cards}
|
||||
/>
|
||||
|
||||
{cta.heading ? (
|
||||
<div className={s.inPracticeCta}>
|
||||
<div className={s.inPracticeCtaContent}>
|
||||
<h3 className={s.inPracticeCtaHeading}>{cta.heading}</h3>
|
||||
{cta.description ? (
|
||||
<p className={s.inPracticeCtaDescription}>{cta.description}</p>
|
||||
) : null}
|
||||
{cta.link ? (
|
||||
<Button
|
||||
title="Learn more"
|
||||
url={cta.link}
|
||||
theme={{
|
||||
brand: brand,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
{cta.image?.url ? (
|
||||
<div className={s.inPracticeCtaMedia}>
|
||||
<Image
|
||||
src={cta.image.url}
|
||||
width={cta.image.width}
|
||||
height={cta.image.height}
|
||||
alt={cta.image.alt}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
.inPractice {
|
||||
position: relative;
|
||||
margin: 60px auto;
|
||||
padding: 64px 0;
|
||||
max-width: 1600px;
|
||||
|
||||
@media (--medium-up) {
|
||||
padding: 80px 0;
|
||||
margin: 120px auto;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: var(--black);
|
||||
background-image: url('/img/practice-pattern.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 50%;
|
||||
background-position: top 200px left;
|
||||
|
||||
@media (--large) {
|
||||
border-radius: 6px;
|
||||
left: 24px;
|
||||
right: 24px;
|
||||
background-size: 35%;
|
||||
background-position: top 64px left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
composes: g-grid-container from global;
|
||||
}
|
||||
|
||||
.inPracticeCta {
|
||||
--columns: 1;
|
||||
|
||||
position: relative;
|
||||
margin-top: 64px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 64px 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
bottom: -64px;
|
||||
background-image: radial-gradient(
|
||||
42.33% 42.33% at 50% 100%,
|
||||
#363638 0%,
|
||||
#000 100%
|
||||
);
|
||||
|
||||
@media (--medium-up) {
|
||||
bottom: -80px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inPracticeCtaContent {
|
||||
position: relative;
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 1 / 5;
|
||||
}
|
||||
}
|
||||
|
||||
.inPracticeCtaMedia {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 6 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.inPracticeCtaHeading {
|
||||
margin: 0;
|
||||
color: var(--white);
|
||||
composes: g-type-display-3 from global;
|
||||
}
|
||||
|
||||
.inPracticeCtaDescription {
|
||||
margin: 8px 0 32px;
|
||||
color: var(--gray-5);
|
||||
composes: g-type-body from global;
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import Image from 'next/image'
|
||||
import classNames from 'classnames'
|
||||
import { Products } from '@hashicorp/platform-product-meta'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import IoVideoCallout, {
|
||||
IoHomeVideoCalloutProps,
|
||||
} from 'components/io-video-callout'
|
||||
import IoHomeFeature, { IoHomeFeatureProps } from 'components/io-home-feature'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoHomeIntroProps {
|
||||
brand: Products
|
||||
heading: string
|
||||
description: string
|
||||
features?: Array<IoHomeFeatureProps>
|
||||
offerings?: {
|
||||
image: {
|
||||
src: string
|
||||
width: number
|
||||
height: number
|
||||
alt: string
|
||||
}
|
||||
list: Array<{
|
||||
heading: string
|
||||
description: string
|
||||
}>
|
||||
cta?: {
|
||||
title: string
|
||||
link: string
|
||||
}
|
||||
}
|
||||
video?: IoHomeVideoCalloutProps
|
||||
}
|
||||
|
||||
export default function IoHomeIntro({
|
||||
brand,
|
||||
heading,
|
||||
description,
|
||||
features,
|
||||
offerings,
|
||||
video,
|
||||
}: IoHomeIntroProps) {
|
||||
return (
|
||||
<section
|
||||
className={classNames(
|
||||
s.root,
|
||||
s[brand],
|
||||
features && s.withFeatures,
|
||||
offerings && s.withOfferings
|
||||
)}
|
||||
style={
|
||||
{
|
||||
'--brand': `var(--${brand})`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<header className={s.header}>
|
||||
<div className={s.container}>
|
||||
<div className={s.headerInner}>
|
||||
<h2 className={s.heading}>{heading}</h2>
|
||||
<p className={s.description}>{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{features ? (
|
||||
<ul className={s.features}>
|
||||
{features.map((feature, index) => {
|
||||
return (
|
||||
// Index is stable
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<li key={index}>
|
||||
<div className={s.container}>
|
||||
<IoHomeFeature
|
||||
image={{
|
||||
url: feature.image.url,
|
||||
alt: feature.image.alt,
|
||||
}}
|
||||
heading={feature.heading}
|
||||
description={feature.description}
|
||||
link={feature.link}
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
) : null}
|
||||
|
||||
{offerings ? (
|
||||
<div className={s.offerings}>
|
||||
{offerings.image ? (
|
||||
<div className={s.offeringsMedia}>
|
||||
<Image
|
||||
src={offerings.image.src}
|
||||
width={offerings.image.width}
|
||||
height={offerings.image.height}
|
||||
alt={offerings.image.alt}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div className={s.offeringsContent}>
|
||||
<ul className={s.offeringsList}>
|
||||
{offerings.list.map((offering, index) => {
|
||||
return (
|
||||
// Index is stable
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<li key={index}>
|
||||
<h3 className={s.offeringsListHeading}>
|
||||
{offering.heading}
|
||||
</h3>
|
||||
<p className={s.offeringsListDescription}>
|
||||
{offering.description}
|
||||
</p>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
{offerings.cta ? (
|
||||
<div className={s.offeringsCta}>
|
||||
<Button
|
||||
title={offerings.cta.title}
|
||||
url={offerings.cta.link}
|
||||
theme={{
|
||||
brand: 'neutral',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{video ? (
|
||||
<div className={s.video}>
|
||||
<IoVideoCallout
|
||||
youtubeId={video.youtubeId}
|
||||
thumbnail={video.thumbnail}
|
||||
heading={video.heading}
|
||||
description={video.description}
|
||||
person={{
|
||||
name: video.person.name,
|
||||
description: video.person.description,
|
||||
avatar: video.person.avatar,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
)
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
.root {
|
||||
position: relative;
|
||||
margin-bottom: 60px;
|
||||
|
||||
@media (--medium-up) {
|
||||
margin-bottom: 120px;
|
||||
}
|
||||
|
||||
&.withOfferings:not(.withFeatures)::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-image: radial-gradient(
|
||||
93.55% 93.55% at 50% 0%,
|
||||
var(--gray-6) 0%,
|
||||
rgba(242, 242, 243, 0) 100%
|
||||
);
|
||||
|
||||
@media (--large) {
|
||||
border-radius: 6px;
|
||||
left: 24px;
|
||||
right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
composes: g-grid-container from global;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding-top: 64px;
|
||||
padding-bottom: 64px;
|
||||
text-align: center;
|
||||
|
||||
@nest .withFeatures & {
|
||||
background-color: var(--brand);
|
||||
}
|
||||
|
||||
@nest .withFeatures.consul & {
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
||||
|
||||
.headerInner {
|
||||
margin: auto;
|
||||
|
||||
@media (--medium-up) {
|
||||
max-width: calc(100% * 7 / 12);
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 0;
|
||||
composes: g-type-display-2 from global;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 24px 0 0;
|
||||
composes: g-type-body-large from global;
|
||||
|
||||
@nest .withOfferings:not(.withFeatures) & {
|
||||
color: var(--gray-3);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Features
|
||||
*/
|
||||
|
||||
.features {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
gap: 32px;
|
||||
|
||||
& li:first-of-type {
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
var(--brand) 50%,
|
||||
var(--white) 50%
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Offerings
|
||||
*/
|
||||
|
||||
.offerings {
|
||||
--columns: 1;
|
||||
|
||||
composes: g-grid-container from global;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 64px 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
}
|
||||
|
||||
@nest .features + & {
|
||||
margin-top: 60px;
|
||||
|
||||
@media (--medium-up) {
|
||||
margin-top: 120px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.offeringsMedia {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 1 / 6;
|
||||
}
|
||||
}
|
||||
|
||||
.offeringsContent {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 7 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.offeringsList {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 32px;
|
||||
|
||||
@media (--small) {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.offeringsListHeading {
|
||||
margin: 0;
|
||||
composes: g-type-display-4 from global;
|
||||
}
|
||||
|
||||
.offeringsListDescription {
|
||||
margin: 16px 0 0;
|
||||
composes: g-type-body-small from global;
|
||||
}
|
||||
|
||||
.offeringsCta {
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Video
|
||||
*/
|
||||
|
||||
.video {
|
||||
margin-top: 60px;
|
||||
composes: g-grid-container from global;
|
||||
|
||||
@media (--medium-up) {
|
||||
margin-top: 120px;
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { Products } from '@hashicorp/platform-product-meta'
|
||||
import { IconArrowRight16 } from '@hashicorp/flight-icons/svg-react/arrow-right-16'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoHomePreFooterProps {
|
||||
brand: Products
|
||||
heading: string
|
||||
description: string
|
||||
ctas: [IoHomePreFooterCard, IoHomePreFooterCard, IoHomePreFooterCard]
|
||||
}
|
||||
|
||||
export default function IoHomePreFooter({
|
||||
brand,
|
||||
heading,
|
||||
description,
|
||||
ctas,
|
||||
}: IoHomePreFooterProps) {
|
||||
return (
|
||||
<div className={classNames(s.preFooter, s[brand])}>
|
||||
<div className={s.container}>
|
||||
<div className={s.content}>
|
||||
<h2 className={s.heading}>{heading}</h2>
|
||||
<p className={s.description}>{description}</p>
|
||||
</div>
|
||||
<div className={s.cards}>
|
||||
{ctas.map((cta, index) => {
|
||||
return (
|
||||
<IoHomePreFooterCard
|
||||
key={index}
|
||||
brand={brand}
|
||||
link={cta.link}
|
||||
heading={cta.heading}
|
||||
description={cta.description}
|
||||
cta={cta.cta}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface IoHomePreFooterCard {
|
||||
brand?: string
|
||||
link: string
|
||||
heading: string
|
||||
description: string
|
||||
cta: string
|
||||
}
|
||||
|
||||
function IoHomePreFooterCard({
|
||||
brand,
|
||||
link,
|
||||
heading,
|
||||
description,
|
||||
cta,
|
||||
}: IoHomePreFooterCard): React.ReactElement {
|
||||
return (
|
||||
<a
|
||||
href={link}
|
||||
className={s.card}
|
||||
style={
|
||||
{
|
||||
'--primary': `var(--${brand})`,
|
||||
'--secondary': `var(--${brand}-secondary)`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<h3 className={s.cardHeading}>{heading}</h3>
|
||||
<p className={s.cardDescription}>{description}</p>
|
||||
<span className={s.cardCta}>
|
||||
{cta} <IconArrowRight16 />
|
||||
</span>
|
||||
</a>
|
||||
)
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
.preFooter {
|
||||
margin: 60px auto;
|
||||
}
|
||||
|
||||
.container {
|
||||
--columns: 1;
|
||||
|
||||
composes: g-grid-container from global;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 1 / 6;
|
||||
}
|
||||
|
||||
@media (--large) {
|
||||
grid-column: 1 / 4;
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 0;
|
||||
composes: g-type-display-1 from global;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 24px 0 0;
|
||||
composes: g-type-body from global;
|
||||
color: var(--gray-3);
|
||||
}
|
||||
|
||||
.cards {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
--columns: 1;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 3;
|
||||
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
@media (--large) {
|
||||
grid-column: 5 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
padding: 32px 24px;
|
||||
background-color: var(--primary);
|
||||
color: var(--black);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 3px rgba(101, 106, 118, 0.1),
|
||||
0 8px 16px -10px rgba(101, 106, 118, 0.2);
|
||||
transition: ease-in-out 0.2s;
|
||||
transition-property: box-shadow;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 3px rgba(101, 106, 118, 0.15),
|
||||
0 16px 16px -10px rgba(101, 106, 118, 0.2);
|
||||
}
|
||||
|
||||
&:nth-of-type(1) {
|
||||
@nest .consul & {
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
|
||||
&:nth-of-type(3) {
|
||||
background-color: var(--gray-6);
|
||||
}
|
||||
}
|
||||
|
||||
.cardHeading {
|
||||
margin: 0;
|
||||
composes: g-type-display-4 from global;
|
||||
}
|
||||
|
||||
.cardDescription {
|
||||
margin: 8px 0 0;
|
||||
padding-bottom: 48px;
|
||||
composes: g-type-display-6 from global;
|
||||
}
|
||||
|
||||
.cardCta {
|
||||
margin-top: auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
composes: g-type-buttons-and-standalone-links from global;
|
||||
|
||||
& svg {
|
||||
margin-left: 12px;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
@nest .card:hover & svg {
|
||||
transform: translate(2px);
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
import Image from 'next/image'
|
||||
import * as React from 'react'
|
||||
import { Products } from '@hashicorp/platform-product-meta'
|
||||
import classNames from 'classnames'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoUsecaseCallToActionProps {
|
||||
brand: Products
|
||||
theme?: 'light' | 'dark'
|
||||
heading: string
|
||||
description: string
|
||||
links: Array<{
|
||||
text: string
|
||||
url: string
|
||||
}>
|
||||
// TODO document intended usage
|
||||
pattern: string
|
||||
}
|
||||
|
||||
export default function IoUsecaseCallToAction({
|
||||
brand,
|
||||
theme,
|
||||
heading,
|
||||
description,
|
||||
links,
|
||||
pattern,
|
||||
}: IoUsecaseCallToActionProps): React.ReactElement {
|
||||
return (
|
||||
<div
|
||||
className={classNames(s.callToAction, s[theme])}
|
||||
style={
|
||||
{
|
||||
'--background-color': `var(--${brand})`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<h2 className={s.heading}>{heading}</h2>
|
||||
<div className={s.content}>
|
||||
<p className={s.description}>{description}</p>
|
||||
<div className={s.links}>
|
||||
{links.map((link, index) => {
|
||||
return (
|
||||
<Button
|
||||
// Index is stable
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
title={link.text}
|
||||
url={link.url}
|
||||
theme={{
|
||||
brand: 'neutral',
|
||||
variant: index === 0 ? 'primary' : 'secondary',
|
||||
background: theme,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className={s.pattern}>
|
||||
<Image
|
||||
src={pattern}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
objectPosition="center left"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
.callToAction {
|
||||
--columns: 1;
|
||||
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 0 32px;
|
||||
padding: 32px;
|
||||
background-color: var(--background-color);
|
||||
border-radius: 6px;
|
||||
|
||||
&.light {
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
&.dark {
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
grid-column: 1 / -1;
|
||||
margin: 0 0 16px;
|
||||
composes: g-type-display-3 from global;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 1 / 6;
|
||||
padding: 88px 32px 88px 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 6 / 11;
|
||||
padding: 88px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 0 0 32px;
|
||||
composes: g-type-body-large from global;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px 32px;
|
||||
}
|
||||
|
||||
.pattern {
|
||||
position: relative;
|
||||
display: none;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 11 / -1;
|
||||
display: flex;
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import Image from 'next/image'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoUsecaseCustomerProps {
|
||||
media: {
|
||||
src: string
|
||||
width: string
|
||||
height: string
|
||||
alt: string
|
||||
}
|
||||
logo: {
|
||||
src: string
|
||||
width: string
|
||||
height: string
|
||||
alt: string
|
||||
}
|
||||
heading: string
|
||||
description: string
|
||||
stats?: Array<{
|
||||
value: string
|
||||
key: string
|
||||
}>
|
||||
link: string
|
||||
}
|
||||
|
||||
export default function IoUsecaseCustomer({
|
||||
media,
|
||||
logo,
|
||||
heading,
|
||||
description,
|
||||
stats,
|
||||
link,
|
||||
}: IoUsecaseCustomerProps): React.ReactElement {
|
||||
return (
|
||||
<section className={s.customer}>
|
||||
<div className={s.container}>
|
||||
<div className={s.columns}>
|
||||
<div className={s.media}>
|
||||
{/* eslint-disable-next-line jsx-a11y/alt-text */}
|
||||
<Image {...media} layout="responsive" />
|
||||
</div>
|
||||
<div className={s.content}>
|
||||
<div className={s.eyebrow}>
|
||||
<div className={s.eyebrowLogo}>
|
||||
{/* eslint-disable-next-line jsx-a11y/alt-text */}
|
||||
<Image {...logo} />
|
||||
</div>
|
||||
<span className={s.eyebrowLabel}>Customer case study</span>
|
||||
</div>
|
||||
<h2 className={s.heading}>{heading}</h2>
|
||||
<p className={s.description}>{description}</p>
|
||||
{link ? (
|
||||
<div className={s.cta}>
|
||||
<Button
|
||||
title="Read more"
|
||||
url={link}
|
||||
theme={{
|
||||
brand: 'neutral',
|
||||
variant: 'secondary',
|
||||
background: 'dark',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
{stats.length > 0 ? (
|
||||
<ul className={s.stats}>
|
||||
{stats.map(({ key, value }, index) => {
|
||||
return (
|
||||
// Index is stable
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<li key={index}>
|
||||
<p className={s.value}>{value}</p>
|
||||
<p className={s.key}>{key}</p>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
) : null}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
.customer {
|
||||
position: relative;
|
||||
background-color: var(--black);
|
||||
color: var(--white);
|
||||
padding-bottom: 64px;
|
||||
|
||||
@media (--medium-up) {
|
||||
padding-bottom: 132px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
composes: g-grid-container from global;
|
||||
}
|
||||
|
||||
.columns {
|
||||
--columns: 1;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 64px 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
}
|
||||
}
|
||||
|
||||
.media {
|
||||
margin-top: -64px;
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 1 / 7;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
padding-top: 64px;
|
||||
grid-column: 8 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.eyebrowLogo {
|
||||
display: flex;
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
.eyebrowLabel {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
padding-left: 12px;
|
||||
margin-left: 12px;
|
||||
border-left: 1px solid var(--gray-5);
|
||||
align-self: center;
|
||||
composes: g-type-label-small-strong from global;
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 32px 0 24px;
|
||||
composes: g-type-display-2 from global;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 0;
|
||||
composes: g-type-body from global;
|
||||
}
|
||||
|
||||
.cta {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.stats {
|
||||
--columns: 1;
|
||||
|
||||
list-style: none;
|
||||
margin: 64px 0 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
|
||||
margin-top: 132px;
|
||||
}
|
||||
|
||||
& > li {
|
||||
border-top: 1px solid var(--gray-2);
|
||||
grid-column: span 4;
|
||||
}
|
||||
}
|
||||
|
||||
.value {
|
||||
margin: 0;
|
||||
padding-top: 32px;
|
||||
font-family: var(--font-display);
|
||||
font-size: 50px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
|
||||
@media (--large) {
|
||||
font-size: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.key {
|
||||
margin: 12px 0 0;
|
||||
composes: g-type-display-4 from global;
|
||||
color: var(--gray-3);
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import Image from 'next/image'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoUsecaseHeroProps {
|
||||
eyebrow: string
|
||||
heading: string
|
||||
description: string
|
||||
pattern?: string
|
||||
}
|
||||
|
||||
export default function IoUsecaseHero({
|
||||
eyebrow,
|
||||
heading,
|
||||
description,
|
||||
pattern,
|
||||
}: IoUsecaseHeroProps): React.ReactElement {
|
||||
return (
|
||||
<header className={s.hero}>
|
||||
<div className={s.container}>
|
||||
<div className={s.pattern}>
|
||||
{pattern ? (
|
||||
<Image
|
||||
src={pattern}
|
||||
layout="responsive"
|
||||
width={420}
|
||||
height={500}
|
||||
priority={true}
|
||||
alt=""
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className={s.content}>
|
||||
<p className={s.eyebrow}>{eyebrow}</p>
|
||||
<h1 className={s.heading}>{heading}</h1>
|
||||
<p className={s.description}>{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 6.3 KiB |
|
@ -1,83 +0,0 @@
|
|||
.hero {
|
||||
position: relative;
|
||||
max-width: 1600px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-image: radial-gradient(
|
||||
95.97% 95.97% at 50% 100%,
|
||||
#f2f2f3 0%,
|
||||
rgba(242, 242, 243, 0) 100%
|
||||
);
|
||||
|
||||
@media (--medium-up) {
|
||||
border-radius: 6px;
|
||||
left: 24px;
|
||||
right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
@media (--medium-up) {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr max-content 1fr;
|
||||
gap: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.pattern {
|
||||
margin-left: 24px;
|
||||
transform: translateY(24px);
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
|
||||
@media (--small) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (--medium) {
|
||||
& > * {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
max-width: 520px;
|
||||
width: 100%;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding: 64px 24px;
|
||||
|
||||
@media (--medium-up) {
|
||||
padding-top: 132px;
|
||||
padding-bottom: 132px;
|
||||
}
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0;
|
||||
composes: g-type-label-strong from global;
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 24px 0;
|
||||
composes: g-type-display-1 from global;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 0;
|
||||
composes: g-type-body-large from global;
|
||||
color: var(--gray-2);
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import { Products } from '@hashicorp/platform-product-meta'
|
||||
import classNames from 'classnames'
|
||||
import Image from 'next/image'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import s from './style.module.css'
|
||||
|
||||
interface IoUsecaseSectionProps {
|
||||
brand?: Products | 'neutral'
|
||||
bottomIsFlush?: boolean
|
||||
eyebrow: string
|
||||
heading: string
|
||||
description: string
|
||||
media?: {
|
||||
src: string
|
||||
width: string
|
||||
height: string
|
||||
alt: string
|
||||
}
|
||||
cta?: {
|
||||
text: string
|
||||
link: string
|
||||
}
|
||||
}
|
||||
|
||||
export default function IoUsecaseSection({
|
||||
brand = 'neutral',
|
||||
bottomIsFlush = false,
|
||||
eyebrow,
|
||||
heading,
|
||||
description,
|
||||
media,
|
||||
cta,
|
||||
}: IoUsecaseSectionProps): React.ReactElement {
|
||||
return (
|
||||
<section
|
||||
className={classNames(s.section, s[brand], bottomIsFlush && s.isFlush)}
|
||||
>
|
||||
<div className={s.container}>
|
||||
<p className={s.eyebrow}>{eyebrow}</p>
|
||||
<div className={s.columns}>
|
||||
<div className={s.column}>
|
||||
<h2 className={s.heading}>{heading}</h2>
|
||||
{media?.src ? (
|
||||
<div
|
||||
className={s.description}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: description,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{cta?.link && cta?.text ? (
|
||||
<div className={s.cta}>
|
||||
<Button
|
||||
title={cta.text}
|
||||
url={cta.link}
|
||||
theme={{
|
||||
brand: brand,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className={s.column}>
|
||||
{media?.src ? (
|
||||
// eslint-disable-next-line jsx-a11y/alt-text
|
||||
<Image {...media} />
|
||||
) : (
|
||||
<div
|
||||
className={s.description}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: description,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
.section {
|
||||
position: relative;
|
||||
max-width: 1600px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding-top: 64px;
|
||||
padding-bottom: 64px;
|
||||
|
||||
@media (--medium-up) {
|
||||
padding-top: 132px;
|
||||
padding-bottom: 132px;
|
||||
}
|
||||
|
||||
& + .section {
|
||||
padding-bottom: 132px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--gray-6);
|
||||
opacity: 0.4;
|
||||
|
||||
@media (--medium-up) {
|
||||
border-radius: 6px;
|
||||
left: 24px;
|
||||
right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.isFlush {
|
||||
padding-bottom: 96px;
|
||||
|
||||
@media (--medium-up) {
|
||||
padding-bottom: 164px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
composes: g-grid-container from global;
|
||||
}
|
||||
|
||||
.columns {
|
||||
--columns: 1;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 32px;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
}
|
||||
}
|
||||
|
||||
.column {
|
||||
&:nth-child(1) {
|
||||
@media (--medium-up) {
|
||||
grid-column: 1 / 7;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
@media (--medium-up) {
|
||||
grid-column: 8 / -1;
|
||||
padding-top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0;
|
||||
composes: g-type-display-5 from global;
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 16px 0 32px;
|
||||
padding-bottom: 32px;
|
||||
composes: g-type-display-3 from global;
|
||||
border-bottom: 1px solid var(--black);
|
||||
}
|
||||
|
||||
.description {
|
||||
composes: g-type-body from global;
|
||||
|
||||
& > p {
|
||||
margin: 0;
|
||||
|
||||
& + p {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cta {
|
||||
margin-top: 32px;
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import Image from 'next/image'
|
||||
import ReactPlayer from 'react-player'
|
||||
import VisuallyHidden from '@reach/visually-hidden'
|
||||
import IoDialog from 'components/io-dialog'
|
||||
import PlayIcon from './play-icon'
|
||||
import s from './style.module.css'
|
||||
|
||||
export interface IoHomeVideoCalloutProps {
|
||||
youtubeId: string
|
||||
thumbnail: string
|
||||
heading: string
|
||||
description: string
|
||||
person: {
|
||||
avatar: string
|
||||
name: string
|
||||
description: string
|
||||
}
|
||||
}
|
||||
|
||||
export default function IoVideoCallout({
|
||||
youtubeId,
|
||||
thumbnail,
|
||||
heading,
|
||||
description,
|
||||
person,
|
||||
}: IoHomeVideoCalloutProps): React.ReactElement {
|
||||
const [showDialog, setShowDialog] = React.useState(false)
|
||||
const showVideo = () => setShowDialog(true)
|
||||
const hideVideo = () => setShowDialog(false)
|
||||
return (
|
||||
<>
|
||||
<figure className={s.videoCallout}>
|
||||
<button className={s.thumbnail} onClick={showVideo}>
|
||||
<VisuallyHidden>Play video</VisuallyHidden>
|
||||
<PlayIcon />
|
||||
<Image src={thumbnail} layout="fill" objectFit="cover" alt="" />
|
||||
</button>
|
||||
<figcaption className={s.content}>
|
||||
<h3 className={s.heading}>{heading}</h3>
|
||||
<p className={s.description}>{description}</p>
|
||||
{person && (
|
||||
<div className={s.person}>
|
||||
{person.avatar ? (
|
||||
<div className={s.personThumbnail}>
|
||||
<Image
|
||||
src={person.avatar}
|
||||
width={52}
|
||||
height={52}
|
||||
alt={`${person.name} avatar`}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div>
|
||||
<p className={s.personName}>{person.name}</p>
|
||||
<p className={s.personDescription}>{person.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</figcaption>
|
||||
</figure>
|
||||
<IoDialog
|
||||
isOpen={showDialog}
|
||||
onDismiss={hideVideo}
|
||||
label={`${heading} video}`}
|
||||
>
|
||||
<h2 className={s.videoHeading}>{heading}</h2>
|
||||
<div className={s.video}>
|
||||
<ReactPlayer
|
||||
url={`https://www.youtube.com/watch?v=${youtubeId}`}
|
||||
width="100%"
|
||||
height="100%"
|
||||
playing={true}
|
||||
controls={true}
|
||||
/>
|
||||
</div>
|
||||
</IoDialog>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
import * as React from 'react'
|
||||
|
||||
export default function PlayIcon(): React.ReactElement {
|
||||
return (
|
||||
<svg
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 96 96"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="48" cy="48" r="48" fill="#fff" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="m63.254 46.653-22.75-14.4a1.647 1.647 0 0 0-1.657-.057c-.522.28-.847.82-.847 1.405V62.4c0 .584.325 1.123.847 1.403a1.639 1.639 0 0 0 1.657-.057l22.75-14.4c.465-.294.746-.802.746-1.346 0-.545-.281-1.052-.746-1.347Z"
|
||||
fill="#fff"
|
||||
stroke="#000"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
.videoCallout {
|
||||
--columns: 1;
|
||||
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
|
||||
gap: 32px;
|
||||
background-color: var(--black);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
|
||||
@media (--medium-up) {
|
||||
--columns: 12;
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
position: relative;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
grid-column: 1 / -1;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
padding: 96px 32px;
|
||||
min-height: 300px;
|
||||
|
||||
@media (--medium-up) {
|
||||
grid-column: 1 / 7;
|
||||
}
|
||||
|
||||
@media (--large) {
|
||||
grid-column: 1 / 9;
|
||||
}
|
||||
|
||||
& > svg {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1;
|
||||
|
||||
@media (--small) {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
opacity: 0.45;
|
||||
transition: opacity ease-in-out 0.2s;
|
||||
}
|
||||
|
||||
&:hover::after {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 32px;
|
||||
grid-column: 1 / -1;
|
||||
|
||||
@media (--medium-up) {
|
||||
padding: 80px 32px;
|
||||
grid-column: 7 / -1;
|
||||
}
|
||||
|
||||
@media (--large) {
|
||||
grid-column: 9 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 0;
|
||||
composes: g-type-display-4 from global;
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 8px 0 0;
|
||||
composes: g-type-body-small from global;
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.person {
|
||||
margin-top: 64px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.personThumbnail {
|
||||
display: flex;
|
||||
border-radius: 9999px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.personName {
|
||||
margin: 0;
|
||||
composes: g-type-body-strong from global;
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.personDescription {
|
||||
margin: 4px 0 0;
|
||||
composes: g-type-label-strong from global;
|
||||
color: var(--gray-3);
|
||||
}
|
||||
|
||||
.videoHeading {
|
||||
margin-top: 0;
|
||||
margin-bottom: 32px;
|
||||
padding-right: 100px;
|
||||
composes: g-type-display-4 from global;
|
||||
}
|
||||
|
||||
.video {
|
||||
position: relative;
|
||||
background-color: var(--gray-2);
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
import Subnav from '@hashicorp/react-subnav'
|
||||
import classNames from 'classnames'
|
||||
import { useRouter } from 'next/router'
|
||||
import s from './style.module.css'
|
||||
|
||||
export default function ProductSubnav({ menuItems }) {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<Subnav
|
||||
className={classNames('g-product-subnav', s.subnav)}
|
||||
hideGithubStars={true}
|
||||
titleLink={{
|
||||
text: 'HashiCorp Vault',
|
||||
url: '/',
|
||||
}}
|
||||
ctaLinks={[
|
||||
{
|
||||
text: 'GitHub',
|
||||
url: 'https://www.github.com/hashicorp/vault',
|
||||
},
|
||||
{
|
||||
text: 'Try Cloud',
|
||||
url: 'https://portal.cloud.hashicorp.com/sign-up?utm_source=vault_io&utm_content=top_nav_vault',
|
||||
},
|
||||
{
|
||||
text: 'Download',
|
||||
url: '/downloads',
|
||||
theme: {
|
||||
brand: 'vault',
|
||||
},
|
||||
},
|
||||
]}
|
||||
currentPath={router.asPath}
|
||||
menuItems={menuItems}
|
||||
menuItemsAlign="right"
|
||||
constrainWidth
|
||||
matchOnBasePath
|
||||
/>
|
||||
)
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
.subnav {
|
||||
border-top: 1px solid transparent;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
import Button from '@hashicorp/react-button'
|
||||
|
||||
export default function UseCaseCtaSection() {
|
||||
return (
|
||||
<section className="g-section-block g-cta-section">
|
||||
<div>
|
||||
<h2 className="g-type-display-2">Ready to get started?</h2>
|
||||
<Button
|
||||
url="/downloads"
|
||||
title="Download"
|
||||
label="Download CLI"
|
||||
linkType="download"
|
||||
className="g-btn"
|
||||
theme={{
|
||||
variant: 'primary',
|
||||
brand: 'neutral',
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
url="/docs"
|
||||
title="Explore Docs"
|
||||
className="g-btn"
|
||||
theme={{ variant: 'secondary' }}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
.g-section-block.g-cta-section {
|
||||
-webkit-box-align: center;
|
||||
align-items: center;
|
||||
background: var(--vault-secondary);
|
||||
display: -webkit-box;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
justify-content: center;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
color: var(--black);
|
||||
|
||||
& .g-btn.white {
|
||||
background: var(--white);
|
||||
border: 2px solid var(--white);
|
||||
color: var(--gray-2);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--gray-1);
|
||||
border-color: var(--gray-1);
|
||||
color: var(--white);
|
||||
|
||||
& path {
|
||||
fill: var(--white);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .g-btn.white-outline {
|
||||
background: none;
|
||||
border: 2px solid var(--white);
|
||||
color: var(--white);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--white);
|
||||
color: var(--gray-2);
|
||||
}
|
||||
}
|
||||
|
||||
& .g-btn.download svg {
|
||||
margin: 0 4px -4px 0;
|
||||
}
|
||||
|
||||
& .g-btn + .g-btn {
|
||||
margin-left: 18px;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
export const ALERT_BANNER_ACTIVE = false
|
||||
|
||||
// https://github.com/hashicorp/web-components/tree/master/packages/alert-banner
|
||||
export default {
|
||||
tag: 'Blog post',
|
||||
url: 'https://www.hashicorp.com/blog/a-new-chapter-for-hashicorp',
|
||||
text:
|
||||
'HashiCorp shares have begun trading on the Nasdaq. Read the blog from our founders, Mitchell Hashimoto and Armon Dadgar.',
|
||||
linkText: 'Read the post',
|
||||
// Set the expirationDate prop with a datetime string (e.g. '2020-01-31T12:00:00-07:00')
|
||||
// if you'd like the component to stop showing at or after a certain date
|
||||
expirationDate: '2021-12-17T23:00:00-07:00',
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
export const productName = 'Vault'
|
||||
export const productSlug = 'vault'
|
|
@ -1,53 +0,0 @@
|
|||
export const VERSION = '1.10.0'
|
||||
export const CHANGELOG_URL =
|
||||
'https://github.com/hashicorp/vault/blob/main/CHANGELOG.md#1100'
|
||||
|
||||
// HashiCorp officially supported package managers
|
||||
export const packageManagers = [
|
||||
{
|
||||
label: 'Homebrew',
|
||||
commands: ['brew tap hashicorp/tap', 'brew install hashicorp/tap/vault'],
|
||||
os: 'darwin',
|
||||
},
|
||||
{
|
||||
label: 'Ubuntu/Debian',
|
||||
commands: [
|
||||
'curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -',
|
||||
'sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"',
|
||||
'sudo apt-get update && sudo apt-get install vault',
|
||||
],
|
||||
os: 'linux',
|
||||
},
|
||||
{
|
||||
label: 'CentOS/RHEL',
|
||||
commands: [
|
||||
'sudo yum install -y yum-utils',
|
||||
'sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo',
|
||||
'sudo yum -y install vault',
|
||||
],
|
||||
os: 'linux',
|
||||
},
|
||||
{
|
||||
label: 'Fedora',
|
||||
commands: [
|
||||
'sudo dnf install -y dnf-plugins-core',
|
||||
'sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/fedora/hashicorp.repo',
|
||||
'sudo dnf -y install vault',
|
||||
],
|
||||
os: 'linux',
|
||||
},
|
||||
{
|
||||
label: 'Amazon Linux',
|
||||
commands: [
|
||||
'sudo yum install -y yum-utils',
|
||||
'sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo',
|
||||
'sudo yum -y install vault',
|
||||
],
|
||||
os: 'linux',
|
||||
},
|
||||
{
|
||||
label: 'Homebrew',
|
||||
commands: ['brew tap hashicorp/tap', 'brew install hashicorp/tap/vault'],
|
||||
os: 'linux',
|
||||
},
|
||||
]
|
|
@ -1 +0,0 @@
|
|||
/// <reference types="@hashicorp/platform-types" />
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "."
|
||||
},
|
||||
"exclude": ["node_modules", ".next", "out"]
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
import query from './query.graphql'
|
||||
import ProductSubnav from 'components/subnav'
|
||||
import Footer from 'components/footer'
|
||||
import { open } from '@hashicorp/react-consent-manager'
|
||||
|
||||
export default function StandardLayout(props: Props): React.ReactElement {
|
||||
const { useCaseNavItems } = props.data
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProductSubnav
|
||||
menuItems={[
|
||||
{ text: 'Overview', url: '/' },
|
||||
{
|
||||
text: 'Use Cases',
|
||||
submenu: useCaseNavItems
|
||||
.sort((a, b) => a.text.localeCompare(b.text))
|
||||
.map((item) => {
|
||||
return {
|
||||
text: item.text,
|
||||
url: `/use-cases/${item.url}`,
|
||||
}
|
||||
}),
|
||||
},
|
||||
{
|
||||
text: 'Enterprise',
|
||||
url: 'https://www.hashicorp.com/products/vault/enterprise',
|
||||
},
|
||||
'divider',
|
||||
{ text: 'Tutorials', url: 'https://learn.hashicorp.com/vault' },
|
||||
{ text: 'Docs', url: '/docs' },
|
||||
{ text: 'API', url: '/api-docs' },
|
||||
{ text: 'Community', url: '/community' },
|
||||
]}
|
||||
/>
|
||||
{props.children}
|
||||
<Footer openConsentManager={open} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
StandardLayout.rivetParams = {
|
||||
query,
|
||||
dependencies: [],
|
||||
}
|
||||
|
||||
interface Props {
|
||||
children: React.ReactChildren
|
||||
data: {
|
||||
useCaseNavItems: Array<{ url: string; text: string }>
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
query UseCasesQuery {
|
||||
useCaseNavItems: allVaultUseCases {
|
||||
url: slug
|
||||
text: heroHeading
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
import { ConsentManagerService } from '@hashicorp/react-consent-manager/types'
|
||||
|
||||
const localConsentManagerServices: ConsentManagerService[] = [
|
||||
{
|
||||
name: 'Qualified Chatbot',
|
||||
description:
|
||||
'Qualified is a chatbot service that allows visitors to chat with our sales staff through the website.',
|
||||
category: 'Email Marketing',
|
||||
url: 'https://js.qualified.com/qualified.js?token=CWQA3q9CaEKHNF2t',
|
||||
async: true,
|
||||
},
|
||||
{
|
||||
name: 'Demandbase Tag',
|
||||
description:
|
||||
'The Demandbase tag is a tracking service to identify website visitors and measure interest on our website.',
|
||||
category: 'Analytics',
|
||||
url: 'https://tag.demandbase.com/960ab0a0f20fb102.min.js',
|
||||
async: true,
|
||||
},
|
||||
]
|
||||
|
||||
export default localConsentManagerServices
|
|
@ -1,18 +0,0 @@
|
|||
export const isInternalLink = (link: string): boolean => {
|
||||
if (
|
||||
link.startsWith('/') ||
|
||||
link.startsWith('#') ||
|
||||
link.startsWith('https://vaultproject.io') ||
|
||||
link.startsWith('https://www.vaultproject.io')
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const chunk = (arr, chunkSize = 1, cache = []) => {
|
||||
const tmp = [...arr]
|
||||
if (chunkSize <= 0) return cache
|
||||
while (tmp.length) cache.push(tmp.splice(0, chunkSize))
|
||||
return cache
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
|
@ -1,38 +0,0 @@
|
|||
const withHashicorp = require('@hashicorp/platform-nextjs-plugin')
|
||||
const redirects = require('./redirects')
|
||||
|
||||
// log out our primary environment variables for clarity in build logs
|
||||
console.log(`HASHI_ENV: ${process.env.HASHI_ENV}`)
|
||||
console.log(`NODE_ENV: ${process.env.NODE_ENV}`)
|
||||
console.log(`VERCEL_ENV: ${process.env.VERCEL_ENV}`)
|
||||
console.log(`MKTG_CONTENT_API: ${process.env.MKTG_CONTENT_API}`)
|
||||
console.log(`ENABLE_VERSIONED_DOCS: ${process.env.ENABLE_VERSIONED_DOCS}`)
|
||||
|
||||
module.exports = withHashicorp({
|
||||
dato: {
|
||||
// This token is safe to be in this public repository, it only has access to content that is publicly viewable on the website
|
||||
token: '88b4984480dad56295a8aadae6caad',
|
||||
},
|
||||
nextOptimizedImages: true,
|
||||
transpileModules: ['@hashicorp/flight-icons'],
|
||||
})({
|
||||
svgo: { plugins: [{ removeViewBox: false }] },
|
||||
rewrites: () => [
|
||||
{
|
||||
source: '/api/:path*',
|
||||
destination: '/api-docs/:path*',
|
||||
},
|
||||
],
|
||||
redirects: () => redirects,
|
||||
env: {
|
||||
HASHI_ENV: process.env.HASHI_ENV || 'development',
|
||||
SEGMENT_WRITE_KEY: 'OdSFDq9PfujQpmkZf03dFpcUlywme4sC',
|
||||
BUGSNAG_CLIENT_KEY: '07ff2d76ce27aded8833bf4804b73350',
|
||||
BUGSNAG_SERVER_KEY: 'fb2dc40bb48b17140628754eac6c1b11',
|
||||
ENABLE_VERSIONED_DOCS: process.env.ENABLE_VERSIONED_DOCS || false,
|
||||
},
|
||||
images: {
|
||||
domains: ['www.datocms-assets.com'],
|
||||
disableStaticImages: true,
|
||||
},
|
||||
})
|
File diff suppressed because it is too large
Load Diff
|
@ -3,53 +3,12 @@
|
|||
"description": "HashiCorp Vault documentation website",
|
||||
"version": "1.0.0",
|
||||
"author": "HashiCorp",
|
||||
"dependencies": {
|
||||
"@hashicorp/flight-icons": "^1.3.0",
|
||||
"@hashicorp/mktg-global-styles": "^4.0.0",
|
||||
"@hashicorp/mktg-logos": "^1.2.0",
|
||||
"@hashicorp/nextjs-scripts": "^19.0.3",
|
||||
"@hashicorp/platform-analytics": "^0.2.0",
|
||||
"@hashicorp/platform-code-highlighting": "^0.1.2",
|
||||
"@hashicorp/platform-markdown-utils": "^0.1.3",
|
||||
"@hashicorp/platform-runtime-error-monitoring": "^0.1.0",
|
||||
"@hashicorp/platform-util": "^0.1.0",
|
||||
"@hashicorp/react-alert-banner": "^7.0.1",
|
||||
"@hashicorp/react-button": "^6.0.1",
|
||||
"@hashicorp/react-call-to-action": "^4.1.1",
|
||||
"@hashicorp/react-consent-manager": "^7.0.1",
|
||||
"@hashicorp/react-docs-page": "^14.14.3",
|
||||
"@hashicorp/react-featured-slider": "^5.0.1",
|
||||
"@hashicorp/react-head": "^3.1.2",
|
||||
"@hashicorp/react-hero": "^8.0.2",
|
||||
"@hashicorp/react-image": "^4.0.3",
|
||||
"@hashicorp/react-inline-svg": "^6.0.3",
|
||||
"@hashicorp/react-markdown-page": "^1.4.3",
|
||||
"@hashicorp/react-product-downloads-page": "^2.5.3",
|
||||
"@hashicorp/react-section-header": "^5.0.4",
|
||||
"@hashicorp/react-subnav": "^9.3.2",
|
||||
"@hashicorp/react-text-splits": "^3.2.7",
|
||||
"@hashicorp/react-use-cases": "^5.0.0",
|
||||
"@hashicorp/react-vertical-text-block-list": "^7.0.0",
|
||||
"@reach/dialog": "^0.16.2",
|
||||
"@reach/visually-hidden": "^0.16.0",
|
||||
"framer-motion": "^5.3.0",
|
||||
"next": "^11.1.2",
|
||||
"next-mdx-remote": "^3.0.8",
|
||||
"next-remote-watch": "1.0.0",
|
||||
"react": "^17.0.2",
|
||||
"react-datocms": "^1.6.6",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-player": "^2.9.0"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@hashicorp/platform-cli": "^1.2.0",
|
||||
"@hashicorp/platform-nextjs-plugin": "^1.0.1",
|
||||
"@hashicorp/platform-types": "^0.1.1",
|
||||
"@types/react": "^17.0.27",
|
||||
"dart-linkcheck": "^2.0.15",
|
||||
"prettier": "^2.4.1",
|
||||
"dart-linkcheck": "2.0.15",
|
||||
"simple-git-hooks": "^2.6.1",
|
||||
"typescript": "^4.4.3"
|
||||
"prettier": "2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"npm": ">=7.0.0",
|
||||
|
@ -62,16 +21,13 @@
|
|||
},
|
||||
"scripts": {
|
||||
"build": "./scripts/website-build.sh",
|
||||
"dynamic": "NODE_ENV=production next build && next start",
|
||||
"export": "next export",
|
||||
"format": "next-hashicorp format",
|
||||
"generate:component": "next-hashicorp generate component",
|
||||
"generate:readme": "next-hashicorp markdown-blocks README.md",
|
||||
"linkcheck": "linkcheck https://www.vaultproject.io",
|
||||
"lint": "next-hashicorp lint",
|
||||
"postinstall": "simple-git-hooks",
|
||||
"start": "./scripts/website-start.sh",
|
||||
"static": "npm run build && npm run export && cp _redirects out/."
|
||||
"start": "./scripts/website-start.sh"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"pre-commit": "cd website && ./node_modules/.bin/next-hashicorp precommit"
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
import NotFound from './not-found'
|
||||
export default NotFound
|
|
@ -1,86 +0,0 @@
|
|||
import './style.css'
|
||||
import '@hashicorp/platform-util/nprogress/style.css'
|
||||
|
||||
import Router from 'next/router'
|
||||
import Head from 'next/head'
|
||||
import rivetQuery from '@hashicorp/nextjs-scripts/dato/client'
|
||||
import { ErrorBoundary } from '@hashicorp/platform-runtime-error-monitoring'
|
||||
import createConsentManager from '@hashicorp/react-consent-manager/loader'
|
||||
import localConsentManagerServices from 'lib/consent-manager-services'
|
||||
import NProgress from '@hashicorp/platform-util/nprogress'
|
||||
import useFathomAnalytics from '@hashicorp/platform-analytics'
|
||||
import useAnchorLinkAnalytics from '@hashicorp/platform-util/anchor-link-analytics'
|
||||
import HashiHead from '@hashicorp/react-head'
|
||||
import Error from './_error'
|
||||
import AlertBanner from '@hashicorp/react-alert-banner'
|
||||
import alertBannerData, { ALERT_BANNER_ACTIVE } from '../data/alert-banner'
|
||||
import StandardLayout from 'layouts/standard'
|
||||
|
||||
NProgress({ Router })
|
||||
const { ConsentManager } = createConsentManager({
|
||||
preset: 'oss',
|
||||
otherServices: [...localConsentManagerServices],
|
||||
})
|
||||
|
||||
export default function App({ Component, pageProps, layoutData }) {
|
||||
useFathomAnalytics()
|
||||
useAnchorLinkAnalytics()
|
||||
|
||||
const Layout = Component.layout ?? StandardLayout
|
||||
|
||||
return (
|
||||
<ErrorBoundary FallbackComponent={Error}>
|
||||
<HashiHead
|
||||
is={Head}
|
||||
title="Vault by HashiCorp"
|
||||
siteName="Vault by HashiCorp"
|
||||
description="Vault secures, stores, and tightly controls access to tokens, passwords, certificates, API keys, and other secrets in modern computing. Vault handles leasing, key revocation, key rolling, auditing, and provides secrets as a service through a unified API."
|
||||
image="https://www.vaultproject.io/img/og-image.png"
|
||||
icon={[
|
||||
{
|
||||
href: 'https://www.datocms-assets.com/2885/1597163356-vault-favicon.png?h=16&w=16',
|
||||
type: 'image/png',
|
||||
sizes: '16x16',
|
||||
},
|
||||
{
|
||||
href: 'https://www.datocms-assets.com/2885/1597163356-vault-favicon.png?h=32&w=32',
|
||||
type: 'image/png',
|
||||
sizes: '32x32',
|
||||
},
|
||||
{
|
||||
href: 'https://www.datocms-assets.com/2885/1597163356-vault-favicon.png?h=96&w=96',
|
||||
type: 'image/png',
|
||||
sizes: '96x96',
|
||||
},
|
||||
{
|
||||
href: 'https://www.datocms-assets.com/2885/1597163356-vault-favicon.png?h=192&w=192',
|
||||
type: 'image/png',
|
||||
sizes: '192x192',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{ALERT_BANNER_ACTIVE && (
|
||||
<AlertBanner {...alertBannerData} product="vault" hideOnMobile />
|
||||
)}
|
||||
<Layout {...(layoutData && { data: layoutData })}>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
<ConsentManager className="g-consent-manager" />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
App.getInitialProps = async ({ Component, ctx }) => {
|
||||
const layoutQuery = Component.layout
|
||||
? Component.layout?.rivetParams ?? null
|
||||
: StandardLayout.rivetParams
|
||||
|
||||
const layoutData = layoutQuery ? await rivetQuery(layoutQuery) : null
|
||||
|
||||
let pageProps = {}
|
||||
|
||||
if (Component.getInitialProps) {
|
||||
pageProps = await Component.getInitialProps(ctx)
|
||||
}
|
||||
return { pageProps, layoutData }
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
import HashiHead from '@hashicorp/react-head'
|
||||
|
||||
export default class MyDocument extends Document {
|
||||
static async getInitialProps(ctx) {
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
return { ...initialProps }
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head>
|
||||
<HashiHead />
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
<script
|
||||
noModule
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `window.MSInputMethodContext && document.documentMode && document.write('<script src="/ie-custom-properties.js"><\\x2fscript>');`,
|
||||
}}
|
||||
/>
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import NotFound from './404'
|
||||
import Bugsnag from '@hashicorp/platform-runtime-error-monitoring'
|
||||
|
||||
function Error({ statusCode }) {
|
||||
return <NotFound statusCode={statusCode} />
|
||||
}
|
||||
|
||||
Error.getInitialProps = ({ res, err }) => {
|
||||
if (err) Bugsnag.notify(err)
|
||||
const statusCode = res ? res.statusCode : err ? err.statusCode : 404
|
||||
return { statusCode }
|
||||
}
|
||||
|
||||
export default Error
|
|
@ -1,38 +0,0 @@
|
|||
import { productName, productSlug } from 'data/metadata'
|
||||
import DocsPage from '@hashicorp/react-docs-page'
|
||||
// Imports below are used in server-side only
|
||||
import { getStaticGenerationFunctions } from '@hashicorp/react-docs-page/server'
|
||||
|
||||
const NAV_DATA_FILE_HIDDEN = 'data/api-docs-nav-data-hidden.json'
|
||||
const NAV_DATA_FILE = 'data/api-docs-nav-data.json'
|
||||
const CONTENT_DIR = 'content/api-docs'
|
||||
const basePath = 'api-docs'
|
||||
|
||||
export default function DocsLayout(props) {
|
||||
return (
|
||||
<DocsPage
|
||||
product={{ name: productName, slug: productSlug }}
|
||||
baseRoute={basePath}
|
||||
staticProps={props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const { getStaticPaths, getStaticProps } = getStaticGenerationFunctions(
|
||||
process.env.ENABLE_VERSIONED_DOCS === 'true'
|
||||
? {
|
||||
strategy: 'remote',
|
||||
basePath: basePath,
|
||||
fallback: 'blocking',
|
||||
revalidate: 360, // 1 hour
|
||||
product: productSlug,
|
||||
}
|
||||
: {
|
||||
strategy: 'fs',
|
||||
localContentDir: CONTENT_DIR,
|
||||
navDataFile: NAV_DATA_FILE,
|
||||
product: productSlug,
|
||||
}
|
||||
)
|
||||
|
||||
export { getStaticPaths, getStaticProps }
|
|
@ -1,45 +0,0 @@
|
|||
import VerticalTextBlockList from '@hashicorp/react-vertical-text-block-list/index.tsx'
|
||||
import SectionHeader from '@hashicorp/react-section-header'
|
||||
import Head from 'next/head'
|
||||
import HashiHead from '@hashicorp/react-head'
|
||||
import s from './style.module.css'
|
||||
|
||||
function CommunityPage() {
|
||||
return (
|
||||
<main className={s.root}>
|
||||
<HashiHead is={Head} title="Community | Vault by HashiCorp" />
|
||||
<SectionHeader
|
||||
headline="Community"
|
||||
description="Vault is an open source project with a growing community. There are active, dedicated users willing to help you through various mediums."
|
||||
useH1={true}
|
||||
/>
|
||||
<VerticalTextBlockList
|
||||
product="vault"
|
||||
data={[
|
||||
{
|
||||
header: 'Discussion List',
|
||||
body:
|
||||
'<a href="https://discuss.hashicorp.com/c/vault">Vault Community Forum</a>',
|
||||
},
|
||||
{
|
||||
header: 'Bug Tracker',
|
||||
body:
|
||||
'<a href="https://github.com/hashicorp/vault/issues">Issue tracker on GitHub</a> for reporting bugs. Use IRC or the mailing list for general help.',
|
||||
},
|
||||
{
|
||||
header: 'Training',
|
||||
body:
|
||||
'<a href="https://www.hashicorp.com/training">Paid HashiCorp</a> training courses are available in a city near you. Private training courses are also available.',
|
||||
},
|
||||
{
|
||||
header: 'Certification',
|
||||
body:
|
||||
'Learn more about our <a href="https://www.hashicorp.com/certification/">Cloud Engineer Certification program</a> and <a href="https://www.hashicorp.com/certification/vault-associate/">HashiCorp's Security Automation Certification</a> exams.',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommunityPage
|
|
@ -1,9 +0,0 @@
|
|||
.root {
|
||||
composes: g-grid-container from global;
|
||||
margin-top: 72px;
|
||||
margin-bottom: 72px;
|
||||
|
||||
& :global(.g-section-header) {
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
import { productName, productSlug } from 'data/metadata'
|
||||
import DocsPage from '@hashicorp/react-docs-page'
|
||||
import Columns from 'components/columns'
|
||||
import Tag from 'components/inline-tag'
|
||||
// Imports below are used in server-side only
|
||||
import { getStaticGenerationFunctions } from '@hashicorp/react-docs-page/server'
|
||||
|
||||
const NAV_DATA_FILE = 'data/docs-nav-data.json'
|
||||
const CONTENT_DIR = 'content/docs'
|
||||
const basePath = 'docs'
|
||||
const additionalComponents = { Columns, Tag }
|
||||
|
||||
export default function DocsLayout(props) {
|
||||
return (
|
||||
<DocsPage
|
||||
product={{ name: productName, slug: productSlug }}
|
||||
baseRoute={basePath}
|
||||
staticProps={props}
|
||||
additionalComponents={additionalComponents}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const { getStaticPaths, getStaticProps } = getStaticGenerationFunctions(
|
||||
process.env.ENABLE_VERSIONED_DOCS === 'true'
|
||||
? {
|
||||
strategy: 'remote',
|
||||
basePath: basePath,
|
||||
fallback: 'blocking',
|
||||
revalidate: 360, // 1 hour
|
||||
product: productSlug,
|
||||
}
|
||||
: {
|
||||
strategy: 'fs',
|
||||
localContentDir: CONTENT_DIR,
|
||||
navDataFile: NAV_DATA_FILE,
|
||||
product: productSlug,
|
||||
}
|
||||
)
|
||||
|
||||
export { getStaticPaths, getStaticProps }
|
|
@ -1,38 +0,0 @@
|
|||
import { VERSION } from 'data/version'
|
||||
import { productSlug } from 'data/metadata'
|
||||
import ProductDownloadsPage from '@hashicorp/react-product-downloads-page'
|
||||
import { generateStaticProps } from '@hashicorp/react-product-downloads-page/server'
|
||||
import baseProps from 'components/downloads-props'
|
||||
import s from './style.module.css'
|
||||
|
||||
export default function DownloadsPage(staticProps) {
|
||||
return (
|
||||
<>
|
||||
<ProductDownloadsPage
|
||||
enterpriseMode={true}
|
||||
{...baseProps(
|
||||
<p className={s.legalNotice}>
|
||||
<em>
|
||||
The following shall apply unless your organization has a
|
||||
separately signed Enterprise License Agreement or Evaluation
|
||||
Agreement governing your use of the package: Enterprise packages
|
||||
in this repository are subject to the license terms located in the
|
||||
package. Please read the license terms prior to using the package.
|
||||
Your installation and use of the package constitutes your
|
||||
acceptance of these terms. If you do not accept the terms, do not
|
||||
use the package.
|
||||
</em>
|
||||
</p>
|
||||
)}
|
||||
{...staticProps}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
return generateStaticProps({
|
||||
product: productSlug,
|
||||
latestVersion: VERSION,
|
||||
})
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
import ProductDownloadsPage from '@hashicorp/react-product-downloads-page'
|
||||
import { generateStaticProps } from '@hashicorp/react-product-downloads-page/server'
|
||||
import { VERSION } from 'data/version'
|
||||
import { productSlug } from 'data/metadata'
|
||||
import baseProps from 'components/downloads-props'
|
||||
|
||||
export default function DownloadsPage(staticProps) {
|
||||
return <ProductDownloadsPage {...baseProps()} {...staticProps} />
|
||||
}
|
||||
|
||||
export function getStaticProps() {
|
||||
return generateStaticProps({
|
||||
product: productSlug,
|
||||
latestVersion: VERSION,
|
||||
})
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
.root {
|
||||
composes: .g-grid-container from global;
|
||||
margin-top: 72px;
|
||||
margin-bottom: 72px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 105px;
|
||||
}
|
||||
|
||||
.releaseNote {
|
||||
composes: .g-type-body from global;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.merchandisingSlot {
|
||||
width: 100%;
|
||||
border: 1px solid var(--gray-5);
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
& .centerWrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
& p {
|
||||
margin: 0;
|
||||
max-width: 400px;
|
||||
margin-right: 26px;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
flex-direction: column;
|
||||
& p {
|
||||
text-align: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.legalNotice {
|
||||
margin-bottom: 50px;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{}
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 13 KiB |
|
@ -1 +0,0 @@
|
|||
<svg fill="none" height="80" viewBox="0 0 80 80" width="80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="8" x2="55.9123" y1="52" y2="12.7793"><stop offset="0" stop-color="#fff9cf"/><stop offset="1" stop-color="#ffec6e"/></linearGradient><path d="m0 0h80v80h-80z" fill="#fff"/><rect fill="url(#a)" height="44" opacity=".6" rx="1.5" width="44" x="8" y="8"/><path d="m26 26h44v44h-44z" fill="#000"/><rect fill="#ffec6e" height="44" rx="1.5" width="44" x="17" y="17"/><g stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path clip-rule="evenodd" d="m31.5 40.167c0-1.1046.8954-2 2-2h11c1.1046 0 2 .8954 2 2v5.1667c0 1.1045-.8954 2-2 2h-11c-1.1046 0-2-.8955-2-2z" fill-rule="evenodd"/><path d="m34.833 38.167v-3.3333c0-2.3012 1.8655-4.1667 4.1667-4.1667s4.1666 1.8655 4.1666 4.1667v3.3333"/></g></svg>
|
Before Width: | Height: | Size: 915 B |
|
@ -1 +0,0 @@
|
|||
<svg fill="none" height="80" viewBox="0 0 80 80" width="80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="14" x2="31.342" y1="9" y2="11.7336"><stop offset="0" stop-color="#fff9cf"/><stop offset="1" stop-color="#ffec6e"/></linearGradient><path d="m0 0h80v80h-80z" fill="#fff"/><rect fill="#000" height="54" rx="1.5" width="43" x="23" y="13"/><path d="m57 69.5c0 .8284-.6716 1.5-1.5 1.5h-33.5v-62h33.5c.8284 0 1.5.67158 1.5 1.5z" fill="#ffec6e"/><rect fill="#000" height="3" rx="1.5" width="12" x="32" y="14"/><path d="m22 9v62h-6.5c-.8284 0-1.5-.6716-1.5-1.5v-59c0-.82843.6716-1.5 1.5-1.5z" fill="url(#a)" opacity=".7"/><g stroke="#000" stroke-linecap="round" stroke-linejoin="round"><path d="m43.6663 53.5v-1.6667c0-1.8409-1.4923-3.3333-3.3333-3.3333h-6.6667c-1.8409 0-3.3333 1.4924-3.3333 3.3333v1.6667" stroke-width="2"/><path clip-rule="evenodd" d="m37.0003 45.1667c1.841 0 3.3334-1.4924 3.3334-3.3334 0-1.8409-1.4924-3.3333-3.3334-3.3333-1.8409 0-3.3333 1.4924-3.3333 3.3333 0 1.841 1.4924 3.3334 3.3333 3.3334z" fill-rule="evenodd" stroke-width="1.5"/></g></svg>
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1 +0,0 @@
|
|||
<svg fill="none" height="80" viewBox="0 0 80 80" width="80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="11.5" x2="36.3586" y1="45" y2="71.4797"><stop offset="0" stop-color="#fff9cf"/><stop offset="1" stop-color="#ffec6e"/></linearGradient><path d="m0 0h80v80h-80z" fill="#fff"/><circle cx="40" cy="40" fill="url(#a)" fill-opacity=".65" r="32"/><path d="m40 69c16.0163 0 29-12.9837 29-29s-12.9837-29-29-29-29 12.9837-29 29" stroke="#000" stroke-width="6"/><circle cx="40" cy="40" fill="#ffec6e" r="26"/><path d="m48.0259 31.978c-1.2759-1.2756-2.9739-1.978-4.779-1.978-.2992 0-.6017.0189-.8978.0598-2.0729.2772-3.9316 1.5276-4.9711 3.3449-1.0396 1.8173-1.1719 4.0504-.3592 5.9811.0126.0284.0063.063-.0189.0882l-6.9999 6.9984v3.5276h3.5126l.9041-.9039c.0914-.0977.1323-.2142.126-.3307v-1.6599c0-.1512.1229-.2772.2772-.2772h1.5122c.1575 0 .3118-.0629.4221-.1763.1103-.1166.1701-.2614.1733-.4158v-1.5023c0-.1512.1228-.2772.2772-.2772h1.6885c.1198 0 .2363-.0504.3182-.1386l1.3263-1.326c.0157-.0126.0315-.0189.0504-.0189l.0315.0063c.8348.3496 1.7169.5292 2.621.5292 1.1751 0 2.3344-.3087 3.3551-.8914 1.8145-1.0362 3.0652-2.8945 3.3456-4.9669.2772-2.0724-.4379-4.1921-1.9154-5.6724zm-2.347 5.4299c-.4095.4126-.9576.6393-1.5404.6393-.8853 0-1.6728-.5291-2.0131-1.3448-.3371-.8158-.1543-1.7481.4726-2.3717.4127-.4126.9577-.6362 1.5405-.6362.2866 0 .567.0567.8316.1669.816.3402 1.3452 1.1276 1.3452 2.0126 0 .5669-.2331 1.1276-.6364 1.5339z" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.75"/></svg>
|
Before Width: | Height: | Size: 1.6 KiB |
BIN
website/pages/home/img/vault_dynamic_isometric@2x.png (Stored with Git LFS)
BIN
website/pages/home/img/vault_dynamic_isometric@2x.png (Stored with Git LFS)
Binary file not shown.
BIN
website/pages/home/img/vault_static_isometric@2x.png (Stored with Git LFS)
BIN
website/pages/home/img/vault_static_isometric@2x.png (Stored with Git LFS)
Binary file not shown.
|
@ -1,170 +0,0 @@
|
|||
import * as React from 'react'
|
||||
import Head from 'next/head'
|
||||
import rivetQuery from '@hashicorp/nextjs-scripts/dato/client'
|
||||
import homepageQuery from './query.graphql'
|
||||
import { renderMetaTags } from 'react-datocms'
|
||||
import IoHomeHero from 'components/io-home-hero'
|
||||
import IoHomeIntro from 'components/io-home-intro'
|
||||
import IoHomeInPractice from 'components/io-home-in-practice'
|
||||
import IoCardContainer from 'components/io-card-container'
|
||||
import IoHomeCaseStudies from 'components/io-home-case-studies'
|
||||
import IoHomeCallToAction from 'components/io-home-call-to-action'
|
||||
import IoHomePreFooter from 'components/io-home-pre-footer'
|
||||
import s from './style.module.css'
|
||||
|
||||
export default function Homepage({ data }): React.ReactElement {
|
||||
const {
|
||||
seo,
|
||||
heroHeading,
|
||||
heroDescription,
|
||||
heroCtas,
|
||||
heroCards,
|
||||
introHeading,
|
||||
introDescription,
|
||||
introFeatures,
|
||||
introVideo,
|
||||
inPracticeHeading,
|
||||
inPracticeDescription,
|
||||
inPracticeCards,
|
||||
inPracticeCtaHeading,
|
||||
inPracticeCtaDescription,
|
||||
inPracticeCtaLink,
|
||||
inPracticeCtaImage,
|
||||
useCasesHeading,
|
||||
useCasesDescription,
|
||||
useCasesCards,
|
||||
caseStudiesHeading,
|
||||
caseStudiesDescription,
|
||||
caseStudiesFeatured,
|
||||
caseStudiesLinks,
|
||||
callToActionHeading,
|
||||
callToActionDescription,
|
||||
callToActionCtas,
|
||||
preFooterHeading,
|
||||
preFooterDescription,
|
||||
preFooterCtas,
|
||||
} = data
|
||||
const _introVideo = introVideo[0]
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>{renderMetaTags(seo)}</Head>
|
||||
|
||||
<IoHomeHero
|
||||
pattern="/img/home-hero-pattern.svg"
|
||||
brand="vault"
|
||||
heading={heroHeading}
|
||||
description={heroDescription}
|
||||
ctas={heroCtas}
|
||||
cards={heroCards.map((card) => {
|
||||
return {
|
||||
...card,
|
||||
cta: card.cta[0],
|
||||
}
|
||||
})}
|
||||
/>
|
||||
|
||||
<IoHomeIntro
|
||||
brand="vault"
|
||||
heading={introHeading}
|
||||
description={introDescription}
|
||||
features={introFeatures}
|
||||
video={{
|
||||
youtubeId: _introVideo.youtubeId,
|
||||
thumbnail: _introVideo.thumbnail.url,
|
||||
heading: _introVideo.heading,
|
||||
description: _introVideo.description,
|
||||
person: {
|
||||
name: _introVideo.personName,
|
||||
description: _introVideo.personDescription,
|
||||
avatar: _introVideo.personAvatar?.url,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<section className={s.useCases}>
|
||||
<div className={s.container}>
|
||||
<IoCardContainer
|
||||
heading={useCasesHeading}
|
||||
description={useCasesDescription}
|
||||
cardsPerRow={4}
|
||||
cards={useCasesCards.map((card) => {
|
||||
return {
|
||||
eyebrow: card.eyebrow,
|
||||
link: {
|
||||
url: card.link,
|
||||
type: 'inbound',
|
||||
},
|
||||
heading: card.heading,
|
||||
description: card.description,
|
||||
products: card.products,
|
||||
}
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<IoHomeInPractice
|
||||
brand="vault"
|
||||
pattern="/img/practice-pattern.svg"
|
||||
heading={inPracticeHeading}
|
||||
description={inPracticeDescription}
|
||||
cards={inPracticeCards.map((card) => {
|
||||
return {
|
||||
eyebrow: card.eyebrow,
|
||||
link: {
|
||||
url: card.link,
|
||||
type: 'inbound',
|
||||
},
|
||||
heading: card.heading,
|
||||
description: card.description,
|
||||
products: card.products,
|
||||
}
|
||||
})}
|
||||
cta={{
|
||||
heading: inPracticeCtaHeading,
|
||||
description: inPracticeCtaDescription,
|
||||
link: inPracticeCtaLink,
|
||||
image: inPracticeCtaImage,
|
||||
}}
|
||||
/>
|
||||
|
||||
<IoHomeCaseStudies
|
||||
heading={caseStudiesHeading}
|
||||
description={caseStudiesDescription}
|
||||
primary={caseStudiesFeatured}
|
||||
secondary={caseStudiesLinks}
|
||||
/>
|
||||
|
||||
<IoHomeCallToAction
|
||||
brand="vault"
|
||||
heading={callToActionHeading}
|
||||
content={callToActionDescription}
|
||||
links={callToActionCtas}
|
||||
/>
|
||||
|
||||
<IoHomePreFooter
|
||||
brand="vault"
|
||||
heading={preFooterHeading}
|
||||
description={preFooterDescription}
|
||||
ctas={preFooterCtas}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
const { vaultHomepage } = await rivetQuery({
|
||||
query: homepageQuery,
|
||||
})
|
||||
|
||||
return {
|
||||
props: {
|
||||
data: vaultHomepage,
|
||||
},
|
||||
revalidate:
|
||||
process.env.HASHI_ENV === 'production'
|
||||
? process.env.GLOBAL_REVALIDATE
|
||||
: 10,
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
query homepageQuery {
|
||||
vaultHomepage {
|
||||
seo: _seoMetaTags {
|
||||
attributes
|
||||
content
|
||||
tag
|
||||
}
|
||||
heroHeading
|
||||
heroDescription
|
||||
heroCtas {
|
||||
title
|
||||
link
|
||||
}
|
||||
heroCards {
|
||||
heading
|
||||
description
|
||||
cta {
|
||||
title
|
||||
link
|
||||
}
|
||||
subText: subtext
|
||||
}
|
||||
introHeading
|
||||
introDescription
|
||||
introFeatures {
|
||||
heading
|
||||
description
|
||||
link
|
||||
image {
|
||||
url
|
||||
alt
|
||||
}
|
||||
}
|
||||
introVideo {
|
||||
youtubeId
|
||||
heading
|
||||
description
|
||||
thumbnail {
|
||||
url
|
||||
}
|
||||
personName
|
||||
personDescription
|
||||
personAvatar {
|
||||
url
|
||||
}
|
||||
}
|
||||
inPracticeHeading
|
||||
inPracticeDescription
|
||||
inPracticeCards {
|
||||
eyebrow
|
||||
heading
|
||||
description
|
||||
link
|
||||
products {
|
||||
name
|
||||
}
|
||||
}
|
||||
inPracticeCtaHeading
|
||||
inPracticeCtaDescription
|
||||
inPracticeCtaLink
|
||||
inPracticeCtaImage {
|
||||
url
|
||||
alt
|
||||
width
|
||||
height
|
||||
}
|
||||
useCasesHeading
|
||||
useCasesDescription
|
||||
useCasesCards {
|
||||
eyebrow
|
||||
heading
|
||||
description
|
||||
link
|
||||
products {
|
||||
name
|
||||
}
|
||||
}
|
||||
caseStudiesHeading
|
||||
caseStudiesDescription
|
||||
caseStudiesFeatured {
|
||||
thumbnail {
|
||||
url
|
||||
alt
|
||||
}
|
||||
heading
|
||||
link
|
||||
}
|
||||
caseStudiesLinks {
|
||||
heading
|
||||
link
|
||||
}
|
||||
callToActionHeading
|
||||
callToActionDescription
|
||||
callToActionCtas {
|
||||
text: title
|
||||
url: link
|
||||
}
|
||||
preFooterHeading
|
||||
preFooterDescription
|
||||
preFooterCtas {
|
||||
link
|
||||
heading
|
||||
description
|
||||
cta
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
.container {
|
||||
composes: g-grid-container from global;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use cases
|
||||
*/
|
||||
|
||||
.useCases {
|
||||
margin: 60px auto;
|
||||
|
||||
@media (--medium-up) {
|
||||
margin: 120px auto;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
import Homepage, { getStaticProps } from './home'
|
||||
export { getStaticProps }
|
||||
export default Homepage
|
|
@ -1,32 +0,0 @@
|
|||
import Link from 'next/link'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export default function NotFound() {
|
||||
useEffect(() => {
|
||||
if (
|
||||
typeof window !== 'undefined' &&
|
||||
typeof window?.analytics?.track === 'function' &&
|
||||
typeof window?.document?.referrer === 'string' &&
|
||||
typeof window?.location?.href === 'string'
|
||||
)
|
||||
window.analytics.track(window.location.href, {
|
||||
category: '404 Response',
|
||||
label: window.document.referrer || 'No Referrer',
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<main id="p-404">
|
||||
<h1 className="g-type-display-1">Page Not Found</h1>
|
||||
<p>
|
||||
We‘re sorry but we can‘t find the page you‘re looking
|
||||
for.
|
||||
</p>
|
||||
<p>
|
||||
<Link href="/">
|
||||
<a>Back to Home</a>
|
||||
</Link>
|
||||
</p>
|
||||
</main>
|
||||
)
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#p-404 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin: 64px auto; /* this is being overridden at the request of the learn team */
|
||||
max-width: 784px;
|
||||
min-height: 50vh;
|
||||
padding-inline: 32px;
|
||||
text-align: center;
|
||||
|
||||
@media (--large) {
|
||||
padding-inline: 24px;
|
||||
}
|
||||
|
||||
& h1 {
|
||||
font-size: 1.5rem;
|
||||
letter-spacing: -0.004em;
|
||||
line-height: 1.375em;
|
||||
|
||||
@media (--medium-up) {
|
||||
font-size: 1.75rem;
|
||||
line-height: 1.321em;
|
||||
}
|
||||
|
||||
@media (--large) {
|
||||
font-size: 2rem;
|
||||
letter-spacing: -0.006em;
|
||||
line-height: 1.313em;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
/* Print Styles - Hide Elements */
|
||||
@media print {
|
||||
iframe,
|
||||
[class*='hashi-stack-menu'],
|
||||
.g-footer,
|
||||
[aria-hidden='true'],
|
||||
[id='sidebar'],
|
||||
[id='edit-this-page'],
|
||||
[id='jump-to-section'],
|
||||
[id='__next-build-watcher'] {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print Styles - Page Spacing */
|
||||
@media print {
|
||||
@page {
|
||||
margin: 2cm 0.5cm;
|
||||
}
|
||||
|
||||
@page :first {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@page :last {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
break-inside: avoid;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: 2cm;
|
||||
margin-top: 2cm;
|
||||
}
|
||||
|
||||
dl,
|
||||
ol,
|
||||
ul {
|
||||
break-before: avoid;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
break-after: avoid;
|
||||
break-inside: avoid;
|
||||
}
|
||||
|
||||
img {
|
||||
break-inside: avoid;
|
||||
break-after: avoid;
|
||||
}
|
||||
|
||||
pre,
|
||||
table {
|
||||
break-inside: avoid;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
/* @todo: remove alongside @hashicorp/react-global-styles/_temporary-to-remove/layout.css */
|
||||
.g-grid-container {
|
||||
/*
|
||||
* A “measure” is the number of characters in a line of text.
|
||||
* Long lines fatique readers as they find the start of a new line of text.
|
||||
* It seems widely accepted that an ideal measure is 66 characters per line.
|
||||
* An average character takes up .5em, and so we define a measure of 33em.
|
||||
* See: https://webtypography.net/2.1.2
|
||||
*/
|
||||
max-width: 33em;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* @todo: remove alongside @hashicorp/react-global-styles/_temporary-to-remove/tables.css */
|
||||
table {
|
||||
margin-bottom: 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* @todo: move print styles to @hashicorp/react-global-styles/global.css */
|
||||
@media print {
|
||||
pre code,
|
||||
code,
|
||||
pre {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: transparent;
|
||||
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15);
|
||||
color: inherit;
|
||||
padding: 0.5em;
|
||||
|
||||
& > code {
|
||||
white-space: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* @todo: move print styles to @hashicorp/react-content/dist/style.css */
|
||||
@media print {
|
||||
.g-content {
|
||||
& a {
|
||||
color: inherit;
|
||||
font-weight: 700;
|
||||
|
||||
&:not(.anchor) {
|
||||
&::after {
|
||||
background-color: transparent;
|
||||
position: static;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&[href^='http'] {
|
||||
&::after {
|
||||
content: ' <' attr(href) '>';
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
letter-spacing: -0.01875em;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
&:not([href^='http']) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
& > code {
|
||||
color: inherit;
|
||||
font-weight: 700;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& h1,
|
||||
& h2,
|
||||
& h3,
|
||||
& h4,
|
||||
& h5,
|
||||
& h6 {
|
||||
& code {
|
||||
background: none;
|
||||
font-size: 1em;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
& h2 {
|
||||
margin: 1em 0 0;
|
||||
}
|
||||
|
||||
& h3 {
|
||||
margin: 1em 0 0;
|
||||
padding-bottom: 0.25em;
|
||||
}
|
||||
|
||||
& img {
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
|
||||
margin: 1em 0 0;
|
||||
}
|
||||
|
||||
& ol,
|
||||
& ul {
|
||||
margin: 1em 0 0;
|
||||
|
||||
& li {
|
||||
margin-bottom: 0;
|
||||
margin-top: 0.5em;
|
||||
|
||||
& p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& p {
|
||||
margin: 1em 0 0;
|
||||
}
|
||||
|
||||
& pre {
|
||||
background-color: transparent;
|
||||
border-radius: 0;
|
||||
margin: 1.5em 0 0;
|
||||
|
||||
& code {
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
& dd,
|
||||
& dt,
|
||||
& li,
|
||||
& p,
|
||||
& td,
|
||||
& th {
|
||||
& > :not(pre) code,
|
||||
& > code {
|
||||
background: transparent;
|
||||
font-weight: 700;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
& .alert.alert-danger,
|
||||
& .alert.alert-info,
|
||||
& .alert.alert-success,
|
||||
& .alert.alert-warning {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
import MarkdownPage from '@hashicorp/react-markdown-page'
|
||||
import generateStaticProps from '@hashicorp/react-markdown-page/server'
|
||||
|
||||
export default function SecurityPage(staticProps) {
|
||||
return <MarkdownPage {...staticProps} />
|
||||
}
|
||||
|
||||
export const getStaticProps = generateStaticProps({
|
||||
pagePath: 'content/security.mdx',
|
||||
})
|
|
@ -1,60 +0,0 @@
|
|||
/* Global Component Styles */
|
||||
@import '~@hashicorp/mktg-global-styles/style.css';
|
||||
|
||||
:root {
|
||||
--highlight-color: var(--brand-link);
|
||||
}
|
||||
|
||||
/* Local Components */
|
||||
@import '../components/footer/style.css';
|
||||
@import '../components/use-case-cta-section/style.css';
|
||||
|
||||
/* Pages */
|
||||
@import './not-found/style.css';
|
||||
|
||||
/* Print Styles */
|
||||
@import './print.css';
|
||||
|
||||
/*
|
||||
* Layout Styles
|
||||
*
|
||||
* Note: this is possibly debt we want to replace.
|
||||
* ref: https://app.asana.com/0/1100423001970639/1200768863236365/f
|
||||
*/
|
||||
.g-section-block section {
|
||||
padding-top: 96px;
|
||||
padding-bottom: 96px;
|
||||
|
||||
& > .g-section-header + *,
|
||||
& > .g-grid-container > .g-section-header + * {
|
||||
margin-top: 72px;
|
||||
}
|
||||
|
||||
&:not(.no-section-spacing) > * + *,
|
||||
&:not(.g-featured-slider-section) > .g-grid-container > * + * {
|
||||
margin-top: 96px;
|
||||
}
|
||||
}
|
||||
|
||||
.g-section-block .button-container {
|
||||
display: -webkit-box;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
-webkit-box-pack: center;
|
||||
justify-content: center;
|
||||
margin: auto -8px -16px;
|
||||
}
|
||||
|
||||
.g-section-block section > * + .button-container,
|
||||
.g-section-block section > .g-grid-container > * + .button-container {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.g-section-block .button-container > * {
|
||||
margin: auto 8px 16px;
|
||||
}
|
||||
|
||||
.g-section-block.theme-black-background-white-text {
|
||||
background: var(--gray-1);
|
||||
color: white;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue