diff --git a/src/components/SectionSearchLinks/SectionSearchLinks.js b/src/components/SectionSearchLinks/SectionSearchLinks.js deleted file mode 100644 index 538e11b1..00000000 --- a/src/components/SectionSearchLinks/SectionSearchLinks.js +++ /dev/null @@ -1,86 +0,0 @@ -import React from 'react'; -import { string, arrayOf, shape, node, oneOf } from 'prop-types'; -import classNames from 'classnames'; -import { NamedLink } from '../../components'; - -import css from './SectionSearchLinks.css'; - -const SearchLink = props => { - const { linksPerRow, imageUrl, imageAltText, searchQuery, text } = props; - const classes = classNames(css.link, { - [css.link2Columns]: linksPerRow === 2, - [css.link3Columns]: linksPerRow === 3, - }); - return ( - -
-
- {imageAltText} -
-
-
{text}
-
- ); -}; - -const SectionSearchLinks = props => { - const { - rootClassName, - className, - linksPerRow, - links, - heading, - subHeading, - headingRootClassName, - subHeadingRootClassName, - } = props; - const classes = classNames(rootClassName || css.root, className); - const headingClasses = headingRootClassName || css.heading; - const subHeadingClasses = subHeadingRootClassName || css.subHeading; - return ( -
- {heading ?

{heading}

: null} - {subHeading ?

{subHeading}

: null} -
- {links.map(link => ( - - ))} -
-
- ); -}; - -SectionSearchLinks.defaultProps = { - rootClassName: null, - className: null, - heading: null, - subHeading: null, - headingRootClassName: null, - subHeadingRootClassName: null, -}; - -SectionSearchLinks.propTypes = { - rootClassName: string, - className: string, - - linksPerRow: oneOf([2, 3]).isRequired, - links: arrayOf( - shape({ - imageUrl: string.isRequired, - imageAltText: string.isRequired, - searchQuery: string.isRequired, - text: node.isRequired, - }) - ).isRequired, - - // Styles are defined with the assumption that either both the - // heading and the subHeading are given, or neither of them are. If - // only one of them is given, the margins most likely won't make - // sense. - heading: node, - subHeading: node, - headingRootClassName: string, - subHeadingRootClassName: string, -}; - -export default SectionSearchLinks; diff --git a/src/components/SectionSearchLinks/SectionSearchLinks.css b/src/components/SectionThumbnailLinks/SectionThumbnailLinks.css similarity index 100% rename from src/components/SectionSearchLinks/SectionSearchLinks.css rename to src/components/SectionThumbnailLinks/SectionThumbnailLinks.css diff --git a/src/components/SectionSearchLinks/SectionSearchLinks.example.js b/src/components/SectionThumbnailLinks/SectionThumbnailLinks.example.js similarity index 61% rename from src/components/SectionSearchLinks/SectionSearchLinks.example.js rename to src/components/SectionThumbnailLinks/SectionThumbnailLinks.example.js index 85fc5a36..a3b93fb9 100644 --- a/src/components/SectionSearchLinks/SectionSearchLinks.example.js +++ b/src/components/SectionThumbnailLinks/SectionThumbnailLinks.example.js @@ -1,22 +1,22 @@ -import SectionSearchLinks from './SectionSearchLinks'; +import SectionThumbnailLinks from './SectionThumbnailLinks'; const imageAltText = 'styleguide alt text'; -export const TwoLinksWithHeadings = { - component: SectionSearchLinks, +export const TwoNamedLinksWithHeadings = { + component: SectionThumbnailLinks, props: { linksPerRow: 2, links: [ { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?1', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?1' } }, text: 'Link 1', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?2', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?2' } }, text: 'Link 2', }, ], @@ -26,27 +26,27 @@ export const TwoLinksWithHeadings = { group: 'sections', }; -export const ThreeLinksWithHeadings = { - component: SectionSearchLinks, +export const ThreeExternalLinksWithHeadings = { + component: SectionThumbnailLinks, props: { linksPerRow: 3, links: [ { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?1', + linkProps: { type: 'ExternalLink', href: 'http://example.com/1' }, text: 'Link 1', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?2', + linkProps: { type: 'ExternalLink', href: 'http://example.com/2' }, text: 'Link 2', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?3', + linkProps: { type: 'ExternalLink', href: 'http://example.com/3' }, text: 'Link 3', }, ], @@ -57,32 +57,32 @@ export const ThreeLinksWithHeadings = { }; export const FourLinks = { - component: SectionSearchLinks, + component: SectionThumbnailLinks, props: { linksPerRow: 2, links: [ { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?1', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?1' } }, text: 'Link 1 with quite a long text that tests how the items below align', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?2', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?2' } }, text: 'Link 2', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?3', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?3' } }, text: 'Link 3', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?4', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?4' } }, text: 'Link 4', }, ], @@ -91,44 +91,45 @@ export const FourLinks = { }; export const SixLinks = { - component: SectionSearchLinks, + component: SectionThumbnailLinks, props: { linksPerRow: 3, links: [ { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?1', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?1' } }, text: 'Link 1', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?2' } }, searchQuery: '?2', text: 'Link 2', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?3', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?3' } }, text: 'Link 3', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?4', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?4' } }, text: 'Link 4', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?5', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?5' } }, text: 'Link 5', }, { imageUrl: 'http://lorempixel.com/648/448/', imageAltText, - searchQuery: '?6', + linkProps: { type: 'NamedLink', name: 'SearchPage', to: { search: '?6' } }, text: 'Link 6', }, ], diff --git a/src/components/SectionThumbnailLinks/SectionThumbnailLinks.js b/src/components/SectionThumbnailLinks/SectionThumbnailLinks.js new file mode 100644 index 00000000..65a2bbb0 --- /dev/null +++ b/src/components/SectionThumbnailLinks/SectionThumbnailLinks.js @@ -0,0 +1,129 @@ +import React from 'react'; +import { string, arrayOf, shape, node, oneOf, oneOfType } from 'prop-types'; +import classNames from 'classnames'; +import { ExternalLink, NamedLink } from '../../components'; + +import css from './SectionThumbnailLinks.css'; + +const ThumbnailLink = props => { + const { + className, + rootClassName, + imageWrapperClassName, + linksPerRow, + imageUrl, + imageAltText, + linkProps, + text, + } = props; + const { type, name, to, href } = linkProps; + const classes = classNames(rootClassName || css.link, className, { + [css.link2Columns]: linksPerRow === 2, + [css.link3Columns]: linksPerRow === 3, + }); + const imageWrapperClasses = classNames(css.imageWrapper, imageWrapperClassName); + + const LinkComponentProps = type === 'NamedLink' ? { name, to } : { href }; + const LinkComponent = type === 'NamedLink' ? NamedLink : ExternalLink; + + return ( + +
+
+ {imageAltText} +
+
+
{text}
+
+ ); +}; + +const SectionThumbnailLinks = props => { + const { + rootClassName, + className, + linksPerRow, + links, + heading, + subHeading, + headingRootClassName, + subHeadingRootClassName, + linkClassName, + linkRootClassName, + imageWrapperClassName, + } = props; + const classes = classNames(rootClassName || css.root, className); + const headingClasses = headingRootClassName || css.heading; + const subHeadingClasses = subHeadingRootClassName || css.subHeading; + return ( +
+ {heading ?

{heading}

: null} + {subHeading ?

{subHeading}

: null} +
+ {links.map((link, i) => ( + + ))} +
+
+ ); +}; + +SectionThumbnailLinks.defaultProps = { + rootClassName: null, + className: null, + heading: null, + subHeading: null, + headingRootClassName: null, + subHeadingRootClassName: null, + imageWrapperClassName: null, +}; + +const namedLinkShape = shape({ + type: oneOf(['NamedLink']).isRequired, + name: string.isRequired, + to: shape({ + search: string, + hash: string, + }), +}); + +const externalLinkShape = shape({ + type: oneOf(['ExternalLink']).isRequired, + href: string.isRequired, +}); + +SectionThumbnailLinks.propTypes = { + rootClassName: string, + className: string, + + linksPerRow: oneOf([2, 3]).isRequired, + links: arrayOf( + shape({ + imageUrl: string.isRequired, + imageAltText: string.isRequired, + linkProps: oneOfType([namedLinkShape, externalLinkShape]).isRequired, + text: node.isRequired, + }) + ).isRequired, + + // Styles are defined with the assumption that either both the + // heading and the subHeading are given, or neither of them are. If + // only one of them is given, the margins most likely won't make + // sense. + heading: node, + subHeading: node, + headingRootClassName: string, + subHeadingRootClassName: string, + linkClassName: string, + linkRootClassName: string, + imageWrapperClassName: string, +}; + +export default SectionThumbnailLinks; diff --git a/src/components/index.js b/src/components/index.js index d0d271bc..98955b6a 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -98,7 +98,7 @@ export { default as SearchResultsPanel } from './SearchResultsPanel/SearchResult export { default as SectionHero } from './SectionHero/SectionHero'; export { default as SectionHowItWorks } from './SectionHowItWorks/SectionHowItWorks'; export { default as SectionLocations } from './SectionLocations/SectionLocations'; -export { default as SectionSearchLinks } from './SectionSearchLinks/SectionSearchLinks'; +export { default as SectionThumbnailLinks } from './SectionThumbnailLinks/SectionThumbnailLinks'; export { default as SelectField } from './SelectField/SelectField'; export { default as SelectSingleFilter } from './SelectSingleFilter/SelectSingleFilter'; export { diff --git a/src/examples.js b/src/examples.js index 9a35f297..5f705ca7 100644 --- a/src/examples.js +++ b/src/examples.js @@ -40,7 +40,7 @@ import * as PaginationLinks from './components/PaginationLinks/PaginationLinks.e import * as ResponsiveImage from './components/ResponsiveImage/ResponsiveImage.example'; import * as ReviewRating from './components/ReviewRating/ReviewRating.example'; import * as Reviews from './components/Reviews/Reviews.example'; -import * as SectionSearchLinks from './components/SectionSearchLinks/SectionSearchLinks.example'; +import * as SectionThumbnailLinks from './components/SectionThumbnailLinks/SectionThumbnailLinks.example'; import * as SelectField from './components/SelectField/SelectField.example'; import * as StripeBankAccountTokenInputField from './components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.example'; import * as TabNav from './components/TabNav/TabNav.example'; @@ -124,7 +124,7 @@ export { ReviewForm, ReviewRating, Reviews, - SectionSearchLinks, + SectionThumbnailLinks, SelectField, SendMessageForm, SignupForm,