Merge pull request #933 from sharetribe/landing-cta

Landing cta
This commit is contained in:
Janne Koivistoinen 2018-09-24 16:10:30 +03:00 committed by GitHub
commit d37c90fb1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 85 additions and 189 deletions

View file

@ -12,6 +12,14 @@ way to update this template, but currently, we follow a pattern:
---
## Upcoming version 2018-09-XX
* [add] New default design for the landing page's hero section. Now the CTA button's default
behavior is 'Browse'.
* marketplaceH1FontStyles: changed letter spacing to be more tight.
* SectionHero has now a search page link that should be customized to point to your marketplace
primary area [#933](https://github.com/sharetribe/flex-template-web/pull/933)
## v2.0.0 2018-09-19
* [add] New default map provider (Mapbox) and complete refactoring to all map and geocoding

View file

@ -47,14 +47,26 @@
height: 100%;
/* Text positioning is done with paddings */
padding: 0 24px 0 24px;
}
.heroContent {
margin: 0 24px 0 24px;
@media (--viewportMedium) {
padding: 0 0 0 7.5vw;
margin: 0 7.5vw 0 7.5vw;
}
@media (--viewportLarge) {
padding: 0 0 0 15vw;
/* Special viewport for adjusting the heroContent's placement */
@media only screen and (min-width: 1025px) and (max-width: 1366px) {
padding: 0 36px 0 36px;
}
@media only screen and (min-width: 1367px) {
margin: 0 auto;
max-width: calc(1052px + 36px + 36px);
width: 100%;
padding: 0 36px 0 36px;
}
}
@ -85,39 +97,14 @@
}
}
.mobileSearchButton {
border-radius: 4px;
flex-shrink: 0;
.heroButton {
@apply --marketplaceButtonStyles;
@apply --SectionHero_animation;
animation-delay: 0.8s;
@media (--viewportMedium) {
display: none;
}
}
.searchIcon {
vertical-align: top;
stroke: var(--matterColorLight);
width: 16px;
height: 16px;
margin-top: 5px;
margin-right: 10px;
}
.desktopSearchForm {
display: none;
background-color: var(--matterColorLight);
border-bottom: 4px solid var(--marketplaceColor);
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
@apply --SectionHero_animation;
animation-delay: 0.8s;
@media (--viewportMedium) {
display: block;
width: 400px;
width: 260px;
}
}

View file

@ -1,66 +1,45 @@
import React from 'react';
import PropTypes from 'prop-types';
import { string } from 'prop-types';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { stringify } from '../../util/urlHelpers';
import { createResourceLocatorString } from '../../util/routes';
import routeConfiguration from '../../routeConfiguration';
import { IconSearch, Button } from '../../components';
import { LocationSearchForm } from '../../forms';
import config from '../../config';
import { NamedLink } from '../../components';
import css from './SectionHero.css';
const SectionHero = props => {
const { rootClassName, className, history, location } = props;
const handleMobileSearchClick = () => {
const params = { mobilesearch: 'open' };
const path = `${location.pathname}?${stringify(params)}`;
history.push(path);
};
const handleSearchSubmit = values => {
const { search, selectedPlace } = values.location;
const { origin, bounds } = selectedPlace;
const originMaybe = config.sortSearchByDistance ? { origin } : {};
const searchParams = { ...originMaybe, address: search, bounds };
history.push(createResourceLocatorString('SearchPage', routeConfiguration(), {}, searchParams));
};
const { rootClassName, className } = props;
const classes = classNames(rootClassName || css.root, className);
return (
<div className={classes}>
<h1 className={css.heroMainTitle}>
<FormattedMessage id="SectionHero.title" />
</h1>
<h2 className={css.heroSubTitle}>
<FormattedMessage id="SectionHero.subTitle" />
</h2>
<Button className={css.mobileSearchButton} onClick={handleMobileSearchClick}>
<IconSearch rootClassName={css.searchIcon} />
<FormattedMessage id="SectionHero.mobileSearchButtonText" />
</Button>
<LocationSearchForm className={css.desktopSearchForm} onSubmit={handleSearchSubmit} />
<div className={css.heroContent}>
<h1 className={css.heroMainTitle}>
<FormattedMessage id="SectionHero.title" />
</h1>
<h2 className={css.heroSubTitle}>
<FormattedMessage id="SectionHero.subTitle" />
</h2>
<NamedLink
name="SearchPage"
to={{
search:
's?address=Finland&bounds=70.0922932%2C31.5870999%2C59.693623%2C20.456500199999937',
}}
className={css.heroButton}
>
<FormattedMessage id="SectionHero.browseButton" />
</NamedLink>
</div>
</div>
);
};
SectionHero.defaultProps = { rootClassName: null, className: null };
const { string, shape, func } = PropTypes;
SectionHero.propTypes = {
rootClassName: string,
className: string,
history: shape({
push: func.isRequired,
}).isRequired,
location: shape({
search: string.isRequired,
}).isRequired,
};
export default SectionHero;

View file

@ -4,102 +4,28 @@ exports[`SectionHero matches snapshot 1`] = `
<div
className=""
>
<h1>
<span>
SectionHero.title
</span>
</h1>
<h2>
<span>
SectionHero.subTitle
</span>
</h2>
<button
className=""
disabled={false}
onClick={[Function]}
>
<svg
<div>
<h1>
<span>
SectionHero.title
</span>
</h1>
<h2>
<span>
SectionHero.subTitle
</span>
</h2>
<a
className=""
height="22"
viewBox="0 0 21 22"
width="21"
xmlns="http://www.w3.org/2000/svg"
href="/s?s?address=Finland&bounds=70.0922932%2C31.5870999%2C59.693623%2C20.456500199999937"
onClick={[Function]}
style={Object {}}
title={null}
>
<g
fill="none"
fillRule="evenodd"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
transform="matrix(-1 0 0 1 20 1)"
>
<path
d="M13 14l5.241 5.241"
/>
<circle
cx="7.5"
cy="7.5"
r="7.5"
/>
</g>
</svg>
<span>
SectionHero.mobileSearchButtonText
</span>
</button>
<form
action="/"
className=""
method="post"
onSubmit={[Function]}
>
<div
className=""
>
<div
className=""
>
<svg
height="22"
viewBox="0 0 21 22"
width="21"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fillRule="evenodd"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
transform="matrix(-1 0 0 1 20 1)"
>
<path
d="M13 14l5.241 5.241"
/>
<circle
cx="7.5"
cy="7.5"
r="7.5"
/>
</g>
</svg>
</div>
<input
autoComplete="off"
autoFocus={false}
className=""
disabled={false}
name="location"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder="LocationSearchForm.placeholder"
type="search"
value=""
/>
</div>
</form>
<span>
SectionHero.browseButton
</span>
</a>
</div>
</div>
`;

View file

@ -11,10 +11,6 @@
}
}
.paragraph {
max-width: 672px;
}
.locations {
display: flex;
flex-direction: column;

View file

@ -40,11 +40,6 @@ const SectionLocations = props => {
<div className={css.title}>
<FormattedMessage id="SectionLocations.title" />
</div>
<div className={css.paragraph}>
<p>
<FormattedMessage id="SectionLocations.subtitle" />
</p>
</div>
<div className={css.locations}>
{locationLink(
'Helsinki',

View file

@ -31,13 +31,14 @@
@media (--viewportMedium) {
min-height: 500px;
height: 80vh;
height: 70vh;
max-height: none;
}
@media (--viewportLarge) {
max-height: 800px;
min-height: 600px;
height: calc(100vh - var(--topbarHeightDesktop));
height: calc(70vh - var(--topbarHeightDesktop));
}
}
@ -94,6 +95,11 @@
}
}
.sectionContentFirstChild {
composes: sectionContent;
margin-top: 3vh;
}
/* A bar on top of light sections */
.section:nth-of-type(2n) .sectionContent:before {
background: var(--marketplaceColor);

View file

@ -63,7 +63,7 @@ export const LandingPageComponent = props => {
</div>
<ul className={css.sections}>
<li className={css.section}>
<div className={css.sectionContent}>
<div className={css.sectionContentFirstChild}>
<SectionLocations />
</div>
</li>

View file

@ -177,7 +177,7 @@
margin: 0;
/* Padding is only for <a> elements where button styles are applied,
buttons elements should have zero padding */
buttons elements should have zero padding */
padding: 20px 0 0 0;
/* Borders */

View file

@ -73,7 +73,7 @@
margin-bottom: 31px;
}
@media (min-width: 1441px) {
@media (min-width: 1681px) {
font-size: 90px;
line-height: 96px;
letter-spacing: -2px;
@ -104,7 +104,7 @@
font-weight: var(--fontWeightBold);
font-size: 30px;
line-height: 36px;
letter-spacing: -0.5px;
letter-spacing: -1px;
/* margin-top + n * line-height + margin-bottom => x * 6px */
margin-top: 18px;
margin-bottom: 18px;
@ -113,7 +113,7 @@
font-size: 48px;
font-weight: var(--fontWeightSemiBold);
line-height: 56px;
letter-spacing: -1px;
letter-spacing: -2px;
/* margin-top + n * line-height + margin-bottom => x * 8px */
margin-top: 24px;
margin-bottom: 24px;

View file

@ -555,10 +555,10 @@
"SearchPage.searchError": "Search failed. Please try again.",
"SearchResultsPanel.nextPage": "Next page",
"SearchResultsPanel.previousPage": "Previous page",
"SectionHero.mobileSearchButtonText": "Search saunas",
"SectionHero.browseButton": "Browse saunas",
"SectionHero.subTitle": "The largest online community to rent saunas in Finland.",
"SectionHero.title": "Book saunas everywhere.",
"SectionHowItWorks.createListingLink": "PS. You can also become a Saunatime host in just a few clicks.",
"SectionHowItWorks.createListingLink": "PS. You can also become a Saunatime host in just a few clicks!",
"SectionHowItWorks.part1Text": "Start by searching for a location. Once you find a sauna you like, simply check the availability, book it, and make a secure payment right away.",
"SectionHowItWorks.part1Title": "1. Browse and book",
"SectionHowItWorks.part2Text": "Meet your host on the chosen date and enjoy a home sauna experience. We'll handle the payment to the host after your experience.",
@ -568,8 +568,7 @@
"SectionHowItWorks.titleLineOne": "The sauna ritual",
"SectionHowItWorks.titleLineTwo": "(or how Saunatime works).",
"SectionLocations.listingsInLocation": "Saunas in {location}",
"SectionLocations.subtitle": "We have more than 1000 saunas around Finland. Here are some of our most popular locations.",
"SectionLocations.title": "We have wooden saunas, electric saunas, and even tent saunas.",
"SectionLocations.title": "Explore exotic locations in Finland",
"SelectMultipleFilter.labelSelected": "{labelText} • {count}",
"SelectMultipleFilterForm.cancel": "Cancel",
"SelectMultipleFilterForm.clear": "Clear",