mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-27 19:42:11 +10:00
Merge pull request #647 from sharetribe/search-link-section
Search links section
This commit is contained in:
commit
0004e9837d
5 changed files with 341 additions and 0 deletions
115
src/components/SectionSearchLinks/SectionSearchLinks.css
Normal file
115
src/components/SectionSearchLinks/SectionSearchLinks.css
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
@import '../../marketplace.css';
|
||||
|
||||
.root {
|
||||
}
|
||||
|
||||
.heading {
|
||||
@apply --marketplaceH1FontStyles;
|
||||
margin: 0 0 18px 0;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin: 0 0 23px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.subHeading {
|
||||
margin: 0 0 57px 0;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin: 0 0 57px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
width: 100%;
|
||||
margin-top: 25px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* First link should not have top margin */
|
||||
&:nth-of-type(1) {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.link2Columns {
|
||||
@media (--viewportMedium) {
|
||||
width: calc(50% - 20px);
|
||||
|
||||
/* First row should not have top margin */
|
||||
&:nth-of-type(1),
|
||||
&:nth-of-type(2) {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.link3Columns {
|
||||
@media (--viewportMedium) {
|
||||
width: calc(33.333% - 20px);
|
||||
|
||||
/* First row should not have top margin */
|
||||
&:nth-of-type(1),
|
||||
&:nth-of-type(2),
|
||||
&:nth-of-type(3) {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.imageWrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
transition: var(--transitionStyleButton);
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.02);
|
||||
box-shadow: var(--boxShadowSectionLocationHover);
|
||||
}
|
||||
}
|
||||
|
||||
.aspectWrapper {
|
||||
padding-bottom: calc(6 / 13 * 100%); /* 13:6 Aspect Ratio */
|
||||
|
||||
@media (--viewportMedium) {
|
||||
padding-bottom: calc(2 / 3 * 100%); /* 3:2 Aspect Ratio */
|
||||
}
|
||||
}
|
||||
|
||||
.image {
|
||||
/* Layout - image will take space defined by aspect ratio wrapper */
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.text {
|
||||
@apply --marketplaceH2FontStyles;
|
||||
color: var(--matterColor);
|
||||
margin-top: 15px;
|
||||
margin-bottom: 0;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin-top: 21px;
|
||||
}
|
||||
}
|
||||
137
src/components/SectionSearchLinks/SectionSearchLinks.example.js
Normal file
137
src/components/SectionSearchLinks/SectionSearchLinks.example.js
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
import SectionSearchLinks from './SectionSearchLinks';
|
||||
|
||||
const imageAltText = 'styleguide alt text';
|
||||
|
||||
export const TwoLinksWithHeadings = {
|
||||
component: SectionSearchLinks,
|
||||
props: {
|
||||
linksPerRow: 2,
|
||||
links: [
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?1',
|
||||
text: 'Link 1',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?2',
|
||||
text: 'Link 2',
|
||||
},
|
||||
],
|
||||
heading: 'Two links side by side',
|
||||
subHeading: 'One column in mobile, two columns in desktop.',
|
||||
},
|
||||
group: 'sections',
|
||||
};
|
||||
|
||||
export const ThreeLinksWithHeadings = {
|
||||
component: SectionSearchLinks,
|
||||
props: {
|
||||
linksPerRow: 3,
|
||||
links: [
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?1',
|
||||
text: 'Link 1',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?2',
|
||||
text: 'Link 2',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?3',
|
||||
text: 'Link 3',
|
||||
},
|
||||
],
|
||||
heading: 'Three links side by side',
|
||||
subHeading: 'One column in mobile, three columns in desktop.',
|
||||
},
|
||||
group: 'sections',
|
||||
};
|
||||
|
||||
export const FourLinks = {
|
||||
component: SectionSearchLinks,
|
||||
props: {
|
||||
linksPerRow: 2,
|
||||
links: [
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?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',
|
||||
text: 'Link 2',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?3',
|
||||
text: 'Link 3',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?4',
|
||||
text: 'Link 4',
|
||||
},
|
||||
],
|
||||
},
|
||||
group: 'sections',
|
||||
};
|
||||
|
||||
export const SixLinks = {
|
||||
component: SectionSearchLinks,
|
||||
props: {
|
||||
linksPerRow: 3,
|
||||
links: [
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?1',
|
||||
text: 'Link 1',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?2',
|
||||
text: 'Link 2',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?3',
|
||||
text: 'Link 3',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?4',
|
||||
text: 'Link 4',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?5',
|
||||
text: 'Link 5',
|
||||
},
|
||||
{
|
||||
imageUrl: 'http://lorempixel.com/648/448/',
|
||||
imageAltText,
|
||||
searchQuery: '?6',
|
||||
text: 'Link 6',
|
||||
},
|
||||
],
|
||||
},
|
||||
group: 'sections',
|
||||
};
|
||||
86
src/components/SectionSearchLinks/SectionSearchLinks.js
Normal file
86
src/components/SectionSearchLinks/SectionSearchLinks.js
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
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;
|
||||
|
|
@ -98,6 +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 SelectField } from './SelectField/SelectField';
|
||||
export { default as SelectSingleFilter } from './SelectSingleFilter/SelectSingleFilter';
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -40,6 +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 SelectField from './components/SelectField/SelectField.example';
|
||||
import * as StripeBankAccountTokenInputField from './components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.example';
|
||||
import * as TabNav from './components/TabNav/TabNav.example';
|
||||
|
|
@ -123,6 +124,7 @@ export {
|
|||
ReviewForm,
|
||||
ReviewRating,
|
||||
Reviews,
|
||||
SectionSearchLinks,
|
||||
SelectField,
|
||||
SendMessageForm,
|
||||
SignupForm,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue