1
0
Fork 0
This commit is contained in:
Enoch Riese 2023-07-19 21:11:59 -06:00
parent a88ae25e57
commit b7fcd80cae
10 changed files with 175 additions and 34 deletions

View file

@ -19,8 +19,10 @@ import { PrevNext } from 'shared/components/prev-next.mjs'
export const ns = [navNs, 'docs'] //navNs export const ns = [navNs, 'docs'] //navNs
/** checks for a slug that isn't a post, to prevent a prev or next button to it */
const isEndSlug = (slug) => slug.split('/').length === 1 const isEndSlug = (slug) => slug.split('/').length === 1
/** layout for a page that displays a blog, showcase or newsletter */
export const PostLayout = ({ children = [], slug, frontmatter, locale }) => { export const PostLayout = ({ children = [], slug, frontmatter, locale }) => {
const { siteNav } = useNavigation({ ignoreControl: true }) const { siteNav } = useNavigation({ ignoreControl: true })

View file

@ -2,21 +2,32 @@ import { localePath } from 'shared/utils.mjs'
const preGenerate = 6 const preGenerate = 6
export const numPerPage = 12 export const numPerPage = 12
export const getPostSlugPaths = (order) => { /**
* get pre-generated paths for each language for post slug pages
* @param {Object} sortedPaths a dictionary keyed by locale of post paths sorted by date published
* @return {Sting[]} paths for the latest 6 posts in all locales
*/
export const getPostSlugPaths = (sortedPaths) => {
const paths = [] const paths = []
for (const lang in order) { for (const lang in sortedPaths) {
for (let i = 0; i < preGenerate; i++) { for (let i = 0; i < preGenerate; i++) {
paths.push(localePath(lang, `${order[lang][i]}`)) paths.push(localePath(lang, `${sortedPaths[lang][i]}`))
} }
} }
return paths return paths
} }
export const getPostIndexPaths = (order, type) => { /**
* get pre-generated paths for each language for post index pages
* @param {Object} sortedPaths a dictionary keyed by locale of post paths sorted by date published
* @param {String} type post type: blog, showcase, or newsletter
* @return {String[]} paths for the first two pages of posts in all locales
*/
export const getPostIndexPaths = (sortedPaths, type) => {
const paths = [] const paths = []
for (const language in order) { for (const language in sortedPaths) {
paths.push(localePath(language, `${type}/page/1`)) paths.push(localePath(language, `${type}/page/1`))
paths.push(localePath(language, `${type}/page/2`)) paths.push(localePath(language, `${type}/page/2`))
} }
@ -24,12 +35,23 @@ export const getPostIndexPaths = (order, type) => {
return paths return paths
} }
export const getPostIndexProps = (locale, params, order, postInfo) => { /**
* get static props for a post index page
* @param {String} locale the locale
* @param {Object} params path params
* @param {Object} sortedPaths [description]
* @param {Object} postInfo data on all posts, loaded from prebuild
* @return {Object} props page props
* @return {Object[]} props.posts the posts to link to on the page
* @return {Number} props.current the current page number
* @return {Number} props.total the total number of pages
*/
export const getPostIndexProps = (locale, params, sortedPaths, postInfo) => {
const pageNum = parseInt(params.page) const pageNum = parseInt(params.page)
const numLocPages = Math.ceil(order[locale].length / numPerPage) const numLocPages = Math.ceil(sortedPaths[locale].length / numPerPage)
if (pageNum > numLocPages) return false if (pageNum > numLocPages) return false
const postSlugs = order[locale].slice(numPerPage * (pageNum - 1), numPerPage * pageNum) const postSlugs = sortedPaths[locale].slice(numPerPage * (pageNum - 1), numPerPage * pageNum)
const posts = postSlugs.map((s) => ({ ...postInfo[locale][s], s })) const posts = postSlugs.map((s) => ({ ...postInfo[locale][s], s }))
return { posts, current: pageNum, total: numLocPages } return { posts, current: pageNum, total: numLocPages }

View file

@ -53,6 +53,11 @@ const BlogPage = ({ locale, slug, page }) => {
export async function getStaticProps({ params, locale }) { export async function getStaticProps({ params, locale }) {
const { slug } = params const { slug } = params
// if the slug isn't present in the prebuilt order, return 404
if (order[locale].indexOf(`blog/${slug}`) === -1) {
return { notFound: true }
}
return { return {
props: { props: {
slug, slug,
@ -66,6 +71,21 @@ export async function getStaticProps({ params, locale }) {
} }
} }
/*
* getStaticPaths() is used to specify for which routes (think URLs)
* this page should be used to generate the result.
*
* On this page, it is returning a truncated list of routes (think URLs) for all
* the mdx blog (markdown) content.
* That list comes from prebuild/blog-paths.mjs, which is built in the prebuild step
* and contains paths, titles, imageUrls, and intro for all blog posts.
*
* the fallback: 'blocking' property means that
* any pages that haven't been pre-generated
* will generate and cache the first time someone visits them
*
* To learn more, see: https://nextjs.org/docs/basic-features/data-fetching
*/
export const getStaticPaths = async () => { export const getStaticPaths = async () => {
return { return {
paths: getPostSlugPaths(order), paths: getPostSlugPaths(order),

View file

@ -68,6 +68,7 @@ const Preview = ({ post, t }) => (
</Link> </Link>
</div> </div>
) )
/* /*
* Each page MUST be wrapped in the PageWrapper component. * Each page MUST be wrapped in the PageWrapper component.
* You also MUST spread props.page into this wrapper component * You also MUST spread props.page into this wrapper component
@ -90,9 +91,20 @@ const BlogIndexPage = ({ posts, page, current, total }) => {
export default BlogIndexPage export default BlogIndexPage
/*
* getStaticProps() is used to fetch data at build-time.
*
* On this page, it fetches data for the blogs to be linked to on this page
*
* This, in combination with getStaticPaths() below means this
* page will be used to link to all blogs.
*
* To learn more, see: https://nextjs.org/docs/basic-features/data-fetching
*/
export async function getStaticProps({ locale, params }) { export async function getStaticProps({ locale, params }) {
const props = getPostIndexProps(locale, params, order, postInfo) const props = getPostIndexProps(locale, params, order, postInfo)
// if there shouldn't be a page with these params, return 404
if (props === false) return { notFound: true } if (props === false) return { notFound: true }
return { return {
@ -108,6 +120,21 @@ export async function getStaticProps({ locale, params }) {
} }
} }
/*
* getStaticPaths() is used to specify for which routes (think URLs)
* this page should be used to generate the result.
*
* On this page, it is returning a truncated list of routes (think URLs) for pages that list and link to
* the mdx blog (markdown) content.
* That list comes from prebuild/blog-paths.mjs, which is built in the prebuild step
* and contains paths, titles, imageUrls, and intro for all blog posts.
*
* the fallback: 'blocking' property means that
* any pages that haven't been pre-generated
* will generate and cache the first time someone visits them
*
* To learn more, see: https://nextjs.org/docs/basic-features/data-fetching
*/
export const getStaticPaths = async () => { export const getStaticPaths = async () => {
return { return {
paths: getPostIndexPaths(order, 'blog'), paths: getPostIndexPaths(order, 'blog'),

View file

@ -12,27 +12,13 @@ import { DocsLayout, ns as layoutNs } from 'site/components/layouts/docs.mjs'
import { loaders } from 'shared/components/dynamic-docs/org.mjs' import { loaders } from 'shared/components/dynamic-docs/org.mjs'
export const ns = [...pageNs, layoutNs] export const ns = [...pageNs, layoutNs]
/*
* PLEASE READ THIS BEFORE YOU TRY TO REFACTOR THIS PAGE /**
* * a page to display documentation markdown
* You will notice that this page has a page component for each language * Each page MUST be wrapped in the PageWrapper component.
* and that those components are 95% identical. So you may be thinking: * You also MUST spread props.page into this wrapper component
* * when path and locale come from static props (as here)
* This is not DRY, let me refactor this real quick * or set them manually.
*
* Before you do so, please reflect on these topics:
*
* - Do you know the pitfalls of dynamic imports in Webpack?
* - Do you know how much documentation we have?
* - Do you know we support 5 languages?
*
* If you do know all of these thigns, and you think you can improve this page. Go ahead.
*
* If you are not sure, then I would recommend you find something else to work on, unless
* you consider this a learning opportunity.
*
* joost
*
*/ */
export const Page = ({ page, locale, frontmatter, MDX }) => ( export const Page = ({ page, locale, frontmatter, MDX }) => (
<PageWrapper <PageWrapper
@ -46,6 +32,7 @@ export const Page = ({ page, locale, frontmatter, MDX }) => (
) )
const DocsPage = ({ page, locale, slug }) => { const DocsPage = ({ page, locale, slug }) => {
// get the appropriate loader for the locale, and load the mdx for this page
const loader = useCallback(() => loaders[locale](slug), [locale, slug]) const loader = useCallback(() => loaders[locale](slug), [locale, slug])
// State // State
const { frontmatter, MDX } = useDynamicMdx(loader) const { frontmatter, MDX } = useDynamicMdx(loader)
@ -97,6 +84,6 @@ export async function getStaticPaths() {
...somePaths.map((key) => `/fr/${key}`), ...somePaths.map((key) => `/fr/${key}`),
...somePaths.map((key) => `/nl/${key}`), ...somePaths.map((key) => `/nl/${key}`),
], ],
fallback: 'blocking', fallback: false,
} }
} }

View file

@ -9,14 +9,21 @@ import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
const namespaces = [...layoutNs, ...postNs, ...pageNs] const namespaces = [...layoutNs, ...postNs, ...pageNs]
/*
* Each page MUST be wrapped in the PageWrapper component.
* You also MUST spread props.page into this wrapper component
* when path and locale come from static props (as here)
* or set them manually.
*/
const ShowcasePage = ({ locale, slug, page }) => { const ShowcasePage = ({ locale, slug, page }) => {
// function to load the correct markdown
const loader = useCallback( const loader = useCallback(
() => import(`orgmarkdown/showcase/${slug}/${locale}.md`), () => import(`orgmarkdown/showcase/${slug}/${locale}.md`),
[slug, locale] [slug, locale]
) )
const { frontmatter, MDX } = useDynamicMdx(loader) const { frontmatter, MDX } = useDynamicMdx(loader)
if (!MDX) return null
return ( return (
<PageWrapper <PageWrapper
{...page} {...page}
@ -39,7 +46,7 @@ const ShowcasePage = ({ locale, slug, page }) => {
/* /*
* getStaticProps() is used to fetch data at build-time. * getStaticProps() is used to fetch data at build-time.
* *
* On this page, it is loading the showcase content from strapi. * On this page, it it passes the name of the bundle to be loaded on the client.
* *
* This, in combination with getStaticPaths() below means this * This, in combination with getStaticPaths() below means this
* page will be used to render/generate all showcase content. * page will be used to render/generate all showcase content.
@ -49,6 +56,11 @@ const ShowcasePage = ({ locale, slug, page }) => {
export async function getStaticProps({ params, locale }) { export async function getStaticProps({ params, locale }) {
const { slug } = params const { slug } = params
// if the slug isn't present in the prebuilt order, return 404
if (order[locale].indexOf(`showcase/${slug}`) === -1) {
return { notFound: true }
}
return { return {
props: { props: {
slug, slug,
@ -62,6 +74,21 @@ export async function getStaticProps({ params, locale }) {
} }
} }
/*
* getStaticPaths() is used to specify for which routes (think URLs)
* this page should be used to generate the result.
*
* On this page, it is returning a truncated list of routes (think URLs) for all
* the mdx showcase (markdown) content.
* That list comes from prebuild/showcase-paths.mjs, which is built in the prebuild step
* and contains paths, titles, imageUrls, and intro for all showcase posts.
*
* the fallback: 'blocking' property means that
* any pages that haven't been pre-generated
* will generate and cache the first time someone visits them
*
* To learn more, see: https://nextjs.org/docs/basic-features/data-fetching
*/
export const getStaticPaths = async () => { export const getStaticPaths = async () => {
return { return {
paths: getPostSlugPaths(order), paths: getPostSlugPaths(order),

View file

@ -58,6 +58,12 @@ const Posts = ({ posts }) => {
) )
} }
/*
* Each page MUST be wrapped in the PageWrapper component.
* You also MUST spread props.page into this wrapper component
* when path and locale come from static props (as here)
* or set them manually.
*/
const ShowcaseIndexPage = ({ posts, page, current, total }) => { const ShowcaseIndexPage = ({ posts, page, current, total }) => {
const { t } = useTranslation() const { t } = useTranslation()
@ -74,9 +80,20 @@ const ShowcaseIndexPage = ({ posts, page, current, total }) => {
export default ShowcaseIndexPage export default ShowcaseIndexPage
/*
* getStaticProps() is used to fetch data at build-time.
*
* On this page, it fetches data for the showcases to be linked to on this page
*
* This, in combination with getStaticPaths() below means this
* page will be used to link to all showcases.
*
* To learn more, see: https://nextjs.org/docs/basic-features/data-fetching
*/
export async function getStaticProps({ locale, params }) { export async function getStaticProps({ locale, params }) {
const props = getPostIndexProps(locale, params, order, postInfo) const props = getPostIndexProps(locale, params, order, postInfo)
// if there shouldn't be a page with these params, return 404
if (props === false) return { notFound: true } if (props === false) return { notFound: true }
return { return {
@ -92,6 +109,21 @@ export async function getStaticProps({ locale, params }) {
} }
} }
/*
* getStaticPaths() is used to specify for which routes (think URLs)
* this page should be used to generate the result.
*
* On this page, it is returning a truncated list of routes (think URLs) for pages that list and link to
* the mdx showcase (markdown) content.
* That list comes from prebuild/showcase-paths.mjs, which is built in the prebuild step
* and contains paths, titles, imageUrls, and intro for all showcase posts.
*
* the fallback: 'blocking' property means that
* any pages that haven't been pre-generated
* will generate and cache the first time someone visits them
*
* To learn more, see: https://nextjs.org/docs/basic-features/data-fetching
*/
export const getStaticPaths = async () => { export const getStaticPaths = async () => {
return { return {
paths: getPostIndexPaths(order, 'showcase'), paths: getPostIndexPaths(order, 'showcase'),

View file

@ -31,14 +31,32 @@ const NextPage = ({ t, s }) =>
<span></span> <span></span>
) )
/**
* get slug at the given index, or null if it should not be displayed
* @param {Number} index the index of the page to get
* @param {String[]} slugLut the lut for navigation slugs
* @param {Object} siteNav nav data
* @param {Boolen | Function} shouldHide should this element be hidden?
* Function arguments should accept the slug that this element would display and return a boolean
* @return {String | null} the slug for the page, or null if it shouldn't display
*/
const getItemWithCaveat = (index, slugLut, siteNav, shouldHide) => { const getItemWithCaveat = (index, slugLut, siteNav, shouldHide) => {
// boolean shouldHide, return null
if (shouldHide === true) return null if (shouldHide === true) return null
// function shouldHide, return null if it returns true
if (typeof shouldHide === 'function' && shouldHide(slugLut[index])) return null if (typeof shouldHide === 'function' && shouldHide(slugLut[index])) return null
// get the slug at the index
return get(siteNav, slugLut[index].split('/')) return get(siteNav, slugLut[index].split('/'))
} }
/**
* Previous and Next buttons
* @param {String} options.slug the current slug
* @param {Boolean | Function} options.noPrev should the previous button be hidden? You can pass a function that accepts the slug for the previous button and returns a boolean, or just pass a boolean
* @param {Boolean | Function} options.noNext should the next button be hidden? You can pass a function that accepts the slug for the next button and returns a boolean, or just pass a boolean
*/
export const PrevNext = ({ slug, noPrev = false, noNext = false }) => { export const PrevNext = ({ slug, noPrev = false, noNext = false }) => {
// Grab site navigation and slug lookup table from the useNavigatin hook // Grab site navigation and slug lookup table from the useNavigatin hook
const { siteNav, slugLut } = useNavigation() const { siteNav, slugLut } = useNavigation()

View file

@ -2,6 +2,14 @@ import { components } from 'shared/components/mdx/index.mjs'
import { Loading } from 'shared/components/spinner.mjs' import { Loading } from 'shared/components/spinner.mjs'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
/**
* Dynamically load and compile mdx
* @param {Function} loader an import function to use to load the mdx
* @param {String} site the site whose component set will be used in rendering the mdx
* @return {Object} props
* @return {React.component} props.MDX an component to render the loaded MDX
* @return {Object} props.frontmatter the frontmatter loaded from the markdown
*/
export const useDynamicMdx = (loader, site = 'org') => { export const useDynamicMdx = (loader, site = 'org') => {
// State // State
const [frontmatter, setFrontmatter] = useState({ title: `freeSewing.${site}` }) const [frontmatter, setFrontmatter] = useState({ title: `freeSewing.${site}` })

View file

@ -26,8 +26,6 @@ export const prebuildPosts = async (site) => {
sorted[lang] = Object.keys(resultPages[lang]).sort( sorted[lang] = Object.keys(resultPages[lang]).sort(
(a, b) => resultPages[lang][a].o - resultPages[lang][b].o (a, b) => resultPages[lang][a].o - resultPages[lang][b].o
) )
// get rid of the index page
sorted[lang].shift()
} }
writeOps.push( writeOps.push(