From 1a90dbba097ae394e779c9521906f46aa96cb71e Mon Sep 17 00:00:00 2001 From: Jan Florian Dietrich Date: Wed, 13 Feb 2019 17:52:27 +0100 Subject: [PATCH] fix(#21): create pages for each image --- gatsby-node.js | 134 +++++++++++++++++++++++++-------- src/components/Layout/index.js | 2 +- src/templates/gallery.js | 33 ++++---- src/utils/fragments.js | 8 +- src/utils/mappings.js | 30 +++----- 5 files changed, 137 insertions(+), 70 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 5b3a6a9..2ca28f9 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,16 +1,26 @@ const path = require('path'); -const { pathOr, prop, ifElse, identity, has } = require('rambda'); +const { pathOr, prop, ifElse, identity, has, map } = require('rambda'); const galleryTemplate = path.resolve(`src/templates/gallery.js`); const pipe = (...fns) => input => fns.reduce((chain, func) => chain.then(func), Promise.resolve(input)); -// NOTE: does not guard against 0 args -const unary = fn => (...args) => fn(args[0]); +const handleError = error => { + throw new Error(error); +}; + +const handleGraphQlQueryErrors = ifElse( + has('errors'), + pipe( + prop('errors'), + handleError + ), + identity +); -// NOTE: cannot be pulled out and rused because of the diverging es6/common.js exports in `src` vs. here +// NOTE: cannot be pulled out and reused because of the diverging es6/common.js exports in `src` vs. here const queryGalleries = graphql => () => graphql(` query GalleriesQuery { @@ -19,53 +29,113 @@ const queryGalleries = graphql => () => node { folderName path + title } } } } `); -const mapGalleriesToPage = galleries => - galleries.map(gallery => { - const { - node: { folderName, path }, - } = gallery; - - return { - path: `${path}/*`, - component: galleryTemplate, - context: { folderName }, - }; - }); - -const handleError = error => { - throw new Error(error); -}; +const extractGalleryData = galleries => + galleries.map(({ node: { folderName, path, title } }) => ({ + folderName, + path, + title, + })); -const handleGraphQlQueryErrors = ifElse( - has('errors'), +const getAllGalleries = ({ graphql }) => pipe( - prop('errors'), - handleError - ), - identity + queryGalleries(graphql), + handleGraphQlQueryErrors, + pathOr([], 'data.allGalleriesYaml.edges'), + extractGalleryData + ); + +const queryImagesForGallery = ({ graphql }) => ({ folderName }) => + graphql( + ` + query GalleryQuery($folderName: String!) { + allFile( + filter: { relativeDirectory: { eq: $folderName } } + sort: { fields: [relativePath] } + ) { + edges { + node { + childImageSharp { + internal { + contentDigest + } + } + } + } + } + } + `, + { + folderName, + } + ); + +const extractImagesData = pipe( + pathOr([], 'data.allFile.edges'), + map(pathOr(undefined, 'node.childImageSharp.internal.contentDigest')) ); -const getAllGalleriesAndImages = ({ graphql }) => +const getImagesForGalleries = ({ graphql }) => pipe( - queryGalleries(graphql), + queryImagesForGallery({ graphql }), handleGraphQlQueryErrors, - pathOr([], 'data.allGalleriesYaml.edges'), - mapGalleriesToPage + extractImagesData ); +const getCreatePagePayload = ({ + path, + basePath, + title, + folderName, + initialId, +}) => ({ + path, + component: galleryTemplate, + context: { + pathname: basePath, + initialId, + folderName, + title, + }, +}); + exports.createPages = async ({ actions, graphql }) => { const { createPage } = actions; try { - const galleries = await getAllGalleriesAndImages({ graphql })(); + const galleries = await getAllGalleries({ graphql })(); + + galleries.forEach(async gallery => { + const { path, title, folderName } = gallery; + const imageIds = await getImagesForGalleries({ graphql })(gallery); + + const createPagePayload = getCreatePagePayload({ + path: `${path}`, + basePath: path, + title, + folderName, + }); + + imageIds.forEach(contentDigest => + createPage( + getCreatePagePayload({ + path: `${path}/${contentDigest}`, + basePath: path, + title, + folderName, + initialId: contentDigest, + }) + ) + ); - galleries.forEach(unary(createPage)); + createPage(createPagePayload); + }); } catch (err) { throw err; } diff --git a/src/components/Layout/index.js b/src/components/Layout/index.js index b760865..c98b4b0 100644 --- a/src/components/Layout/index.js +++ b/src/components/Layout/index.js @@ -77,7 +77,7 @@ LayoutComponent.displayName = 'LayoutComponent'; const pageQuery = graphql` query GalleriesQuery { - ...allGalleriesYamlFragment + ...AllGalleriesYamlFragment } `; diff --git a/src/templates/gallery.js b/src/templates/gallery.js index dda97b4..3c99289 100644 --- a/src/templates/gallery.js +++ b/src/templates/gallery.js @@ -7,17 +7,14 @@ import KeyHandler from 'react-key-handler'; import { compose, mapProps } from 'recompose'; import styled, { createGlobalStyle } from 'styled-components'; import { themeGet } from 'styled-system'; -import { pathOr, pipe, replace, path } from 'rambda'; +import { path } from 'rambda'; import { ReactComponent as PrevIcon } from 'assets/prev.svg'; import { ReactComponent as NextIcon } from 'assets/next.svg'; import { locationType, imageType } from 'utils/types'; import { useGallery } from 'utils/hooks'; import { ContentContainer, Layout } from 'components'; -import { - mapGalleryImagesGraphQLResponse, - mapSingleGalleryYamlGraphQLResponse, -} from 'utils/mappings'; +import { mapGalleryImagesGraphQLResponse } from 'utils/mappings'; import { mediaScreen } from '../theme'; @@ -103,8 +100,8 @@ const StyledNextIcon = styled(NextIcon)` width: ${themeGet('space.5')}; `; -const getImageUrl = ({ pathname = '/portraits/', id }) => - `${pathname}${id ? `#${id}` : ''}`; +const getImageUrl = ({ pathname = '/portraits', id }) => + `${pathname}/${id ? `${id}` : ''}`; export const Gallery = ({ images, title, location, pathname, initialId }) => { const { currentId, nextId, prevId } = useGallery({ @@ -158,28 +155,34 @@ Gallery.propTypes = { images: PropTypes.arrayOf(imageType).isRequired, title: PropTypes.string.isRequired, location: locationType.isRequired, - initialId: PropTypes.string.isRequired, + initialId: PropTypes.string, pathname: PropTypes.string.isRequired, }; +Gallery.defaultProps = { + initialId: undefined, +}; + Gallery.displayName = 'Gallery'; export default compose( mapProps(props => ({ ...props, images: mapGalleryImagesGraphQLResponse(props), - title: mapSingleGalleryYamlGraphQLResponse(props), - pathname: path('location.pathname')(props), - initialId: pipe( - pathOr('', 'location.hash'), - replace('#', '') - )(props), + title: path('pageContext.title', props), + pathname: path('pageContext.pathname', props), + initialId: path('pageContext.initialId', props), })) )(Gallery); +/** + * NOTE: experimented with passing the `contentDigest`-ids here and getting them with `allImageSharp` + * in order to not query twice -> did not work because the correct ordering could not be applied + * without the relation to the filepath and manual ordering felt unexpected + */ export const pageQuery = graphql` query Gallery($folderName: String!) { - ...singleGalleryYamlFragment + ...SingleGalleryYamlFragment allFile( filter: { relativeDirectory: { eq: $folderName } } sort: { fields: [relativePath] } diff --git a/src/utils/fragments.js b/src/utils/fragments.js index 6e0e1e5..f35eb65 100644 --- a/src/utils/fragments.js +++ b/src/utils/fragments.js @@ -16,8 +16,8 @@ export const GalleryImagesFragment = graphql` } `; -export const allGalleriesYamlFragment = graphql` - fragment allGalleriesYamlFragment on Query { +export const AllGalleriesYamlFragment = graphql` + fragment AllGalleriesYamlFragment on Query { allGalleriesYaml(sort: { fields: [order] }) { group(field: album) { fieldValue @@ -32,8 +32,8 @@ export const allGalleriesYamlFragment = graphql` } `; -export const singleGalleryYamlFragment = graphql` - fragment singleGalleryYamlFragment on Query { +export const SingleGalleryYamlFragment = graphql` + fragment SingleGalleryYamlFragment on Query { galleriesYaml(folderName: { eq: $folderName }) { title } diff --git a/src/utils/mappings.js b/src/utils/mappings.js index f0ac8ee..82de7f4 100644 --- a/src/utils/mappings.js +++ b/src/utils/mappings.js @@ -1,9 +1,9 @@ -import { path, pathOr, pipe } from 'rambda'; +import { path, pathOr, pipe, map } from 'rambda'; const flattenAllGalleriesGraphQLResponse = response => response.map(({ fieldValue: albumTitle, edges: galleries }) => ({ albumTitle, - galleries: galleries.map(gallery => gallery.node), + galleries: galleries.map(path('node')), })); export const mapAllGalleriesGraphQLResponse = pipe( @@ -11,23 +11,17 @@ export const mapAllGalleriesGraphQLResponse = pipe( flattenAllGalleriesGraphQLResponse ); -const flattenGalleryImagesGraphQLResponse = response => - response - .filter(item => item.node && item.node.childImageSharp) - .map( - ({ - node: { - childImageSharp: { - fluid, - internal: { contentDigest }, - }, - }, - }) => ({ fluid, contentDigest }) - ); - export const mapGalleryImagesGraphQLResponse = pipe( - path('data.allFile.edges'), - flattenGalleryImagesGraphQLResponse + pathOr([], 'data.allFile.edges'), + map( + pipe( + pathOr([], 'node.childImageSharp'), + img => ({ + fluid: img.fluid, + contentDigest: path('internal.contentDigest', img), + }) + ) + ) ); export const mapSingleGalleryYamlGraphQLResponse = path(