Permalink
Browse files

New Feed component

  • Loading branch information...
lmorchard committed Oct 12, 2017
1 parent ae430c1 commit 59fad7db31f5b874c08c44310a772433444c0b67
View
@@ -17,7 +17,7 @@ old-school Web 2.0 mashup using my own personal data exhaust.
## TODO
- [ ] RSS / Atom component
- [ ] DRY out the SCSS in common between components
- [ ] Flickr photos component
@@ -14,7 +14,7 @@ export class ActivityPub extends React.Component {
return (
<Card {...this.props} className={classnames('activitypub', name)}>
<h3>
{name} (<a href={`${profileUrl}`} title={username}>@{username}</a>)
{name} (<a href={profileUrl} title={username}>@{username}</a>)
</h3>
<section>
<ul>
@@ -0,0 +1,28 @@
import fetch from 'node-fetch';
import FeedParser from 'feedparser';
export default async function fetchData(config, name) {
const { title, feedUrls } = config;
return Promise.all(
feedUrls.map(async feedUrl => {
const res = await fetch(feedUrl);
return new Promise((resolve, reject) => {
const feed = { name, title, meta: {}, items: [] };
res.body
.on('error', error => reject(error))
.pipe(new FeedParser())
.on('error', error => reject(error))
.on('meta', meta => (feed.meta = meta))
.on('readable', function() {
const stream = this;
let item;
while ((item = stream.read())) {
feed.items.push(item);
}
})
.on('end', () => resolve(feed));
});
})
).then(feeds => ({ name, title, feeds }));
}
@@ -0,0 +1,54 @@
import React from 'react';
import classnames from 'classnames';
import timeago from 'timeago.js';
import Card from '../Card';
import './index.scss';
export class Feed extends React.Component {
render() {
const { name, title, feeds } = this.props;
const maxItems = this.props.maxItems || 12;
const seenUrls = new Set();
// Merge, de-dupe, and sort items from all feeds.
const items = feeds
.reduce((acc, curr) => acc.concat(curr.items), [])
.filter(item => {
const { link } = item;
const seen = seenUrls.has(link);
seenUrls.add(link);
return !seen;
})
.sort((a, b) => b.date.localeCompare(a.date));
return (
<Card {...this.props} className={classnames('feed', name)}>
<h3>{title}</h3>
<section>
<ul>
{items
.slice(0, maxItems)
.map((item, idx) => this.renderItem(item, idx))}
</ul>
</section>
</Card>
);
}
renderItem(item, idx) {
const { title, summary, link, date } = item;
const createMarkup = () => ({ __html: summary });
return (
<li key={idx} className="item">
<a className="createdAt" href={link} title={date} dateTime={date}>
{timeago().format(date)}
</a>
<a className="link" href={link}><span className="title">{title}</span></a>
{summary && <div className="content" dangerouslySetInnerHTML={createMarkup()} />}
</li>
);
}
}
export default Feed;
@@ -0,0 +1,32 @@
.card.feed {
ul {
list-style: none;
margin: 0.5em 1em;
padding: 0;
li {
clear: both;
margin-bottom: 1.5em;
padding-left: 1.75em;
&::before {
float: left;
width: 1.75em;
margin-left: -1.75em;
font-style: normal;
font-weight: normal;
font-family: "fxemoji-symbols";
content: "\1F501";
}
a {
font-weight: bold;
}
.createdAt {
float: right;
font-weight: normal;
white-space: nowrap;
padding: 0 0 1em 1em;
font-size: 0.75em;
text-decoration: underline dotted;
}
}
}
}
View
@@ -16,6 +16,7 @@ import Goodreads from '../components/Goodreads';
import Pocket from '../components/Pocket';
import Project from '../components/Project';
import ActivityPub from '../components/ActivityPub';
import Feed from '../components/Feed';
const themes = [
'default',
@@ -80,6 +81,7 @@ export default class App extends Component {
/>
<Blog {...this.props.Blog} theme={theme()} />
<ActivityPub {...this.props.Toots} name="Toots" maxItems={7} theme={theme()} />
<Feed {...this.props.TTRSS} maxItems={12} theme={theme()} />
<Twitter {...this.props.Twitter} maxItems={7} theme={theme()} />
<Github {...this.props.Github} maxItems={7} theme={theme()} />
<Pocket {...this.props.Pocket} maxItems={7} theme={theme()} />

0 comments on commit 59fad7d

Please sign in to comment.