wip(org): Added blog post pages
This commit is contained in:
parent
8b7ea76325
commit
e47f47cf99
5 changed files with 142 additions and 24 deletions
|
@ -1,12 +1,14 @@
|
|||
import Page from 'shared/components/wrappers/page.js'
|
||||
import useApp from 'site/hooks/useApp.js'
|
||||
import strapiLoader from 'shared/strapi/loader'
|
||||
import { posts } from 'site/prebuild/strapi.blog.en.js'
|
||||
import TimeAgo from 'react-timeago'
|
||||
import MdxWrapper from 'shared/components/wrappers/mdx'
|
||||
import mdxCompiler from 'shared/mdx/compiler'
|
||||
import Markdown from 'react-markdown'
|
||||
import Head from 'next/head'
|
||||
import HelpUs from 'site/components/help-us.js'
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import { strapiHost } from 'shared/config/freesewing.mjs'
|
||||
import { strapiImage } from 'shared/utils.js'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
const strapi = "https://posts.freesewing.org"
|
||||
|
||||
|
@ -18,7 +20,7 @@ const Author = ({ author }) => (
|
|||
w-lg bg-cover bg-center rounded-full aspect-square
|
||||
hidden lg:block
|
||||
`}
|
||||
style={{backgroundImage: `url(${strapi}${author?.img})`}}
|
||||
style={{backgroundImage: `url(${strapiHost}${author?.image?.sizes?.small?.url})`}}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -26,10 +28,10 @@ const Author = ({ author }) => (
|
|||
<div className="theme-gradient p-2 rounded-full aspect-square w-40 h-40 lg:hidden m-auto">
|
||||
<img
|
||||
className={`block w-full h-full mx-auto rounded-full`}
|
||||
src={`${strapi}${author?.img}`}
|
||||
src={`${strapiHost}${author?.image?.sizes.small.url}`}
|
||||
alt={author?.displayname}
|
||||
width={author?.picture?.width}
|
||||
height={author?.picture?.height}
|
||||
width={author?.image?.sizes.small.w}
|
||||
height={author?.image?.sizes.small.h}
|
||||
/>
|
||||
</div>
|
||||
<div className={`
|
||||
|
@ -42,7 +44,7 @@ const Author = ({ author }) => (
|
|||
<span className="text-sm pl-2 opacity-70">Wrote this</span>
|
||||
</p>
|
||||
<div className="prose mdx">
|
||||
<Markdown>{author?.about}</Markdown>
|
||||
<MdxWrapper mdx={author?.mdx} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -80,7 +82,7 @@ const PostPage = ({ post, author }) => {
|
|||
</div>
|
||||
<figure>
|
||||
<img
|
||||
src={`${strapi}${post.image.formats.large.url}`}
|
||||
src={`${strapiHost}${post.image.url}`}
|
||||
alt={post.caption}
|
||||
className="shadow m-auto"
|
||||
/>
|
||||
|
@ -95,23 +97,66 @@ const PostPage = ({ post, author }) => {
|
|||
<div className="max-w-prose text-lg lg:text-xl">
|
||||
<Author author={author} />
|
||||
</div>
|
||||
<HelpUs blog slug={`/blog/${post.slug}`} />
|
||||
</article>
|
||||
<pre>{JSON.stringify(author, null ,2)}</pre>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
export const getStaticProps = async (props) => {
|
||||
const { post, author } = await strapiLoader('en', 'dev', 'blog', props.params.slug)
|
||||
/*
|
||||
* getStaticProps() is used to fetch data at build-time.
|
||||
*
|
||||
* On this page, it is loading the blog content from strapi.
|
||||
*
|
||||
* This, in combination with getStaticPaths() below means this
|
||||
* page will be used to render/generate all blog content.
|
||||
*
|
||||
* To learn more, see: https://nextjs.org/docs/basic-features/data-fetching
|
||||
*/
|
||||
export async function getStaticProps({ params, locale }) {
|
||||
|
||||
return { props: { post, author, slug: `blog/${props.params.slug}` } }
|
||||
const { slug } = params
|
||||
const post = await fetch(
|
||||
`${strapiHost}/blogposts?_locale=${locale}&dev_ne=true&slug_eq=${slug}`
|
||||
)
|
||||
.then(response => response.json())
|
||||
.then(data => data[0])
|
||||
.catch(err => console.log(err))
|
||||
|
||||
return {
|
||||
props: {
|
||||
post: {
|
||||
slug,
|
||||
...(await mdxCompiler(post.body)),
|
||||
title: post.title,
|
||||
linktitle: post.linktitle,
|
||||
date: post.date,
|
||||
caption: post.caption,
|
||||
image: {
|
||||
w: post.image.width,
|
||||
h: post.image.height,
|
||||
url: post.image.url
|
||||
},
|
||||
},
|
||||
author: {
|
||||
displayname: post.author.displayname,
|
||||
slug: post.author.slug,
|
||||
about: post.author.about,
|
||||
image: strapiImage(post.author.picture, ['small']),
|
||||
...(await mdxCompiler(post.author.about)),
|
||||
},
|
||||
...(await serverSideTranslations(locale)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getStaticPaths = async () => {
|
||||
const paths = []
|
||||
for (const post of posts) paths.push({
|
||||
params: {slug: post.slug}
|
||||
})
|
||||
const paths = await fetch(
|
||||
`${strapiHost}/blogposts?_locale=en&dev_ne=true`
|
||||
)
|
||||
.then(response => response.json())
|
||||
.then(data => data.map(post => ({ params: { slug: post.slug } })))
|
||||
.catch(err => console.log(err))
|
||||
|
||||
return {
|
||||
paths,
|
||||
|
@ -120,3 +165,4 @@ export const getStaticPaths = async () => {
|
|||
}
|
||||
|
||||
export default PostPage
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import rendertest from '@freesewing/rendertest'
|
|||
import tutorial from '@freesewing/tutorial'
|
||||
|
||||
|
||||
const mdxCustomComponents = (app, t) => ({
|
||||
const mdxCustomComponents = (app=false) => ({
|
||||
// Custom components
|
||||
Example: props => <Example
|
||||
{...props}
|
||||
|
|
|
@ -8,6 +8,8 @@ const currentChildren = current => Object.values(order(current))
|
|||
.filter(entry => (typeof entry === 'object'))
|
||||
|
||||
const ReadMore = props => {
|
||||
// Don't bother if we don't have the navigation tree in app
|
||||
if (!props.app) return null
|
||||
|
||||
const root = get(props.app.navigation, props.slug.split('/'))
|
||||
const list = []
|
||||
|
|
|
@ -38,12 +38,13 @@ const MdxWrapper = ({mdx, app, t, components={}}) => {
|
|||
// React component for MDX content
|
||||
const MdxContent = mdxModule ? mdxModule.default : Fragment
|
||||
|
||||
return (
|
||||
<div className="text-primary mdx max-w-prose text-base-content max-w-prose text-lg lg:text-xl">
|
||||
{mdxModule && <MdxContent components={allComponents}/>}
|
||||
<PrevNext app={app} />
|
||||
</div>
|
||||
)
|
||||
return app
|
||||
? (
|
||||
<div className="text-primary mdx max-w-prose text-base-content max-w-prose text-lg lg:text-xl">
|
||||
{mdxModule && <MdxContent components={allComponents}/>}
|
||||
<PrevNext app={app} />
|
||||
</div>
|
||||
) : <MdxContent components={allComponents}/>
|
||||
}
|
||||
|
||||
export default MdxWrapper
|
||||
|
|
69
packages/freesewing.shared/mdx/compiler.js
Normal file
69
packages/freesewing.shared/mdx/compiler.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
// MDX compiler
|
||||
import { compile } from '@mdx-js/mdx'
|
||||
|
||||
// Remark plugins we want to use
|
||||
import remarkFrontmatter from 'remark-frontmatter'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { remarkIntroPlugin } from './remark-intro-plugin.mjs'
|
||||
import smartypants from 'remark-smartypants'
|
||||
import mdxPluginToc from './mdx-plugin-toc.mjs'
|
||||
// Rehype plugins we want to use
|
||||
import rehypeHighlight from 'rehype-highlight'
|
||||
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
// Simple frontmatter extractor
|
||||
import frontmatter from 'front-matter'
|
||||
/*
|
||||
* Summary: Compiles the markdown it receives to MDX.
|
||||
*
|
||||
* @param (string) language - language to load (eg: 'en')
|
||||
* @param (string) site - site to load (either 'dev' or 'org')
|
||||
* @param (string) slug - slug of the page (eg: 'guides/patterns')
|
||||
*
|
||||
* @link https://mdxjs.com/guides/mdx-on-demand/
|
||||
*
|
||||
*/
|
||||
const mdxCompiler = async (md) => {
|
||||
|
||||
const intro = []
|
||||
const mdx = String(
|
||||
await compile(md, {
|
||||
outputFormat: 'function-body',
|
||||
remarkPlugins: [
|
||||
remarkFrontmatter,
|
||||
remarkGfm,
|
||||
smartypants,
|
||||
[
|
||||
remarkIntroPlugin,
|
||||
{ intro }
|
||||
]
|
||||
],
|
||||
rehypePlugins: [
|
||||
[rehypeHighlight, { plainText: ['dot', 'http'] }],
|
||||
rehypeSlug,
|
||||
rehypeAutolinkHeadings,
|
||||
],
|
||||
})
|
||||
)
|
||||
|
||||
// This is not ideal as we're adding a second pass but for now it will do
|
||||
// See: https://github.com/remarkjs/remark-toc/issues/37
|
||||
const toc = String(
|
||||
await compile(md, {
|
||||
outputFormat: 'function-body',
|
||||
remarkPlugins: [
|
||||
remarkFrontmatter,
|
||||
remarkGfm,
|
||||
smartypants,
|
||||
mdxPluginToc,
|
||||
],
|
||||
rehypePlugins: [
|
||||
rehypeSlug,
|
||||
],
|
||||
})
|
||||
)
|
||||
|
||||
return { mdx, intro, toc, frontmatter: frontmatter(md)?.attributes }
|
||||
}
|
||||
|
||||
export default mdxCompiler
|
Loading…
Add table
Add a link
Reference in a new issue