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