Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions lib/Hero/Carousel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { useState } from "react";
import { AiOutlineLeft, AiOutlineRight } from "react-icons/ai";
import Swipe from "react-easy-swipe";

const Carousel = ({children}) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave spaces in your object destructuring notation: const Carousel = ({ children }) => {

const slideLength = children.length;
const handleNextClick = () => {
const index = currentIndex === slideLength - 1 ? 0 : currentIndex + 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget the trailing semicolons! Same comment for most of the lines below

setCurrentIndex(index)
}
const handleOnPrevClick = () => {
const index = currentIndex === 0 ? slideLength - 1 : currentIndex - 1
setCurrentIndex(index)
};

const [currentIndex, setCurrentIndex] = useState(0)
return (
<div className="m-auto">
<div className="w-full relative select-none">
<AiOutlineLeft
onClick={handleOnPrevClick}
className="absolute left-0 text-3xl inset-y-1/2 text-white cursor-pointer"
/>
<Swipe>
{
children.map((child, index) =>
React.cloneElement(child, {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite smart! Well done.

className: `
${index === currentIndex
? "block w-full h-auto object-cover"
: "hidden"}
`})
)
}
<div>
</div>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the empty div?

</Swipe>
<div className="absolute w-full flex justify-center bottom-0">
{children.map((element, index) => {
return (
<div
className={
index === currentIndex
? "h-2 w-2 bg-black rounded-full mx-2 mb-2 cursor-pointer"
: "h-2 w-2 bg-white rounded-full mx-2 mb-2 cursor-pointer"
Comment thread
ikhoaA marked this conversation as resolved.
Outdated
}
key={index}
onClick={() => {
Comment thread
ikhoaA marked this conversation as resolved.
Outdated
setCurrentIndex(index);
}}
/>
);
})}
</div>
<AiOutlineRight
onClick={handleNextClick}
className="absolute right-0 text-3xl inset-y-1/2 text-white cursor-pointer"
/>
</div>
</div>
);
};

export default Carousel;
84 changes: 84 additions & 0 deletions lib/Hero/Content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React from 'react';
import clsx from 'clsx';

const Content = ({
classNames = {},
title,
subTitle,
imageUrl,
hasOverlay,
Image,
Button,
}) => {
return (
<>
<div
className={clsx('flex items-center justify-center', classNames.wrapper)}
style={{
background: Image === undefined ? 'url(' + imageUrl + ')' : '',
backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
height: '100vh',
width: '100vw',
}}
>
{Image && (
<div
style={{
position: 'fixed',
height: '100vh',
width: '100vw',
overflow: 'hidden',
zIndex: -1,
}}
>
<Image/>
</div>
)}
<div
style={{
background: hasOverlay
? 'linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.6))'
: '',
height: '100vh',
width: '100vw',
}}
className={clsx(
' px-4 py-16 sm:px-6 sm:py-24 lg:py-32 lg:px-8',
classNames.contentWrapper,
)}
>
<h1
className={clsx(
'text-center text-4xl font-extrabold mt-32 tracking-tight sm:text-5xl lg:text-6xl',
classNames.titleWrapper,
)}
>
<span className={clsx('block text-white', classNames.title)}>
{title}
</span>
</h1>
<p
className={clsx(
'mt-6 max-w-lg mx-auto text-center text-xl text-white sm:max-w-3xl',
classNames.subTitle,
)}
>
{subTitle}
</p>
<div
className={clsx(
'mt-10 max-w-sm mx-auto sm:max-w-none sm:flex sm:justify-center lg:max-w-sm',
classNames.buttonWrapper,
)}
>
<Button />
</div>
</div>
</div>
</>
);
};

export default Content;
109 changes: 109 additions & 0 deletions lib/Hero/Hero.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React, { lazy, Suspense } from 'react';
import PropTypes, { element, elementType, node } from 'prop-types';
import { Button as ButtonComponent } from '../Button';
import Content from './Content';
const Carousel = lazy(() =>
Comment thread
loan-laux marked this conversation as resolved.
Outdated
import('./Carousel'),
);


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for an extra line break here

const Hero = ({
classNames = {},
hasOverlay,
slides,
Button
}) => {

const isSlider = slides.length > 1
return (
<>
{isSlider ? (
<Suspense fallback={<div>Loading...</div>}>
<Carousel>
{slides.map((slide, index) => (
<div className="" key={index}>
<Content
title={slide.title}
classNames={classNames}
subTitle={slide.subTitle}
Button={Button}
Image={slide.imageComponent}
imageUrl={slide.imageUrl}
hasOverlay={hasOverlay}
/>
</div>
))}
</Carousel>
</Suspense>
) : (
<Content
title={slides[0].title}
classNames={classNames}
subTitle={slides[0].subTitle}
Button={Button}
imageUrl={slides[0].imageUrl}
Image={slides[0].imageComponent}
hasOverlay={hasOverlay}
/>
)}
</>
);
};
Hero.propTypes = {
/**
* Object of classNames to be added to each part of the component.
* e.g. `{ container: 'my-custom-class', container: 'my-other-custom-class' }`
*/
classNames: PropTypes.shape({
container: PropTypes.string,
title: PropTypes.string,
featureWrapper: PropTypes.string,
featureTitle: PropTypes.string,
featureSubtitle: PropTypes.string,
}),
/**
* Boolean that toggles the overlay
* e.g. `true`
*/
hasOverlay: PropTypes.bool,
/**
* React Button component
* e.g. `<ButtonComponent
* displayText="Shop Now"
* onClick={() => {
* alert('You clicked me');
* }}
* />`
*/
Button: PropTypes.elementType.isRequired,
/**
* Array of objects for each slide to display
* e.g. `[{title: "Women's History Month",subTitle: "Discover our latest women's releases in celebration of Women's History Month",imageUrl: "https://images.unsplash.com/photo-1469334031218-e382a71b716b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2670&q=80"}]`
*/
slides: PropTypes.arrayOf(
PropTypes.shape({
/**
* Custom Image optimizer component
* e.g. `import Image from 'next/image'`
*/
imageComponent: PropTypes.elementType,
/**
* Title of Hero component
* e.g. `Hello world`
*/
title: PropTypes.string.isRequired,
/**
* Subtitle of Hero component
* e.g. `How to make you feel good`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate the effort, but I don't think we necessarily need these examples. The names of the props are self-explanatory and the types provide enough info as to what they should be.

*/
subTitle: PropTypes.string.isRequired,
/**
* Hero image URL
* e.g. `https://images.unsplash.com/photo-1469334031218-e382a71b716b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2670&q=80`
*/
imageUrl: PropTypes.string ,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove the space before this trailing coma

}),
),
};

export default Hero;
1 change: 1 addition & 0 deletions lib/Hero/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Hero } from './Hero';
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { StarRating } from './StarRating';
export { VariantSelector } from './VariantSelector';
export { Toggle } from './Toggle';
export { Pricing } from './Pricing';
export { Hero } from './Hero';
export { Metrics } from './Metrics';
export { Features } from './Features';
export { OrderPricingSummary } from './OrderPricingSummary';
Expand Down
Loading