UnkApp written in React and PostCSS (with Lost)
A Pen by Alessio Occhipinti on CodePen.
| <div id="app"> | |
| </div> |
| const API = { | |
| getNews(id) { | |
| return fetch(`https://jsonplaceholder.typicode.com/posts/${id}`) | |
| .then(res => res.json()) | |
| .catch(err => console.log(err)) | |
| } | |
| } | |
| const Logo = ({screenType}) => ( | |
| <div className={`HeaderLogo ${screenType}`}> | |
| <img src="http://www.ynap.com/wp-content/themes/yoox/img/logo-ynap.svg"></img> | |
| </div> | |
| ) | |
| const Header = () => { | |
| return ( | |
| <div className="HeaderWrapper"> | |
| <Logo screenType="ForSmallScreen" /> | |
| <div className="HeaderImage"></div> | |
| <Logo screenType="ForWideScreen" /> | |
| </div> | |
| ) | |
| } | |
| const Intro = () => { | |
| return ( | |
| <div className="MainBox"> | |
| <p>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 have <strong>revolutionized the luxury fashion industry</strong> since their birth in 2000. | |
| </p> | |
| </div> | |
| ) | |
| } | |
| const BadButtonsGroup = ({quantity, selected, handleChange}) => { | |
| const buttons = Array(quantity).fill().map((_, i) => { | |
| const actualIndex = i + 1; | |
| return ( | |
| <button | |
| className={actualIndex === selected ? 'ButtonSelected' : ''} | |
| onClick={handleChange} data-index={actualIndex}>{actualIndex}</button> | |
| ) | |
| }); | |
| return ( | |
| <div className="BadButtonsGroupWrapper"> | |
| {buttons} | |
| </div> | |
| ) | |
| } | |
| const NewsBody = ({post, quantity}) => { | |
| const postBody = post.body || ''; | |
| const capitalizeFirst = text => text.charAt(0).toUpperCase() + text.slice(1); | |
| const body = Array(quantity).fill().map((_, i) => <p>{capitalizeFirst(postBody)}</p>); | |
| return ( | |
| <div className="NewsContent"> | |
| <div className="NewsTitle"> | |
| <h1>{post.title}</h1> | |
| </div> | |
| <div className="NewsBody">{body}</div> | |
| </div> | |
| ) | |
| } | |
| const News = ({data, selected, handleChangeNews}) => { | |
| return ( | |
| <div className="NewsBox"> | |
| <BadButtonsGroup quantity={5} selected={selected} handleChange={handleChangeNews} /> | |
| <NewsBody post={data} quantity={5} /> | |
| </div> | |
| ) | |
| } | |
| const NewsletterForm = ({handleSubmit}) => { | |
| return ( | |
| <form className="NewsletterInputWrapper" onSubmit={handleSubmit}> | |
| <input name="email" placeholder="work@ynap.com" type="email" required/> | |
| <button type="submit">Subscribe</button> | |
| </form> | |
| ) | |
| } | |
| const NewsletterSubscribed = () => { | |
| return ( | |
| <span>You were successfully subscribed to our newsletter. Thank you!</span> | |
| ) | |
| } | |
| const Newsletter = ({subscribed, handleSubmit}) => { | |
| const body = subscribed ? | |
| <NewsletterSubscribed /> : | |
| <NewsletterForm handleSubmit={handleSubmit} />; | |
| return ( | |
| <div className="NewsletterBox"> | |
| <div><h1>Newsletter</h1></div> | |
| <div>{body}</div> | |
| </div> | |
| ) | |
| } | |
| const Footer = () => { | |
| return ( | |
| <footer> | |
| <p>COPYRIGHT © 2000-2017 YOOX NET-A-PORTER GROUP</p> | |
| </footer> | |
| ) | |
| } | |
| class YooxApp extends React.Component { | |
| constructor() { | |
| super() | |
| /* The state should be Redux... */ | |
| this.state = { | |
| currentPost: 1, | |
| post: {}, | |
| subscribed: false | |
| }; | |
| this.loadNews(this.state.currentPost); | |
| } | |
| loadNews(id) { | |
| API.getNews(id) | |
| .then(res => res && this.setState({post: Object.assign({}, res), currentPost: res.id})); | |
| } | |
| subscribeNewsletter(email) { | |
| this.setState({subscribed: true}); | |
| } | |
| handleChangeNews(e) { | |
| const id = e.target.dataset.index; | |
| this.loadNews(id); | |
| } | |
| handleSubmit(e) { | |
| e.preventDefault(); | |
| // Another check should be done here. | |
| const email = event.target.email.value; | |
| this.subscribeNewsletter(email); | |
| } | |
| render() { | |
| return ( | |
| <div className="MainWrapper"> | |
| <Header /> | |
| <Intro /> | |
| <News | |
| data={this.state.post} | |
| selected={this.state.currentPost} | |
| handleChangeNews={this.handleChangeNews.bind(this)} /> | |
| <Newsletter | |
| subscribed={this.state.subscribed} | |
| handleSubmit={this.handleSubmit.bind(this)} /> | |
| <Footer /> | |
| </div> | |
| ); | |
| } | |
| } | |
| ReactDOM.render(<YooxApp />, document.getElementById('app')); |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script> |
| @use postcss-nested; | |
| @use cssnext; | |
| @use lost; | |
| /* === Vars === */ | |
| :root { | |
| --fontFamilyBody : 'Open Sans', sans-serif; | |
| --margin: 20px; | |
| --padding: 20px; | |
| --lineHeight: 1.4rem; | |
| --lineHeightHeading: 1.8rem; | |
| /* Colors */ | |
| --fontColor: #333; | |
| --fontLightColor: #FFF; | |
| --bgColor: #666666; | |
| --plainBgColor: #F2F2F2; | |
| --contentBgColor: #FFF; | |
| --darkBgColor: #333; | |
| --borderColor: #ABABAB; | |
| --mainGradient: linear-gradient(to bottom right, #FFF 0%, #ccc 100%); | |
| --selectedGradient: linear-gradient(to bottom right, #ccc 0%, #FFF 100%); | |
| /* wrapper width */ | |
| --wrapperWidth: 64rem; | |
| /* Sizes */ | |
| --fontSizeSmall: 10px; | |
| --fontSize: 14px; | |
| --fontSizeH1: 24px; | |
| } | |
| /* === Mediaqueries === */ | |
| @custom-media --wide-screen320 (min-width: 20.0625rem); /* > 320px */ | |
| @custom-media --wide-screen412 (min-width: 25.75rem); /* > 412px */ | |
| @custom-media --wide-screen640 (min-width: 40rem); /* > 640px */ | |
| @custom-media --wide-screen750 (min-width: 46.875rem); /* > 750px */ | |
| @custom-media --wide-screen768 (min-width: 48rem); /* > 768px */ | |
| @custom-media --wide-screen824 (min-width: 51.5rem); /* > 824px */ | |
| @custom-media --wider-screen (min-width: 64rem); /* > 1024px */ | |
| @lost flexbox; | |
| /* === Reset == */ | |
| *, | |
| *:before, | |
| *:after { | |
| box-sizing: border-box; | |
| } | |
| html, | |
| body { | |
| height: 100%; | |
| margin: 0; | |
| background-color: var(--bgColor); | |
| } | |
| p { | |
| margin: 0; | |
| } | |
| img { | |
| max-width: 100%; | |
| } | |
| button:focus, | |
| input:focus { | |
| outline: none; | |
| } | |
| /* === Main styles == */ | |
| p { | |
| font-size: var(--fontSize); | |
| margin-bottom: var(--margin); | |
| } | |
| p:last-child { | |
| margin-bottom: 0; | |
| } | |
| span { | |
| font-size: var(--fontSize); | |
| } | |
| button { | |
| cursor: pointer; | |
| font-family: var(--fontFamilyBody); | |
| font-size: var(--fontSize); | |
| } | |
| input { | |
| border: 1px solid var(--borderColor); | |
| padding: 10px; | |
| } | |
| input::placeholder { | |
| padding-left: 0px; | |
| font-size: var(--fontSize); | |
| } | |
| /* Heading */ | |
| h1, | |
| h2, | |
| h3 { | |
| font-weight: 500; | |
| line-height: var(--lineHeightHeading); | |
| margin-top: 0; | |
| } | |
| h1 { | |
| font-size: var(--fontSizeH1); | |
| margin-bottom: var(--margin); | |
| } | |
| /* Transitions */ | |
| section, h1, li, img, div, p { | |
| transition: width 1s ease-in-out, left 1.5s ease-in-out; | |
| } | |
| div { | |
| transition: background-image 0.3s ease-in-out, left 0.3s ease-in-out; | |
| } | |
| /* Main */ | |
| .MainWrapper { | |
| lost-center: var(--wrapperWidth); | |
| lost-utility: clearfix; | |
| font-family: var(--fontFamilyBody); | |
| line-height: var(--lineHeight); | |
| color: var(--fontColor); | |
| background-color: var(--contentBgColor); | |
| } | |
| .HeaderWrapper { | |
| & { | |
| width: 100%; | |
| } | |
| & div { | |
| lost-column: 1; | |
| width: 100%; | |
| } | |
| & .HeaderLogo { | |
| padding: var(--padding); | |
| } | |
| & .HeaderLogo.ForSmallScreen { | |
| visibility: visible; | |
| display: block; | |
| } | |
| & .HeaderLogo.ForWideScreen { | |
| visibility: hidden; | |
| display: none; | |
| } | |
| & .HeaderImage { | |
| background-size: contain; | |
| background: url('https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-320w.jpg') no-repeat; | |
| height: 152px; | |
| } | |
| } | |
| .MainBox { | |
| padding-top: var(--padding); | |
| padding-left: var(--padding); | |
| padding-right: var(--padding); | |
| } | |
| .NewsBox { | |
| & { | |
| margin-top: var(--margin); | |
| padding: var(--padding); | |
| background-color: var(--plainBgColor); | |
| width: 100%; | |
| } | |
| & h1 { | |
| text-transform: uppercase; | |
| } | |
| & .NewsContent { | |
| padding-top: var(--padding); | |
| } | |
| & .NewsContent span { | |
| margin-bottom: var(--margin); | |
| } | |
| } | |
| .BadButtonsGroupWrapper { | |
| & button { | |
| border: 1px solid var(--borderColor); | |
| width: 27px; | |
| height: 27px; | |
| margin-right: 14px; | |
| background-image: var(--mainGradient); | |
| } | |
| & button:focus, | |
| & button.ButtonSelected { | |
| background-image: var(--selectedGradient); | |
| } | |
| } | |
| .NewsletterBox { | |
| & { | |
| padding: var(--padding); | |
| width: 100%; | |
| } | |
| & h1 { | |
| text-transform: uppercase; | |
| } | |
| & .NewsletterInputWrapper { | |
| display: flex; | |
| } | |
| & .NewsletterInputWrapper, | |
| & .NewsletterInputWrapper input { | |
| width: 100%; | |
| height: 30px; | |
| } | |
| & .NewsletterInputWrapper button { | |
| border: 1px solid var(--borderColor); | |
| width: 100px; | |
| background-image: var(--mainGradient); | |
| height: 30px; | |
| } | |
| & .NewsletterInputWrapper button:focus { | |
| background-image: var(--selectedGradient); | |
| } | |
| } | |
| footer { | |
| & { | |
| width: 100%; | |
| background-color: var(--darkBgColor); | |
| padding: var(--padding); | |
| text-align: center; | |
| } | |
| & p { | |
| font-size: var(--fontSizeSmall); | |
| color: var(--fontLightColor); | |
| } | |
| } | |
| @media (--wide-screen320) { | |
| .HeaderWrapper { | |
| & .HeaderImage { | |
| background: url('https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-412w.jpg') no-repeat; | |
| height: 195px; | |
| } | |
| } | |
| } | |
| @media (--wide-screen412) { | |
| .HeaderWrapper .HeaderImage { | |
| background: url('https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-640w.jpg') no-repeat; | |
| height: 303px; | |
| } | |
| } | |
| @media (--wide-screen640) { | |
| .HeaderWrapper .HeaderImage { | |
| background: url('https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-750w.jpg') no-repeat; | |
| height: 355px; | |
| } | |
| } | |
| @media (--wide-screen750) { | |
| .HeaderWrapper .HeaderImage { | |
| background: url('https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-768w.jpg') no-repeat; | |
| height: 364px; | |
| } | |
| } | |
| @media (--wide-screen768) { | |
| .HeaderWrapper .HeaderImage { | |
| background: url('https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-824w.jpg') no-repeat; | |
| height: 390px; | |
| } | |
| } | |
| @media (--wide-screen824) { | |
| .HeaderWrapper .HeaderImage { | |
| background: url('https://media.yoox.biz/ytos/resources/FEDTEST/images/man-yellow-jacket/man-yellow-jacket-1024w.jpg') no-repeat; | |
| height: 485px; | |
| } | |
| } | |
| @media (--wider-screen) { | |
| .HeaderWrapper { | |
| & .HeaderLogo.ForSmallScreen { | |
| visibility: hidden; | |
| display: none; | |
| } | |
| & .HeaderLogo.ForWideScreen { | |
| visibility: visible; | |
| display: block; | |
| } | |
| } | |
| .MainBox { | |
| padding: 0 var(--padding); | |
| } | |
| .NewsBox .NewsContent .NewsTitle, | |
| .NewsletterBox div:first-child { | |
| lost-column: 1/3; | |
| } | |
| .NewsletterBox div:last-child { | |
| lost-column: 2/3; | |
| } | |
| .NewsletterBox > * { | |
| lost-column: 1/2; | |
| } | |
| .NewsBox .NewsContent .NewsBody { | |
| columns: 2 10em; | |
| } | |
| .NewsletterBox h1 { | |
| margin-bottom: 0; | |
| } | |
| } |
UnkApp written in React and PostCSS (with Lost)
A Pen by Alessio Occhipinti on CodePen.