From 2768adc36c7400e0af85d302b1dbbdc979af8e1c Mon Sep 17 00:00:00 2001 From: Enoch Riese Date: Tue, 18 Jul 2023 21:27:36 -0600 Subject: [PATCH] refactor blog and showcase implementation --- sites/org/components/layouts/docs.mjs | 48 ++++---- sites/org/components/layouts/post.mjs | 55 +++++++++ sites/org/components/mdx/posts/article.mjs | 55 +++++++++ .../{sanity => mdx/posts}/author.mjs | 1 - sites/org/components/mdx/posts/utils.mjs | 37 ++++++ sites/org/components/sanity/mdx-wrapper.mjs | 30 ----- sites/org/components/sanity/page-wrapper.mjs | 114 ------------------ sites/org/components/sanity/utils.mjs | 43 ------- sites/org/pages/blog/[slug].mjs | 62 ++++++---- sites/org/pages/blog/page/[page].mjs | 31 ++--- sites/org/pages/showcase/[slug].mjs | 43 ++++--- sites/org/pages/showcase/page/[page].mjs | 31 ++--- sites/shared/prebuild/index.mjs | 6 +- sites/shared/utils.mjs | 7 ++ 14 files changed, 266 insertions(+), 297 deletions(-) create mode 100644 sites/org/components/layouts/post.mjs create mode 100644 sites/org/components/mdx/posts/article.mjs rename sites/org/components/{sanity => mdx/posts}/author.mjs (95%) create mode 100644 sites/org/components/mdx/posts/utils.mjs delete mode 100644 sites/org/components/sanity/mdx-wrapper.mjs delete mode 100644 sites/org/components/sanity/page-wrapper.mjs delete mode 100644 sites/org/components/sanity/utils.mjs diff --git a/sites/org/components/layouts/docs.mjs b/sites/org/components/layouts/docs.mjs index 908459ec70a..5c611f51a06 100644 --- a/sites/org/components/layouts/docs.mjs +++ b/sites/org/components/layouts/docs.mjs @@ -18,32 +18,38 @@ import { Toc } from 'shared/components/mdx/toc.mjs' import { MdxMetaData } from 'shared/components/mdx/meta.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 }) => ( + + + + + + + + + + + + + {frontmatter.title + '- FreeSewing.org'} + +) + +export const DocsLayout = ({ children = [], slug, frontmatter, locale }) => { const { siteNav } = useNavigation({ ignoreControl: true }) return ( <> - - - - - - - - - - - - - {frontmatter.title + '- FreeSewing.org'} - - diff --git a/sites/org/components/layouts/post.mjs b/sites/org/components/layouts/post.mjs new file mode 100644 index 00000000000..f3a00d8fcf5 --- /dev/null +++ b/sites/org/components/layouts/post.mjs @@ -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 ( + <> + + + + + + + +
+ +

{frontmatter.title}

+
+ +
+
+ {children} + +
+ + +
+ +
+
+
+ + ) +} diff --git a/sites/org/components/mdx/posts/article.mjs b/sites/org/components/mdx/posts/article.mjs new file mode 100644 index 00000000000..f097b0a13c5 --- /dev/null +++ b/sites/org/components/mdx/posts/article.mjs @@ -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 ( + + ) +} diff --git a/sites/org/components/sanity/author.mjs b/sites/org/components/mdx/posts/author.mjs similarity index 95% rename from sites/org/components/sanity/author.mjs rename to sites/org/components/mdx/posts/author.mjs index 7cd308a7cfe..16da37a1d88 100644 --- a/sites/org/components/sanity/author.mjs +++ b/sites/org/components/mdx/posts/author.mjs @@ -1,4 +1,3 @@ -import { SanityMdxWrapper } from './mdx-wrapper.mjs' import { useTranslation } from 'next-i18next' export const Author = ({ author = '' }) => { diff --git a/sites/org/components/mdx/posts/utils.mjs b/sites/org/components/mdx/posts/utils.mjs new file mode 100644 index 00000000000..eafcf6b676e --- /dev/null +++ b/sites/org/components/mdx/posts/utils.mjs @@ -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 } +} diff --git a/sites/org/components/sanity/mdx-wrapper.mjs b/sites/org/components/sanity/mdx-wrapper.mjs deleted file mode 100644 index 8fe4fe79160..00000000000 --- a/sites/org/components/sanity/mdx-wrapper.mjs +++ /dev/null @@ -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 -} - -export const SanityMdxWrapper = MdxEvalWrapper diff --git a/sites/org/components/sanity/page-wrapper.mjs b/sites/org/components/sanity/page-wrapper.mjs deleted file mode 100644 index 9e594fd36e4..00000000000 --- a/sites/org/components/sanity/page-wrapper.mjs +++ /dev/null @@ -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 ( - - - - - - - - - - - - - - - s.split('/').length === 1} - noNext={(s) => s.split('/').length === 1} - /> - - ) -} - -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', - } - } -} diff --git a/sites/org/components/sanity/utils.mjs b/sites/org/components/sanity/utils.mjs deleted file mode 100644 index 87c3e951cd8..00000000000 --- a/sites/org/components/sanity/utils.mjs +++ /dev/null @@ -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 diff --git a/sites/org/pages/blog/[slug].mjs b/sites/org/pages/blog/[slug].mjs index 9c941d2921d..29b7f1ff78a 100644 --- a/sites/org/pages/blog/[slug].mjs +++ b/sites/org/pages/blog/[slug].mjs @@ -1,36 +1,49 @@ -import { - SanityPageWrapper, - getSanityStaticPaths, - ns as sanityNs, -} from 'site/components/sanity/page-wrapper.mjs' +import { order } from 'site/prebuild/blog-paths.mjs' +import { getPostSlugPaths } from 'site/components/mdx/posts/utils.mjs' import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import { useDynamicMdx } from 'shared/hooks/use-dynamic-mdx.mjs' 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]) - + // load the markdown const { frontmatter, MDX } = useDynamicMdx(loader) - if (!MDX) return null + return ( - + } + > + + ) } /* * 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 * page will be used to render/generate all blog content. @@ -43,8 +56,8 @@ export async function getStaticProps({ params, locale }) { return { props: { slug, - ...(await serverSideTranslations(locale, namespaces)), locale, + ...(await serverSideTranslations(locale, namespaces)), page: { locale, 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 diff --git a/sites/org/pages/blog/page/[page].mjs b/sites/org/pages/blog/page/[page].mjs index 7fe362a99b6..bc15271e869 100644 --- a/sites/org/pages/blog/page/[page].mjs +++ b/sites/org/pages/blog/page/[page].mjs @@ -1,5 +1,7 @@ // Dependencies 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 import { useTranslation } from 'next-i18next' // Components @@ -7,13 +9,10 @@ import Link from 'next/link' import { TimeAgo } from 'shared/components/mdx/meta.mjs' import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs' import { Pagination } from 'shared/components/navigation/pagination.mjs' -import { postInfo, order } from 'site/prebuild/blog-paths.mjs' // Translation namespaces used on this page const namespaces = [...new Set(['designs', 'sections', ...pageNs])] -export const numPerPage = 12 - const textShadow = { style: { textShadow: @@ -92,42 +91,26 @@ const BlogIndexPage = ({ posts, page, current, total }) => { export default BlogIndexPage export async function getStaticProps({ locale, params }) { - const pageNum = parseInt(params.page) - 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) + const props = getPostIndexProps(locale, params, order, postInfo) - if (pageNum > numLocPages) { - return { - notFound: true, - } - } + if (props === false) return { notFound: true } return { props: { // designs, - posts, - current: pageNum, - total: numLocPages, + ...props, ...(await serverSideTranslations(locale, namespaces)), page: { locale, - path: ['blog'], + path: ['showcase'], }, }, } } 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 { - paths, + paths: getPostIndexPaths(order, 'blog'), fallback: 'blocking', } } diff --git a/sites/org/pages/showcase/[slug].mjs b/sites/org/pages/showcase/[slug].mjs index 7fab9b82f99..5fc9a5bd170 100644 --- a/sites/org/pages/showcase/[slug].mjs +++ b/sites/org/pages/showcase/[slug].mjs @@ -1,13 +1,13 @@ -import { - SanityPageWrapper, - getSanityStaticPaths, - ns as sanityNs, -} from 'site/components/sanity/page-wrapper.mjs' +import { order } from 'site/prebuild/showcase-paths.mjs' +import { getPostSlugPaths } from 'site/components/mdx/posts/utils.mjs' import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import { useDynamicMdx } from 'shared/hooks/use-dynamic-mdx.mjs' 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 loader = useCallback( @@ -18,15 +18,21 @@ const ShowcasePage = ({ locale, slug, page }) => { const { frontmatter, MDX } = useDynamicMdx(loader) if (!MDX) return null return ( - + } + > + + ) } @@ -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 diff --git a/sites/org/pages/showcase/page/[page].mjs b/sites/org/pages/showcase/page/[page].mjs index 5cc582f0e58..ed792a8f79f 100644 --- a/sites/org/pages/showcase/page/[page].mjs +++ b/sites/org/pages/showcase/page/[page].mjs @@ -1,14 +1,13 @@ // Dependencies 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 import { useTranslation } from 'next-i18next' // Components -import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs' 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 { postInfo, order } from 'site/prebuild/showcase-paths.mjs' - -export const numPerPage = 12 // Translation namespaces used on this page const namespaces = [...new Set(['common', 'designs', ...pageNs])] @@ -76,23 +75,14 @@ const ShowcaseIndexPage = ({ posts, page, current, total }) => { export default ShowcaseIndexPage export async function getStaticProps({ locale, params }) { - const pageNum = parseInt(params.page) - 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) + const props = getPostIndexProps(locale, params, order, postInfo) - if (pageNum > numLocPages) { - return { - notFound: true, - } - } + if (props === false) return { notFound: true } return { props: { // designs, - posts, - current: pageNum, - total: numLocPages, + ...props, ...(await serverSideTranslations(locale, namespaces)), page: { locale, @@ -103,15 +93,8 @@ export async function getStaticProps({ locale, params }) { } 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 { - paths, + paths: getPostIndexPaths(order), fallback: 'blocking', } } diff --git a/sites/shared/prebuild/index.mjs b/sites/shared/prebuild/index.mjs index 08e16ca6c12..41396ae1ee7 100644 --- a/sites/shared/prebuild/index.mjs +++ b/sites/shared/prebuild/index.mjs @@ -18,9 +18,11 @@ const run = async () => { const SITE = process.env.SITE || 'lab' await prebuildDesigns() if (['org', 'dev'].includes(SITE)) { - if (!FAST) await prebuildGitData(SITE) + if (!FAST) { + await prebuildGitData(SITE) + await prebuildCrowdin() + } const docPages = await prebuildDocs(SITE) - await prebuildCrowdin() const postPages = await prebuildPosts(SITE) prebuildNavigation(docPages, postPages, SITE) if (!FAST && process.env.GENERATE_OG_IMAGES) { diff --git a/sites/shared/utils.mjs b/sites/shared/utils.mjs index e86027e920a..23d32368b97 100644 --- a/sites/shared/utils.mjs +++ b/sites/shared/utils.mjs @@ -349,3 +349,10 @@ export const maxPovDepthSlug = (slug, site) => { * In that case, this will return true */ 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