├── .husky ├── .gitignore └── pre-commit ├── .eslintignore ├── .prettierignore ├── netlify.toml ├── src ├── index.js ├── slices │ ├── FaqSection │ │ ├── preview.png │ │ ├── meta.json │ │ ├── index.stories.js │ │ ├── README.md │ │ ├── model.json │ │ ├── index.js │ │ └── mock.json │ ├── AlternateGrid │ │ ├── preview.png │ │ ├── model.json │ │ ├── index.stories.js │ │ ├── index.js │ │ └── mock.json │ ├── CallToAction │ │ ├── preview.png │ │ ├── index.stories.js │ │ ├── mock.json │ │ ├── model.json │ │ └── index.js │ ├── CardsCarousel │ │ ├── preview.png │ │ ├── index.stories.js │ │ ├── meta.json │ │ ├── model.json │ │ ├── index.js │ │ └── mock.json │ ├── CustomerLogos │ │ ├── preview.png │ │ ├── index.stories.js │ │ ├── meta.json │ │ ├── README.md │ │ ├── model.json │ │ ├── index.js │ │ └── mock.json │ ├── ImagesSlider │ │ ├── preview.png │ │ ├── index.stories.js │ │ ├── meta.json │ │ ├── README.md │ │ ├── model.json │ │ ├── mock.json │ │ └── index.js │ ├── PricingTable │ │ ├── preview.png │ │ ├── index.stories.js │ │ ├── meta.json │ │ ├── styles.js │ │ ├── README.md │ │ ├── model.json │ │ ├── index.js │ │ └── mock.json │ ├── VideoHighlights │ │ ├── preview.png │ │ ├── meta.json │ │ ├── styles.js │ │ ├── index.stories.js │ │ ├── README.md │ │ ├── model.json │ │ ├── index.js │ │ └── mock.json │ ├── TestimonialsSlider │ │ ├── preview.png │ │ ├── index.stories.js │ │ ├── meta.json │ │ ├── README.md │ │ ├── model.json │ │ ├── index.js │ │ └── mock.json │ └── index.js ├── components │ ├── Tabs │ │ ├── index.js │ │ ├── index.stories.js │ │ ├── styles.js │ │ ├── TabsItem.js │ │ └── Tabs.js │ ├── Accordion │ │ ├── index.js │ │ ├── index.stories.js │ │ ├── Accordion.js │ │ ├── AccordionItem.js │ │ └── mock.json │ ├── Card │ │ ├── index.js │ │ ├── CardContent.js │ │ ├── CardFooter.js │ │ ├── Card.js │ │ ├── CardImage.js │ │ ├── mock.json │ │ └── index.stories.js │ ├── Head │ │ ├── index.stories.js │ │ └── index.js │ ├── Wrap │ │ ├── index.stories.js │ │ └── index.js │ ├── Desc │ │ ├── index.stories.js │ │ └── index.js │ ├── Title │ │ ├── index.stories.js │ │ └── index.js │ ├── Slice │ │ ├── index.stories.js │ │ └── index.js │ ├── Eyebrow │ │ ├── index.stories.js │ │ └── index.js │ ├── Slider │ │ ├── DotsWithLabel.js │ │ ├── index.stories.js │ │ ├── index.js │ │ └── styles.js │ ├── index.js │ ├── TextBlock │ │ ├── index.js │ │ └── index.stories.js │ ├── Video │ │ ├── index.js │ │ └── index.stories.js │ ├── Button │ │ ├── index.stories.js │ │ └── index.js │ ├── GridLayout │ │ ├── index.js │ │ └── index.stories.js │ └── Icon │ │ ├── index.stories.js │ │ └── index.js ├── utils │ └── prop-types.js └── theme.js ├── .storybook ├── preview-head.html ├── main.js └── preview.js ├── .lintstagedrc ├── .prettierrc ├── README.md ├── sm.config.json ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── package.json └── sm.json /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | !.eslintrc.js 3 | *.test.js 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-staged 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | node_modules 5 | public 6 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "/" 3 | command = "yarn run build-storybook" 4 | publish = "storybook-static" 5 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { default as theme } from './theme' 2 | import * as Slices from './slices' 3 | export { Slices } 4 | -------------------------------------------------------------------------------- /src/slices/FaqSection/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/essential-slices/master/src/slices/FaqSection/preview.png -------------------------------------------------------------------------------- /src/slices/AlternateGrid/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/essential-slices/master/src/slices/AlternateGrid/preview.png -------------------------------------------------------------------------------- /src/slices/CallToAction/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/essential-slices/master/src/slices/CallToAction/preview.png -------------------------------------------------------------------------------- /src/slices/CardsCarousel/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/essential-slices/master/src/slices/CardsCarousel/preview.png -------------------------------------------------------------------------------- /src/slices/CustomerLogos/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/essential-slices/master/src/slices/CustomerLogos/preview.png -------------------------------------------------------------------------------- /src/slices/ImagesSlider/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/essential-slices/master/src/slices/ImagesSlider/preview.png -------------------------------------------------------------------------------- /src/slices/PricingTable/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/essential-slices/master/src/slices/PricingTable/preview.png -------------------------------------------------------------------------------- /src/slices/VideoHighlights/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/essential-slices/master/src/slices/VideoHighlights/preview.png -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/slices/TestimonialsSlider/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/essential-slices/master/src/slices/TestimonialsSlider/preview.png -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | '*.{js,jsx}': [ 3 | 'eslint . --fix' 4 | ], 5 | '**/*.{js, jsx, json,md}': [ 6 | 'prettier --write' 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /src/components/Tabs/index.js: -------------------------------------------------------------------------------- 1 | import Tabs from './Tabs' 2 | import TabsItem from './TabsItem' 3 | 4 | Tabs.Item = TabsItem 5 | 6 | export default Tabs 7 | -------------------------------------------------------------------------------- /src/components/Accordion/index.js: -------------------------------------------------------------------------------- 1 | import Accordion from './Accordion' 2 | import AccordionItem from './AccordionItem' 3 | 4 | Accordion.Item = AccordionItem 5 | 6 | export default Accordion 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "arrowParens": "always", 4 | "semi": false, 5 | "singleQuote": true, 6 | "tabWidth": 2, 7 | "trailingComma": "es5", 8 | "bracketSpacing": true 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | React essential slices 2 | 3 | Storybook automatically deployed to Netlify: 4 | https://react-essential-slices.netlify.app 5 | 6 | Run `yarn build` to bundle the slices library (using `microbundle`) and create 7 | the library manifest (`sm.json` file) 8 | -------------------------------------------------------------------------------- /sm.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "libraryName": "React essentials", 3 | "framework": "next", 4 | "gitUrl": "//github.com/prismicio/essential-slices", 5 | "pathToLibrary": "src", 6 | "dependencies": ["theme-ui"], 7 | "css": [], 8 | "devDependencies": [] 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/slices/ImagesSlider/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ImagesSlider from '.' 3 | import mock from './mock.json' 4 | 5 | export default { 6 | title: 'Slices/ImagesSlider', 7 | component: ImagesSlider, 8 | } 9 | export const Default = () => 10 | -------------------------------------------------------------------------------- /src/components/Card/index.js: -------------------------------------------------------------------------------- 1 | import Card from './Card' 2 | import CardContent from './CardContent' 3 | import CardFooter from './CardFooter' 4 | import CardImage from './CardImage' 5 | 6 | Card.Content = CardContent 7 | Card.Footer = CardFooter 8 | Card.Image = CardImage 9 | 10 | export default Card 11 | -------------------------------------------------------------------------------- /src/slices/CardsCarousel/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CardsCarousel from '.' 3 | import mock from './mock.json' 4 | 5 | export default { 6 | title: 'Slices/CardsCarousel', 7 | component: CardsCarousel, 8 | } 9 | export const Default = () => 10 | -------------------------------------------------------------------------------- /src/slices/PricingTable/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PricingTable from '.' 3 | import mock from './mock.json' 4 | 5 | export default { 6 | title: 'Slices/PricingTable', 7 | component: PricingTable, 8 | } 9 | 10 | export const Default = () => 11 | -------------------------------------------------------------------------------- /src/slices/CustomerLogos/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CustomerLogos from '.' 3 | import mock from './mock.json' 4 | 5 | export default { 6 | title: 'Slices/CustomerLogos', 7 | component: CustomerLogos, 8 | } 9 | 10 | export const Default = () => 11 | -------------------------------------------------------------------------------- /src/slices/TestimonialsSlider/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import TestimonialsSlider from '.' 3 | import mock from './mock.json' 4 | 5 | export default { 6 | title: 'Slices/TestimonialsSlider', 7 | component: TestimonialsSlider, 8 | } 9 | export const Default = () => 10 | -------------------------------------------------------------------------------- /src/slices/CardsCarousel/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Cards Carousel Section", 3 | "description": "A Carousel section by Octahedroid", 4 | "contributors": ["https://github.com/octahedroid/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Call to action"], 8 | "collection": "essentials ", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/slices/ImagesSlider/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Cards Carousel Section", 3 | "description": "A Carousel section by Octahedroid", 4 | "contributors": ["https://github.com/octahedroid/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Call to action"], 8 | "collection": "essentials ", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Head/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Head from '.' 3 | 4 | export default { 5 | title: 'Components/Head', 6 | component: Head, 7 | } 8 | 9 | export const Default = () => ( 10 | Content 11 | ) 12 | 13 | Default.story = { 14 | name: 'Default', 15 | } 16 | -------------------------------------------------------------------------------- /src/components/Wrap/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Wrap from '.' 3 | 4 | export default { 5 | title: 'Components/Wrap', 6 | component: Wrap, 7 | } 8 | 9 | export const Default = () => ( 10 | Content 11 | ) 12 | 13 | Default.story = { 14 | name: 'Default', 15 | } 16 | -------------------------------------------------------------------------------- /src/slices/CustomerLogos/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Customer Logos Section", 3 | "description": "A Customer Logos section by Octahedroid", 4 | "contributors": ["https://github.com/octahedroid/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Call to action"], 8 | "collection": "essentials ", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/slices/PricingTable/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Pricing Table Section", 3 | "description": "A Pricing Table section by Octahedroid", 4 | "contributors": ["https://github.com/octahedroid/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Call to action"], 8 | "collection": "essentials ", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Desc/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Desc from '.' 3 | 4 | export default { 5 | title: 'Components/Desc', 6 | component: Desc, 7 | } 8 | 9 | export const Default = () => ( 10 | Content 11 | ) 12 | 13 | Default.story = { 14 | name: 'Default', 15 | } 16 | -------------------------------------------------------------------------------- /src/components/Card/CardContent.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const CardContent = ({ children, ...props }) => { 6 | return {children} 7 | } 8 | 9 | CardContent.propTypes = { 10 | children: PropTypes.node.isRequired, 11 | } 12 | 13 | export default CardContent 14 | -------------------------------------------------------------------------------- /src/slices/TestimonialsSlider/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Testimonials Slider Section", 3 | "description": "A Call to action section by Octahedroid", 4 | "contributors": ["https://github.com/octahedroid/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Slider", "Testimonial"], 8 | "collection": "essentials ", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Video Highlights", 3 | "description": "A list of video elements", 4 | "imageUrl": "", 5 | "contributors": ["https://github.com/sarasoueidan/"], 6 | "sandboxUrl": "", 7 | "components": [], 8 | "tags": ["Essentials", "Videos", "Slider"], 9 | "collection": "essentials", 10 | "dependencies": [] 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Title/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Title from '.' 3 | 4 | export default { 5 | title: 'Components/Title', 6 | component: Title, 7 | } 8 | 9 | export const Default = () => ( 10 | 11 | <h1>Title text</h1> 12 | 13 | ) 14 | 15 | Default.story = { 16 | name: 'Default', 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Desc/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const Desc = ({ children, ...props }) => { 6 | return ( 7 | 8 | {children} 9 | 10 | ) 11 | } 12 | 13 | Desc.propTypes = { 14 | children: PropTypes.node.isRequired, 15 | } 16 | 17 | export default Desc 18 | -------------------------------------------------------------------------------- /src/slices/FaqSection/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "FAQ section", 3 | "description": "Display an accordion FAQ, with optional image", 4 | "contributors": [ 5 | "https://github.com/SaraSoueidan", 6 | "https://github.com/hypervillain/" 7 | ], 8 | "sandboxUrl": "", 9 | "components": ["ps-accordion"], 10 | "tags": ["Essentials", "Landing pages"], 11 | "collection": "prismic-essentials", 12 | "dependencies": [] 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Card/CardFooter.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const CardFooter = ({ children, ...props }) => { 6 | return ( 7 | 8 | {children} 9 | 10 | ) 11 | } 12 | 13 | CardFooter.propTypes = { 14 | children: PropTypes.node.isRequired, 15 | } 16 | 17 | export default CardFooter 18 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: [ 3 | '../src/slices/**/*.stories.js', 4 | '../src/components/**/*.stories.js', 5 | '../src/**/*.stories.mdx', 6 | ], 7 | addons: [ 8 | '@storybook/addon-docs', 9 | '@storybook/addon-viewport/register', 10 | '@storybook/addon-a11y/register', 11 | '@storybook/addon-actions', 12 | '@storybook/addon-links', 13 | 'storybook-addon-color-mode/register', 14 | ], 15 | } 16 | -------------------------------------------------------------------------------- /src/components/Slice/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Box } from 'theme-ui' 3 | import Slice from '.' 4 | 5 | export default { 6 | title: 'Components/Slice', 7 | component: Slice, 8 | } 9 | 10 | export const Default = () => ( 11 | 12 | Content 13 | 14 | ) 15 | 16 | Default.story = { 17 | name: 'Default', 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Tabs/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Tabs from '.' 3 | 4 | export default { 5 | title: 'Components/Tabs', 6 | component: Tabs, 7 | } 8 | 9 | export const Default = () => ( 10 | 11 | Content1 12 | Content2 13 | Content3 14 | 15 | ) 16 | 17 | Default.story = { 18 | name: 'Default', 19 | } 20 | -------------------------------------------------------------------------------- /src/components/Eyebrow/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Box } from 'theme-ui' 3 | import Eyebrow from '.' 4 | 5 | export default { 6 | title: 'Components/Eyebrow', 7 | component: Eyebrow, 8 | } 9 | 10 | export const Default = () => ( 11 | 19 | Title text 20 | 21 | ) 22 | -------------------------------------------------------------------------------- /src/slices/CallToAction/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CallToAction from '.' 3 | import mock from './mock.json' 4 | 5 | export default { 6 | title: 'Slices/CallToAction', 7 | component: CallToAction, 8 | } 9 | 10 | function linkResolver(doc) { 11 | return `/link/to/${doc.uid}` 12 | } 13 | 14 | export const Simple = () => ( 15 | 16 | ) 17 | 18 | Simple.story = { 19 | name: 'Simple Example', 20 | } 21 | -------------------------------------------------------------------------------- /src/slices/index.js: -------------------------------------------------------------------------------- 1 | export { default as AlternateGrid } from './AlternateGrid' 2 | export { default as CallToAction } from './CallToAction' 3 | export { default as CardsCarousel } from './CardsCarousel' 4 | export { default as CustomerLogos } from './CustomerLogos' 5 | export { default as FaqSection } from './FaqSection' 6 | export { default as ImagesSlider } from './ImagesSlider' 7 | export { default as PricingTable } from './PricingTable' 8 | export { default as VideoHighlights } from './VideoHighlights' 9 | -------------------------------------------------------------------------------- /src/components/Head/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const Head = ({ children, ...props }) => { 6 | return ( 7 | 14 | {children} 15 | 16 | ) 17 | } 18 | 19 | Head.propTypes = { 20 | children: PropTypes.node.isRequired, 21 | } 22 | 23 | export default Head 24 | -------------------------------------------------------------------------------- /src/components/Slider/DotsWithLabel.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Box } from 'theme-ui' 3 | import { dotStyles, dotLabelStyles } from './styles' 4 | 5 | const DotsWithLabel = (index, dotsLabel) => { 6 | return ( 7 | 13 | {`${dotsLabel} ${index + 1}`} 14 | 15 | ) 16 | } 17 | 18 | export default DotsWithLabel 19 | -------------------------------------------------------------------------------- /src/utils/prop-types.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | 3 | export const structuredTextPropTypes = PropTypes.arrayOf( 4 | PropTypes.shape({ 5 | type: PropTypes.string, 6 | text: PropTypes.string, 7 | spans: PropTypes.array, 8 | }) 9 | ) 10 | 11 | export const imagePropTypes = PropTypes.shape({ 12 | dimensions: PropTypes.shape({ 13 | width: PropTypes.number, 14 | height: PropTypes.number, 15 | }), 16 | alt: PropTypes.string, 17 | copyright: PropTypes.string, 18 | url: PropTypes.string, 19 | }) 20 | -------------------------------------------------------------------------------- /src/components/Wrap/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const Wrap = ({ children, ...props }) => { 6 | return ( 7 | 16 | {children} 17 | 18 | ) 19 | } 20 | 21 | Wrap.propTypes = { 22 | children: PropTypes.node.isRequired, 23 | } 24 | 25 | export default Wrap 26 | -------------------------------------------------------------------------------- /src/components/Title/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const Title = ({ children, ...props }) => { 6 | return ( 7 | 16 | {children} 17 | 18 | ) 19 | } 20 | 21 | Title.propTypes = { 22 | children: PropTypes.node.isRequired, 23 | } 24 | 25 | export default Title 26 | -------------------------------------------------------------------------------- /src/components/Card/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const Card = ({ children, ...props }) => { 6 | return ( 7 | 18 | {children} 19 | 20 | ) 21 | } 22 | 23 | Card.propTypes = { 24 | children: PropTypes.node.isRequired, 25 | } 26 | 27 | export default Card 28 | -------------------------------------------------------------------------------- /src/components/Card/CardImage.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Box } from 'theme-ui' 3 | 4 | import { imagePropTypes } from '../../utils/prop-types' 5 | 6 | const CardImage = ({ image, ...props }) => { 7 | const { url, alt, dimensions } = image 8 | return ( 9 | 17 | ) 18 | } 19 | 20 | CardImage.propTypes = { 21 | image: imagePropTypes.isRequired, 22 | } 23 | 24 | export default CardImage 25 | -------------------------------------------------------------------------------- /src/components/Accordion/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Accordion from '.' 3 | import mock from './mock.json' 4 | 5 | export default { 6 | title: 'components/Accordion', 7 | component: Accordion, 8 | } 9 | 10 | export const Default = () => { 11 | return ( 12 | 13 | {mock.items.map(({ text, title }) => { 14 | return ( 15 | 22 | ) 23 | })} 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /src/components/Eyebrow/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const Eyebrow = ({ children, ...props }) => { 6 | return ( 7 | 18 | {children} 19 | 20 | ) 21 | } 22 | 23 | Eyebrow.propTypes = { 24 | children: PropTypes.node.isRequired, 25 | } 26 | 27 | export default Eyebrow 28 | -------------------------------------------------------------------------------- /src/components/Slice/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const Slice = ({ children, ...props }) => { 6 | return ( 7 | 19 | {children} 20 | 21 | ) 22 | } 23 | 24 | Slice.propTypes = { 25 | children: PropTypes.node.isRequired, 26 | } 27 | 28 | export default Slice 29 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/styles.js: -------------------------------------------------------------------------------- 1 | import { Icon } from '../../components' 2 | 3 | const tabItem = { 4 | marginBottom: 0, 5 | px: 'small', 6 | py: 'xsmall', 7 | display: 'block', 8 | width: 'inherit', 9 | textAlign: 'left', 10 | textOverflow: 'ellipsis', 11 | whiteSpace: 'nowrap', 12 | overflow: 'hidden', 13 | backgroundSize: '1em 1em', 14 | backgroundRepeat: 'no-repeat', 15 | backgroundPosition: 'right center', 16 | backgroundImage: `url('${Icon.encode('play')}')`, 17 | ':hover': { 18 | textDecoration: 'underline', 19 | }, 20 | '&.active': { 21 | backgroundImage: `url('${Icon.encode('playBlack')}')`, 22 | fontWeight: 'bold', 23 | }, 24 | } 25 | 26 | export default tabItem 27 | -------------------------------------------------------------------------------- /src/components/Accordion/Accordion.js: -------------------------------------------------------------------------------- 1 | import React, { Children, cloneElement, useState } from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const Accordion = ({ children }) => { 6 | const [active, setActive] = useState() 7 | 8 | const items = Children.map(children, (item, index) => { 9 | if (!item) return undefined 10 | 11 | const isActive = index === active 12 | 13 | return cloneElement(item, { 14 | active: isActive, 15 | onClick: () => setActive(index === active ? null : index), 16 | }) 17 | }) 18 | return {items} 19 | } 20 | 21 | Accordion.propTypes = { 22 | children: PropTypes.node.isRequired, 23 | } 24 | 25 | export default Accordion 26 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as Button } from './Button' 2 | export { default as Card } from './Card' 3 | export { default as Desc } from './Desc' 4 | export { default as Eyebrow } from './Eyebrow' 5 | export { default as Grid } from './GridLayout' 6 | export { default as Head } from './Head' 7 | export { default as Slice } from './Slice' 8 | export { default as Slider } from './Slider' 9 | export { default as Title } from './Title' 10 | export { default as Wrap } from './Wrap' 11 | export { default as Icon } from './Icon' 12 | export { default as Accordion } from './Accordion' 13 | export { default as TextBlock } from './TextBlock' 14 | export { default as Video } from './Video' 15 | export { default as Tabs } from './Tabs' 16 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globals: { 3 | __PATH_PREFIX__: true, 4 | }, 5 | env: { 6 | browser: true, 7 | es6: true, 8 | node: true, 9 | }, 10 | settings: { 11 | react: { 12 | pragma: 'React', 13 | version: 'detect', 14 | }, 15 | }, 16 | extends: ['airbnb', 'plugin:prettier/recommended'], 17 | parserOptions: { 18 | ecmaVersion: 2018, 19 | sourceType: 'module', 20 | }, 21 | rules: { 22 | camelcase: [2, { properties: 'never' }], 23 | 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], 24 | 'import/no-cycle': 0, 25 | 'no-underscore-dangle': 0, 26 | 'jsx-a11y/anchor-is-valid': 0, 27 | 'react/jsx-props-no-spreading': 'off', 28 | }, 29 | } 30 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { ThemeProvider } from 'theme-ui' 3 | import theme from '../../theme' 4 | import VideoHighlights from '.' 5 | import mock from './mock.json' 6 | 7 | export default { 8 | title: 'Slices/VideoHighlights', 9 | component: VideoHighlights, 10 | } 11 | 12 | export const Default = () => 13 | 14 | export const WithCustomTheme = () => { 15 | const customTheme = { 16 | ...theme, 17 | container: { 18 | ...theme.container, 19 | slice: { 20 | color: '#FFF', 21 | background: 'rgb(112, 99, 255)', 22 | border: '8px solid pink', 23 | }, 24 | title: { 25 | textAlign: 'right', 26 | }, 27 | description: { 28 | mr: 0, 29 | textAlign: 'right', 30 | }, 31 | }, 32 | } 33 | return ( 34 | 35 | 36 | 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /src/components/Tabs/styles.js: -------------------------------------------------------------------------------- 1 | export const baseTabsStyles = {} 2 | 3 | // Tabs styles. 4 | export const getTabsHeaderStyles = (hideDivider) => { 5 | const dividerStyles = !hideDivider 6 | ? { borderBottom: '1px solid', borderColor: 'border' } 7 | : {} 8 | 9 | return { 10 | display: 'flex', 11 | mb: 'small', 12 | ...dividerStyles, 13 | } 14 | } 15 | 16 | // Tabs Item styles. 17 | export const getBaseTabsItemStyles = (disabled) => { 18 | const disabledStyles = disabled ? { opacity: 0.5, cursor: 'not-allowed' } : {} 19 | 20 | return { 21 | alignItems: 'center', 22 | display: 'flex', 23 | cursor: 'pointer', 24 | fontSize: 'small', 25 | mx: 'xsmall', 26 | position: 'relative', 27 | py: 'xsmall', 28 | outline: 'none', 29 | ...disabledStyles, 30 | '&:first-of-type': { 31 | ml: 0, 32 | }, 33 | '&.active': { 34 | fontWeight: 'bold', 35 | outline: '3px solid currentColor', 36 | outlineOffset: '5px', 37 | }, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/components/TextBlock/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { RichText } from 'prismic-reactjs' 4 | import { Box } from 'theme-ui' 5 | import { structuredTextPropTypes } from '../../utils/prop-types' 6 | 7 | const TextBlock = ({ title, description, icon, ...props }) => { 8 | return ( 9 | 15 | {icon && } 16 | 17 | 18 | 19 | ) 20 | } 21 | 22 | TextBlock.propTypes = { 23 | title: structuredTextPropTypes, 24 | description: structuredTextPropTypes, 25 | icon: PropTypes.shape({ 26 | url: PropTypes.string, 27 | }), 28 | } 29 | 30 | TextBlock.defaultProps = { 31 | title: '', 32 | description: '', 33 | icon: null, 34 | } 35 | 36 | export default TextBlock 37 | -------------------------------------------------------------------------------- /src/components/Video/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Box } from 'theme-ui' 4 | 5 | const Video = ({ source, ...props }) => { 6 | const { html } = source 7 | return ( 8 | 9 | 27 | 32 | 33 | 34 | ) 35 | } 36 | 37 | Video.propTypes = { 38 | source: PropTypes.shape({ 39 | html: PropTypes.string, 40 | }).isRequired, 41 | } 42 | 43 | export default Video 44 | -------------------------------------------------------------------------------- /src/components/Button/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Button from '.' 3 | 4 | export default { 5 | title: 'Components/Button', 6 | component: Button, 7 | } 8 | 9 | export const Default = () =>