From fa241c0f611b52ec714eeaec8c0f4f0902d18c52 Mon Sep 17 00:00:00 2001 From: Serge Latyntsev Date: Thu, 21 Nov 2019 10:26:11 +1300 Subject: [PATCH] Add Children "only, includeFolders, reverse" flags, add document unhideSelf (#209) --- gatsby-node.js | 20 +++++++++++--------- src/components/ChildrenOf.tsx | 35 +++++++++++++++++++++-------------- src/types/index.ts | 6 +++++- src/utils/nodes.ts | 21 ++++++++++++--------- src/utils/parseChildrenOf.ts | 29 ++++++++++++++++++++++------- 5 files changed, 71 insertions(+), 40 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index af61f75..3aeeef5 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -12,7 +12,7 @@ const createSlug = (filePath, version) => { .toLowerCase() }; -exports.onCreateNode = async ({ node, getNode, getNodesByType, actions, createNodeId, createContentDigest }) => { +exports.onCreateNode = async ({ node, getNode, getNodesByType, actions, createNodeId, createContentDigest }) => { if (node.internal.type !== 'MarkdownRemark') { return; } @@ -29,14 +29,14 @@ exports.onCreateNode = async ({ node, getNode, getNodesByType, actions, createNo if (version.match(/^watcher--/)) { const existing = getNodesByType('SilverstripeDocument') .find(n => n.fileAbsolutePath === node.fileAbsolutePath); - + if (existing) { // Pair the document with its watched file so we can inject it into the template // as a dependency. existing.watchFile___NODE = node.id; return; - } - } + } + } const filePath = createFilePath({ node, @@ -51,6 +51,7 @@ exports.onCreateNode = async ({ node, getNode, getNodesByType, actions, createNo const docTitle = fileToTitle(fileTitle); const slug = createSlug(filePath, version); const parentSlug = `${path.resolve(slug, '../')}/`; + const unhideSelf = false; const docData = { isIndex, @@ -58,7 +59,8 @@ exports.onCreateNode = async ({ node, getNode, getNodesByType, actions, createNo fileTitle, slug, parentSlug, - ...node.frontmatter, + unhideSelf, + ...node.frontmatter, }; if (!docData.title || docData.title === '') { @@ -72,7 +74,7 @@ exports.onCreateNode = async ({ node, getNode, getNodesByType, actions, createNo rawMarkdownBody: node.rawMarkdownBody, }), }; - const nodeData = { + const nodeData = { ...node, id: createNodeId(`SilverstripeDocument${node.id}`), ...docData, @@ -95,7 +97,7 @@ exports.createPages = async ({ actions, graphql }) => { slug } } - }`); + }`); if (result.errors) { @@ -111,6 +113,6 @@ exports.createPages = async ({ actions, graphql }) => { slug: node.slug, } }); - }) + }) -}; +}; diff --git a/src/components/ChildrenOf.tsx b/src/components/ChildrenOf.tsx index c0eccc6..e712342 100644 --- a/src/components/ChildrenOf.tsx +++ b/src/components/ChildrenOf.tsx @@ -11,7 +11,7 @@ const createCards = (children: SilverstripeDocument[]): ReactElement[] => {
- + {title} @@ -28,7 +28,7 @@ const createCards = (children: SilverstripeDocument[]): ReactElement[] => { }; const createList = (children: SilverstripeDocument[]): ReactElement[] => { - return children.map(({ summary, slug, title }) => { + return children.map(({ summary, slug, title }) => { return (
{title}
@@ -38,33 +38,40 @@ const createList = (children: SilverstripeDocument[]): ReactElement[] => { }); }; -const ChildrenOf: StatelessComponent = ({ folderName, exclude, currentNode, asList }) => { +const ChildrenOf: StatelessComponent = ({ folderName, exclude, only, currentNode, asList, includeFolders, reverse }) => { if (!currentNode) { return null; } - let children: ReactElement[] = []; - if (!folderName && !exclude) { - const sourceNodes = currentNode.isIndex ? getChildren(currentNode, false) : getSiblings(currentNode) - children = asList ? createList(sourceNodes) : createCards(sourceNodes); + + var nodes: SilverstripeDocument[] = []; + + if (!folderName && !exclude && !only) { + nodes = currentNode.isIndex ? getChildren(currentNode, false) : getSiblings(currentNode) + } else if (folderName) { const targetFolder = getChildren(currentNode, true).find( child => child.isIndex && child.fileTitle.toLowerCase() === folderName.toLowerCase() ); if (targetFolder) { - children = asList - ? createList(getChildren(targetFolder, false)) - : createCards(getChildren(targetFolder, false)); - } else { - children = []; + nodes = getChildren(targetFolder, false); } } else if (exclude) { const exclusions = exclude.split(',').map(e => e.toLowerCase()); - const nodes = getChildren(currentNode, false).filter( + nodes = getChildren(currentNode, includeFolders).filter( child => !exclusions.includes(child.fileTitle.toLowerCase()) ); - children = asList ? createList(nodes) : createCards(nodes); + } else if (only) { + const inclusions = only.split(',').map(e => e.toLowerCase()); + nodes = getChildren(currentNode, includeFolders).filter( + child => inclusions.includes(child.fileTitle.toLowerCase()) + ); } + if (reverse) { + nodes.reverse(); + } + let children: ReactElement[] = asList ? createList(nodes) : createCards(nodes); + return (
{asList && diff --git a/src/types/index.ts b/src/types/index.ts index 1e0881a..7e9e02e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -19,7 +19,7 @@ export interface SinglePage { webLink: string; } } - } + } }; @@ -33,6 +33,7 @@ export interface SilverstripeDocument { iconBrand?: string; hideChildren?: boolean; hideSelf?: boolean; + unhideSelf?: boolean; parentSlug: string; summary: string; fileTitle: string; @@ -48,6 +49,9 @@ export interface HierarchyQuery { export interface ChildrenOfProps { folderName?: string; exclude?: string; + only?: string; currentNode: SilverstripeDocument | null; asList?: boolean; + includeFolders?: boolean; + reverse?: boolean; }; diff --git a/src/utils/nodes.ts b/src/utils/nodes.ts index 83d8208..45a8912 100644 --- a/src/utils/nodes.ts +++ b/src/utils/nodes.ts @@ -31,6 +31,7 @@ const getNodes = (): SilverstripeDocument[] => { icon iconBrand hideChildren + unhideSelf slug parentSlug fileTitle @@ -49,9 +50,9 @@ const getNodes = (): SilverstripeDocument[] => { /** * Get the children of a given node - * + * * @param node - * @param includeFolders + * @param includeFolders */ const getChildren = ( node: SilverstripeDocument, @@ -75,8 +76,8 @@ const getChildren = ( /** * Get children of a given node that should be shown in navigation - * - * @param node + * + * @param node */ const getNavChildren = (node: SilverstripeDocument): SilverstripeDocument[] => { if (navChildrenMap.has(node.slug)) { @@ -87,6 +88,8 @@ const getNavChildren = (node: SilverstripeDocument): SilverstripeDocument[] => { children = getChildren(node, true).filter(n => !n.hideSelf); } + getChildren(node, true).filter(n => n.unhideSelf).forEach(c => children.push(c)); + navChildrenMap.set(node.slug, children); return navChildrenMap.get(node.slug); @@ -94,10 +97,10 @@ const getNavChildren = (node: SilverstripeDocument): SilverstripeDocument[] => { /** * Get the siblings of a given node - * - * @param node + * + * @param node */ -const getSiblings = (node: SilverstripeDocument): SilverstripeDocument[] => { +const getSiblings = (node: SilverstripeDocument): SilverstripeDocument[] => { if (siblingMap.has(node.slug)) { return siblingMap.get(node.slug); } @@ -111,7 +114,7 @@ const getSiblings = (node: SilverstripeDocument): SilverstripeDocument[] => { /** * Get the parent of a given node - * @param node + * @param node */ const getParent = (node: SilverstripeDocument): SilverstripeDocument | null => { if (parentMap.has(node.slug)) { @@ -154,7 +157,7 @@ const getCurrentVersion = (): string => __currentVersion || '4'; /** * Set the current node by its slug. - * @param slug + * @param slug */ const setCurrentNode = (slug: string): void => { const currentNode = getNodes().find(n => n.slug === slug) || null; diff --git a/src/utils/parseChildrenOf.ts b/src/utils/parseChildrenOf.ts index bbb02e7..9800426 100644 --- a/src/utils/parseChildrenOf.ts +++ b/src/utils/parseChildrenOf.ts @@ -9,23 +9,38 @@ import { getCurrentNode } from '../utils/nodes'; const parseChildrenOf = (data: any): ReactElement|false => { const currentNode = getCurrentNode(); let matches; - matches = data.match(/\[CHILDREN(\sasList)?\]/); - if (matches) { - const asList = !!matches[1]; - return createElement(ChildrenOf, { currentNode, asList }) - } matches = data.match(/\[CHILDREN Folder="?([A-Za-z0-9_<>\/]+)"?.*?\]/); if (matches) { const folderName = matches[1].replace(/<\/?em>/g, '_'); const asList = matches[0].match(' asList'); - return createElement(ChildrenOf, { folderName, currentNode, asList }) + const includeFolders = matches[0].match(' includeFolders'); + const reverse = matches[0].match(' reverse'); + return createElement(ChildrenOf, { folderName, currentNode, asList, includeFolders, reverse }) } matches = data.match(/\[CHILDREN Exclude="?([A-Za-z0-9_,]+)"?.*?\]/); if (matches) { const asList = matches[0].match(' asList'); + const includeFolders = matches[0].match(' includeFolders'); + const reverse = matches[0].match(' reverse'); const exclude = matches[1].replace(/<\/?em>/g, '_'); - return createElement(ChildrenOf, { exclude, currentNode, asList }) + return createElement(ChildrenOf, { exclude, currentNode, asList, includeFolders, reverse }) + } + matches = data.match(/\[CHILDREN Only="?([A-Za-z0-9_,]+)"?.*?\]/); + if (matches) { + const asList = matches[0].match(' asList'); + const includeFolders = matches[0].match(' includeFolders'); + const reverse = matches[0].match(' reverse'); + const only = matches[1].replace(/<\/?em>/g, '_'); + return createElement(ChildrenOf, { only, currentNode, asList, includeFolders, reverse }) + } + matches = data.match(/\[CHILDREN(\sasList)?.*?\]/); + if (matches) { + const asList = !!matches[1]; + const includeFolders = matches[0].match(' includeFolders'); + const reverse = matches[0].match(' reverse'); + + return createElement(ChildrenOf, { currentNode, asList, includeFolders, reverse }) } return false;