fix(layout): Adjust layout

This commit is contained in:
Stuart Taylor
2018-08-03 14:01:15 +01:00
committed by mrugesh mohapatra
parent 9cdb0ec7a2
commit fc19bf4fd3
4 changed files with 148 additions and 43 deletions

View File

@ -0,0 +1,80 @@
import React from 'react';
import PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import differenceInMinutes from 'date-fns/difference_in_minutes';
import differenceInHours from 'date-fns/difference_in_hours';
import differenceInDays from 'date-fns/difference_in_calendar_days';
import format from 'date-fns/format';
const propTypes = {
article: PropTypes.object
};
const styles = `
.meta-wrapper {
padding-top: 10px;
}
.meta-wrapper span,
.meta-wrapper a {
font-size: 16px;
}
.meta-item {
margin-right: 20px;
}
`;
function pluralise(singular, count) {
return `${singular}${count === 1 ? '' : 's'}`;
}
function getTimeString(pubDate) {
const now = new Date(Date.now());
const minuteDiff = differenceInMinutes(now, pubDate);
console.log(typeof minuteDiff);
if (minuteDiff < 60) {
return `${minuteDiff} ${pluralise('minute', minuteDiff)} ago`;
}
const hourDiff = differenceInHours(now, pubDate);
if (hourDiff < 24) {
return `${hourDiff} ${pluralise('hour', hourDiff)} ago`;
}
const dayDiff = differenceInDays(now, pubDate);
if (dayDiff < 8) {
return `${dayDiff} ${pluralise('day', dayDiff)} ago`;
}
if (dayDiff < 365) {
return format(pubDate, 'MMM D');
}
return format(pubDate, 'MMM D YYYY');
}
function ArticleMeta({
article: { viewCount, author, meta, firstPublishedDate }
}) {
return (
<div className='meta-wrapper'>
<Helmet>
<style>{styles}</style>
</Helmet>
<div className='meta-item-wrapper'>
<span className='meta-item'>By {author.name}</span>
<span className='meta-item'>{getTimeString(firstPublishedDate)}</span>
<span className='meta-item'>{`${meta.readTime} minute read`}</span>
{viewCount >= 100 ? (
<span className='meta-item'>{`${viewCount} views`}</span>
) : null}
</div>
</div>
);
}
ArticleMeta.displayName = 'ArticleMeta';
ArticleMeta.propTypes = propTypes;
export default ArticleMeta;

View File

@ -1,4 +1,5 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { Image } from 'react-bootstrap';
import Helmet from 'react-helmet';
@ -6,17 +7,36 @@ import Helmet from 'react-helmet';
import { getFeaturedList } from '../../utils/ajax';
import { Loader, Spacer } from '../../../common/app/helperComponents';
import BannerWide from '../../components/BannerWide';
import ArticleMeta from '../../components/ArticleMeta';
const propTypes = {};
const propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired
})
};
const styles = `
.featured-list {
list-style: none;
padding-left: 0;
margin-top: 40px;
}
.featured-list-item {
padding-bottom: 20px;
}
.featured-list-item .title {
color: #333;
padding-bottom: 20px;
}
.featured-list-item a {
padding-top: 5px;
}
.featured-list-image {
margin: 0 auto;
}
.featured-list-item a:hover,
@ -29,19 +49,6 @@ const styles = `
.featured-list-item a:focus > .meta-wrapper {
color: #006400;
}
.meta-wrapper {
display: flex;
justify-content: space-between;
}
.meta-wrapper span {
font-size: 14px;
}
.meta-stats {
text-align: end;
}
`;
class Featured extends Component {
@ -100,16 +107,24 @@ class Featured extends Component {
'--',
article.shortId
);
const { featureImage, shortId, author, title, meta } = article;
const { featureImage, shortId, title } = article;
return (
<li className='featured-list-item' key={shortId}>
{featureImage && featureImage.src ? (<Image responsive={true} src={featureImage.src} />) : (<BannerWide />)}
<a href={slug} onClick={this.createHandleArticleClick(slug, article)}>
<a
href={'/news' + slug}
onClick={this.createHandleArticleClick(slug, article)}
>
<h3 className='title'>{title}</h3>
<div className='meta-wrapper'>
<span>By {author.name}</span>
<span className='meta-stats'>{`${meta.readTime} minute read`}<br />{`${article.viewCount} views`}</span>
</div>
{featureImage && featureImage.src ? (
<Image
className='featured-list-image'
responsive={true}
src={featureImage.src}
/>
) : (
<BannerWide />
)}
<ArticleMeta article={article} />
</a>
<Spacer />
</li>
@ -134,12 +149,7 @@ class Featured extends Component {
<Helmet>
<style>{styles}</style>
</Helmet>
<h2>Welcome to freeCodeCamp News</h2>
<hr />
<h2>Featured Articles</h2>
<ul className='featured-list'>
{this.renderFeatured(featuredList)}
</ul>
<ul className='featured-list'>{this.renderFeatured(featuredList)}</ul>
</div>
);
}

View File

@ -14,7 +14,8 @@ const propTypes = {
push: PropTypes.func.isRequired
}),
location: PropTypes.shape({
state: PropTypes.object
state: PropTypes.object,
pathname: PropTypes.string
}),
match: PropTypes.shape({
params: PropTypes.shape({
@ -33,6 +34,20 @@ const youtubeOpts = {
const styles = `
.show-article figure {
display: flex;
flex-direction: column;
align-items: center;
}
.show-article figcaption > * {
font-size: 16px;
}
.show-article figcaption {
padding-top: 5px;
}
.feature-image-wrapper {
padding-top: 32px;
}
@ -70,6 +85,7 @@ class ShowArticle extends Component {
}
componentDidMount() {
window.scrollTo(0, 0);
const {
history,
match: {
@ -142,13 +158,8 @@ class ShowArticle extends Component {
render() {
const {
fetchState: { pending, complete, errored },
currentArticle: {
title,
renderableContent,
youtubeId,
featureImage,
author
}
currentArticle: { title, renderableContent, youtubeId, featureImage },
currentArticle
} = this.state;
if (pending || !complete) {
return <Loader />;
@ -159,11 +170,11 @@ class ShowArticle extends Component {
}
return (
<article>
<article className='show-article'>
<Helmet>
<style>{styles}</style>
</Helmet>
<Author author={author} />
<Author article={currentArticle} />
<h2>{title}</h2>
<div className='feature-image-wrapper'>
<figure>
@ -179,7 +190,6 @@ class ShowArticle extends Component {
) : null}
</figure>
</div>
<hr />
<div dangerouslySetInnerHTML={{ __html: renderableContent }} />
<div className='youtube-wrapper'>
{youtubeId ? (

View File

@ -2,8 +2,12 @@ import React from 'react';
import PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import ArticleMeta from '../../../components/ArticleMeta';
const propTypes = {
author: PropTypes.objectOf(PropTypes.string)
article: PropTypes.shape({
author: PropTypes.objectOf(PropTypes.string)
})
};
const styles = `
@ -33,7 +37,10 @@ const styles = `
}
`;
function Author({ author: { name, avatar, bio } }) {
function Author({ article }) {
const {
author: { avatar, bio }
} = article;
return (
<div className='author-block'>
<Helmet>
@ -41,9 +48,7 @@ function Author({ author: { name, avatar, bio } }) {
</Helmet>
<img height='50px' src={avatar} />
<div className='author-bio'>
<a href='https://www.freecodecamp.org/quincylarson'>
<span>By {name}</span>
</a>
<ArticleMeta article={article} />
<span>{bio.slice(0, 101)}</span>
</div>
</div>