diff --git a/examples/using-medium/.eslintrc b/examples/using-medium/.eslintrc new file mode 100644 index 0000000000000..d1e4cdd12970e --- /dev/null +++ b/examples/using-medium/.eslintrc @@ -0,0 +1,8 @@ +{ + "env": { + "browser": true + }, + "globals": { + "graphql": false + } +} diff --git a/examples/using-medium/README.md b/examples/using-medium/README.md new file mode 100644 index 0000000000000..b197f1131a2f7 --- /dev/null +++ b/examples/using-medium/README.md @@ -0,0 +1,5 @@ +# Using Medium + +https://using-medium.gatsbyjs.org + +Gatsby example site that shows how to use the gatsby-source-medium plugin. diff --git a/examples/using-medium/gatsby-config.js b/examples/using-medium/gatsby-config.js new file mode 100644 index 0000000000000..9eeeb13abc69c --- /dev/null +++ b/examples/using-medium/gatsby-config.js @@ -0,0 +1,13 @@ +module.exports = { + siteMetadata: { + title: `Using Medium`, + }, + plugins: [ + { + resolve: `gatsby-source-medium`, + options: { + username: `smartive`, + }, + }, + ], +} diff --git a/examples/using-medium/package.json b/examples/using-medium/package.json new file mode 100644 index 0000000000000..f08401e6d1d4d --- /dev/null +++ b/examples/using-medium/package.json @@ -0,0 +1,18 @@ +{ + "name": "gatsby-example-using-medmium", + "private": true, + "version": "1.0.0", + "description": "Gatsby example site that shows how to use the Medium source plugin", + "main": "index.js", + "author": "Robert Vogt ", + "license": "MIT", + "dependencies": { + "gatsby": "latest", + "gatsby-link": "latest" + }, + "keywords": ["gatsby"], + "scripts": { + "develop": "gatsby develop", + "build": "gatsby build" + } +} diff --git a/examples/using-medium/src/layouts/index.js b/examples/using-medium/src/layouts/index.js new file mode 100644 index 0000000000000..e38c6208493f0 --- /dev/null +++ b/examples/using-medium/src/layouts/index.js @@ -0,0 +1,13 @@ +import React from "react" + +export const DefaultLayout = props => ( +
+

Example showing Medium posts

+ +
+ {props.children()} +
+
+ ) + +export default DefaultLayout diff --git a/examples/using-medium/src/pages/index.js b/examples/using-medium/src/pages/index.js new file mode 100644 index 0000000000000..1bf585568f8ec --- /dev/null +++ b/examples/using-medium/src/pages/index.js @@ -0,0 +1,48 @@ +import React from "react" + +const mediumCDNUrl = `https://cdn-images-1.medium.com/max/150/` + +const IndexPage = ({ data }) => { + const posts = data.allMediumPost.edges + + return ( +
+ {posts.map(post => +
+

+ {post.node.title} +

+

+ by {post.node.author.name} +

+ {post.node.title} +
+ )} +
+ ) +} + +IndexPage.propTypes + +export default IndexPage + +export const pageQuery = graphql` + query IndexQuery { + allMediumPost(limit: 5, sort: { fields: [createdAt], order: DESC }) { + edges { + node { + id + title + author { + name + } + virtuals { + previewImage { + imageId + } + } + } + } + } + } +` diff --git a/packages/gatsby-source-medium/README.md b/packages/gatsby-source-medium/README.md new file mode 100644 index 0000000000000..4e1274900ec1b --- /dev/null +++ b/packages/gatsby-source-medium/README.md @@ -0,0 +1,59 @@ +# gatsby-source-medium + +Source plugin for pulling data into Gatsby from an unofficial Medium JSON +endpoint. Unfortunately the JSON endpoint does not provide the complete stories, +but only previews. If you need the complete stories, you might have a look at +something like [gatsby-source-rss](https://github.com/jondubin/gatsby-source-rss). + +## Install + +`npm install --save gatsby-source-medium` + +## How to use + +```javascript +// In your gatsby-config.js +plugins: [ + { + resolve: `gatsby-source-medium`, + options: { + username: `username/publication` + } + } +] +``` + +## How to query + +You can query nodes created from Medium like the following: + +```graphql + +query StoriesQuery { + allMediumPost(sort: { fields: [createdAt], order: DESC }) { + edges { + node { + id + title + creatorId + slug + uniqueSlug + virtuals { + subtitle + previewImage { + imageId + } + } + } + } + } + allMediumUser { + edges { + node { + id + name + } + } + } + } +``` diff --git a/packages/gatsby-source-medium/gatsby-node.js b/packages/gatsby-source-medium/gatsby-node.js new file mode 100644 index 0000000000000..e475da099bb49 --- /dev/null +++ b/packages/gatsby-source-medium/gatsby-node.js @@ -0,0 +1,65 @@ +const axios = require(`axios`) +const crypto = require(`crypto`) + +const fetch = username => { + const url = `https://medium.com/${username}/latest?format=json` + return axios.get(url) +} + +const prefix = `])}while(1);` + +const strip = payload => payload.replace(prefix, ``) + +exports.sourceNodes = async ({ boundActionCreators }, { username }) => { + const { createNode } = boundActionCreators + + try { + const result = await fetch(username) + const json = JSON.parse(strip(result.data)) + + const { posts } = json.payload + const collectionKeys = Object.keys(json.payload.references.Collection) + const userKeys = Object.keys(json.payload.references.User) + + const importableResources = [ + userKeys.map(key => json.payload.references.User[key]), + posts, + collectionKeys.map(key => json.payload.references.Collection[key]), + ] + + const resources = Array.prototype.concat(...importableResources) + resources.map(resource => { + const digest = crypto.createHash(`md5`).update(JSON.stringify(resource)).digest(`hex`) + + const links = + resource.type === `Post` + ? { + author___NODE: resource.creatorId, + } + : resource.type === `User` + ? { + posts___NODE: posts.filter(post => post.creatorId === resource.userId).map(post => post.id), + } + : {} + + const node = Object.assign( + resource, + { + id: resource.id ? resource.id : resource.userId, + parent: `__SOURCE__`, + children: [], + internal: { + type: `Medium${resource.type}`, + contentDigest: digest, + }, + }, + links + ) + + createNode(node) + }) + } catch (error) { + console.error(error) + process.exit(1) + } +} diff --git a/packages/gatsby-source-medium/package.json b/packages/gatsby-source-medium/package.json new file mode 100644 index 0000000000000..8173f8beddae3 --- /dev/null +++ b/packages/gatsby-source-medium/package.json @@ -0,0 +1,10 @@ +{ + "name": "gatsby-source-medium", + "version": "1.0.0", + "description": "Gatsby source plugin for building websites using Medium as a data source", + "author": "Robert Vogt ", + "license": "MIT", + "dependencies": { + "axios": "^0.16.2" + } +}