fix: removed all guide bits from gatsby
This commit is contained in:
		
				
					committed by
					
						
						mrugesh
					
				
			
			
				
	
			
			
			
						parent
						
							7bc6367d68
						
					
				
				
					commit
					0124e7556d
				
			@@ -6,16 +6,8 @@ const {
 | 
				
			|||||||
  localeChallengesRootDir
 | 
					  localeChallengesRootDir
 | 
				
			||||||
} = require('./utils/buildChallenges');
 | 
					} = require('./utils/buildChallenges');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const {
 | 
					const { API_PROXY: proxyUrl = 'http://localhost:3000' } = process.env;
 | 
				
			||||||
  NODE_ENV: env,
 | 
					 | 
				
			||||||
  LOCALE: locale = 'english',
 | 
					 | 
				
			||||||
  API_PROXY: proxyUrl = 'http://localhost:3000'
 | 
					 | 
				
			||||||
} = process.env;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const selectedGuideDir = `../${
 | 
					 | 
				
			||||||
  env === 'production' ? 'guide' : 'mock-guide'
 | 
					 | 
				
			||||||
}/${locale}`;
 | 
					 | 
				
			||||||
const guideRoot = path.resolve(__dirname, selectedGuideDir);
 | 
					 | 
				
			||||||
const curriculumIntroRoot = path.resolve(__dirname, './src/pages');
 | 
					const curriculumIntroRoot = path.resolve(__dirname, './src/pages');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
@@ -50,13 +42,6 @@ module.exports = {
 | 
				
			|||||||
        curriculumPath: localeChallengesRootDir
 | 
					        curriculumPath: localeChallengesRootDir
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      resolve: 'gatsby-source-filesystem',
 | 
					 | 
				
			||||||
      options: {
 | 
					 | 
				
			||||||
        name: 'guides',
 | 
					 | 
				
			||||||
        path: guideRoot
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      resolve: 'gatsby-source-filesystem',
 | 
					      resolve: 'gatsby-source-filesystem',
 | 
				
			||||||
      options: {
 | 
					      options: {
 | 
				
			||||||
@@ -97,19 +82,6 @@ module.exports = {
 | 
				
			|||||||
        ]
 | 
					        ]
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      resolve: 'gatsby-remark-node-identity',
 | 
					 | 
				
			||||||
      options: {
 | 
					 | 
				
			||||||
        identity: 'guideMarkdown',
 | 
					 | 
				
			||||||
        predicate: ({ frontmatter }) => {
 | 
					 | 
				
			||||||
          if (!frontmatter) {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          const { title, block, superBlock } = frontmatter;
 | 
					 | 
				
			||||||
          return title && !block && !superBlock;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      resolve: 'gatsby-remark-node-identity',
 | 
					      resolve: 'gatsby-remark-node-identity',
 | 
				
			||||||
      options: {
 | 
					      options: {
 | 
				
			||||||
@@ -136,7 +108,6 @@ module.exports = {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    { resolve: 'fcc-create-nav-data' },
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      resolve: 'gatsby-plugin-manifest',
 | 
					      resolve: 'gatsby-plugin-manifest',
 | 
				
			||||||
      options: {
 | 
					      options: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,16 +4,13 @@ const { createFilePath } = require('gatsby-source-filesystem');
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const { dasherize } = require('./utils');
 | 
					const { dasherize } = require('./utils');
 | 
				
			||||||
const { blockNameify } = require('./utils/blockNameify');
 | 
					const { blockNameify } = require('./utils/blockNameify');
 | 
				
			||||||
const { getGithubPath } = require('./utils/getGithubPath');
 | 
					 | 
				
			||||||
const {
 | 
					const {
 | 
				
			||||||
  createChallengePages,
 | 
					  createChallengePages,
 | 
				
			||||||
  createBlockIntroPages,
 | 
					  createBlockIntroPages,
 | 
				
			||||||
  createSuperBlockIntroPages,
 | 
					  createSuperBlockIntroPages
 | 
				
			||||||
  createGuideArticlePages
 | 
					 | 
				
			||||||
} = require('./utils/gatsby');
 | 
					} = require('./utils/gatsby');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const createByIdentityMap = {
 | 
					const createByIdentityMap = {
 | 
				
			||||||
  guideMarkdown: createGuideArticlePages,
 | 
					 | 
				
			||||||
  blockIntroMarkdown: createBlockIntroPages,
 | 
					  blockIntroMarkdown: createBlockIntroPages,
 | 
				
			||||||
  superBlockIntroMarkdown: createSuperBlockIntroPages
 | 
					  superBlockIntroMarkdown: createSuperBlockIntroPages
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -34,16 +31,10 @@ exports.onCreateNode = function onCreateNode({ node, actions, getNode }) {
 | 
				
			|||||||
    const slug = createFilePath({ node, getNode });
 | 
					    const slug = createFilePath({ node, getNode });
 | 
				
			||||||
    if (!slug.includes('LICENSE')) {
 | 
					    if (!slug.includes('LICENSE')) {
 | 
				
			||||||
      const {
 | 
					      const {
 | 
				
			||||||
        fileAbsolutePath,
 | 
					 | 
				
			||||||
        frontmatter: { component = '' }
 | 
					        frontmatter: { component = '' }
 | 
				
			||||||
      } = node;
 | 
					      } = node;
 | 
				
			||||||
      createNodeField({ node, name: 'slug', value: slug });
 | 
					      createNodeField({ node, name: 'slug', value: slug });
 | 
				
			||||||
      createNodeField({ node, name: 'component', value: component });
 | 
					      createNodeField({ node, name: 'component', value: component });
 | 
				
			||||||
      createNodeField({
 | 
					 | 
				
			||||||
        node,
 | 
					 | 
				
			||||||
        name: 'githubPath',
 | 
					 | 
				
			||||||
        value: getGithubPath(fileAbsolutePath)
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -86,7 +77,6 @@ exports.createPages = function createPages({ graphql, actions }) {
 | 
				
			|||||||
                  slug
 | 
					                  slug
 | 
				
			||||||
                  nodeIdentity
 | 
					                  nodeIdentity
 | 
				
			||||||
                  component
 | 
					                  component
 | 
				
			||||||
                  githubPath
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                frontmatter {
 | 
					                frontmatter {
 | 
				
			||||||
                  block
 | 
					                  block
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,66 +0,0 @@
 | 
				
			|||||||
const crypto = require('crypto');
 | 
					 | 
				
			||||||
const path = require('path');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const commonREs = require('../../utils/regEx');
 | 
					 | 
				
			||||||
const readDir = require('../../utils/readDir');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { isAStubRE } = commonREs;
 | 
					 | 
				
			||||||
// default locale to english for testing
 | 
					 | 
				
			||||||
const { NODE_ENV: env, LOCALE: locale = 'english' } = process.env;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const guideDir = `../../../${
 | 
					 | 
				
			||||||
  env === 'production' ? 'guide' : 'mock-guide'
 | 
					 | 
				
			||||||
}/${locale}`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const pagesDir = path.resolve(__dirname, guideDir);
 | 
					 | 
				
			||||||
const indexMdRe = new RegExp(`\\${path.sep}index.md$`);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function withGuidePrefix(str) {
 | 
					 | 
				
			||||||
  return `/guide${str}`;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
exports.createNavigationNode = function createNavigationNode(node) {
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    fileAbsolutePath,
 | 
					 | 
				
			||||||
    frontmatter: { title },
 | 
					 | 
				
			||||||
    internal: { content },
 | 
					 | 
				
			||||||
    parent
 | 
					 | 
				
			||||||
  } = node;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const nodeDir = path.resolve(fileAbsolutePath).replace(indexMdRe, '');
 | 
					 | 
				
			||||||
  const dashedName = nodeDir.split(path.sep).slice(-1)[0];
 | 
					 | 
				
			||||||
  const nodePath = nodeDir
 | 
					 | 
				
			||||||
    .split(pagesDir)[1]
 | 
					 | 
				
			||||||
    .split(path.sep)
 | 
					 | 
				
			||||||
    .join('/');
 | 
					 | 
				
			||||||
  const parentPath = nodePath
 | 
					 | 
				
			||||||
    .split('/')
 | 
					 | 
				
			||||||
    .slice(0, -1)
 | 
					 | 
				
			||||||
    .join('/');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const categoryChildren = readDir(nodeDir);
 | 
					 | 
				
			||||||
  const navNode = {
 | 
					 | 
				
			||||||
    categoryChildren,
 | 
					 | 
				
			||||||
    hasChildren: !!categoryChildren.length,
 | 
					 | 
				
			||||||
    dashedName,
 | 
					 | 
				
			||||||
    isStubbed: isAStubRE.test(content),
 | 
					 | 
				
			||||||
    path: withGuidePrefix(nodePath),
 | 
					 | 
				
			||||||
    parentPath: withGuidePrefix(parentPath),
 | 
					 | 
				
			||||||
    title
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const gatsbyRequired = {
 | 
					 | 
				
			||||||
    id: fileAbsolutePath + ' >>> NavigationNode',
 | 
					 | 
				
			||||||
    parent,
 | 
					 | 
				
			||||||
    children: [],
 | 
					 | 
				
			||||||
    internal: {
 | 
					 | 
				
			||||||
      type: 'NavigationNode',
 | 
					 | 
				
			||||||
      contentDigest: crypto
 | 
					 | 
				
			||||||
        .createHash('md5')
 | 
					 | 
				
			||||||
        .update(JSON.stringify(navNode))
 | 
					 | 
				
			||||||
        .digest('hex')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return { ...navNode, ...gatsbyRequired };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -1,85 +0,0 @@
 | 
				
			|||||||
const path = require('path');
 | 
					 | 
				
			||||||
const { expect } = require('chai');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { createNavigationNode } = require('./create-navigation-node');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe('fcc-create-nav-data', () => {
 | 
					 | 
				
			||||||
  describe('create-vanigation-node', () => {
 | 
					 | 
				
			||||||
    const mockNode = {
 | 
					 | 
				
			||||||
      internal: {
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          '---\ntitle: File Writing\n---\n## File Writing\n\nThis is a stub.' +
 | 
					 | 
				
			||||||
          " <a href='https://github.com/freeCodeCamp/guides/tree/master/src/" +
 | 
					 | 
				
			||||||
          "pages/php/functions/files/writing/index.md' target='_blank' " +
 | 
					 | 
				
			||||||
          "rel='nofollow'>Help our community expand it</a>.\n\n<a href=" +
 | 
					 | 
				
			||||||
          "'https://github.com/freeCodeCamp/freeCodeCamp/blob/master/docs/style-guide-for-guide-articles.md' " +
 | 
					 | 
				
			||||||
          "target='_blank' rel='nofollow'>This quick style guide will help " +
 | 
					 | 
				
			||||||
          'ensure your pull request gets accepted</a>.\n\n<!-- The article ' +
 | 
					 | 
				
			||||||
          'goes here, in GitHub-flavored Markdown. Feel free to add YouTube ' +
 | 
					 | 
				
			||||||
          'videos, images, and CodePen/JSBin embeds  -->\n\n#### More ' +
 | 
					 | 
				
			||||||
          'Information:\n<!-- Please add any articles you think might be ' +
 | 
					 | 
				
			||||||
          'helpful to read before writing the article -->\n'
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      frontmatter: {
 | 
					 | 
				
			||||||
        title: 'File Writing'
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      fileAbsolutePath: path.resolve(
 | 
					 | 
				
			||||||
        __dirname,
 | 
					 | 
				
			||||||
        '../../../mock-guide/english/php/functions/files/file-writing/index.md'
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const result = createNavigationNode(mockNode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it('should return an object', () => {
 | 
					 | 
				
			||||||
      expect(result).to.be.an('object');
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it('node.children should be an array', () => {
 | 
					 | 
				
			||||||
      expect(result.categoryChildren).to.be.an('array');
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it('node.dashedName should equal the containing folder name', () => {
 | 
					 | 
				
			||||||
      expect(result.dashedName).equal('file-writing');
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it(
 | 
					 | 
				
			||||||
      'node.path should equal the file path from pagesDir, ' +
 | 
					 | 
				
			||||||
        'prefixed with `/guide`',
 | 
					 | 
				
			||||||
      () => {
 | 
					 | 
				
			||||||
        expect(result.path).to.equal('/guide/php/functions/files/file-writing');
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it(
 | 
					 | 
				
			||||||
      'node.parentPath should equal the path of the parent page, ' +
 | 
					 | 
				
			||||||
        'prefixed with `/guide`',
 | 
					 | 
				
			||||||
      () => {
 | 
					 | 
				
			||||||
        expect(result.parentPath).to.equal('/guide/php/functions/files');
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it('node.title should equal srcNode.frontmatter.title', () => {
 | 
					 | 
				
			||||||
      expect(result.title).to.equal(mockNode.frontmatter.title);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it('node.isStubbed should be a boolean', () => {
 | 
					 | 
				
			||||||
      expect(result.isStubbed).to.be.a('boolean');
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it('node.isStubbed should be true for a stubbed article', () => {
 | 
					 | 
				
			||||||
      expect(result.isStubbed).to.equal(true);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it('node.isStubbed should be false for a non-stubbed article', () => {
 | 
					 | 
				
			||||||
      const notAStub = {
 | 
					 | 
				
			||||||
        ...mockNode,
 | 
					 | 
				
			||||||
        internal: {
 | 
					 | 
				
			||||||
          content: 'this is not a stub article. Infact, it is very informative'
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
      const result = createNavigationNode(notAStub);
 | 
					 | 
				
			||||||
      expect(result.isStubbed).to.equal(false);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@@ -1,21 +0,0 @@
 | 
				
			|||||||
const { createNavigationNode } = require('./create-navigation-node');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
exports.onCreateNode = function createNavDataOnCreateNode({ actions, node }) {
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    internal: { type },
 | 
					 | 
				
			||||||
    fields
 | 
					 | 
				
			||||||
  } = node;
 | 
					 | 
				
			||||||
  if (
 | 
					 | 
				
			||||||
    type === 'MarkdownRemark' &&
 | 
					 | 
				
			||||||
    fields &&
 | 
					 | 
				
			||||||
    fields.nodeIdentity === 'guideMarkdown'
 | 
					 | 
				
			||||||
  ) {
 | 
					 | 
				
			||||||
    if (node.fileAbsolutePath.includes('LICENSE.md')) {
 | 
					 | 
				
			||||||
      return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    const { createNode } = actions;
 | 
					 | 
				
			||||||
    const navNode = createNavigationNode(node);
 | 
					 | 
				
			||||||
    return createNode(navNode);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return null;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										218
									
								
								client/plugins/fcc-create-nav-data/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										218
									
								
								client/plugins/fcc-create-nav-data/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,218 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "name": "fcc-create-nav-data",
 | 
					 | 
				
			||||||
  "version": "0.0.1",
 | 
					 | 
				
			||||||
  "lockfileVersion": 1,
 | 
					 | 
				
			||||||
  "requires": true,
 | 
					 | 
				
			||||||
  "dependencies": {
 | 
					 | 
				
			||||||
    "assertion-error": {
 | 
					 | 
				
			||||||
      "version": "1.1.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "balanced-match": {
 | 
					 | 
				
			||||||
      "version": "1.0.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "brace-expansion": {
 | 
					 | 
				
			||||||
      "version": "1.1.11",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "balanced-match": "^1.0.0",
 | 
					 | 
				
			||||||
        "concat-map": "0.0.1"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "browser-stdout": {
 | 
					 | 
				
			||||||
      "version": "1.3.1",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "chai": {
 | 
					 | 
				
			||||||
      "version": "4.2.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "assertion-error": "^1.1.0",
 | 
					 | 
				
			||||||
        "check-error": "^1.0.2",
 | 
					 | 
				
			||||||
        "deep-eql": "^3.0.1",
 | 
					 | 
				
			||||||
        "get-func-name": "^2.0.0",
 | 
					 | 
				
			||||||
        "pathval": "^1.1.0",
 | 
					 | 
				
			||||||
        "type-detect": "^4.0.5"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "check-error": {
 | 
					 | 
				
			||||||
      "version": "1.0.2",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "commander": {
 | 
					 | 
				
			||||||
      "version": "2.15.1",
 | 
					 | 
				
			||||||
      "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "concat-map": {
 | 
					 | 
				
			||||||
      "version": "0.0.1",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "debug": {
 | 
					 | 
				
			||||||
      "version": "3.1.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "ms": "2.0.0"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "deep-eql": {
 | 
					 | 
				
			||||||
      "version": "3.0.1",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "type-detect": "^4.0.0"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "diff": {
 | 
					 | 
				
			||||||
      "version": "3.5.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "escape-string-regexp": {
 | 
					 | 
				
			||||||
      "version": "1.0.5",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "fs.realpath": {
 | 
					 | 
				
			||||||
      "version": "1.0.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "get-func-name": {
 | 
					 | 
				
			||||||
      "version": "2.0.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "glob": {
 | 
					 | 
				
			||||||
      "version": "7.1.2",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "fs.realpath": "^1.0.0",
 | 
					 | 
				
			||||||
        "inflight": "^1.0.4",
 | 
					 | 
				
			||||||
        "inherits": "2",
 | 
					 | 
				
			||||||
        "minimatch": "^3.0.4",
 | 
					 | 
				
			||||||
        "once": "^1.3.0",
 | 
					 | 
				
			||||||
        "path-is-absolute": "^1.0.0"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "growl": {
 | 
					 | 
				
			||||||
      "version": "1.10.5",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "has-flag": {
 | 
					 | 
				
			||||||
      "version": "3.0.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "he": {
 | 
					 | 
				
			||||||
      "version": "1.1.1",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "inflight": {
 | 
					 | 
				
			||||||
      "version": "1.0.6",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "once": "^1.3.0",
 | 
					 | 
				
			||||||
        "wrappy": "1"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "inherits": {
 | 
					 | 
				
			||||||
      "version": "2.0.3",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "minimatch": {
 | 
					 | 
				
			||||||
      "version": "3.0.4",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "brace-expansion": "^1.1.7"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "minimist": {
 | 
					 | 
				
			||||||
      "version": "0.0.8",
 | 
					 | 
				
			||||||
      "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "mkdirp": {
 | 
					 | 
				
			||||||
      "version": "0.5.1",
 | 
					 | 
				
			||||||
      "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "minimist": "0.0.8"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "mocha": {
 | 
					 | 
				
			||||||
      "version": "5.2.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "browser-stdout": "1.3.1",
 | 
					 | 
				
			||||||
        "commander": "2.15.1",
 | 
					 | 
				
			||||||
        "debug": "3.1.0",
 | 
					 | 
				
			||||||
        "diff": "3.5.0",
 | 
					 | 
				
			||||||
        "escape-string-regexp": "1.0.5",
 | 
					 | 
				
			||||||
        "glob": "7.1.2",
 | 
					 | 
				
			||||||
        "growl": "1.10.5",
 | 
					 | 
				
			||||||
        "he": "1.1.1",
 | 
					 | 
				
			||||||
        "minimatch": "3.0.4",
 | 
					 | 
				
			||||||
        "mkdirp": "0.5.1",
 | 
					 | 
				
			||||||
        "supports-color": "5.4.0"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "ms": {
 | 
					 | 
				
			||||||
      "version": "2.0.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "once": {
 | 
					 | 
				
			||||||
      "version": "1.4.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "wrappy": "1"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "path-is-absolute": {
 | 
					 | 
				
			||||||
      "version": "1.0.1",
 | 
					 | 
				
			||||||
      "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "pathval": {
 | 
					 | 
				
			||||||
      "version": "1.1.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "supports-color": {
 | 
					 | 
				
			||||||
      "version": "5.4.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "has-flag": "^3.0.0"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "type-detect": {
 | 
					 | 
				
			||||||
      "version": "4.0.8",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "wrappy": {
 | 
					 | 
				
			||||||
      "version": "1.0.2",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "name": "fcc-create-nav-data",
 | 
					 | 
				
			||||||
  "private": true,
 | 
					 | 
				
			||||||
  "version": "0.0.1",
 | 
					 | 
				
			||||||
  "scripts": {
 | 
					 | 
				
			||||||
    "test": "mocha  -R spec \"./{,!(node_modules)/**/}*.test.js\"",
 | 
					 | 
				
			||||||
    "test:watch": "mocha  -R spec \"./{,!(node_modules)/**/}*.test.js\" --watch"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "dependencies": {
 | 
					 | 
				
			||||||
    "chai": "^4.1.2",
 | 
					 | 
				
			||||||
    "mocha": "^5.0.5"
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,131 +0,0 @@
 | 
				
			|||||||
import React, { Fragment } from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import { StaticQuery, graphql } from 'gatsby';
 | 
					 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					 | 
				
			||||||
import { bindActionCreators } from 'redux';
 | 
					 | 
				
			||||||
import { createSelector } from 'reselect';
 | 
					 | 
				
			||||||
import { Grid, Col, Row } from '@freecodecamp/react-bootstrap';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import SideNav from './components/guide/SideNav';
 | 
					 | 
				
			||||||
import Spacer from '../helpers/Spacer';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import 'prismjs/themes/prism.css';
 | 
					 | 
				
			||||||
import './guide.css';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  toggleExpandedState,
 | 
					 | 
				
			||||||
  toggleDisplayMenu,
 | 
					 | 
				
			||||||
  displayMenuSelector,
 | 
					 | 
				
			||||||
  expandedStateSelector
 | 
					 | 
				
			||||||
} from './components/guide/redux';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const propTypes = {
 | 
					 | 
				
			||||||
  children: PropTypes.any,
 | 
					 | 
				
			||||||
  data: PropTypes.shape({
 | 
					 | 
				
			||||||
    allNavigationNode: PropTypes.shape({
 | 
					 | 
				
			||||||
      edges: PropTypes.arrayOf(
 | 
					 | 
				
			||||||
        PropTypes.shape({
 | 
					 | 
				
			||||||
          node: PropTypes.shape({
 | 
					 | 
				
			||||||
            dashedName: PropTypes.string,
 | 
					 | 
				
			||||||
            isStubbed: PropTypes.bool,
 | 
					 | 
				
			||||||
            path: PropTypes.string,
 | 
					 | 
				
			||||||
            title: PropTypes.string
 | 
					 | 
				
			||||||
          })
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }),
 | 
					 | 
				
			||||||
  displayMenu: PropTypes.bool,
 | 
					 | 
				
			||||||
  expandedState: PropTypes.object,
 | 
					 | 
				
			||||||
  location: PropTypes.object,
 | 
					 | 
				
			||||||
  toggleDisplayMenu: PropTypes.func,
 | 
					 | 
				
			||||||
  toggleExpandedState: PropTypes.func
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const mapStateToProps = createSelector(
 | 
					 | 
				
			||||||
  displayMenuSelector,
 | 
					 | 
				
			||||||
  expandedStateSelector,
 | 
					 | 
				
			||||||
  (displayMenu, expandedState) => ({
 | 
					 | 
				
			||||||
    displayMenu,
 | 
					 | 
				
			||||||
    expandedState
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const mapDispatchToProps = dispatch =>
 | 
					 | 
				
			||||||
  bindActionCreators({ toggleExpandedState, toggleDisplayMenu }, dispatch);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class GuideLayout extends React.Component {
 | 
					 | 
				
			||||||
  getContentRef = ref => (this.contentRef = ref);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  handleNavigation = () => {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  hideSideNav = () => {
 | 
					 | 
				
			||||||
    if (this.props.displayMenu) {
 | 
					 | 
				
			||||||
      this.props.toggleDisplayMenu();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render() {
 | 
					 | 
				
			||||||
    const { expandedState, toggleExpandedState, displayMenu } = this.props;
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <StaticQuery
 | 
					 | 
				
			||||||
        query={graphql`
 | 
					 | 
				
			||||||
          query GuideLayoutQuery {
 | 
					 | 
				
			||||||
            allNavigationNode {
 | 
					 | 
				
			||||||
              edges {
 | 
					 | 
				
			||||||
                node {
 | 
					 | 
				
			||||||
                  dashedName
 | 
					 | 
				
			||||||
                  hasChildren
 | 
					 | 
				
			||||||
                  isStubbed
 | 
					 | 
				
			||||||
                  parentPath
 | 
					 | 
				
			||||||
                  path
 | 
					 | 
				
			||||||
                  title
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        `}
 | 
					 | 
				
			||||||
        render={data => {
 | 
					 | 
				
			||||||
          const { edges } = data.allNavigationNode;
 | 
					 | 
				
			||||||
          const pages = edges.map(edge => edge.node);
 | 
					 | 
				
			||||||
          return (
 | 
					 | 
				
			||||||
            <Fragment>
 | 
					 | 
				
			||||||
              <Spacer size={1} />
 | 
					 | 
				
			||||||
              <Grid className='guide-container'>
 | 
					 | 
				
			||||||
                <Row>
 | 
					 | 
				
			||||||
                  <Col md={4} smHidden={!displayMenu} xsHidden={!displayMenu}>
 | 
					 | 
				
			||||||
                    <SideNav
 | 
					 | 
				
			||||||
                      expandedState={expandedState}
 | 
					 | 
				
			||||||
                      onNavigate={this.handleNavigation}
 | 
					 | 
				
			||||||
                      pages={pages}
 | 
					 | 
				
			||||||
                      toggleDisplaySideNav={this.hideSideNav}
 | 
					 | 
				
			||||||
                      toggleExpandedState={toggleExpandedState}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                  </Col>
 | 
					 | 
				
			||||||
                  <Col md={8} smHidden={displayMenu} xsHidden={displayMenu}>
 | 
					 | 
				
			||||||
                    <main
 | 
					 | 
				
			||||||
                      className='content'
 | 
					 | 
				
			||||||
                      id='main'
 | 
					 | 
				
			||||||
                      ref={this.getContentRef}
 | 
					 | 
				
			||||||
                      tabIndex='-1'
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      {this.props.children}
 | 
					 | 
				
			||||||
                    </main>
 | 
					 | 
				
			||||||
                  </Col>
 | 
					 | 
				
			||||||
                </Row>
 | 
					 | 
				
			||||||
              </Grid>
 | 
					 | 
				
			||||||
            </Fragment>
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GuideLayout.displayName = 'GuideLayout';
 | 
					 | 
				
			||||||
GuideLayout.propTypes = propTypes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default connect(
 | 
					 | 
				
			||||||
  mapStateToProps,
 | 
					 | 
				
			||||||
  mapDispatchToProps
 | 
					 | 
				
			||||||
)(GuideLayout);
 | 
					 | 
				
			||||||
@@ -1,36 +0,0 @@
 | 
				
			|||||||
import React from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import Link from 'gatsby-link';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const propTypes = {
 | 
					 | 
				
			||||||
  isStubbed: PropTypes.bool,
 | 
					 | 
				
			||||||
  onNavigate: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
  path: PropTypes.string,
 | 
					 | 
				
			||||||
  router: PropTypes.object,
 | 
					 | 
				
			||||||
  title: PropTypes.string,
 | 
					 | 
				
			||||||
  toggleDisplaySideNav: PropTypes.func.isRequired
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class NavItem extends React.Component {
 | 
					 | 
				
			||||||
  handleClick = () => {
 | 
					 | 
				
			||||||
    this.props.toggleDisplaySideNav();
 | 
					 | 
				
			||||||
    this.props.onNavigate();
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  render() {
 | 
					 | 
				
			||||||
    const { isStubbed, path, title } = this.props;
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <li>
 | 
					 | 
				
			||||||
        <Link onClick={this.handleClick} to={path}>
 | 
					 | 
				
			||||||
          <span className={'navItemTitle' + (isStubbed ? ' stubbed' : '')}>
 | 
					 | 
				
			||||||
            {title}
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
        </Link>
 | 
					 | 
				
			||||||
      </li>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
NavItem.displayName = 'NavItem';
 | 
					 | 
				
			||||||
NavItem.propTypes = propTypes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default NavItem;
 | 
					 | 
				
			||||||
@@ -1,45 +0,0 @@
 | 
				
			|||||||
import React from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					 | 
				
			||||||
import { bindActionCreators } from 'redux';
 | 
					 | 
				
			||||||
import { createSelector } from 'reselect';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import MenuButton from '../../../../components/Header/components/MenuButton';
 | 
					 | 
				
			||||||
import MenuLinks from '../../../../components/Header/components/MenuLinks';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { toggleDisplayMenu, displayMenuSelector } from './redux';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const mapStateToProps = createSelector(
 | 
					 | 
				
			||||||
  displayMenuSelector,
 | 
					 | 
				
			||||||
  displayMenu => ({
 | 
					 | 
				
			||||||
    displayMenu
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const mapDispatchToProps = dispatch =>
 | 
					 | 
				
			||||||
  bindActionCreators({ toggleDisplayMenu }, dispatch);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function GuideNavigationMenu(props) {
 | 
					 | 
				
			||||||
  const { displayMenu, toggleDisplayMenu } = props;
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <MenuButton
 | 
					 | 
				
			||||||
        className={'guide-menu-button'}
 | 
					 | 
				
			||||||
        displayMenu={displayMenu}
 | 
					 | 
				
			||||||
        onClick={toggleDisplayMenu}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <MenuLinks className={'guide-top-nav'} />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GuideNavigationMenu.displayName = 'GuideNavigationMenu';
 | 
					 | 
				
			||||||
GuideNavigationMenu.propTypes = {
 | 
					 | 
				
			||||||
  displayMenu: PropTypes.bool.isRequired,
 | 
					 | 
				
			||||||
  toggleDisplayMenu: PropTypes.func.isRequired
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default connect(
 | 
					 | 
				
			||||||
  mapStateToProps,
 | 
					 | 
				
			||||||
  mapDispatchToProps
 | 
					 | 
				
			||||||
)(GuideNavigationMenu);
 | 
					 | 
				
			||||||
@@ -1,106 +0,0 @@
 | 
				
			|||||||
import React, { Component } from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import { Panel } from '@freecodecamp/react-bootstrap';
 | 
					 | 
				
			||||||
import { Link } from 'gatsby';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const propTypes = {
 | 
					 | 
				
			||||||
  children: PropTypes.any,
 | 
					 | 
				
			||||||
  dashedName: PropTypes.string,
 | 
					 | 
				
			||||||
  handleClick: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
  hasChildren: PropTypes.bool,
 | 
					 | 
				
			||||||
  isExpanded: PropTypes.bool,
 | 
					 | 
				
			||||||
  onNavigate: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
  path: PropTypes.string,
 | 
					 | 
				
			||||||
  title: PropTypes.string,
 | 
					 | 
				
			||||||
  toggleDisplaySideNav: PropTypes.func.isRequired
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function NoArticles() {
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <li>
 | 
					 | 
				
			||||||
      <span>
 | 
					 | 
				
			||||||
        No articles yet.
 | 
					 | 
				
			||||||
        <br />
 | 
					 | 
				
			||||||
        Could you 
 | 
					 | 
				
			||||||
        <a
 | 
					 | 
				
			||||||
          href={
 | 
					 | 
				
			||||||
            'https://github.com/freeCodeCamp/freeCodeCamp/blob/master/docs/' +
 | 
					 | 
				
			||||||
            'how-to-work-on-guide-articles.md#how-to-work-on-guide-articles'
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          rel='noopener noreferrer'
 | 
					 | 
				
			||||||
          target='_blank'
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          write one?
 | 
					 | 
				
			||||||
        </a>
 | 
					 | 
				
			||||||
      </span>
 | 
					 | 
				
			||||||
    </li>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class NavPanel extends Component {
 | 
					 | 
				
			||||||
  constructor() {
 | 
					 | 
				
			||||||
    super();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.renderHeader = this.renderHeader.bind(this);
 | 
					 | 
				
			||||||
    this.handleHeaderClick = this.handleHeaderClick.bind(this);
 | 
					 | 
				
			||||||
    this.handleTitleClick = this.handleTitleClick.bind(this);
 | 
					 | 
				
			||||||
    this.renderBody = this.renderBody.bind(this);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  handleHeaderClick() {
 | 
					 | 
				
			||||||
    const { path, handleClick } = this.props;
 | 
					 | 
				
			||||||
    handleClick(path);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  handleTitleClick() {
 | 
					 | 
				
			||||||
    const { toggleDisplaySideNav, onNavigate } = this.props;
 | 
					 | 
				
			||||||
    toggleDisplaySideNav();
 | 
					 | 
				
			||||||
    onNavigate();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  renderHeader() {
 | 
					 | 
				
			||||||
    const { isExpanded, path, title } = this.props;
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <div className='title' onClick={this.handleHeaderClick}>
 | 
					 | 
				
			||||||
        <span
 | 
					 | 
				
			||||||
          className={
 | 
					 | 
				
			||||||
            'caret ' + (isExpanded ? 'caretStyle expanded' : 'caretStyle')
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <Link onClick={this.handleTitleClick} to={path}>
 | 
					 | 
				
			||||||
          {title}
 | 
					 | 
				
			||||||
        </Link>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  renderBody() {
 | 
					 | 
				
			||||||
    const { hasChildren, children, isExpanded } = this.props;
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <div className={isExpanded ? 'body' : ''}>
 | 
					 | 
				
			||||||
        <ul className='navPanelUl'>
 | 
					 | 
				
			||||||
          {hasChildren ? children : <NoArticles />}
 | 
					 | 
				
			||||||
        </ul>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render() {
 | 
					 | 
				
			||||||
    const { isExpanded, dashedName } = this.props;
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <Panel
 | 
					 | 
				
			||||||
        bsClass='panelStyle panel'
 | 
					 | 
				
			||||||
        id={`${dashedName}-panel`}
 | 
					 | 
				
			||||||
        role='listitem'
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <Panel.Heading>{this.renderHeader()}</Panel.Heading>
 | 
					 | 
				
			||||||
        {isExpanded ? <Panel.Body>{this.renderBody()}</Panel.Body> : null}
 | 
					 | 
				
			||||||
      </Panel>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
NavPanel.displayName = 'NavPanel';
 | 
					 | 
				
			||||||
NavPanel.propTypes = propTypes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default NavPanel;
 | 
					 | 
				
			||||||
@@ -1,108 +0,0 @@
 | 
				
			|||||||
import React, { Component } from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import PanelGroup from '@freecodecamp/react-bootstrap/lib/PanelGroup';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import NavPanel from './NavPanel';
 | 
					 | 
				
			||||||
import NavItem from './NavItem';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const propTypes = {
 | 
					 | 
				
			||||||
  expandedState: PropTypes.object,
 | 
					 | 
				
			||||||
  onNavigate: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
  pages: PropTypes.arrayOf(PropTypes.object),
 | 
					 | 
				
			||||||
  parents: PropTypes.arrayOf(PropTypes.object),
 | 
					 | 
				
			||||||
  toggleDisplaySideNav: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
  toggleExpandedState: PropTypes.func.isRequired
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function parentFilter(node) {
 | 
					 | 
				
			||||||
  return node.path.split('/').filter(Boolean).length === 2;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class SideNav extends Component {
 | 
					 | 
				
			||||||
  constructor(...props) {
 | 
					 | 
				
			||||||
    super(...props);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.renderChildren = this.renderChildren.bind(this);
 | 
					 | 
				
			||||||
    this.renderPanels = this.renderPanels.bind(this);
 | 
					 | 
				
			||||||
    this.renderParent = this.renderParent.bind(this);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  renderPanels(parents, pages) {
 | 
					 | 
				
			||||||
    if (!parents) {
 | 
					 | 
				
			||||||
      return 'No Parents Here';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return parents.map(parent => this.renderParent(parent, pages));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  renderParent(parent, pages) {
 | 
					 | 
				
			||||||
    const childrenForParent = pages.filter(
 | 
					 | 
				
			||||||
      page => page.parentPath === parent.path
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    const { path } = parent;
 | 
					 | 
				
			||||||
    const isExpanded = !!this.props.expandedState[path];
 | 
					 | 
				
			||||||
    const [category] = pages.filter(page => page.path === path);
 | 
					 | 
				
			||||||
    const { title, hasChildren, dashedName } = category;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const children = isExpanded
 | 
					 | 
				
			||||||
      ? this.renderChildren(childrenForParent, pages)
 | 
					 | 
				
			||||||
      : null;
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <NavPanel
 | 
					 | 
				
			||||||
        dashedName={dashedName}
 | 
					 | 
				
			||||||
        handleClick={this.props.toggleExpandedState}
 | 
					 | 
				
			||||||
        hasChildren={hasChildren}
 | 
					 | 
				
			||||||
        isExpanded={isExpanded}
 | 
					 | 
				
			||||||
        key={parent.path}
 | 
					 | 
				
			||||||
        onNavigate={this.props.onNavigate}
 | 
					 | 
				
			||||||
        path={parent.path}
 | 
					 | 
				
			||||||
        title={title}
 | 
					 | 
				
			||||||
        toggleDisplaySideNav={this.props.toggleDisplaySideNav}
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        {children}
 | 
					 | 
				
			||||||
      </NavPanel>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  renderChildren(children, pages) {
 | 
					 | 
				
			||||||
    return children.map(child => {
 | 
					 | 
				
			||||||
      if (child.hasChildren) {
 | 
					 | 
				
			||||||
        return this.renderParent(child, pages);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        <NavItem
 | 
					 | 
				
			||||||
          isStubbed={child.isStubbed}
 | 
					 | 
				
			||||||
          key={child.path}
 | 
					 | 
				
			||||||
          onNavigate={this.props.onNavigate}
 | 
					 | 
				
			||||||
          path={child.path}
 | 
					 | 
				
			||||||
          title={child.title}
 | 
					 | 
				
			||||||
          toggleDisplaySideNav={this.props.toggleDisplaySideNav}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render() {
 | 
					 | 
				
			||||||
    const { pages, expandedState } = this.props;
 | 
					 | 
				
			||||||
    const parents = pages.filter(parentFilter);
 | 
					 | 
				
			||||||
    const panels = this.renderPanels(parents, pages);
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <nav className='sideNav' id='side-nav'>
 | 
					 | 
				
			||||||
        <PanelGroup id='guide-navigation-side-panel' role='list'>
 | 
					 | 
				
			||||||
          {!parents || !expandedState ? (
 | 
					 | 
				
			||||||
            <NavPanel
 | 
					 | 
				
			||||||
              title='No Parents Here'
 | 
					 | 
				
			||||||
              toggleDisplaySideNav={this.props.toggleDisplaySideNav}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          ) : (
 | 
					 | 
				
			||||||
            panels
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </PanelGroup>
 | 
					 | 
				
			||||||
      </nav>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SideNav.displayName = 'SideNav';
 | 
					 | 
				
			||||||
SideNav.propTypes = propTypes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default SideNav;
 | 
					 | 
				
			||||||
@@ -1,38 +0,0 @@
 | 
				
			|||||||
import { createAction, handleActions } from 'redux-actions';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { createTypes } from '../../../../../utils/createTypes';
 | 
					 | 
				
			||||||
import { createSideNavigationSaga } from './side-navigation-saga';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const ns = 'guideNav';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const initialState = {
 | 
					 | 
				
			||||||
  displayMenu: false,
 | 
					 | 
				
			||||||
  expandedState: {}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const types = createTypes(['toggleExpandedState', 'toggleDisplayMenu'], ns);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const sagas = [...createSideNavigationSaga(types)];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const toggleExpandedState = createAction(types.toggleExpandedState);
 | 
					 | 
				
			||||||
export const toggleDisplayMenu = createAction(types.toggleDisplayMenu);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const displayMenuSelector = state => state[ns].displayMenu;
 | 
					 | 
				
			||||||
export const expandedStateSelector = state => state[ns].expandedState;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const reducer = handleActions(
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    [types.toggleExpandedState]: (state, { payload }) => ({
 | 
					 | 
				
			||||||
      ...state,
 | 
					 | 
				
			||||||
      expandedState: {
 | 
					 | 
				
			||||||
        ...state.expandedState,
 | 
					 | 
				
			||||||
        [payload]: !state.expandedState[payload]
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }),
 | 
					 | 
				
			||||||
    [types.toggleDisplayMenu]: state => ({
 | 
					 | 
				
			||||||
      ...state,
 | 
					 | 
				
			||||||
      displayMenu: !state.displayMenu
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  initialState
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
@@ -1,31 +0,0 @@
 | 
				
			|||||||
import { takeEvery, put, all } from 'redux-saga/effects';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { toggleExpandedState } from './';
 | 
					 | 
				
			||||||
import { types as appTypes } from '../../../../../redux';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function* expandSideNavOnMountSaga() {
 | 
					 | 
				
			||||||
  let guideRegex = /^\/guide\//;
 | 
					 | 
				
			||||||
  let onGuide = guideRegex.test(window.location.pathname);
 | 
					 | 
				
			||||||
  if (onGuide && typeof window !== 'undefined') {
 | 
					 | 
				
			||||||
    const pathMap = window.location.pathname
 | 
					 | 
				
			||||||
      .slice(1)
 | 
					 | 
				
			||||||
      .split('/')
 | 
					 | 
				
			||||||
      .slice(0, -1)
 | 
					 | 
				
			||||||
      .reduce((map, current, i, pathArray) => {
 | 
					 | 
				
			||||||
        const path =
 | 
					 | 
				
			||||||
          i !== 0 ? map[pathArray[i - 1]] + `/${current}` : `/${current}`;
 | 
					 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
          ...map,
 | 
					 | 
				
			||||||
          [current]: path
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
      }, {});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let routes = Object.keys(pathMap).map(key => pathMap[key]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    yield all(routes.map(route => put(toggleExpandedState(route))));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function createSideNavigationSaga() {
 | 
					 | 
				
			||||||
  return [takeEvery(appTypes.appMount, expandSideNavOnMountSaga)];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,141 +0,0 @@
 | 
				
			|||||||
.guide-container {
 | 
					 | 
				
			||||||
  font-size: 16px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Breadcrumbs */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.breadcrumb {
 | 
					 | 
				
			||||||
  display: inline-block;
 | 
					 | 
				
			||||||
  padding: 5px 10px;
 | 
					 | 
				
			||||||
  margin: 0;
 | 
					 | 
				
			||||||
  margin-bottom: 5px;
 | 
					 | 
				
			||||||
  opacity: 0.8;
 | 
					 | 
				
			||||||
  transition: opacity 0.1s ease-out;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.breadcrumb:hover {
 | 
					 | 
				
			||||||
  opacity: 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.breadcrumb > li a {
 | 
					 | 
				
			||||||
  color: #006400;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.breadcrumb > li {
 | 
					 | 
				
			||||||
  margin: 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.breadcrumb > li + li:before {
 | 
					 | 
				
			||||||
  content: '\203A';
 | 
					 | 
				
			||||||
  color: #555;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.breadcrumb > .active {
 | 
					 | 
				
			||||||
  color: #555;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Layout */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.content,
 | 
					 | 
				
			||||||
.sideNav {
 | 
					 | 
				
			||||||
  /* 100vh - (navbar height) - (spacer height) */
 | 
					 | 
				
			||||||
  height: 100%;
 | 
					 | 
				
			||||||
  overflow-y: auto;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.content img {
 | 
					 | 
				
			||||||
  max-width: 100%;
 | 
					 | 
				
			||||||
  display: block;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.content img.forum-image {
 | 
					 | 
				
			||||||
  display: inline-block;
 | 
					 | 
				
			||||||
  width: 20px;
 | 
					 | 
				
			||||||
  height: 20px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* SideNav */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.caretStyle {
 | 
					 | 
				
			||||||
  border-top: 8px dashed;
 | 
					 | 
				
			||||||
  border-right: 6px solid transparent;
 | 
					 | 
				
			||||||
  border-left: 6px solid transparent;
 | 
					 | 
				
			||||||
  color: darkgray;
 | 
					 | 
				
			||||||
  margin-right: 5px;
 | 
					 | 
				
			||||||
  transform: rotate(-90deg);
 | 
					 | 
				
			||||||
  transition: transform 150ms ease;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.caretStyle.expanded {
 | 
					 | 
				
			||||||
  transform: rotate(0deg);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.navPanelUl {
 | 
					 | 
				
			||||||
  list-style: none;
 | 
					 | 
				
			||||||
  margin-bottom: 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.navPanelUl > li {
 | 
					 | 
				
			||||||
  margin-bottom: 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.navItemTitle {
 | 
					 | 
				
			||||||
  margin-left: 19px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.panelStyle {
 | 
					 | 
				
			||||||
  border: none !important;
 | 
					 | 
				
			||||||
  border-radius: 0;
 | 
					 | 
				
			||||||
  box-shadow: none;
 | 
					 | 
				
			||||||
  padding: 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.sideNav {
 | 
					 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.stubbed {
 | 
					 | 
				
			||||||
  color: #777;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.stubbed::after {
 | 
					 | 
				
			||||||
  content: 'stub';
 | 
					 | 
				
			||||||
  background-color: #aaa;
 | 
					 | 
				
			||||||
  color: #fff;
 | 
					 | 
				
			||||||
  border-radius: 3px;
 | 
					 | 
				
			||||||
  padding: 0 4px;
 | 
					 | 
				
			||||||
  margin-left: 5px;
 | 
					 | 
				
			||||||
  line-height: 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.title {
 | 
					 | 
				
			||||||
  background-color: white;
 | 
					 | 
				
			||||||
  border: none;
 | 
					 | 
				
			||||||
  border-radius: 0;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.night .panelStyle,
 | 
					 | 
				
			||||||
.night .title {
 | 
					 | 
				
			||||||
  background-color: #333;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@media (max-width: 992px) {
 | 
					 | 
				
			||||||
  .content {
 | 
					 | 
				
			||||||
    height: auto;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  #top-right-nav.guide-top-nav {
 | 
					 | 
				
			||||||
    display: none;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@media (min-width: 993px) {
 | 
					 | 
				
			||||||
  #top-nav .guide-menu-button {
 | 
					 | 
				
			||||||
    display: none;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.content,
 | 
					 | 
				
			||||||
.article {
 | 
					 | 
				
			||||||
  outline: 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
export { default as CertificationLayout } from './Certification';
 | 
					export { default as CertificationLayout } from './Certification';
 | 
				
			||||||
export { default as DefaultLayout } from './Default';
 | 
					export { default as DefaultLayout } from './Default';
 | 
				
			||||||
export { default as GuideLayout } from './Guide';
 | 
					 | 
				
			||||||
export { default as LearnLayout } from './Learn';
 | 
					export { default as LearnLayout } from './Learn';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,53 +0,0 @@
 | 
				
			|||||||
import React, { Fragment } from 'react';
 | 
					 | 
				
			||||||
import Helmet from 'react-helmet';
 | 
					 | 
				
			||||||
import { Link } from '../components/helpers';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function Index() {
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <Fragment>
 | 
					 | 
				
			||||||
      <Helmet>
 | 
					 | 
				
			||||||
        <title>Guide | freeCodeCamp.org</title>
 | 
					 | 
				
			||||||
        <meta
 | 
					 | 
				
			||||||
          content='Short, concise guides and how-tos for the busy developer.'
 | 
					 | 
				
			||||||
          name='description'
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </Helmet>
 | 
					 | 
				
			||||||
      <h2>freeCodeCamp Guide</h2>
 | 
					 | 
				
			||||||
      <p>
 | 
					 | 
				
			||||||
        This website is full of articles about all things related to
 | 
					 | 
				
			||||||
        programming. You can use the search bar above to find something would
 | 
					 | 
				
			||||||
        like to learn about, or use the navigation to explore the content.
 | 
					 | 
				
			||||||
      </p>
 | 
					 | 
				
			||||||
      <p>There are articles on:</p>
 | 
					 | 
				
			||||||
      <ul>
 | 
					 | 
				
			||||||
        <li>SQL</li>
 | 
					 | 
				
			||||||
        <li>Mathematics</li>
 | 
					 | 
				
			||||||
        <li>JavaScript</li>
 | 
					 | 
				
			||||||
        <li>Bootstrap</li>
 | 
					 | 
				
			||||||
        <li>Git</li>
 | 
					 | 
				
			||||||
        <li>and a whole lot more</li>
 | 
					 | 
				
			||||||
      </ul>
 | 
					 | 
				
			||||||
      <h3>Not sure where to start?</h3>
 | 
					 | 
				
			||||||
      <p>
 | 
					 | 
				
			||||||
        If you want to learn programming but you're not sure where to start,
 | 
					 | 
				
			||||||
        check out <Link to='https://freecodecamp.org'>freeCodeCamp.org</Link>.
 | 
					 | 
				
			||||||
        It has a curriculum that starts from zero and helps you learn to code.
 | 
					 | 
				
			||||||
      </p>
 | 
					 | 
				
			||||||
      <h3>Contribute to the Guide</h3>
 | 
					 | 
				
			||||||
      <p>
 | 
					 | 
				
			||||||
        This site and the articles on it are{' '}
 | 
					 | 
				
			||||||
        <Link to='https://github.com/freeCodeCamp/freeCodeCamp'>
 | 
					 | 
				
			||||||
          {' '}
 | 
					 | 
				
			||||||
          open source{' '}
 | 
					 | 
				
			||||||
        </Link>{' '}
 | 
					 | 
				
			||||||
        . Your help in making it better is greatly appreciated!
 | 
					 | 
				
			||||||
      </p>
 | 
					 | 
				
			||||||
      <hr />
 | 
					 | 
				
			||||||
      <p>Happy coding!</p>
 | 
					 | 
				
			||||||
    </Fragment>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Index.displayName = 'IndexPage';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default Index;
 | 
					 | 
				
			||||||
@@ -6,10 +6,6 @@ import {
 | 
				
			|||||||
  reducer as flash,
 | 
					  reducer as flash,
 | 
				
			||||||
  ns as flashNameSpace
 | 
					  ns as flashNameSpace
 | 
				
			||||||
} from '../components/Flash/redux';
 | 
					} from '../components/Flash/redux';
 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  reducer as guideNav,
 | 
					 | 
				
			||||||
  ns as guideNavNameSpace
 | 
					 | 
				
			||||||
} from '../components/layouts/components/guide/redux';
 | 
					 | 
				
			||||||
import { reducer as settings, ns as settingsNameSpace } from './settings';
 | 
					import { reducer as settings, ns as settingsNameSpace } from './settings';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  reducer as curriculumMap,
 | 
					  reducer as curriculumMap,
 | 
				
			||||||
@@ -38,7 +34,6 @@ export default combineReducers({
 | 
				
			|||||||
  [challengeNameSpace]: challenge,
 | 
					  [challengeNameSpace]: challenge,
 | 
				
			||||||
  [curriculumMapNameSpace]: curriculumMap,
 | 
					  [curriculumMapNameSpace]: curriculumMap,
 | 
				
			||||||
  [flashNameSpace]: flash,
 | 
					  [flashNameSpace]: flash,
 | 
				
			||||||
  [guideNavNameSpace]: guideNav,
 | 
					 | 
				
			||||||
  form: formReducer,
 | 
					  form: formReducer,
 | 
				
			||||||
  [searchNameSpace]: search,
 | 
					  [searchNameSpace]: search,
 | 
				
			||||||
  [settingsNameSpace]: settings
 | 
					  [settingsNameSpace]: settings
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,15 +5,6 @@ import { sagas as appSagas } from './';
 | 
				
			|||||||
import { sagas as challengeSagas } from '../templates/Challenges/redux';
 | 
					import { sagas as challengeSagas } from '../templates/Challenges/redux';
 | 
				
			||||||
import { sagas as settingsSagas } from './settings';
 | 
					import { sagas as settingsSagas } from './settings';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// eslint-disable-next-line max-len
 | 
					 | 
				
			||||||
import { sagas as sideNavigationSaga } from '../components/layouts/components/guide/redux';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default function* rootSaga() {
 | 
					export default function* rootSaga() {
 | 
				
			||||||
  yield all([
 | 
					  yield all([...errorSagas, ...appSagas, ...challengeSagas, ...settingsSagas]);
 | 
				
			||||||
    ...errorSagas,
 | 
					 | 
				
			||||||
    ...appSagas,
 | 
					 | 
				
			||||||
    ...challengeSagas,
 | 
					 | 
				
			||||||
    ...settingsSagas,
 | 
					 | 
				
			||||||
    ...sideNavigationSaga
 | 
					 | 
				
			||||||
  ]);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,41 +0,0 @@
 | 
				
			|||||||
import React from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import { graphql } from 'gatsby';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import ArticleLayout from './components/ArticleLayout';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const propTypes = {
 | 
					 | 
				
			||||||
  data: PropTypes.object
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const GuideArticle = props => {
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    data: {
 | 
					 | 
				
			||||||
      markdownRemark: { html }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } = props;
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <ArticleLayout {...props}>
 | 
					 | 
				
			||||||
      <article
 | 
					 | 
				
			||||||
        className='article'
 | 
					 | 
				
			||||||
        dangerouslySetInnerHTML={{ __html: html }}
 | 
					 | 
				
			||||||
        id='article'
 | 
					 | 
				
			||||||
        tabIndex='-1'
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </ArticleLayout>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GuideArticle.displayName = 'GuideArticle';
 | 
					 | 
				
			||||||
GuideArticle.propTypes = propTypes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default GuideArticle;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const pageQuery = graphql`
 | 
					 | 
				
			||||||
  query ArticleById($id: String!) {
 | 
					 | 
				
			||||||
    markdownRemark(id: { eq: $id }) {
 | 
					 | 
				
			||||||
      html
 | 
					 | 
				
			||||||
      ...ArticleLayout
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
`;
 | 
					 | 
				
			||||||
@@ -1,72 +0,0 @@
 | 
				
			|||||||
import React, { Fragment } from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import { graphql } from 'gatsby';
 | 
					 | 
				
			||||||
import Helmet from 'react-helmet';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import Breadcrumbs from './Breadcrumbs';
 | 
					 | 
				
			||||||
import GuideFooter from './GuideFooter';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const propTypes = {
 | 
					 | 
				
			||||||
  children: PropTypes.any,
 | 
					 | 
				
			||||||
  data: PropTypes.object,
 | 
					 | 
				
			||||||
  location: PropTypes.object,
 | 
					 | 
				
			||||||
  pageContext: PropTypes.shape({
 | 
					 | 
				
			||||||
    meta: PropTypes.objectOf(PropTypes.string)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ArticleLayout = props => {
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    children,
 | 
					 | 
				
			||||||
    location: { pathname },
 | 
					 | 
				
			||||||
    data: {
 | 
					 | 
				
			||||||
      markdownRemark: {
 | 
					 | 
				
			||||||
        fields: { slug, githubPath },
 | 
					 | 
				
			||||||
        frontmatter: { title }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    pageContext: { meta }
 | 
					 | 
				
			||||||
  } = props;
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <Fragment>
 | 
					 | 
				
			||||||
      <Helmet>
 | 
					 | 
				
			||||||
        <title>{`${title} | freeCodeCamp.org`}</title>
 | 
					 | 
				
			||||||
        <link href={`https://www.freecodecamp.org${slug}`} rel='canonical' />
 | 
					 | 
				
			||||||
        <meta
 | 
					 | 
				
			||||||
          content={`https://www.freecodecamp.org${slug}`}
 | 
					 | 
				
			||||||
          property='og:url'
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <meta content={title} property='og:title' />
 | 
					 | 
				
			||||||
        <meta
 | 
					 | 
				
			||||||
          content={meta.description ? meta.description : ''}
 | 
					 | 
				
			||||||
          property='og:description'
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <meta
 | 
					 | 
				
			||||||
          content={meta.description ? meta.description : ''}
 | 
					 | 
				
			||||||
          name='description'
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <meta content={meta.featureImage} property='og:image' />
 | 
					 | 
				
			||||||
      </Helmet>
 | 
					 | 
				
			||||||
      <Breadcrumbs path={pathname} />
 | 
					 | 
				
			||||||
      {children}
 | 
					 | 
				
			||||||
      <GuideFooter githubPath={githubPath} />
 | 
					 | 
				
			||||||
    </Fragment>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ArticleLayout.displayName = 'ArticleLayout';
 | 
					 | 
				
			||||||
ArticleLayout.propTypes = propTypes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default ArticleLayout;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const fragmentQuery = graphql`
 | 
					 | 
				
			||||||
  fragment ArticleLayout on MarkdownRemark {
 | 
					 | 
				
			||||||
    fields {
 | 
					 | 
				
			||||||
      slug
 | 
					 | 
				
			||||||
      githubPath
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    frontmatter {
 | 
					 | 
				
			||||||
      title
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
`;
 | 
					 | 
				
			||||||
@@ -1,55 +0,0 @@
 | 
				
			|||||||
import React from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import Link from 'gatsby-link';
 | 
					 | 
				
			||||||
import titleify from '../../../../utils/titleify';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const propTypes = {
 | 
					 | 
				
			||||||
  path: PropTypes.string.isRequired
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function Breadcrumbs(props) {
 | 
					 | 
				
			||||||
  const { path } = props;
 | 
					 | 
				
			||||||
  if (path === '/') {
 | 
					 | 
				
			||||||
    return null;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const pathMap = path
 | 
					 | 
				
			||||||
    // remove leading and trailing slash
 | 
					 | 
				
			||||||
    .replace(/^\/([a-z0-9/-]+[^/])\/?$/i, '$1')
 | 
					 | 
				
			||||||
    .split('/')
 | 
					 | 
				
			||||||
    .reduce((accu, current, i, pathArray) => {
 | 
					 | 
				
			||||||
      const path =
 | 
					 | 
				
			||||||
        i !== 0 ? accu[pathArray[i - 1]].path + `/${current}` : `/${current}`;
 | 
					 | 
				
			||||||
      return {
 | 
					 | 
				
			||||||
        ...accu,
 | 
					 | 
				
			||||||
        [current]: {
 | 
					 | 
				
			||||||
          path,
 | 
					 | 
				
			||||||
          title: titleify(current)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
    }, {});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const crumbs = Object.keys(pathMap)
 | 
					 | 
				
			||||||
    .map(key => pathMap[key])
 | 
					 | 
				
			||||||
    .map((page, i, thisArray) => {
 | 
					 | 
				
			||||||
      if (i === thisArray.length - 1) {
 | 
					 | 
				
			||||||
        return (
 | 
					 | 
				
			||||||
          <li className='active' key={i}>
 | 
					 | 
				
			||||||
            {page.title}
 | 
					 | 
				
			||||||
          </li>
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        <li key={i}>
 | 
					 | 
				
			||||||
          <Link to={page.path}>{page.title}</Link>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <ol className='breadcrumb'>{crumbs}</ol>;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Breadcrumbs.displayName = 'Breadcrumbs';
 | 
					 | 
				
			||||||
Breadcrumbs.propTypes = propTypes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default Breadcrumbs;
 | 
					 | 
				
			||||||
@@ -1,37 +0,0 @@
 | 
				
			|||||||
import React from 'react';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import { Link, Spacer } from '../../../components/helpers';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const propTypes = {
 | 
					 | 
				
			||||||
  githubPath: PropTypes.string
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const GuideFooter = ({ githubPath }) => (
 | 
					 | 
				
			||||||
  <>
 | 
					 | 
				
			||||||
    <Spacer />
 | 
					 | 
				
			||||||
    <hr />
 | 
					 | 
				
			||||||
    <h4>Contributing to the Guide</h4>
 | 
					 | 
				
			||||||
    <p>
 | 
					 | 
				
			||||||
      This open source guide is curated by thousands of contributors. You can
 | 
					 | 
				
			||||||
      help by researching, writing and updating these articles. It is an easy
 | 
					 | 
				
			||||||
      and fun way to get started with contributing to open source.
 | 
					 | 
				
			||||||
    </p>
 | 
					 | 
				
			||||||
    <ul>
 | 
					 | 
				
			||||||
      <li>
 | 
					 | 
				
			||||||
        <Link to='https://github.com/freeCodeCamp/freeCodeCamp/blob/master/CONTRIBUTING.md#research-write-and-update-our-guide-articles'>
 | 
					 | 
				
			||||||
          Follow our contributing guidelines for working on guide articles
 | 
					 | 
				
			||||||
        </Link>
 | 
					 | 
				
			||||||
        .
 | 
					 | 
				
			||||||
      </li>
 | 
					 | 
				
			||||||
      <li>
 | 
					 | 
				
			||||||
        <Link to={githubPath}>Edit this article on GitHub</Link>.
 | 
					 | 
				
			||||||
      </li>
 | 
					 | 
				
			||||||
    </ul>
 | 
					 | 
				
			||||||
    <Spacer />
 | 
					 | 
				
			||||||
  </>
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GuideFooter.displayName = 'GuideFooter';
 | 
					 | 
				
			||||||
GuideFooter.propTypes = propTypes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default GuideFooter;
 | 
					 | 
				
			||||||
@@ -1,80 +0,0 @@
 | 
				
			|||||||
import React from 'react';
 | 
					 | 
				
			||||||
import ReactDOM from 'react-dom';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import { graphql } from 'gatsby';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import ArticleLayout from '../../ArticleLayout';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const propTypes = {
 | 
					 | 
				
			||||||
  data: PropTypes.object
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CustomClickCounter extends React.Component {
 | 
					 | 
				
			||||||
  state = {
 | 
					 | 
				
			||||||
    init: false,
 | 
					 | 
				
			||||||
    span: null,
 | 
					 | 
				
			||||||
    div: null,
 | 
					 | 
				
			||||||
    counter: 0
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  initComponent() {
 | 
					 | 
				
			||||||
    const span = document.getElementById('example-component_span');
 | 
					 | 
				
			||||||
    const div = document.getElementById('example-component_div');
 | 
					 | 
				
			||||||
    this.setState({ init: true, span, div });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  handleClick = () => {
 | 
					 | 
				
			||||||
    this.setState(state => ({ counter: state.counter + 1 }));
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  componentDidMount() {
 | 
					 | 
				
			||||||
    this.initComponent();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render() {
 | 
					 | 
				
			||||||
    if (!this.state.init) {
 | 
					 | 
				
			||||||
      return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <div>
 | 
					 | 
				
			||||||
        {ReactDOM.createPortal(this.state.counter, this.state.span)}
 | 
					 | 
				
			||||||
        {ReactDOM.createPortal(
 | 
					 | 
				
			||||||
          <button onClick={this.handleClick}>Click me!</button>,
 | 
					 | 
				
			||||||
          this.state.div
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ExampleComponent = props => {
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    data: {
 | 
					 | 
				
			||||||
      markdownRemark: { html }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } = props;
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <ArticleLayout {...props}>
 | 
					 | 
				
			||||||
      <article
 | 
					 | 
				
			||||||
        className='article'
 | 
					 | 
				
			||||||
        dangerouslySetInnerHTML={{ __html: html }}
 | 
					 | 
				
			||||||
        id='article'
 | 
					 | 
				
			||||||
        tabIndex='-1'
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <CustomClickCounter />
 | 
					 | 
				
			||||||
    </ArticleLayout>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ExampleComponent.displayName = 'ExampleComponent';
 | 
					 | 
				
			||||||
ExampleComponent.propTypes = propTypes;
 | 
					 | 
				
			||||||
export default ExampleComponent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const pageQuery = graphql`
 | 
					 | 
				
			||||||
  query ExampleComponent($id: String!) {
 | 
					 | 
				
			||||||
    markdownRemark(id: { eq: $id }) {
 | 
					 | 
				
			||||||
      html
 | 
					 | 
				
			||||||
      ...ArticleLayout
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
`;
 | 
					 | 
				
			||||||
@@ -1,47 +0,0 @@
 | 
				
			|||||||
const path = require('path');
 | 
					 | 
				
			||||||
const select = require('unist-util-select');
 | 
					 | 
				
			||||||
const { head } = require('lodash');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { isAStubRE } = require('../regEx');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const guideArticle = path.resolve(
 | 
					 | 
				
			||||||
  __dirname,
 | 
					 | 
				
			||||||
  '../../src/templates/Guide/GuideArticle.js'
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
exports.createGuideArticlePages = createPage => ({
 | 
					 | 
				
			||||||
  node: {
 | 
					 | 
				
			||||||
    htmlAst,
 | 
					 | 
				
			||||||
    excerpt,
 | 
					 | 
				
			||||||
    fields: { slug, component },
 | 
					 | 
				
			||||||
    id
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  let meta = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!isAStubRE.test(excerpt)) {
 | 
					 | 
				
			||||||
    const featureImage = head(select(htmlAst, 'element[tagName=img]'));
 | 
					 | 
				
			||||||
    meta.featureImage = featureImage
 | 
					 | 
				
			||||||
      ? featureImage.properties.src
 | 
					 | 
				
			||||||
      : 'https://s3.amazonaws.com/freecodecamp' +
 | 
					 | 
				
			||||||
        '/freecodecamp-square-logo-large.jpg';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const description = head(select(htmlAst, 'element[tagName=p]'));
 | 
					 | 
				
			||||||
    meta.description = description ? description.children[0].value : '';
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return createPage({
 | 
					 | 
				
			||||||
    path: `/guide${slug}`,
 | 
					 | 
				
			||||||
    component: !component
 | 
					 | 
				
			||||||
      ? guideArticle
 | 
					 | 
				
			||||||
      : path.resolve(
 | 
					 | 
				
			||||||
          __dirname,
 | 
					 | 
				
			||||||
          '../../src/templates/Guide/components/',
 | 
					 | 
				
			||||||
          component
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    context: {
 | 
					 | 
				
			||||||
      id,
 | 
					 | 
				
			||||||
      meta
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -1,7 +1,5 @@
 | 
				
			|||||||
const challengePageCreators = require('./challengePageCreator');
 | 
					const challengePageCreators = require('./challengePageCreator');
 | 
				
			||||||
const guidePageCreators = require('./guidePageCreator');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
  ...challengePageCreators,
 | 
					  ...challengePageCreators
 | 
				
			||||||
  ...guidePageCreators
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,11 +3,8 @@ import PropTypes from 'prop-types';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  CertificationLayout,
 | 
					  CertificationLayout,
 | 
				
			||||||
  DefaultLayout,
 | 
					  DefaultLayout
 | 
				
			||||||
  GuideLayout
 | 
					 | 
				
			||||||
} from '../../src/components/layouts';
 | 
					} from '../../src/components/layouts';
 | 
				
			||||||
// eslint-disable-next-line max-len
 | 
					 | 
				
			||||||
import GuideNavMenu from '../../src/components/layouts/components/guide/NavMenu';
 | 
					 | 
				
			||||||
import FourOhFourPage from '../../src/pages/404';
 | 
					import FourOhFourPage from '../../src/pages/404';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function layoutSelector({ element, props }) {
 | 
					export default function layoutSelector({ element, props }) {
 | 
				
			||||||
@@ -28,11 +25,7 @@ export default function layoutSelector({ element, props }) {
 | 
				
			|||||||
    return <CertificationLayout>{element}</CertificationLayout>;
 | 
					    return <CertificationLayout>{element}</CertificationLayout>;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (/^\/guide(\/.*)*/.test(pathname)) {
 | 
					  if (/^\/guide(\/.*)*/.test(pathname)) {
 | 
				
			||||||
    return (
 | 
					    console.log('Hitting guide for some reason. Need a redirect.');
 | 
				
			||||||
      <DefaultLayout navigationMenu={<GuideNavMenu />} pathname={pathname}>
 | 
					 | 
				
			||||||
        <GuideLayout>{element}</GuideLayout>
 | 
					 | 
				
			||||||
      </DefaultLayout>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (/^\/learn(\/.*)*/.test(pathname)) {
 | 
					  if (/^\/learn(\/.*)*/.test(pathname)) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user