add majority of home page components

This commit is contained in:
nicolelyn 2020-04-24 17:46:02 -04:00 committed by Brandon Romano
parent e0ea39fcf0
commit cb678b8859
13 changed files with 529 additions and 202 deletions

View File

@ -7,7 +7,6 @@ export default function BasicHero({
brand,
backgroundImage,
}) {
console.log('background?', backgroundImage)
return (
<div className={`g-basic-hero ${backgroundImage ? 'has-background' : ''}`}>
<div className="g-grid-container">

View File

@ -1,55 +0,0 @@
function BeforeAfterDiagram({
beforeHeading,
beforeSubTitle,
beforeImage,
beforeDescription,
afterHeading,
afterSubTitle,
afterImage,
afterDescription,
}) {
return (
<div className="g-timeline">
<div>
<span className="line"></span>
<span className="line">
<svg
xmlns="http://www.w3.org/2000/svg"
width="11"
height="15"
viewBox="0 0 11 15"
>
<path
fill="#CA2171"
d="M0 0v15l5.499-3.751L11 7.5 5.499 3.749.002 0z"
/>
</svg>
</span>
<span className="dot"></span>
<h3>{beforeHeading}</h3>
<span className="sub-heading">{beforeSubTitle}</span>
<img
src={beforeImage}
alt={beforeSubTitle}
className="static-callout"
/>
{beforeDescription && <p>{beforeDescription}</p>}
</div>
<div>
<span className="dot"></span>
<h3>{afterHeading}</h3>
<span className="sub-heading">{afterSubTitle}</span>
<div id="index-dynamic-animation">
<img
src={afterImage}
alt={afterSubTitle}
className="static-callout"
/>
</div>
{afterDescription && <p>{afterDescription}</p>}
</div>
</div>
)
}
export default BeforeAfterDiagram

View File

@ -1,146 +0,0 @@
.g-timeline {
align-content: space-between;
display: flex;
flex-direction: column;
justify-content: center;
margin: 0 -15px;
@media (min-width: 768px) {
flex-direction: row;
text-align: center;
}
&.no-intro {
margin-top: -30px;
@media (min-width: 768px) {
margin-top: -90px;
}
@media (min-width: 992px) {
margin-top: -116px;
}
}
& > div {
margin-left: 18px;
padding: 40px 15px 0 42px;
position: relative;
@media (min-width: 768px) {
margin-left: 0;
padding-left: 15px;
width: 50%;
}
&:last-child {
& .dot {
border-color: #ca2171;
}
}
& .line {
background-image: linear-gradient(180deg, #d2d4dc 50%, #c82070 100%);
height: calc(100% - 12px);
left: 8px;
position: absolute;
top: 45px;
width: 2px;
@media (min-width: 768px) {
background-image: linear-gradient(
90deg,
rgba(229, 230, 235, 0),
#d2d4dc 0%,
#c82070 100%
);
height: 2px;
left: 50%;
top: 8px;
width: calc(100% - 34px);
}
&:first-child {
background-image: linear-gradient(
180deg,
rgba(229, 230, 235, 0) 5%,
#dadce3 70%,
#d2d4dc 100%
);
bottom: calc(100% - 45px);
height: 60px;
top: auto;
@media (min-width: 768px) {
background-image: linear-gradient(
90deg,
rgba(229, 230, 235, 0) 5%,
#dadce3 26%,
#d2d4dc 100%
);
height: 2px;
left: auto;
right: 50%;
top: 8px;
width: calc(50% + 120px);
}
}
& svg {
position: absolute;
top: calc(100% - 8px);
transform: rotate(90deg);
left: -4px;
@media (min-width: 768px) {
left: auto;
right: -10px;
top: -6px;
transform: none;
}
}
}
& h2 {
margin: 0 0 8px;
}
& .sub-heading {
display: block;
margin-bottom: 24px;
@media (min-width: 992px) {
margin-bottom: 40px;
}
}
& .dot {
background: #f7f8fa;
border: 2px solid #d2d4dc;
border-radius: 50%;
display: inline-block;
height: 18px;
left: 0;
position: absolute;
top: 45px;
width: 18px;
z-index: 1;
@media (min-width: 768px) {
margin: 0 0 0 -9px;
left: 50%;
top: 0;
}
}
& img {
display: block;
margin: 0 auto;
max-width: 100%;
}
& p {
margin-top: 40px;
}
}
}

View File

@ -0,0 +1,44 @@
import InlineSvg from '@hashicorp/react-inline-svg'
import Image from '@hashicorp/react-image'
import Button from '@hashicorp/react-button'
import QuoteMarksIcon from './img/quote.svg?include'
export default function CaseStudySlide({
caseStudy: { person, quote, company, caseStudyURL }
}) {
return (
<blockquote className="g-grid-container case-slide">
<InlineSvg className="quotes" src={QuoteMarksIcon} />
<h4 className="case g-type-display-4">{quote}</h4>
<div className="case-content">
<div className="person-container">
<Image
className="person-photo"
url={person.photo}
aspectRatio={[1, 1]}
alt={`${person.firstName} ${person.lastName}`}
/>
<div className="person-name">
<h5 className="g-type-display-5">
{person.firstName} {person.lastName}
</h5>
<p>
{person.title}, {company.name}
</p>
</div>
</div>
<Image className="company-logo" url={company.logo} alt={company.name} />
</div>
<Button
title="Read more"
url={caseStudyURL}
theme={{
variant: 'tertiary',
brand: 'nomad',
background: 'light'
}}
linkType="outbound"
/>
</blockquote>
)
}

View File

@ -0,0 +1 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="4" r="4" fill="#333"/></svg>

After

Width:  |  Height:  |  Size: 139 B

View File

@ -0,0 +1 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="4" r="4" fill="#c4c4c4"/></svg>

After

Width:  |  Height:  |  Size: 142 B

View File

@ -0,0 +1 @@
<svg width="56" height="56" xmlns="http://www.w3.org/2000/svg"><g stroke="#323339" stroke-width="1.5" fill="none" fill-rule="evenodd"><path d="M.75 28c0 15.05 12.2 27.25 27.25 27.25S55.25 43.05 55.25 28 43.05.75 28 .75.75 12.95.75 28z" fill="#FFF"/><path d="M36 28H20M26 22l-6 6 6 6" stroke-linecap="round" stroke-linejoin="round"/></g></svg>

After

Width:  |  Height:  |  Size: 342 B

View File

@ -0,0 +1,3 @@
<svg width="19" height="15" viewBox="0 0 19 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.15 0.5H3.95L0 14.35H6.95L9.15 0.5ZM18.7 0.5H13.45L9.55 14.35H16.5L18.7 0.5Z" fill="#00BC7F"/>
</svg>

After

Width:  |  Height:  |  Size: 209 B

View File

@ -0,0 +1 @@
<svg width="56" height="56" xmlns="http://www.w3.org/2000/svg"><g stroke="#323339" stroke-width="1.5" fill="none" fill-rule="evenodd"><path d="M55.25 28c0 15.05-12.2 27.25-27.25 27.25S.75 43.05.75 28 12.95.75 28 .75 55.25 12.95 55.25 28z" fill="#FFF"/><path d="M20 28h16M30 22l6 6-6 6" stroke-linecap="round" stroke-linejoin="round"/></g></svg>

After

Width:  |  Height:  |  Size: 344 B

View File

@ -0,0 +1,99 @@
import { useState } from 'react'
import { isIE } from 'react-device-detect'
import Carousel from 'nuka-carousel'
import CaseSlide from './case-study-slide'
import Image from '@hashicorp/react-image'
import InlineSvg from '@hashicorp/react-inline-svg'
import ActiveControlDot from './img/active-control-dot.svg?include'
import InactiveControlDot from './img/inactive-control-dot.svg?include'
import LeftArrow from './img/left-arrow-control.svg?include'
import RightArrow from './img/right-arrow-control.svg?include'
export default function CaseStudyCarousel({
caseStudies,
title,
logoSection = { grayBackground: false, featuredLogos: [] },
}) {
const [slideIndex, setSlideIndex] = useState(0)
const { grayBackground, featuredLogos } = logoSection
const caseStudySlides = caseStudies.map((caseStudy) => (
<CaseSlide key={caseStudy.quote} caseStudy={caseStudy} />
))
const logoRows = featuredLogos && Math.ceil(featuredLogos.length / 3)
function renderControls() {
return (
<div className="carousel-controls">
{caseStudies.map((caseStudy, stableIdx) => {
return (
<button
key={caseStudy.quote}
className="carousel-controls-button"
onClick={() => setSlideIndex(stableIdx)}
>
<InlineSvg
src={
slideIndex === stableIdx
? ActiveControlDot
: InactiveControlDot
}
/>
</button>
)
})}
</div>
)
}
function sideControls(icon, direction) {
return (
<button className="side-control" onClick={direction}>
<InlineSvg src={icon} />
</button>
)
}
console.log('logo rows', logoRows)
return (
<section
className={`g-case-carousel ${grayBackground ? 'has-background' : ''}`}
style={{ '--background-height': `${300 + logoRows * 100}px` }}
>
<h2 className="g-type-display-2">{title}</h2>
{!isIE ? (
<Carousel
cellAlign="left"
wrapAround={true}
heightMode="current"
slideIndex={slideIndex}
slidesToShow={1}
autoGenerateStyleTag
renderBottomCenterControls={() => renderControls()}
renderCenterLeftControls={({ previousSlide }) => {
return sideControls(LeftArrow, previousSlide)
}}
renderCenterRightControls={({ nextSlide }) => {
return sideControls(RightArrow, nextSlide)
}}
afterSlide={(slideIndex) => setSlideIndex(slideIndex)}
>
{caseStudySlides}
</Carousel>
) : null}
<div className="background-section">
{featuredLogos && featuredLogos.length > 0 && (
<div className="mono-logos">
{featuredLogos.map((featuredLogo) => (
<Image
key={featuredLogo.url}
url={featuredLogo.url}
alt={featuredLogo.companyName}
/>
))}
</div>
)}
</div>
</section>
)
}

View File

@ -0,0 +1,257 @@
.g-case-carousel {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
padding-top: 128px;
& h2 {
margin-bottom: 30px;
max-width: 600px;
text-align: center;
white-space: pre-wrap;
@media (max-width: 800px) {
margin-top: 64px;
white-space: initial;
margin-left: 24px;
margin-right: 24px;
}
}
&::after {
content: '';
width: 100%;
height: var(--background-height);
position: absolute;
bottom: 0px;
z-index: -1;
}
&.has-background {
&::after {
content: '';
background: var(--gray-7);
}
& .background-section {
background: var(--gray-7);
}
}
& .background-section {
width: 100%;
& .mono-logos {
display: flex;
justify-content: center;
max-width: 750px;
margin: 0 auto;
margin-top: 70px;
flex-wrap: wrap;
& img {
max-height: 40px;
width: 33.33%;
padding: 0 30px;
margin: 24px 0px;
@media (max-width: 800px) {
padding: 0 20px;
max-height: 28px;
}
}
}
}
& .slider-control-bottomcenter {
bottom: -35px !important;
}
/* Begin `nuka-carousel` styles */
& .slider {
max-width: 1200px;
&:focus {
outline: none !important;
}
@media (max-width: 800px) {
width: calc(100% - 48px) !important;
}
& .slider-list {
margin-bottom: 50px !important;
@media (max-width: 800px) {
margin-bottom: 30px !important;
}
}
& .slider-frame:focus {
outline: none !important;
}
& .slider-slide:focus {
outline: none !important;
}
}
/* End `nuka-carousel` styles */
& .side-control {
border: none;
background: none;
margin: 20px;
&:focus {
outline: none;
}
&:hover:not([disabled]) {
cursor: pointer;
}
@media (max-width: 991px) {
display: none;
}
& svg path {
stroke: var(--gray-2);
}
&:disabled svg path {
stroke: var(--gray-5);
}
}
& .case-slide {
display: flex;
flex-wrap: wrap;
width: 100%;
background: var(--white);
padding: 64px;
box-shadow: 0px 8px 22px #dedede;
@media (max-width: 800px) {
box-shadow: none;
border: 1px solid var(--gray-6);
padding: 48px;
}
@media (--medium-up) {
max-width: 750px;
}
& button {
margin-top: 24px;
}
& .quotes {
display: flex;
margin-bottom: 24px;
}
& h4 {
margin: 0;
&.case {
min-height: 130px;
margin-bottom: 24px;
color: var(--gray-2);
@media (max-width: 800px) {
min-height: 155px;
font-size: 22px;
}
@media (max-width: 650px) {
min-height: 190px;
}
@media (max-width: 550px) {
font-size: 20px;
}
@media (max-width: 400px) {
font-size: 18px;
line-height: 28px;
}
}
}
& p {
margin: 0;
}
& a {
margin-top: 24px;
}
& .case-content {
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
}
& .person-container {
display: flex;
align-items: center;
& picture {
display: flex;
}
& .person-photo {
border-radius: 50%;
max-height: 72px;
margin-right: 24px;
}
& .person-name {
& h5 {
margin: 0;
}
@media (max-width: 400px) {
& h5 {
font-size: 16px;
}
& p {
font-size: 15px;
}
}
}
}
& .company-logo {
max-height: 40px;
max-width: 180px;
@media (max-width: 800px) {
display: none;
}
}
& .case {
color: var(--gray-5);
font-size: 24px;
line-height: 31px; /* Called for within the design, no custom property seemed appropriate*/
}
}
& .carousel-controls {
width: 100%;
display: flex;
flex-wrap: nowrap;
justify-content: center;
& .carousel-controls-button {
height: 20px;
background: transparent;
box-shadow: none;
cursor: pointer;
border: none;
}
}
}

View File

@ -3,6 +3,7 @@ import UseCases from '@hashicorp/react-use-cases'
import BasicHero from '../../components/basic-hero'
import ConsulEnterpriseComparison from '../../components/consul-enterprise-comparison'
import LearnCallout from '../../components/learn-callout'
import CaseStudyCarousel from '../../components/case-study-carousel'
export default function HomePage() {
return (
@ -25,6 +26,126 @@ export default function HomePage() {
]}
backgroundImage
/>
<CaseStudyCarousel
title="Trusted by startups and the worlds largest organizations"
caseStudies={[
{
quote:
'Kubernetes is the 800-pound gorilla of container orchestration, coming with a price tag. So we looked into alternatives - and fell in love with Nomad.',
caseStudyURL:
'https://endler.dev/2019/maybe-you-dont-need-kubernetes/',
person: {
firstName: 'Matthias',
lastName: 'Endler',
photo:
'https://www.datocms-assets.com/2885/1582163422-matthias-endler.png',
title: 'Backend Engineer',
},
company: {
name: 'Trivago',
logo:
'https://www.datocms-assets.com/2885/1582162145-trivago.svg',
},
},
{
quote:
'We have people who are first-time system administrators deploying applications. There is a guy on our team who worked in IT help desk for 8 years - just today he upgraded an entire cluster himself.',
caseStudyURL: 'https://www.hashicorp.com/case-studies/roblox/',
person: {
firstName: 'Rob',
lastName: 'Cameron',
photo:
'https://www.datocms-assets.com/2885/1582180216-rob-cameron.jpeg',
title: 'Technical Director of Infrastructure',
},
company: {
name: 'Roblox',
logo:
'https://www.datocms-assets.com/2885/1582180369-roblox-color.svg',
},
},
{
quote:
'Our customers jobs are changing constantly. Its challenging to dynamically predict demand, what types of jobs, and the resource requirements. We found that Nomad excelled in this area.',
caseStudyURL:
'https://www.hashicorp.com/resources/nomad-vault-circleci-security-scheduling',
person: {
firstName: 'Rob',
lastName: 'Zuber',
photo:
'https://www.datocms-assets.com/2885/1582180618-rob-zuber.jpeg',
title: 'CTO',
},
company: {
name: 'CircleCI',
logo:
'https://www.datocms-assets.com/2885/1582180745-circleci-logo.svg',
},
},
{
quote:
'Adopting Nomad did not require us to change our packaging format — we could continue to package Python in Docker and build binaries for the rest of our applications.',
caseStudyURL:
'https://medium.com/@copyconstruct/schedulers-kubernetes-and-nomad-b0f2e14a896',
person: {
firstName: 'Cindy',
lastName: 'Sridharan',
photo:
'https://www.datocms-assets.com/2885/1582181517-cindy-sridharan.png',
title: 'Engineer',
},
company: {
name: 'imgix',
logo: 'https://www.datocms-assets.com/2885/1582181250-imgix.svg',
},
},
]}
logoSection={{
grayBackground: true,
featuredLogos: [
{
companyName: 'Trivago',
url:
'https://www.datocms-assets.com/2885/1582162317-trivago-monochromatic.svg',
},
{
companyName: 'Roblox',
url:
'https://www.datocms-assets.com/2885/1582180373-roblox-monochrome.svg',
},
{
companyName: 'CircleCI',
url:
'https://www.datocms-assets.com/2885/1582180745-circleci-logo.svg',
},
// {
// companyName: 'SAP Ariba',
// url:
// 'https://www.datocms-assets.com/2885/1580419436-logosap-ariba.svg',
// },
// {
// companyName: 'Pandora',
// url:
// 'https://www.datocms-assets.com/2885/1523044075-pandora-black.svg',
// },
// {
// companyName: 'Citadel',
// url:
// 'https://www.datocms-assets.com/2885/1582323352-logocitadelwhite-knockout.svg',
// },
// {
// companyName: 'Jet',
// url:
// 'https://www.datocms-assets.com/2885/1522341143-jet-black.svg',
// },
// {
// companyName: 'Deluxe',
// url:
// 'https://www.datocms-assets.com/2885/1582323254-deluxe-logo.svg',
// },
],
}}
/>
<div className="use-cases g-grid-container">
<UseCases
items={[

View File

@ -46,6 +46,7 @@
@import '../components/before-after/style.css';
@import '../components/tabs/style.css';
@import '../components/learn-callout/style.css';
@import '../components/case-study-carousel/style.css';
/* Local Pages */
@import './downloads/style.css';