mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 20:53:24 +10:00
SectionThumbnailLinks
This commit is contained in:
parent
d62aa61fe0
commit
82c1330d13
6 changed files with 154 additions and 110 deletions
|
|
@ -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 (
|
||||
<NamedLink name="SearchPage" to={{ search: searchQuery }} className={classes}>
|
||||
<div className={css.imageWrapper}>
|
||||
<div className={css.aspectWrapper}>
|
||||
<img src={imageUrl} alt={imageAltText} className={css.image} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={css.text}>{text}</div>
|
||||
</NamedLink>
|
||||
);
|
||||
};
|
||||
|
||||
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 (
|
||||
<div className={classes}>
|
||||
{heading ? <h2 className={headingClasses}>{heading}</h2> : null}
|
||||
{subHeading ? <p className={subHeadingClasses}>{subHeading}</p> : null}
|
||||
<div className={css.links}>
|
||||
{links.map(link => (
|
||||
<SearchLink key={link.searchQuery} linksPerRow={linksPerRow} {...link} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
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;
|
||||
|
|
@ -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',
|
||||
},
|
||||
],
|
||||
129
src/components/SectionThumbnailLinks/SectionThumbnailLinks.js
Normal file
129
src/components/SectionThumbnailLinks/SectionThumbnailLinks.js
Normal file
|
|
@ -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 (
|
||||
<LinkComponent {...LinkComponentProps} className={classes}>
|
||||
<div className={imageWrapperClasses}>
|
||||
<div className={css.aspectWrapper}>
|
||||
<img src={imageUrl} alt={imageAltText} className={css.image} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={css.text}>{text}</div>
|
||||
</LinkComponent>
|
||||
);
|
||||
};
|
||||
|
||||
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 (
|
||||
<div className={classes}>
|
||||
{heading ? <h2 className={headingClasses}>{heading}</h2> : null}
|
||||
{subHeading ? <p className={subHeadingClasses}>{subHeading}</p> : null}
|
||||
<div className={css.links}>
|
||||
{links.map((link, i) => (
|
||||
<ThumbnailLink
|
||||
key={i}
|
||||
linksPerRow={linksPerRow}
|
||||
linkRootClassName={linkRootClassName}
|
||||
className={linkClassName}
|
||||
imageWrapperClassName={imageWrapperClassName}
|
||||
{...link}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
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;
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue