Upload starter template
This commit is contained in:
26
lib/generate-rss.js
Normal file
26
lib/generate-rss.js
Normal file
@ -0,0 +1,26 @@
|
||||
import siteMetadata from '@/data/siteMetadata'
|
||||
|
||||
const generateRssItem = (post) => `
|
||||
<item>
|
||||
<guid>${siteMetadata.siteUrl}${post.slug}</guid>
|
||||
<title>${post.title}</title>
|
||||
<link>${siteMetadata.siteUrl}${post.slug}</link>
|
||||
<description>${post.summary}</description>
|
||||
<pubDate>${new Date(post.date).toUTCString()}</pubDate>
|
||||
</item>
|
||||
`
|
||||
|
||||
const generateRss = (posts) => `
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>${siteMetadata.title}</title>
|
||||
<link>${siteMetadata.siteUrl}/blog</link>
|
||||
<description>${siteMetadata.description}</description>
|
||||
<language>${siteMetadata.language}</language>
|
||||
<lastBuildDate>${new Date(posts[0].date).toUTCString()}</lastBuildDate>
|
||||
<atom:link href="${siteMetadata.siteUrl}/index.xml" rel="self" type="application/rss+xml"/>
|
||||
${posts.map(generateRssItem).join('')}
|
||||
</channel>
|
||||
</rss>
|
||||
`
|
||||
export default generateRss
|
32
lib/img-to-jsx.js
Normal file
32
lib/img-to-jsx.js
Normal file
@ -0,0 +1,32 @@
|
||||
const visit = require('unist-util-visit')
|
||||
const sizeOf = require('image-size')
|
||||
const fs = require('fs')
|
||||
|
||||
module.exports = (options) => (tree) => {
|
||||
visit(
|
||||
tree,
|
||||
// only visit p tags that contain an img element
|
||||
(node) => node.type === 'paragraph' && node.children.some((n) => n.type === 'image'),
|
||||
(node) => {
|
||||
const imageNode = node.children.find((n) => n.type === 'image')
|
||||
|
||||
// only local files
|
||||
if (fs.existsSync(`${process.cwd()}/public${imageNode.url}`)) {
|
||||
const dimensions = sizeOf(`${process.cwd()}/public${imageNode.url}`)
|
||||
|
||||
// Convert original node to next/image
|
||||
imageNode.type = 'jsx'
|
||||
imageNode.value = `<Image
|
||||
alt={\`${imageNode.alt}\`}
|
||||
src={\`${imageNode.url}\`}
|
||||
width={${dimensions.width}}
|
||||
height={${dimensions.height}}
|
||||
/>`
|
||||
|
||||
// Change node type from p to div to avoid nesting error
|
||||
node.type = 'div'
|
||||
node.children = [imageNode]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
101
lib/mdx.js
Normal file
101
lib/mdx.js
Normal file
@ -0,0 +1,101 @@
|
||||
import fs from 'fs'
|
||||
import matter from 'gray-matter'
|
||||
import visit from 'unist-util-visit'
|
||||
import path from 'path'
|
||||
import readingTime from 'reading-time'
|
||||
import renderToString from 'next-mdx-remote/render-to-string'
|
||||
|
||||
import MDXComponents from '@/components/MDXComponents'
|
||||
import imgToJsx from './img-to-jsx'
|
||||
|
||||
const root = process.cwd()
|
||||
|
||||
const tokenClassNames = {
|
||||
tag: 'text-code-red',
|
||||
'attr-name': 'text-code-yellow',
|
||||
'attr-value': 'text-code-green',
|
||||
deleted: 'text-code-red',
|
||||
inserted: 'text-code-green',
|
||||
punctuation: 'text-code-white',
|
||||
keyword: 'text-code-purple',
|
||||
string: 'text-code-green',
|
||||
function: 'text-code-blue',
|
||||
boolean: 'text-code-red',
|
||||
comment: 'text-gray-400 italic',
|
||||
}
|
||||
|
||||
export async function getFiles(type) {
|
||||
return fs.readdirSync(path.join(root, 'data', type))
|
||||
}
|
||||
|
||||
export function dateSortDesc(a, b) {
|
||||
if (a > b) return -1
|
||||
if (a < b) return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
export async function getFileBySlug(type, slug) {
|
||||
const mdxPath = path.join(root, 'data', type, `${slug}.mdx`)
|
||||
const mdPath = path.join(root, 'data', type, `${slug}.md`)
|
||||
const source = fs.existsSync(mdxPath)
|
||||
? fs.readFileSync(mdxPath, 'utf8')
|
||||
: fs.readFileSync(mdPath, 'utf8')
|
||||
|
||||
const { data, content } = matter(source)
|
||||
const mdxSource = await renderToString(content, {
|
||||
components: MDXComponents,
|
||||
mdxOptions: {
|
||||
remarkPlugins: [
|
||||
require('remark-slug'),
|
||||
require('remark-autolink-headings'),
|
||||
require('remark-code-titles'),
|
||||
require('remark-math'),
|
||||
imgToJsx,
|
||||
],
|
||||
inlineNotes: true,
|
||||
rehypePlugins: [
|
||||
require('rehype-katex'),
|
||||
require('@mapbox/rehype-prism'),
|
||||
() => {
|
||||
return (tree) => {
|
||||
visit(tree, 'element', (node, index, parent) => {
|
||||
let [token, type] = node.properties.className || []
|
||||
if (token === 'token') {
|
||||
node.properties.className = [tokenClassNames[type]]
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
mdxSource,
|
||||
frontMatter: {
|
||||
wordCount: content.split(/\s+/gu).length,
|
||||
readingTime: readingTime(content),
|
||||
slug: slug || null,
|
||||
...data,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAllFilesFrontMatter(type) {
|
||||
const files = fs.readdirSync(path.join(root, 'data', type))
|
||||
|
||||
const allFrontMatter = files.reduce((allPosts, postSlug) => {
|
||||
const source = fs.readFileSync(path.join(root, 'data', type, postSlug), 'utf8')
|
||||
const { data } = matter(source)
|
||||
|
||||
return [
|
||||
{
|
||||
...data,
|
||||
slug: postSlug.replace(/\.(mdx|md)/, ''),
|
||||
},
|
||||
...allPosts,
|
||||
]
|
||||
}, [])
|
||||
|
||||
return allFrontMatter.sort((a, b) => dateSortDesc(a.date, b.date))
|
||||
}
|
29
lib/tags.js
Normal file
29
lib/tags.js
Normal file
@ -0,0 +1,29 @@
|
||||
import fs from 'fs'
|
||||
import matter from 'gray-matter'
|
||||
import path from 'path'
|
||||
import kebabCase from 'just-kebab-case'
|
||||
|
||||
const root = process.cwd()
|
||||
|
||||
export async function getAllTags(type) {
|
||||
const files = fs.readdirSync(path.join(root, 'data', type))
|
||||
|
||||
let tagCount = {}
|
||||
// Iterate through each post, putting all found tags into `tags`
|
||||
files.forEach((file) => {
|
||||
const source = fs.readFileSync(path.join(root, 'data', type, file), 'utf8')
|
||||
const { data } = matter(source)
|
||||
if (data.tags) {
|
||||
data.tags.forEach((tag) => {
|
||||
const formattedTag = kebabCase(tag)
|
||||
if (formattedTag in tagCount) {
|
||||
tagCount[formattedTag] += 1
|
||||
} else {
|
||||
tagCount[formattedTag] = 1
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return tagCount
|
||||
}
|
Reference in New Issue
Block a user