UNPKG

gatsby-theme-try-ghost

Version:

A Gatsby theme for building flaring fast blogs from headless Ghost CMS.

292 lines (243 loc) 10.3 kB
const _ = require(`lodash`) const { resolveUrl } = require(`./src/utils/routing`) const { createContentDigest } = require(`gatsby-core-utils`) const mediaConfigDefaults = require(`./src/utils/mediaConfigDefaults`) const gatsbyNodeQuery = require(`./src/utils/gatsbyNodeQuery`) const paginate = require(`./src/utils/pagination`) const infiniteScroll = require(`./src/utils/infinite-scroll`) exports.createSchemaCustomization = require(`./src/utils/create-schema-customization`) exports.setFieldsOnGraphQLNodeType = require(`./src/utils/extend-node-type`) // Simple logging const useLog = (reporter, verbose, severity) => (message) => { verbose && reporter[severity](message) } // Create pages const createOrdinaryPages = (createOptions, pages, template) => { const { createPage, basePath, log } = createOptions pages.forEach(({ node }) => { // Use url to analyze routing structure coming from Ghost CMS const url = resolveUrl(basePath, `/`, node.slug, node.url) createPage({ path: url, component: template, context: { // Data passed to context is available // in page queries as GraphQL variables. slug: node.slug, }, }) }) log(`createOrdinaryPages: finished`) } // Create post pages const createPostPages = (createOptions, posts, tags, template, ampPath = ``) => { const { createPage, log, basePath } = createOptions const prevNodes = _.concat([{ node: { slug: `` } }],_.dropRight(posts)) const nextNodes = _.concat(_.drop(posts),[{ node: { slug: `` } }]) const collectionPaths = getCollectionPaths(posts.map(({ node }) => node.id), posts) log(`createPostPages: ${posts.length > 0 && posts[0].node.title}`) posts.forEach(({ node }, i) => { const collectionPath = collectionPaths[node.id] const url = resolveUrl(basePath, collectionPath, node.slug, node.url) //total number of posts for primary tag let primaryTagCount = _.find(tags, function (t) { return node.primary_tag && t.node.slug === node.primary_tag.slug }) primaryTagCount = primaryTagCount && primaryTagCount.node && primaryTagCount.node.postCount !== null ? primaryTagCount.node.postCount : 0 createPage({ path: `${url}${ampPath}`, component: template, context: { slug: node.slug, prev: prevNodes[i].node.slug, next: nextNodes[i].node.slug, tag: node.primary_tag && node.primary_tag.slug || ``, limit: 3, skip: 0, primaryTagCount: primaryTagCount, collectionPaths: collectionPaths, }, }) }) log(`createPostPages: finished`) } // Create index page with pagination const createIndexPage = (createOptions, posts, postIds, template, collectionPath = `/`) => { const { createPage, log, basePath, iScrollEnabled, postsPerPage } = createOptions const path = resolveUrl(basePath, collectionPath) log(`createIndexPage: ${posts.length > 0 && posts[0].node.title}`) paginate({ createPage, totalItems: posts.length, itemsPerPage: postsPerPage, component: template, pathPrefix: ({ pageNumber }) => ( pageNumber === 0 ? path : `${path}page` ), context: { collectionPath: collectionPath, // Infinite Scroll iScrollEnabled: iScrollEnabled, postIds: postIds, cursor: 0, }, }) log(`createIndexPage: finished`) } // Create taxonomy pages (tags, authors) const createTaxonomyPages = (createOptions, taxonomy, postIds, template, allPosts) => { const { createPage, log, basePath, iScrollEnabled, postsPerPage } = createOptions taxonomy.forEach(({ node }) => { // Use url to analyze routing structure coming from Ghost CMS const url = resolveUrl(basePath, `/`, node.slug, node.url) const collectionPaths = getCollectionPaths(postIds[node.slug], allPosts) paginate({ createPage, totalItems: node.postCount, itemsPerPage: postsPerPage, component: template, pathPrefix: ({ pageNumber }) => ( pageNumber === 0 ? url : `${url}page` ), context: { slug: node.slug, collectionPaths: collectionPaths, // Infinite Scroll iScrollEnabled: iScrollEnabled, postIds: postIds[node.slug], cursor: 0, }, }) }) log(`createTaxonomyPages: finished`) } /** * Collections: Unique group of routes * */ const createCollection = (createOptions, data, templates, allTags, collectionPath) => { const { iScrollEnabled } = createOptions // per collectionPath createPostPages(createOptions, data.posts, allTags, templates.post) const { indexIds } = infiniteScroll(iScrollEnabled, data.posts) createIndexPage(createOptions, data.posts, indexIds, templates.index, collectionPath) } const getCollection = (data, collectionPath, selector = () => false) => { const collection = data.posts.filter(({ node }) => selector(node)) collection.forEach(({ node }) => node.collectionPath = collectionPath) const residualPosts = data.posts.filter(({ node }) => !selector(node)) residualPosts.forEach(({ node }) => node.collectionPath = `/`) return ({ primary: { posts: collection, }, residual: { posts: residualPosts, }, }) } const getCollectionPaths = (ids, posts) => { const paths = {} ids.forEach((id) => { paths[id] = posts.find(({ node }) => node.id === id).node.collectionPath }) return paths } const calcPostCounts = (data) => { data.tags.forEach(({ node: tag }) => { tag.postCount = data.posts.filter(({ node }) => node.tags.find(t => t.slug === tag.slug) !== undefined).length }) data.authors.forEach(({ node: author }) => { author.postCount = data.posts.filter(({ node }) => node.authors.find(a => a.slug === author.slug) !== undefined).length }) } /** * Here is the place where Gatsby creates the URLs for all the * posts, tags, pages and authors that we fetched from the Ghost site. */ exports.createPages = async ({ graphql, actions, reporter }, themeOptions) => { const { createPage } = actions const { routes, siteConfig } = themeOptions const { verbose, severity, infiniteScroll: iScrollEnabled, excludePostsOrPages = (() => false) } = siteConfig const basePath = routes && routes.basePath || `/` const collections = routes && routes.collections || [] const log = useLog(reporter, verbose, severity) /* Fragment are not yet possible here */ /* Further info 👉🏼 https://github.com/gatsbyjs/gatsby/issues/12155 */ const result = await graphql(`${gatsbyNodeQuery}`) // Check for any errors if (result.errors) { throw new Error(result.errors) } log(`GraphQL data sucessfully fetched`) // Extract query results const postsPerPage = result.data.site.siteMetadata.postsPerPage const createOptions = { createPage, log, basePath, iScrollEnabled, postsPerPage } const data = { pages: result.data.allGhostPage.edges, posts: result.data.allGhostPost.edges, tags: result.data.allGhostTag.edges, authors: result.data.allGhostAuthor.edges, } // exclude posts or pages data.posts = data.posts.filter(({ node }) => !excludePostsOrPages(node)) data.pages = data.pages.filter(({ node }) => !excludePostsOrPages(node)) calcPostCounts(data) log(`createPages: ${data.posts.length > 0 && data.posts[0].node.title}`) // Load templates const templates = { page: require.resolve(`./src/templates/page.js`), post: require.resolve(`./src/templates/post.js`), index: require.resolve(`./src/templates/index.js`), tag: require.resolve(`./src/templates/tag.js`), author: require.resolve(`./src/templates/author.js`), } createOrdinaryPages(createOptions, data.pages, templates.page) // Split index pages by collections let collectionData = data collections.forEach((collection) => { collectionData = getCollection(collectionData, collection.path, collection.selector) createCollection(createOptions, collectionData.primary, templates, data.tags, collection.path) collectionData = collectionData.residual }) createCollection(createOptions, collectionData, templates, data.tags) // Taxonomies are not split by collections const { tagIds, authorIds } = infiniteScroll(iScrollEnabled, data.posts) // Only use tags, authors present in posts (page only tags should not create tag/author pages) const postTags = data.tags.filter(({ node }) => (node.postCount > 0 && node.slug.substr(0,5) !== `hash-`)) const postAuthors = data.authors.filter(({ node }) => node.postCount > 0) createTaxonomyPages(createOptions, postTags, tagIds, templates.tag, data.posts) createTaxonomyPages(createOptions, postAuthors, authorIds, templates.author, data.posts) log(`createPages finished`) } // Plugins can access basePath with GraphQL query exports.sourceNodes = ({ actions: { createTypes, createNode } }, { routes = {}, mediaConfig }) => { const { basePath = `/` } = routes const { gatsbyImageLoading, gatsbyImageFadeIn } = _.merge({}, mediaConfigDefaults, mediaConfig) createTypes(` type GhostConfig implements Node @dontinfer { basePath: String! gatsbyImageLoading: String gatsbyImageFadeIn: Boolean } `) const config = { basePath: resolveUrl(basePath), gatsbyImageLoading, gatsbyImageFadeIn, } createNode({ ...config, id: `gatsby-theme-try-ghost-config`, parent: null, children: [], internal: { type: `ghostConfig`, contentDigest: createContentDigest(config), content: JSON.stringify(config), description: `Ghost Config`, }, }) }