A Pen by Luca Fabbri on CodePen.
Created
October 22, 2017 22:03
-
-
Save keul/4e1632d056c2d4b1a056f6d15735db55 to your computer and use it in GitHub Desktop.
RLdXEE
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="main dark-bk"> | |
<div class="grid-container full-size light-bk fontf"> | |
<div class="grid-x margin-1 show-for-small-only"> | |
<div class="cell"> | |
<h1 class="main-title upper"> | |
Yoox<br> | |
Net-A-Porter<br> | |
Group | |
</h1> | |
</div> | |
</div> | |
<div class="grid-x"> | |
<div class="cell"> | |
<picture> | |
<source media="(min-width: 1024px)" srcset="https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-2048w.jpg"> | |
<source media="(min-width: 640px)" srcset="https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-1024w.jpg"> | |
<source media="(min-width: 320px)" srcset="https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-640w.jpg"> | |
<img src="https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-2048w.jpg" alt=""> | |
</picture> | |
</div> | |
</div> | |
<div class="grid-x margin-1"> | |
<div class="cell hide-for-small-only"> | |
<h1 class="main-title upper"> | |
Yoox<br> | |
Net-A-Porter<br> | |
Group | |
</h1> | |
</div> | |
<div class="cell intro"> | |
<p class="lead"> | |
YOOX NET-A-PORTER GROUP is the <strong>world’s leading online luxury fashion retailer</strong>. The Group is a Global company with Anglo-Italian roots, the result of a game-changing merger, which in October 2015 brought together YOOX GROUP and | |
THE NET-A-PORTER GROUP, two companies that <strong>have revolutionized the luxury fashion industry</strong> since their birth in 2000. | |
</p> | |
</div> | |
</div> | |
<div id="news" class="grid-x callout margin-1 plain-bk"> | |
<div class="cell text-center"> | |
<i class="fa fa-circle-o-notch fa-spin fa-4x fa-fw" aria-hidden="true"></i><br> | |
Loading news… | |
</div> | |
</div> | |
<div class="grid-x margin-1 align-middle"> | |
<div class="large-4 cell"> | |
<label class="nl-intro upper" for="newsletter">Newsletter</label> | |
</div> | |
<div class="large-8 cell" id="newsletter-section"> | |
<form class="newsletter" action=""> | |
<input type="email" id="newsletter" name="newsletter" placeholder="[email protected]" /> | |
<button class="button selectable-input">Subscribe</button> | |
</form> | |
</div> | |
</div> | |
<footer class="footer grid-x margin-0 align-middle"> | |
<div class="cell"> | |
<p class="copyright text-center upper"> | |
Copyright © 2000-2017 Yoox Net-A-Porter Group | |
</p> | |
</div> | |
</footer> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* News App | |
*/ | |
const preparePages = (current, total) => { | |
const pages = []; | |
for (let i = 0; i < total; i++) { | |
pages.push(i + 1); | |
} | |
let start = 0; | |
if (current >= 3) { | |
start = current + 2 >= total ? total - 5 : current - 3; | |
} | |
return pages.slice(start, start + 5); | |
}; | |
const NewsNavigation = props => { | |
const { current, total, loadNews } = props; | |
const pages = preparePages(current, total); | |
return ( | |
<ul className="pagination" role="navigation" aria-label="Pagination"> | |
{pages.map(item => ( | |
<li key={item} className={current === item ? "current" : ""}> | |
{current == item ? ( | |
item | |
) : ( | |
<a | |
onClick={ev => { | |
ev.preventDefault(); | |
loadNews(item); | |
}} | |
aria-label={item} | |
> | |
{item} | |
</a> | |
)} | |
</li> | |
))} | |
</ul> | |
); | |
}; | |
class NewsApp extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
newsItem: null, | |
currentIndex: 1, | |
total: 10, // BBB: API does not return number of items, let say we know we have only 10 news | |
loading: true | |
}; | |
this.loadNews = this.loadNews.bind(this); | |
this.fetchNews = this.fetchNews.bind(this); | |
} | |
componentDidMount() { | |
this.fetchNews(this.state.currentIndex); | |
} | |
fetchNews(id) { | |
this.setState({ loading: true }); | |
fetch(`https://jsonplaceholder.typicode.com/posts/${id}`) | |
.then(response => response.json()) | |
.then(json => { | |
this.setState({ newsItem: json, currentIndex: id, loading: false }); | |
}); | |
} | |
loadNews(index) { | |
this.setState({ currentIndex: index }, () => { | |
this.fetchNews(this.state.currentIndex); | |
}); | |
} | |
render() { | |
const { newsItem, total, currentIndex } = this.state; | |
return ( | |
<div className="grid-x plain-bk"> | |
<div className="small-12 cell"> | |
<NewsNavigation | |
total={total} | |
current={currentIndex} | |
loadNews={this.loadNews} | |
/> | |
</div> | |
<div className="large-4 cell"> | |
<h2 className="main-section-title upper"> | |
Lorem ipsum dolor sit amet, consectetur adipiscing elit | |
</h2> | |
</div> | |
<div className="large-8 cell"> | |
<div className="grid-x"> | |
<div | |
className={ | |
this.state.loading | |
? "cell page-content fetching" | |
: "cell page-content" | |
} | |
> | |
{newsItem | |
? new Array(5) | |
.fill(newsItem.body, 0, 5) | |
.map((text, index) => <p key={index}>{text}</p>) | |
: null} | |
</div> | |
</div> | |
</div> | |
</div> | |
); | |
} | |
} | |
ReactDOM.render(<NewsApp />, document.querySelector("#news")); | |
/** | |
* Newsletter App | |
*/ | |
const NewsletterConfirmed = props => { | |
const revealStyle = { | |
display: "block" | |
}; | |
return ( | |
<div className="reveal-overlay" style={{ display: "block" }}> | |
<div | |
className="reveal" | |
id="subscriptionMessage" | |
role="dialog" | |
aria-hidden="true" | |
tabIndex="-1" | |
style={revealStyle} | |
data-events="resize" | |
> | |
<h1>You have been subscribed</h1> | |
<p className="lead">Welcome to the Yoox Net-A-Porter Newsletter.</p> | |
<p> | |
You will receive an email to confirm your subscription and a link to | |
subscription options. | |
</p> | |
<button | |
className="close-button" | |
data-close="" | |
aria-label="Close" | |
type="button" | |
onClick={props.onClose} | |
> | |
<span aria-hidden="true">×</span> | |
</button> | |
</div> | |
</div> | |
); | |
}; | |
class NewsletterApp extends React.Component { | |
constructor(props) { | |
super(props); | |
this.email = null; | |
this.state = { | |
subscribed: false, | |
overlayOpened: false, | |
invalidEmail: false, | |
}; | |
this.handlerSubscription = this.handlerSubscription.bind(this); | |
this.checkValidity = this.checkValidity.bind(this); | |
} | |
handlerSubscription(ev) { | |
ev.preventDefault(); | |
this.setState({ subscribed: false, overlayOpened: true }); | |
} | |
checkValidity(ev) { | |
if (ev.target.value && !ev.target.checkValidity()) { | |
this.setState({ invalidEmail: true }) | |
} else { | |
this.setState({ invalidEmail: false }) | |
} | |
} | |
render() { | |
return this.state.subscribed ? ( | |
<div className="subscription-done"> | |
Well done! You already subscribed our newsletter! | |
</div> | |
) : ( | |
<form className="newsletter" action=""> | |
<input | |
type="email" | |
id="newsletter" | |
name="newsletter" | |
autocomplete="off" | |
placeholder="[email protected]" | |
ref={input => { | |
this.email = input; | |
}} | |
onChange={this.checkValidity} | |
className={this.state.invalidEmail ? 'error border-1' : 'border-1'} | |
/> | |
<button | |
className="button selectable-input border-1" | |
onClick={this.handlerSubscription} | |
disabled={!this.email || !this.email.value || this.state.invalidEmail ? true : false} | |
> | |
Subscribe | |
</button> | |
{this.state.overlayOpened ? ( | |
<NewsletterConfirmed | |
onClose={() => | |
this.setState({ overlayOpened: false, subscribed: true })} | |
/> | |
) : ( | |
"" | |
)} | |
</form> | |
); | |
} | |
} | |
ReactDOM.render( | |
<NewsletterApp />, | |
document.querySelector("#newsletter-section") | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.0.0/umd/react.development.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.0.0/umd/react-dom.development.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$color-darker: #333; | |
$color-dark: #666; | |
$color-lightest: #FFF; | |
$color-plain-bk: #F2F2F2; | |
$color-gradient-a: #CCC; | |
$color-gradient-b: #FFF; | |
$color-error: #E96565; | |
$color-fetching: #c0c0c0; | |
body, | |
h1, | |
h2, | |
h3, | |
h4, | |
h5, | |
h6 { | |
font-family: Open Sans; | |
margin-bottom: 1rem; | |
line-height: 1.1; | |
} | |
@media print, screen and (min-width: 40em) { | |
h2 { | |
font-size: 2.2rem; | |
} | |
} | |
.button[disabled]:hover { | |
color: black; | |
} | |
.dark-bk { | |
background-color: $color-dark; | |
} | |
.light-bk { | |
background-color: $color-lightest; | |
} | |
.plain-bk { | |
background-color: $color-plain-bk; | |
} | |
.fetching { | |
color: $color-fetching; | |
} | |
.full-size { | |
padding-left: 0; | |
padding-right: 0; | |
} | |
.padding-1 { | |
padding-left: 1em; | |
padding-right: 1em; | |
} | |
.margin-1 { | |
margin-left: 2em; | |
margin-right: 2em; | |
} | |
.margin-0 { | |
margin-left: 0; | |
margin-right: 0; | |
} | |
.main-title { | |
margin-top: 1.5rem; | |
margin-bottom: 1.5rem; | |
} | |
.intro { | |
padding-bottom: 1.5em; | |
} | |
.border-1, | |
.border-1:focus { | |
border: 1px solid $color-darker; | |
} | |
.upper { | |
text-transform: uppercase; | |
} | |
.lead { | |
font-size: 1.1rem; | |
} | |
.page-content { | |
@media (min-width: 640px) { | |
column-count: 2; | |
} | |
} | |
.main-section-title { | |
margin-right: 1rem; | |
} | |
.newsletter { | |
display: flex; | |
align-items: center; | |
.error { | |
background-color: $color-error; | |
} | |
input, | |
button { | |
margin-bottom: 0; | |
} | |
button { | |
border-left: 0; | |
padding-top: 0.8em; | |
padding-bottom: 0.8em; | |
} | |
} | |
.nl-intro { | |
font-size: 200%; | |
} | |
.main { | |
.pagination a, | |
.selectable-input { | |
background: $color-gradient-a; | |
background: linear-gradient($color-gradient-b, $color-gradient-a); | |
color: black; | |
&:hover, | |
&:selected, | |
&:focus { | |
background: linear-gradient($color-gradient-a, $color-gradient-b); | |
} | |
} | |
.pagination .current { | |
background: linear-gradient($color-gradient-a, $color-gradient-b); | |
color: black; | |
} | |
} | |
.pagination li { | |
display: inline-block; | |
margin-right: 0.7em; | |
border: 1px solid $color-darker; | |
} | |
.footer { | |
background-color: $color-darker; | |
color: white; | |
font-size: 80%; | |
font-weight: bold; | |
margin-top: 1em; | |
} | |
.copyright { | |
margin-top: 1rem; | |
margin-bottom: 1rem; | |
} | |
.loading { | |
text-align: center; | |
color: $color-darker; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" /> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/css/foundation.min.css" rel="stylesheet" /> | |
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment