Re-jigger articles

There's now a base Article class, and then FullArticle and Articles
classes which are what react-router routes to
This commit is contained in:
Nick Pegg 2017-10-07 14:26:23 -07:00
parent 348703077b
commit 4d9923854d
2 changed files with 97 additions and 36 deletions

View file

@ -11,7 +11,7 @@ import 'highlight.js/styles/github-gist.css';
import { Container, Row, Column } from './skeleton'; import { Container, Row, Column } from './skeleton';
import { Articles, RoutedArticle } from './Article'; import { Articles, FullArticle } from './Article';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { Header } from './Header'; import { Header } from './Header';
import { NavList, TagNav, HistoryNav } from './Nav'; import { NavList, TagNav, HistoryNav } from './Nav';
@ -38,10 +38,10 @@ class App extends Component {
{ /* Article routes */ } { /* Article routes */ }
<Route path="/page/:page" component={Articles} /> <Route path="/page/:page" component={Articles} />
<Route path="/:year/:month/:title" component={RoutedArticle} /> <Route path="/:year/:month/:slug" component={FullArticle} />
{ /* 404 fallback */ } { /* 404 fallback */ }
<Route component={FourOhFour} /> <Route component={NotFound} />
</Switch> </Switch>
</Column> </Column>
</Row> </Row>
@ -82,7 +82,7 @@ class About extends Component {
} }
} }
class FourOhFour extends Component { class NotFound extends Component {
render () { render () {
return ( return (
<article> <article>

View file

@ -1,30 +1,52 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import Icon from 'react-fontawesome'; import Icon from 'react-fontawesome';
import Markdown from 'react-markdown'; import Markdown from 'react-markdown';
import { Link } from 'react-router-dom';
import slugify from 'slugify';
import { ListLink } from './Nav'; import { ListLink } from './Nav';
class Article extends Component { class Article extends Component {
render() { render() {
let postLink = ""; let body = "";
let readMore = "";
if (this.props.blurb) {
body = this.props.article.blurb;
readMore = (<Link to={ this.postLink() }>read more</Link>);
} else {
body = this.props.article.body;
}
return ( return (
<article> <article>
<header> <header>
<a className="post-title" href={ postLink }> <Link className="post-title" to={ this.postLink() }>
<h1>{ this.props.title }</h1> <h1>{ this.props.article.title }</h1>
</a> </Link>
{ this.meta() } { this.meta() }
</header> </header>
<section> <section>
<Markdown source={ this.content() } /> <Markdown source={ body } />
<a href={ postLink }>omg read more</a> { readMore }
</section> </section>
</article> </article>
); );
} }
postLink() {
let date = new Date(this.props.article.date);
let year = date.getUTCFullYear();
let month = date.getUTCMonth() + 1;
let slug = this.props.article.slug;
if (!slug) {
slug = slugify(this.props.article.title);
}
return `/${year}/${month}/${slug}`;
}
meta() { meta() {
// TODO: Fill this in with real metadata. // TODO: Fill this in with real metadata.
// Also should this be hidden for pages? That will require some CSS tweaks // Also should this be hidden for pages? That will require some CSS tweaks
@ -35,7 +57,7 @@ class Article extends Component {
return ( return (
<div className="post-meta"> <div className="post-meta">
<time>{ time_text } { this.props.date }</time> <time>{ time_text } { this.props.article.date }</time>
<div className="post-tags"> <Icon name="tags" /> <div className="post-tags"> <Icon name="tags" />
<ul> <ul>
<ListLink name="tag1" href="" /> <ListLink name="tag1" href="" />
@ -63,28 +85,66 @@ class Article extends Component {
} }
} }
// Goofball article for routing testing
class RoutedArticle extends Component { class FullArticle extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.props = props; this.props = props;
this.params = props.match.params; this.params = props.match.params;
this.state = { this.state = {
body: '', article: null
title: 'default title',
date: 'default date',
tags: [],
} }
} }
fetchArticle() {
fetch('/site.json')
.then((resp) => resp.json())
.then((blob) => {
let found = false;
for (let post of blob.posts) {
let slug = post.slug;
if (!slug) {
slug = slugify(post.title);
}
console.log('title compare:', slug, this.params.slug);
if (slug === this.params.slug) {
this.setState({article: post})
found = true;
}
}
if (!found) {
console.log('article not found');
/* TODO: return 404 */
}
});
}
componentDidMount() {
this.fetchArticle();
}
componentWillReceiveProps(props) {
this.params = props.match.params;
this.fetchArticle();
}
render() { render() {
if (this.state.article) {
return ( return (
<Article title={this.state.title} date={this.state.date} /> <Article
article={this.state.article}
/>
)
} else {
return (
<p>Loading...</p>
) )
} }
} }
}
class Articles extends Component { class Articles extends Component {
constructor(props) { constructor(props) {
@ -115,9 +175,6 @@ class Articles extends Component {
let posts = blob.posts.slice(offset, offset + this.per_page); let posts = blob.posts.slice(offset, offset + this.per_page);
this.setState({articles: posts}); this.setState({articles: posts});
})
.catch(function(error) {
console.log("Oh no! " + error);
}); });
} }
@ -131,18 +188,22 @@ class Articles extends Component {
} }
render() { render() {
if (this.state.articles.length > 0) {
return ( return (
<div> <div>
{this.state.articles.map(article => {this.state.articles.map(article =>
<Article <Article
key={article.title} key={article.title}
title={article.title} article={article}
date="1970-01-01" blurb
/> />
)} )}
</div> </div>
) )
} else {
return <p>Loading...</p>
}
} }
} }
export { Article, Articles, RoutedArticle }; export { Article, FullArticle, Articles };