mirror of
https://github.com/kremalicious/blog.git
synced 2024-12-22 17:23:50 +01:00
255 lines
5.7 KiB
JavaScript
255 lines
5.7 KiB
JavaScript
const path = require('path')
|
|
const { createFilePath } = require('gatsby-source-filesystem')
|
|
const fastExif = require('fast-exif')
|
|
const Fraction = require('fraction.js')
|
|
const dms2dec = require('dms2dec')
|
|
const { itemsPerPage } = require('./config')
|
|
|
|
const redirects = [
|
|
{ f: '/feed', t: '/feed.xml' },
|
|
{ f: '/feed/', t: '/feed.xml' }
|
|
]
|
|
|
|
exports.onCreateNode = ({ node, actions, getNode }) => {
|
|
const { createNodeField } = actions
|
|
|
|
// Markdown files
|
|
if (node.internal.type === 'MarkdownRemark') {
|
|
createMarkdownNodeFields(node, createNodeField, getNode)
|
|
}
|
|
|
|
// Image files
|
|
if (node.internal.mediaType === 'image/jpeg') {
|
|
readAndCreateExifFields(node, createNodeField)
|
|
}
|
|
}
|
|
|
|
// Create slug & date for posts from file path values
|
|
const createMarkdownNodeFields = (node, createNodeField, getNode) => {
|
|
const fileNode = getNode(node.parent)
|
|
const parsedFilePath = path.parse(fileNode.relativePath)
|
|
const slugOriginal = createFilePath({ node, getNode })
|
|
|
|
// slug
|
|
let slug
|
|
|
|
if (parsedFilePath.name === 'index') {
|
|
slug = `/${parsedFilePath.dir.substring(11)}` // remove date from file dir
|
|
} else {
|
|
slug = `/${slugOriginal.substring(12)}` // remove first slash & date from file path
|
|
}
|
|
|
|
createNodeField({
|
|
node,
|
|
name: 'slug',
|
|
value: slug
|
|
})
|
|
|
|
// date
|
|
let date
|
|
|
|
if (node.frontmatter.date) {
|
|
date = `${node.frontmatter.date}`
|
|
} else {
|
|
date = `${slugOriginal.substring(1, 10)}` // grab date from file path
|
|
}
|
|
|
|
createNodeField({
|
|
node,
|
|
name: 'date',
|
|
value: date
|
|
})
|
|
}
|
|
|
|
const readAndCreateExifFields = (node, createNodeField) => {
|
|
fastExif
|
|
.read(node.absolutePath, true)
|
|
.then(exifData => {
|
|
if (!exifData) return
|
|
createExifFields(exifData, createNodeField, node)
|
|
})
|
|
.catch(() => null) // just silently fail when exif can't be extracted
|
|
}
|
|
|
|
const createExifFields = (exifData, createNodeField, node) => {
|
|
const { Model } = exifData.image
|
|
const {
|
|
ISO,
|
|
FNumber,
|
|
ExposureTime,
|
|
FocalLength,
|
|
ExposureBiasValue
|
|
} = exifData.exif
|
|
const {
|
|
GPSLatitudeRef,
|
|
GPSLatitude,
|
|
GPSLongitudeRef,
|
|
GPSLongitude
|
|
} = exifData.gps
|
|
|
|
const { n, d } = new Fraction(ExposureTime)
|
|
const exposureShortened = parseFloat(ExposureBiasValue.toFixed(2))
|
|
|
|
const model = `${Model}`
|
|
const iso = `ISO ${ISO}`
|
|
const fstop = `ƒ ${FNumber}`
|
|
const shutterspeed = `${n}/${d}s`
|
|
const focalLength = `${FocalLength}mm`
|
|
|
|
const GPSdec = dms2dec(
|
|
GPSLatitude,
|
|
GPSLatitudeRef,
|
|
GPSLongitude,
|
|
GPSLongitudeRef
|
|
)
|
|
|
|
const latitude = GPSdec[0]
|
|
const longitude = GPSdec[1]
|
|
|
|
let exposure
|
|
|
|
if (ExposureBiasValue === 0) {
|
|
exposure = `+/- ${exposureShortened} ev`
|
|
} else if (ExposureBiasValue > 0) {
|
|
exposure = `+ ${exposureShortened} ev`
|
|
} else {
|
|
exposure = `${exposureShortened} ev`
|
|
}
|
|
|
|
// add exif fields to type File
|
|
createNodeField({
|
|
node,
|
|
name: 'exif',
|
|
value: {
|
|
iso,
|
|
model,
|
|
fstop,
|
|
shutterspeed,
|
|
focalLength,
|
|
exposure,
|
|
gps: {
|
|
latitude,
|
|
longitude
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
exports.createPages = ({ graphql, actions }) => {
|
|
const { createPage, createRedirect } = actions
|
|
|
|
return new Promise((resolve, reject) => {
|
|
resolve(
|
|
graphql(
|
|
`
|
|
{
|
|
allMarkdownRemark(sort: { fields: [fields___date], order: DESC }) {
|
|
edges {
|
|
node {
|
|
fields {
|
|
slug
|
|
date
|
|
}
|
|
frontmatter {
|
|
type
|
|
tags
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`
|
|
).then(result => {
|
|
if (result.errors) {
|
|
/* eslint no-console: "off" */
|
|
console.log(result.errors)
|
|
reject(result.errors)
|
|
}
|
|
|
|
const posts = result.data.allMarkdownRemark.edges
|
|
const numPages = Math.ceil(posts.length / itemsPerPage)
|
|
|
|
// Generate posts & posts index
|
|
generateContent(createPage, posts, numPages)
|
|
|
|
// Generate Tag Pages
|
|
generateTagPages(createPage, posts, numPages)
|
|
|
|
// create manual redirects
|
|
redirects.forEach(({ f, t }) => {
|
|
createRedirect({
|
|
fromPath: f,
|
|
redirectInBrowser: true,
|
|
toPath: t
|
|
})
|
|
})
|
|
|
|
resolve()
|
|
})
|
|
)
|
|
})
|
|
}
|
|
|
|
const postsTemplate = path.resolve('src/templates/Posts.jsx')
|
|
|
|
const generateContent = (createPage, posts, numPages) => {
|
|
const postTemplate = path.resolve('src/templates/Post.jsx')
|
|
|
|
// Create Post pages
|
|
posts.forEach(post => {
|
|
createPage({
|
|
path: `${post.node.fields.slug}`,
|
|
component: postTemplate,
|
|
context: {
|
|
slug: post.node.fields.slug
|
|
}
|
|
})
|
|
})
|
|
|
|
// Create paginated Blog index pages
|
|
Array.from({ length: numPages }).forEach((_, i) => {
|
|
createPage({
|
|
path: i === 0 ? '/' : `/page/${i + 1}`,
|
|
component: postsTemplate,
|
|
context: {
|
|
limit: itemsPerPage,
|
|
skip: i * itemsPerPage,
|
|
numPages,
|
|
currentPageNumber: i + 1,
|
|
prevPage: i - 1,
|
|
nextPage: i + 2
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
const generateTagPages = (createPage, posts) => {
|
|
const tagList = arrayReducer(posts, 'tags')
|
|
|
|
tagList.forEach(tag => {
|
|
if (tag === 'goodies') return
|
|
|
|
// Create tag pages
|
|
createPage({
|
|
path: `/tags/${tag}/`,
|
|
component: postsTemplate,
|
|
context: { tag }
|
|
})
|
|
})
|
|
}
|
|
|
|
// https://www.adamjberkowitz.com/tags-and-categories-in-gatsby-js/
|
|
const arrayReducer = (postsArray, type) => {
|
|
return (postsArray = postsArray
|
|
.map(({ node }) => {
|
|
return node.frontmatter[type]
|
|
})
|
|
.reduce((a, b) => {
|
|
return a.concat(b)
|
|
}, [])
|
|
.filter((type, index, array) => {
|
|
return array.indexOf(type) === index
|
|
})
|
|
.sort())
|
|
}
|