<|start_filename|>packages/gatsby-source-all-contributors/src/gatsby-node.js<|end_filename|>
/* eslint-disable no-param-reassign */
/* eslint-disable import/prefer-default-export */
import { createRemoteFileNode } from "gatsby-source-filesystem";
import fs from "fs-extra";
import path from "path";

export const sourceNodes = async (gatsby, pluginOptions = {}) => {
  const {
    actions,
    createNodeId,
    createContentDigest,
    store,
    cache,
    reporter
  } = gatsby;
  const { createNode } = actions;

  const { rcPath = "./.all-contributorsrc" } = pluginOptions;

  const contributorsRcPath = path.resolve(rcPath);

  const contributorsRcData = await fs.readFile(contributorsRcPath, "utf-8");

  const { contributors } = JSON.parse(contributorsRcData);

  await Promise.all(
    contributors.map(async contributor => {
      const id = createNodeId(`contributors__${contributor.login}`);
      let fileNode;
      try {
        fileNode = await createRemoteFileNode({
          url: contributor.avatar_url,
          parentNodeId: id,
          store,
          cache,
          ext: ".jpg",
          createNode,
          createNodeId,
          reporter
        });
      } catch (e) {
        reporter.panic(e);
      }

      if (fileNode) {
        contributor.avatar___NODE = fileNode.id;
      }

      const nodeContent = JSON.stringify(contributor);

      const nodeMeta = {
        id,
        internal: {
          type: `Contributor`,
          content: nodeContent,
          contentDigest: createContentDigest(contributor)
        }
      };

      const node = { ...contributor, ...nodeMeta };

      createNode(node);
    })
  );
};


<|start_filename|>examples/starter-blog/src/components/Footer.js<|end_filename|>
import React from "react"
import { Container } from "react-bootstrap"

const Footer = () => {
  return (
    <footer>
      <Container>
        &copy; {new Date().getFullYear()}{" "}
        <a href="https://northxsouth.co">
          North X South - Web Development Agency
        </a>{" "}
        &middot; Made with <a href="https://gatsbyjs.org">Gatsby</a>
      </Container>
    </footer>
  )
}

export default Footer


<|start_filename|>examples/starter-blog/package.json<|end_filename|>
{
  "name": "gatsby-starter-blog",
  "private": true,
  "description": "A starter blog demonstrating https://github.com/rmcfadzean/gatsby-pantry",
  "version": "0.1.0",
  "author": "<NAME> <<EMAIL>>",
  "bugs": {
    "url": "https://github.com/gatsbyjs/gatsby/issues"
  },
  "dependencies": {
    "bootstrap": "^4.3.1",
    "gatsby": "^2.14.1",
    "gatsby-image": "^2.2.14",
    "gatsby-plugin-categories": "^2.3.5",
    "gatsby-plugin-feed": "^2.3.9",
    "gatsby-plugin-react-helmet": "^3.1.5",
    "gatsby-plugin-sass": "^2.1.12",
    "gatsby-plugin-sharp": "^2.2.18",
    "gatsby-plugin-tags": "^2.3.5",
    "gatsby-remark-copy-linked-files": "^2.1.13",
    "gatsby-remark-images": "^3.1.19",
    "gatsby-remark-prismjs": "^3.3.9",
    "gatsby-source-filesystem": "^2.1.18",
    "gatsby-transformer-remark": "^2.6.19",
    "gatsby-transformer-sharp": "^2.2.12",
    "node-sass": "^4.12.0",
    "prismjs": "^1.17.1",
    "react": "^16.9.0",
    "react-bootstrap": "^1.0.0-beta.12",
    "react-dom": "^16.9.0",
    "react-helmet": "^5.2.1",
    "referrer-policy": "^1.2.0"
  },
  "devDependencies": {
    "prettier": "^1.18.2"
  },
  "homepage": "https://github.com/rmcfadzean/gatsby-pantry/tree/master/examples/starter-blog#readme",
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "main": "n/a",
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "format": "prettier --write src/**/*.{js,jsx}",
    "start": "yarn develop",
    "serve": "gatsby serve",
    "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\""
  }
}


<|start_filename|>packages/gatsby-source-all-contributors/package.json<|end_filename|>
{
  "name": "gatsby-source-all-contributors",
  "description": "Gatsby plugin - TODO",
  "version": "2.3.7",
  "author": "<NAME> <<EMAIL>>",
  "keywords": [
    "gatsby",
    "gatsby-plugin",
    "tags"
  ],
  "license": "MIT",
  "main": "index.js",
  "files": [
    "/*.js"
  ],
  "peerDependencies": {
    "gatsby": ">2.0.0"
  },
  "devDependencies": {
    "@babel/cli": "^7.0.0",
    "@babel/core": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "cross-env": "^6.0.3"
  },
  "scripts": {
    "build": "babel src --out-dir .",
    "watch": "babel -w src --out-dir .",
    "prepare": "cross-env NODE_ENV=production npm run build"
  },
  "bugs": {
    "url": "https://github.com/rmcfadzean/gatsby-pantry/issues"
  },
  "homepage": "https://github.com/rmcfadzean/gatsby-pantry/tree/master/packages/gatsby-source-all-contributors#readme",
  "repository": {
    "type": "git",
    "url": "https://github.com/rmcfadzean/gatsby-pantry/tree/master/packages/gatsby-source-all-contributors"
  },
  "dependencies": {
    "fs-extra": "^8.1.0",
    "gatsby-node-helpers": "^0.3.0",
    "gatsby-source-filesystem": "^2.1.33"
  }
}


<|start_filename|>packages/gatsby-plugin-tags/package.json<|end_filename|>
{
  "name": "gatsby-plugin-tags",
  "description": "Gatsby plugin to automatically create index pages for tagged content",
  "version": "2.3.7",
  "author": "<NAME> <<EMAIL>>",
  "keywords": [
    "gatsby",
    "gatsby-plugin",
    "tags"
  ],
  "license": "MIT",
  "main": "index.js",
  "files": [
    "/*.js"
  ],
  "peerDependencies": {
    "gatsby": ">2.0.0-beta"
  },
  "scripts": {
    "build": "babel src --out-dir . --ignore '*/**/__tests__/'",
    "watch": "babel -w src --out-dir . --ignore '*/**/__tests__/'",
    "prepare": "cross-env NODE_ENV=production npm run build"
  },
  "bugs": {
    "url": "https://github.com/rmcfadzean/gatsby-pantry/issues"
  },
  "homepage": "https://github.com/rmcfadzean/gatsby-pantry/tree/master/packages/gatsby-plugin-tags#readme",
  "repository": {
    "type": "git",
    "url": "https://github.com/rmcfadzean/gatsby-pantry/tree/master/packages/gatsby-plugin-tags"
  },
  "dependencies": {
    "lodash": "^4.17.15",
    "slug": "^1.1.0"
  }
}


<|start_filename|>examples/starter-blog/src/templates/blog-post.js<|end_filename|>
import React from "react"
import { Link, graphql } from "gatsby"
import { Container, Row, Col, Card } from "react-bootstrap"

import Layout from "../components/layout"
import SEO from "../components/seo"

const BlogPostTemplate = ({ location, data, pageContext }) => {
  const post = data.markdownRemark
  const siteTitle = data.site.siteMetadata.title
  const { previous, next } = pageContext

  return (
    <Layout location={location} title={siteTitle}>
      <SEO
        title={post.frontmatter.title}
        description={post.frontmatter.description || post.excerpt}
      />
      <Container>
        <Row>
          <Col md={8}>
            <article>
              <h1 className="mt-4">{post.frontmatter.title}</h1>

              <hr />
              <p>Posted on {post.frontmatter.date}</p>

              <hr />

              <img
                className="img-fluid rounded"
                src="https://placehold.it/900x300"
                alt=""
              />

              <hr />

              <div dangerouslySetInnerHTML={{ __html: post.html }} />
            </article>
          </Col>

          <Col md={4}>
            {post.fields.category && (
              <Card className="my-4">
                <Card.Header>Filed Under</Card.Header>
                <Card.Body>
                  <Link to={`/category/${post.fields.category}`}>
                    {post.fields.category}
                  </Link>
                </Card.Body>
              </Card>
            )}
            {post.fields.tags && (
              <Card className="my-4">
                <Card.Header>Tags</Card.Header>
                <Card.Body>
                  {post.fields.tags.map(tag => (
                    <Link
                      to={`/tags/${tag}`}
                      className="badge badge-primary p-2 m-1"
                    >
                      {tag}
                    </Link>
                  ))}
                </Card.Body>
              </Card>
            )}
            <Card>
              <Card.Header>See our other posts</Card.Header>
              <Card.Body>
                {previous && (
                  <Link
                    to={previous.fields.slug}
                    rel="prev"
                    className="btn btn-secondary"
                  >
                    ← {previous.frontmatter.title}
                  </Link>
                )}

                {next && (
                  <Link
                    to={next.fields.slug}
                    rel="next"
                    className="btn btn-secondary"
                  >
                    {next.frontmatter.title} →
                  </Link>
                )}
              </Card.Body>
            </Card>
          </Col>
        </Row>
      </Container>
    </Layout>
  )
}

export const pageQuery = graphql`
  query BlogPostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        author
      }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
      id
      excerpt(pruneLength: 160)
      html
      frontmatter {
        title
        date(formatString: "MMMM DD, YYYY")
        description
      }
      fields {
        category
        tags
      }
    }
  }
`

export default BlogPostTemplate


<|start_filename|>examples/starter-blog/src/components/layout.js<|end_filename|>
import React from "react"
import { Nav, Container } from "react-bootstrap"
import { Link } from "gatsby"
import Footer from "./Footer"
import "../assets/stylesheets/style.scss"

const Layout = ({ children }) => {
  return (
    <div>
      <header>
        <Container>
          <Nav>
            <Nav.Item>
              <Nav.Link to="/" as={Link}>
                Home
              </Nav.Link>
            </Nav.Item>
          </Nav>
        </Container>
      </header>
      <main>{children}</main>
      <Footer />
    </div>
  )
}

export default Layout


<|start_filename|>packages/gatsby-plugin-categories/src/gatsby-node.js<|end_filename|>
import fs from "fs";
import slugify from "slug";

import defaultOptions from "./defaults";
import { pathify } from "./internals";

export const onCreateNode = ({ node, actions }, pluginOptions) => {
  const { createNodeField } = actions;
  if (node.internal.type === `MarkdownRemark`) {
    const { slugOptions } = {
      ...defaultOptions,
      ...pluginOptions
    };
    const {
      frontmatter: { category }
    } = node;

    if (!category) return;

    createNodeField({
      node,
      name: "category",
      value: slugify(category, { ...slugOptions })
    });
  }
};

export const createPages = async (
  { graphql, actions, reporter },
  pluginOptions
) => {
  const { createPage } = actions;
  const { templatePath, prefix, query, transformer } = {
    ...defaultOptions,
    ...pluginOptions
  };

  const data = await graphql(query);
  const pages = transformer(data);

  if (!templatePath) {
    reporter.panic(`
      "templatePath" is a required option for gatsby-plugin-categories
    `);
  }

  if (!fs.existsSync(templatePath)) {
    reporter.panic(`
      The template path passed to gatsby-plugin-categories does not exist
      ${templatePath}
    `);
  }

  const categorySet = new Set();

  pages.forEach(({ fields }) => {
    if (fields && fields.category) {
      categorySet.add(fields.category);
    }
  });

  categorySet.forEach(category => {
    createPage({
      path: pathify(prefix, category),
      component: templatePath,
      context: {
        category
      }
    });
  });
};


<|start_filename|>examples/starter-blog/gatsby-config.js<|end_filename|>
module.exports = {
  siteMetadata: {
    title: `Gatsby Pantry Starter`,
    author: `<NAME>`,
    description: `A starter blog demonstrating https://github.com/rmcfadzean/gatsby-pantry`,
    siteUrl: `https://gatsby-pantry-starter-demo.netlify.com/`,
    social: {
      twitter: `rmcfadzean`,
    },
  },
  plugins: [
    {
      resolve: `gatsby-source-all-contributors`,
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/content/blog`,
        name: `blog`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/assets`,
        name: `assets`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: 590,
            },
          },
          `gatsby-remark-prismjs`,
          `gatsby-remark-copy-linked-files`,
        ],
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    `gatsby-plugin-feed`,
    `gatsby-plugin-react-helmet`,
    {
      resolve: `gatsby-plugin-sass`,
      options: {
        precision: 8,
      },
    },
    // {
    //   resolve: "gatsby-plugin-tags",
    //   options: {
    //     templatePath: path.join(__dirname, "/src/templates/tag.js"),
    //   },
    // },
    {
      resolve: "gatsby-plugin-categories",
      options: {
        templatePath: `${__dirname}/src/templates/category.js`,
      },
    },
    {
      resolve: "gatsby-plugin-tags",
      options: {
        templatePath: `${__dirname}/src/templates/tag.js`,
      },
    },
  ],
}
