refactor blog and showcase implementation
This commit is contained in:
parent
6653e6f5b7
commit
2768adc36c
14 changed files with 266 additions and 297 deletions
|
@ -18,18 +18,18 @@ import { Toc } from 'shared/components/mdx/toc.mjs'
|
||||||
import { MdxMetaData } from 'shared/components/mdx/meta.mjs'
|
import { MdxMetaData } from 'shared/components/mdx/meta.mjs'
|
||||||
import { PrevNext } from 'shared/components/prev-next.mjs'
|
import { PrevNext } from 'shared/components/prev-next.mjs'
|
||||||
|
|
||||||
export const ns = [navNs] //navNs
|
export const ns = [navNs, 'docs'] //navNs
|
||||||
|
|
||||||
export const DocsLayout = ({ children = [], slug, frontmatter }) => {
|
export const FrontmatterHead = ({ frontmatter }) => (
|
||||||
const { siteNav } = useNavigation({ ignoreControl: true })
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
<Head>
|
||||||
<meta property="og:title" content={frontmatter.title} key="title" />
|
<meta property="og:title" content={frontmatter.title} key="title" />
|
||||||
<meta property="og:type" content="article" key="type" />
|
<meta property="og:type" content="article" key="type" />
|
||||||
<meta property="og:description" content={``} key="type" />
|
<meta property="og:description" content={frontmatter.intro || frontmatter.title} key="type" />
|
||||||
<meta property="og:article:author" content="Joost De Cock" key="author" />
|
<meta
|
||||||
|
property="og:article:author"
|
||||||
|
content={frontmatter.author || frontmatter.maker || 'Joost De Cock'}
|
||||||
|
key="author"
|
||||||
|
/>
|
||||||
<meta
|
<meta
|
||||||
property="og:image"
|
property="og:image"
|
||||||
content={`https://canary.backend.freesewing.org/og-img/en/org/${slug}}`}
|
content={`https://canary.backend.freesewing.org/og-img/en/org/${slug}}`}
|
||||||
|
@ -39,11 +39,17 @@ export const DocsLayout = ({ children = [], slug, frontmatter }) => {
|
||||||
<meta property="og:image:width" content="1200" />
|
<meta property="og:image:width" content="1200" />
|
||||||
<meta property="og:image:height" content="630" />
|
<meta property="og:image:height" content="630" />
|
||||||
<meta property="og:url" content={`https://freesewing.org/${slug}`} key="url" />
|
<meta property="og:url" content={`https://freesewing.org/${slug}`} key="url" />
|
||||||
<meta property="og:locale" content="en" key="locale" />
|
<meta property="og:locale" content={locale || 'en'} key="locale" />
|
||||||
<meta property="og:site_name" content="freesewing.org" key="site" />
|
<meta property="og:site_name" content="freesewing.org" key="site" />
|
||||||
<title>{frontmatter.title + '- FreeSewing.org'}</title>
|
<title>{frontmatter.title + '- FreeSewing.org'}</title>
|
||||||
</Head>
|
</Head>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const DocsLayout = ({ children = [], slug, frontmatter, locale }) => {
|
||||||
|
const { siteNav } = useNavigation({ ignoreControl: true })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
<BaseLayout>
|
<BaseLayout>
|
||||||
<BaseLayoutLeft>
|
<BaseLayoutLeft>
|
||||||
<MainSections {...{ siteNav, slug }} />
|
<MainSections {...{ siteNav, slug }} />
|
||||||
|
|
55
sites/org/components/layouts/post.mjs
Normal file
55
sites/org/components/layouts/post.mjs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Hooks
|
||||||
|
import { useNavigation } from 'site/hooks/use-navigation.mjs'
|
||||||
|
// Components
|
||||||
|
import { FrontmatterHead } from './docs.mjs'
|
||||||
|
import {
|
||||||
|
BaseLayout,
|
||||||
|
BaseLayoutLeft,
|
||||||
|
BaseLayoutProse,
|
||||||
|
BaseLayoutRight,
|
||||||
|
} from 'shared/components/base-layout.mjs'
|
||||||
|
import {
|
||||||
|
NavLinks,
|
||||||
|
Breadcrumbs,
|
||||||
|
MainSections,
|
||||||
|
ns as navNs,
|
||||||
|
} from 'shared/components/navigation/sitenav.mjs'
|
||||||
|
import { Toc } from 'shared/components/mdx/toc.mjs'
|
||||||
|
import { PrevNext } from 'shared/components/prev-next.mjs'
|
||||||
|
|
||||||
|
export const ns = [navNs, 'docs'] //navNs
|
||||||
|
|
||||||
|
const isEndSlug = (slug) => slug.split('/').length === 1
|
||||||
|
|
||||||
|
export const PostLayout = ({ children = [], slug, frontmatter }) => {
|
||||||
|
const { siteNav } = useNavigation({ ignoreControl: true })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BaseLayout>
|
||||||
|
<BaseLayoutLeft>
|
||||||
|
<MainSections {...{ siteNav, slug }} />
|
||||||
|
<NavLinks {...{ siteNav, slug }} />
|
||||||
|
</BaseLayoutLeft>
|
||||||
|
|
||||||
|
<BaseLayoutProse>
|
||||||
|
<div className="w-full">
|
||||||
|
<Breadcrumbs {...{ siteNav, slug }} />
|
||||||
|
<h1 className="break-words searchme">{frontmatter.title}</h1>
|
||||||
|
<div className="block xl:hidden">
|
||||||
|
<Toc toc={frontmatter.toc} wrap />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{children}
|
||||||
|
<PrevNext slug={slug} noPrev={isEndSlug} noNext={isEndSlug} />
|
||||||
|
</BaseLayoutProse>
|
||||||
|
|
||||||
|
<BaseLayoutRight>
|
||||||
|
<div className="hidden xl:block">
|
||||||
|
<Toc toc={frontmatter.toc} wrap />
|
||||||
|
</div>
|
||||||
|
</BaseLayoutRight>
|
||||||
|
</BaseLayout>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
55
sites/org/components/mdx/posts/article.mjs
Normal file
55
sites/org/components/mdx/posts/article.mjs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import { PageLink } from 'shared/components/page-link.mjs'
|
||||||
|
import { Lightbox } from 'shared/components/lightbox.mjs'
|
||||||
|
import { ImageWrapper } from 'shared/components/wrappers/img.mjs'
|
||||||
|
import { Author } from './author.mjs'
|
||||||
|
import { TimeAgo } from 'shared/components/mdx/meta.mjs'
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs'
|
||||||
|
|
||||||
|
export const ns = ['common', 'posts']
|
||||||
|
|
||||||
|
export const PostArticle = ({ slug, frontmatter, MDX, page }) => {
|
||||||
|
const { t } = useTranslation('common')
|
||||||
|
return (
|
||||||
|
<article className="mb-12 px-8 max-w-7xl">
|
||||||
|
<div className="flex flex-row justify-between text-sm mb-1 mt-2">
|
||||||
|
<div>
|
||||||
|
<TimeAgo date={frontmatter.date} t={t} /> [{frontmatter.date}]
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{frontmatter.designs?.map((design) => (
|
||||||
|
<PageLink
|
||||||
|
href={`/showcase/designs/${design}`}
|
||||||
|
txt={design}
|
||||||
|
key={design}
|
||||||
|
className="px-2 capitalize"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
By{' '}
|
||||||
|
<a href="#maker" className="text-secondary hover:text-secondary-focus">
|
||||||
|
{frontmatter.author || frontmatter.maker || 'FIXME: No displayname'}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<figure>
|
||||||
|
<Lightbox>
|
||||||
|
<ImageWrapper>
|
||||||
|
<img src={frontmatter.image} alt={frontmatter.caption} className="shadow m-auto" />
|
||||||
|
</ImageWrapper>
|
||||||
|
<figcaption
|
||||||
|
className="text-center mb-8 prose m-auto"
|
||||||
|
dangerouslySetInnerHTML={{ __html: frontmatter.caption }}
|
||||||
|
/>
|
||||||
|
</Lightbox>
|
||||||
|
</figure>
|
||||||
|
<div className="strapi prose lg:prose-lg mb-12 m-auto">
|
||||||
|
<MdxWrapper>{MDX}</MdxWrapper>
|
||||||
|
</div>
|
||||||
|
<div className="max-w-prose text-lg lg:text-xl">
|
||||||
|
<Author author={frontmatter.author || frontmatter.maker} />
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
import { SanityMdxWrapper } from './mdx-wrapper.mjs'
|
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
|
||||||
export const Author = ({ author = '' }) => {
|
export const Author = ({ author = '' }) => {
|
37
sites/org/components/mdx/posts/utils.mjs
Normal file
37
sites/org/components/mdx/posts/utils.mjs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import { localePath } from 'shared/utils.mjs'
|
||||||
|
const preGenerate = 6
|
||||||
|
export const numPerPage = 12
|
||||||
|
|
||||||
|
export const getPostSlugPaths = (order) => {
|
||||||
|
const paths = []
|
||||||
|
|
||||||
|
for (const lang in order) {
|
||||||
|
for (let i = 0; i < preGenerate; i++) {
|
||||||
|
const slug = order[lang][i]
|
||||||
|
paths.push(localePath(lang, `${order[lang][i]}`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPostIndexPaths = (order, type) => {
|
||||||
|
const paths = []
|
||||||
|
for (const language in order) {
|
||||||
|
paths.push(localePath(language, `${type}/page/1`))
|
||||||
|
paths.push(localePath(language, `${type}/page/2`))
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPostIndexProps = (locale, params, order, postInfo) => {
|
||||||
|
const pageNum = parseInt(params.page)
|
||||||
|
const numLocPages = Math.ceil(order[locale].length / numPerPage)
|
||||||
|
if (pageNum > numLocPages) return false
|
||||||
|
|
||||||
|
const postSlugs = order[locale].slice(numPerPage * (pageNum - 1), numPerPage * pageNum)
|
||||||
|
const posts = postSlugs.map((s) => ({ ...postInfo[locale][s], s }))
|
||||||
|
|
||||||
|
return { posts, current: pageNum, total: numLocPages }
|
||||||
|
}
|
|
@ -1,30 +0,0 @@
|
||||||
import { compile, run } from '@mdx-js/mdx'
|
|
||||||
import * as runtime from 'react/jsx-runtime' // Production.
|
|
||||||
import { useState, useEffect } from 'react'
|
|
||||||
|
|
||||||
import { PlainMdxWrapper } from 'shared/components/wrappers/mdx.mjs'
|
|
||||||
|
|
||||||
export const useEvaledMdx = (mdxStr = '') => {
|
|
||||||
const [mdxModule, setMdxModule] = useState(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const runEffect = async () => {
|
|
||||||
const code = await compile(mdxStr, {
|
|
||||||
outputFormat: 'function-body',
|
|
||||||
development: false,
|
|
||||||
})
|
|
||||||
const evaled = await run(code, runtime)
|
|
||||||
setMdxModule(() => evaled.default)
|
|
||||||
}
|
|
||||||
runEffect()
|
|
||||||
}, [mdxStr])
|
|
||||||
|
|
||||||
return mdxModule
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MdxEvalWrapper = ({ MDX = false, components = {}, site = 'org' }) => {
|
|
||||||
const evaled = useEvaledMdx(MDX)
|
|
||||||
return <PlainMdxWrapper {...{ MDX: evaled, components, site }} />
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SanityMdxWrapper = MdxEvalWrapper
|
|
|
@ -1,114 +0,0 @@
|
||||||
import Head from 'next/head'
|
|
||||||
import { PageLink } from 'shared/components/page-link.mjs'
|
|
||||||
import { Lightbox } from 'shared/components/lightbox.mjs'
|
|
||||||
import { ImageWrapper } from 'shared/components/wrappers/img.mjs'
|
|
||||||
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
|
||||||
import { Author } from './author.mjs'
|
|
||||||
import { TimeAgo } from 'shared/components/mdx/meta.mjs'
|
|
||||||
import { useTranslation } from 'next-i18next'
|
|
||||||
import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs'
|
|
||||||
import { DocsLayout, ns as layoutNs } from 'site/components/layouts/docs.mjs'
|
|
||||||
import { PrevNext } from 'shared/components/prev-next.mjs'
|
|
||||||
|
|
||||||
export const ns = ['common', 'posts', ...pageNs]
|
|
||||||
|
|
||||||
const preGenerate = 6
|
|
||||||
export const SanityPageWrapper = ({ slug, frontmatter, MDX, namespaces, page }) => {
|
|
||||||
const { t } = useTranslation(namespaces)
|
|
||||||
return (
|
|
||||||
<PageWrapper {...page} title={frontmatter.title} slug={slug}>
|
|
||||||
<Head>
|
|
||||||
<meta property="og:type" content="article" key="type" />
|
|
||||||
<meta
|
|
||||||
property="og:description"
|
|
||||||
content={frontmatter.intro || frontmatter.title}
|
|
||||||
key="description"
|
|
||||||
/>
|
|
||||||
<meta property="og:article:author" content={frontmatter.author} key="author" />
|
|
||||||
<meta property="og:url" content={`https://freesewing.org/blog/${slug}`} key="url" />
|
|
||||||
<meta
|
|
||||||
property="og:image"
|
|
||||||
content={`https://canary.backend.freesewing.org/og-img/en/dev/blog/${slug}`}
|
|
||||||
key="image"
|
|
||||||
/>
|
|
||||||
<meta property="og:image:type" content="image/png" />
|
|
||||||
<meta property="og:image:width" content="1200" />
|
|
||||||
<meta property="og:image:height" content="630" />
|
|
||||||
<meta property="og:locale" content="en_US" key="locale" />
|
|
||||||
<meta property="og:site_name" content="freesewing.org" key="site" />
|
|
||||||
</Head>
|
|
||||||
<article className="mb-12 px-8 max-w-7xl">
|
|
||||||
<div className="flex flex-row justify-between text-sm mb-1 mt-2">
|
|
||||||
<div>
|
|
||||||
<TimeAgo date={frontmatter.date} t={t} /> [{frontmatter.date}]
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{frontmatter.designs?.map((design) => (
|
|
||||||
<PageLink
|
|
||||||
href={`/showcase/designs/${design}`}
|
|
||||||
txt={design}
|
|
||||||
key={design}
|
|
||||||
className="px-2 capitalize"
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
By{' '}
|
|
||||||
<a href="#maker" className="text-secondary hover:text-secondary-focus">
|
|
||||||
{frontmatter.author || frontmatter.maker || 'FIXME: No displayname'}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<figure>
|
|
||||||
<Lightbox>
|
|
||||||
<ImageWrapper>
|
|
||||||
<img src={frontmatter.image} alt={frontmatter.caption} className="shadow m-auto" />
|
|
||||||
</ImageWrapper>
|
|
||||||
<figcaption
|
|
||||||
className="text-center mb-8 prose m-auto"
|
|
||||||
dangerouslySetInnerHTML={{ __html: frontmatter.caption }}
|
|
||||||
/>
|
|
||||||
</Lightbox>
|
|
||||||
</figure>
|
|
||||||
<div className="strapi prose lg:prose-lg mb-12 m-auto">
|
|
||||||
<MdxWrapper>{MDX}</MdxWrapper>
|
|
||||||
</div>
|
|
||||||
<div className="max-w-prose text-lg lg:text-xl">
|
|
||||||
<Author author={frontmatter.author || frontmatter.maker} />
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
<PrevNext
|
|
||||||
slug={page?.path.join('/')}
|
|
||||||
noPrev={(s) => s.split('/').length === 1}
|
|
||||||
noNext={(s) => s.split('/').length === 1}
|
|
||||||
/>
|
|
||||||
</PageWrapper>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathStr = '../../../../markdown/org/'
|
|
||||||
export const getSanityStaticPaths = (type) => {
|
|
||||||
return async () => {
|
|
||||||
const paths = []
|
|
||||||
const allPathsMod = await import(`../../prebuild/${type}-paths.mjs`)
|
|
||||||
|
|
||||||
for (const lang in allPathsMod.order) {
|
|
||||||
const lPath = lang === 'en' ? '' : `/${lang}`
|
|
||||||
let i = 0,
|
|
||||||
counter = 0
|
|
||||||
while (i < preGenerate && counter < 20) {
|
|
||||||
counter++
|
|
||||||
const slug = allPathsMod.order[lang][i]
|
|
||||||
if (!slug) continue
|
|
||||||
|
|
||||||
paths.push(`${lPath}/${allPathsMod.order[lang][i]}`)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
paths: paths,
|
|
||||||
fallback: 'blocking',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
import { createClient } from '@sanity/client'
|
|
||||||
import { siteConfig } from 'site/site.config.mjs'
|
|
||||||
|
|
||||||
let sanityClient
|
|
||||||
const cache = {}
|
|
||||||
export const sanityLoader = async ({ query, language, type, slug, order, filters = '' }) => {
|
|
||||||
sanityClient =
|
|
||||||
sanityClient ||
|
|
||||||
createClient({
|
|
||||||
projectId: siteConfig.sanity.project,
|
|
||||||
dataset: siteConfig.sanity.dataset,
|
|
||||||
apiVersion: siteConfig.sanity.apiVersion,
|
|
||||||
useCdn: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!query) {
|
|
||||||
query = `*[_type == "${type}${language}"`
|
|
||||||
if (slug) query += ` && slug.current == "${slug}"`
|
|
||||||
query += ']'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (order) {
|
|
||||||
query += ` | order(${order})`
|
|
||||||
}
|
|
||||||
|
|
||||||
query += filters
|
|
||||||
|
|
||||||
if (cache[query]) return cache[query]
|
|
||||||
|
|
||||||
const result = await sanityClient.fetch(query)
|
|
||||||
cache[query] = result
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sanityImage = (image, dataset = 'site-content') => {
|
|
||||||
const [, assetName, origSize, format] = image.asset._ref.split('-')
|
|
||||||
return `https://cdn.sanity.io/images/${siteConfig.sanity.project}/${dataset}/${assetName}-${origSize}.${format}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sanitySiteImage = (image) => sanityImage(image, 'site-content')
|
|
||||||
export const sanityUserImage = (image) => sanityImage(image, 'user-content')
|
|
||||||
|
|
||||||
export const numPerPage = 12
|
|
|
@ -1,36 +1,49 @@
|
||||||
import {
|
import { order } from 'site/prebuild/blog-paths.mjs'
|
||||||
SanityPageWrapper,
|
import { getPostSlugPaths } from 'site/components/mdx/posts/utils.mjs'
|
||||||
getSanityStaticPaths,
|
|
||||||
ns as sanityNs,
|
|
||||||
} from 'site/components/sanity/page-wrapper.mjs'
|
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||||
import { useDynamicMdx } from 'shared/hooks/use-dynamic-mdx.mjs'
|
import { useDynamicMdx } from 'shared/hooks/use-dynamic-mdx.mjs'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
import { PostLayout, ns as layoutNs } from 'site/components/layouts/post.mjs'
|
||||||
|
import { PostArticle, ns as postNs } from 'site/components/mdx/posts/article.mjs'
|
||||||
|
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
||||||
|
|
||||||
const namespaces = [...sanityNs]
|
const namespaces = [...layoutNs, ...postNs, ...pageNs]
|
||||||
|
|
||||||
const BlogPostPage = ({ slug, page, locale }) => {
|
/*
|
||||||
|
* 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 BlogPage = ({ locale, slug, page }) => {
|
||||||
|
// function to load the correct markdown
|
||||||
const loader = useCallback(() => import(`orgmarkdown/blog/${slug}/${locale}.md`), [slug, locale])
|
const loader = useCallback(() => import(`orgmarkdown/blog/${slug}/${locale}.md`), [slug, locale])
|
||||||
|
// load the markdown
|
||||||
const { frontmatter, MDX } = useDynamicMdx(loader)
|
const { frontmatter, MDX } = useDynamicMdx(loader)
|
||||||
if (!MDX) return null
|
|
||||||
return (
|
return (
|
||||||
<SanityPageWrapper
|
<PageWrapper
|
||||||
|
{...page}
|
||||||
|
locale={locale}
|
||||||
|
title={frontmatter.title}
|
||||||
|
layout={(props) => <PostLayout {...props} {...{ slug: page.path.join('/'), frontmatter }} />}
|
||||||
|
>
|
||||||
|
<PostArticle
|
||||||
{...{
|
{...{
|
||||||
|
slug,
|
||||||
frontmatter,
|
frontmatter,
|
||||||
MDX,
|
MDX,
|
||||||
namespaces,
|
|
||||||
page,
|
page,
|
||||||
slug,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</PageWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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 blog content from strapi.
|
* On this page, 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 blog content.
|
* page will be used to render/generate all blog content.
|
||||||
|
@ -43,8 +56,8 @@ export async function getStaticProps({ params, locale }) {
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
slug,
|
slug,
|
||||||
...(await serverSideTranslations(locale, namespaces)),
|
|
||||||
locale,
|
locale,
|
||||||
|
...(await serverSideTranslations(locale, namespaces)),
|
||||||
page: {
|
page: {
|
||||||
locale,
|
locale,
|
||||||
path: ['blog', slug],
|
path: ['blog', slug],
|
||||||
|
@ -53,6 +66,11 @@ export async function getStaticProps({ params, locale }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getStaticPaths = getSanityStaticPaths('blog')
|
export const getStaticPaths = async () => {
|
||||||
|
return {
|
||||||
|
paths: getPostSlugPaths(order, 'blog'),
|
||||||
|
fallback: 'blocking',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default BlogPostPage
|
export default BlogPage
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Dependencies
|
// Dependencies
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||||
|
import { postInfo, order } from 'site/prebuild/blog-paths.mjs'
|
||||||
|
import { getPostIndexPaths, getPostIndexProps } from 'site/components/mdx/posts/utils.mjs'
|
||||||
// Hooks
|
// Hooks
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
// Components
|
// Components
|
||||||
|
@ -7,13 +9,10 @@ import Link from 'next/link'
|
||||||
import { TimeAgo } from 'shared/components/mdx/meta.mjs'
|
import { TimeAgo } from 'shared/components/mdx/meta.mjs'
|
||||||
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
||||||
import { Pagination } from 'shared/components/navigation/pagination.mjs'
|
import { Pagination } from 'shared/components/navigation/pagination.mjs'
|
||||||
import { postInfo, order } from 'site/prebuild/blog-paths.mjs'
|
|
||||||
|
|
||||||
// Translation namespaces used on this page
|
// Translation namespaces used on this page
|
||||||
const namespaces = [...new Set(['designs', 'sections', ...pageNs])]
|
const namespaces = [...new Set(['designs', 'sections', ...pageNs])]
|
||||||
|
|
||||||
export const numPerPage = 12
|
|
||||||
|
|
||||||
const textShadow = {
|
const textShadow = {
|
||||||
style: {
|
style: {
|
||||||
textShadow:
|
textShadow:
|
||||||
|
@ -92,42 +91,26 @@ const BlogIndexPage = ({ posts, page, current, total }) => {
|
||||||
export default BlogIndexPage
|
export default BlogIndexPage
|
||||||
|
|
||||||
export async function getStaticProps({ locale, params }) {
|
export async function getStaticProps({ locale, params }) {
|
||||||
const pageNum = parseInt(params.page)
|
const props = getPostIndexProps(locale, params, order, postInfo)
|
||||||
const postSlugs = order[locale].slice(numPerPage * (pageNum - 1), numPerPage * pageNum)
|
|
||||||
const posts = postSlugs.map((s) => ({ ...postInfo[locale][s], s }))
|
|
||||||
const numLocPages = Math.ceil(order[locale].length / numPerPage)
|
|
||||||
|
|
||||||
if (pageNum > numLocPages) {
|
if (props === false) return { notFound: true }
|
||||||
return {
|
|
||||||
notFound: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
// designs,
|
// designs,
|
||||||
posts,
|
...props,
|
||||||
current: pageNum,
|
|
||||||
total: numLocPages,
|
|
||||||
...(await serverSideTranslations(locale, namespaces)),
|
...(await serverSideTranslations(locale, namespaces)),
|
||||||
page: {
|
page: {
|
||||||
locale,
|
locale,
|
||||||
path: ['blog'],
|
path: ['showcase'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getStaticPaths = async () => {
|
export const getStaticPaths = async () => {
|
||||||
const paths = []
|
|
||||||
for (const language in order) {
|
|
||||||
const lPath = language === 'en' ? '' : `/${language}`
|
|
||||||
paths.push(`${lPath}/blog/page/1`)
|
|
||||||
paths.push(`${lPath}/blog/page/2`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
paths,
|
paths: getPostIndexPaths(order, 'blog'),
|
||||||
fallback: 'blocking',
|
fallback: 'blocking',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import {
|
import { order } from 'site/prebuild/showcase-paths.mjs'
|
||||||
SanityPageWrapper,
|
import { getPostSlugPaths } from 'site/components/mdx/posts/utils.mjs'
|
||||||
getSanityStaticPaths,
|
|
||||||
ns as sanityNs,
|
|
||||||
} from 'site/components/sanity/page-wrapper.mjs'
|
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||||
import { useDynamicMdx } from 'shared/hooks/use-dynamic-mdx.mjs'
|
import { useDynamicMdx } from 'shared/hooks/use-dynamic-mdx.mjs'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
import { PostLayout, ns as layoutNs } from 'site/components/layouts/post.mjs'
|
||||||
|
import { PostArticle, ns as postNs } from 'site/components/mdx/posts/article.mjs'
|
||||||
|
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
||||||
|
|
||||||
const namespaces = [...sanityNs]
|
const namespaces = [...layoutNs, ...postNs, ...pageNs]
|
||||||
|
|
||||||
const ShowcasePage = ({ locale, slug, page }) => {
|
const ShowcasePage = ({ locale, slug, page }) => {
|
||||||
const loader = useCallback(
|
const loader = useCallback(
|
||||||
|
@ -18,15 +18,21 @@ const ShowcasePage = ({ locale, slug, page }) => {
|
||||||
const { frontmatter, MDX } = useDynamicMdx(loader)
|
const { frontmatter, MDX } = useDynamicMdx(loader)
|
||||||
if (!MDX) return null
|
if (!MDX) return null
|
||||||
return (
|
return (
|
||||||
<SanityPageWrapper
|
<PageWrapper
|
||||||
|
{...page}
|
||||||
|
locale={locale}
|
||||||
|
title={frontmatter.title}
|
||||||
|
layout={(props) => <PostLayout {...props} {...{ slug: page.path.join('/'), frontmatter }} />}
|
||||||
|
>
|
||||||
|
<PostArticle
|
||||||
{...{
|
{...{
|
||||||
|
slug,
|
||||||
frontmatter,
|
frontmatter,
|
||||||
MDX,
|
MDX,
|
||||||
namespaces,
|
|
||||||
page,
|
page,
|
||||||
slug,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</PageWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +62,11 @@ export async function getStaticProps({ params, locale }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getStaticPaths = getSanityStaticPaths('showcase')
|
export const getStaticPaths = async () => {
|
||||||
|
return {
|
||||||
|
paths: getPostSlugPaths(order, 'showcase'),
|
||||||
|
fallback: 'blocking',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default ShowcasePage
|
export default ShowcasePage
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
// Dependencies
|
// Dependencies
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||||
|
import { postInfo, order } from 'site/prebuild/showcase-paths.mjs'
|
||||||
|
import { getPostIndexPaths, getPostIndexProps } from 'site/components/mdx/posts/utils.mjs'
|
||||||
// Hooks
|
// Hooks
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
// Components
|
// Components
|
||||||
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
||||||
import { Pagination } from 'shared/components/navigation/pagination.mjs'
|
import { Pagination } from 'shared/components/navigation/pagination.mjs'
|
||||||
import { postInfo, order } from 'site/prebuild/showcase-paths.mjs'
|
|
||||||
|
|
||||||
export const numPerPage = 12
|
|
||||||
|
|
||||||
// Translation namespaces used on this page
|
// Translation namespaces used on this page
|
||||||
const namespaces = [...new Set(['common', 'designs', ...pageNs])]
|
const namespaces = [...new Set(['common', 'designs', ...pageNs])]
|
||||||
|
@ -76,23 +75,14 @@ const ShowcaseIndexPage = ({ posts, page, current, total }) => {
|
||||||
export default ShowcaseIndexPage
|
export default ShowcaseIndexPage
|
||||||
|
|
||||||
export async function getStaticProps({ locale, params }) {
|
export async function getStaticProps({ locale, params }) {
|
||||||
const pageNum = parseInt(params.page)
|
const props = getPostIndexProps(locale, params, order, postInfo)
|
||||||
const postSlugs = order[locale].slice(numPerPage * (pageNum - 1), numPerPage * pageNum)
|
|
||||||
const posts = postSlugs.map((s) => ({ ...postInfo[locale][s], s }))
|
|
||||||
const numLocPages = Math.ceil(order[locale].length / numPerPage)
|
|
||||||
|
|
||||||
if (pageNum > numLocPages) {
|
if (props === false) return { notFound: true }
|
||||||
return {
|
|
||||||
notFound: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
// designs,
|
// designs,
|
||||||
posts,
|
...props,
|
||||||
current: pageNum,
|
|
||||||
total: numLocPages,
|
|
||||||
...(await serverSideTranslations(locale, namespaces)),
|
...(await serverSideTranslations(locale, namespaces)),
|
||||||
page: {
|
page: {
|
||||||
locale,
|
locale,
|
||||||
|
@ -103,15 +93,8 @@ export async function getStaticProps({ locale, params }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getStaticPaths = async () => {
|
export const getStaticPaths = async () => {
|
||||||
const paths = []
|
|
||||||
for (const language in order) {
|
|
||||||
const lPath = language === 'en' ? '' : `/${language}`
|
|
||||||
paths.push(`${lPath}/showcase/page/1`)
|
|
||||||
paths.push(`${lPath}/showcase/page/2`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
paths,
|
paths: getPostIndexPaths(order),
|
||||||
fallback: 'blocking',
|
fallback: 'blocking',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,11 @@ const run = async () => {
|
||||||
const SITE = process.env.SITE || 'lab'
|
const SITE = process.env.SITE || 'lab'
|
||||||
await prebuildDesigns()
|
await prebuildDesigns()
|
||||||
if (['org', 'dev'].includes(SITE)) {
|
if (['org', 'dev'].includes(SITE)) {
|
||||||
if (!FAST) await prebuildGitData(SITE)
|
if (!FAST) {
|
||||||
const docPages = await prebuildDocs(SITE)
|
await prebuildGitData(SITE)
|
||||||
await prebuildCrowdin()
|
await prebuildCrowdin()
|
||||||
|
}
|
||||||
|
const docPages = await prebuildDocs(SITE)
|
||||||
const postPages = await prebuildPosts(SITE)
|
const postPages = await prebuildPosts(SITE)
|
||||||
prebuildNavigation(docPages, postPages, SITE)
|
prebuildNavigation(docPages, postPages, SITE)
|
||||||
if (!FAST && process.env.GENERATE_OG_IMAGES) {
|
if (!FAST && process.env.GENERATE_OG_IMAGES) {
|
||||||
|
|
|
@ -349,3 +349,10 @@ export const maxPovDepthSlug = (slug, site) => {
|
||||||
* In that case, this will return true
|
* In that case, this will return true
|
||||||
*/
|
*/
|
||||||
export const isSlugPart = (part, slug) => slug.slice(0, part.length) === part
|
export const isSlugPart = (part, slug) => slug.slice(0, part.length) === part
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Makes a properly formated path for the given locale
|
||||||
|
* (i.e. skips adding 'en' to localized paths)
|
||||||
|
* Expects a slug with no leading slash
|
||||||
|
* */
|
||||||
|
export const localePath = (locale, slug) => (locale === 'en' ? '/' : `/${locale}/`) + slug
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue