diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index b6fe3292172..f91c6fb0f0d 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -27,6 +27,7 @@ module.exports = {
extends: 'eslint:recommended',
env: {
es2021: true,
+ node: true,
},
// Required when using experimental EcmaScript features
parser: '@babel/eslint-parser',
diff --git a/sites/org/components/sanity/author.mjs b/sites/org/components/sanity/author.mjs
new file mode 100644
index 00000000000..ea79a9e9fea
--- /dev/null
+++ b/sites/org/components/sanity/author.mjs
@@ -0,0 +1,43 @@
+import { SanityMdxWrapper } from './mdx-wrapper.mjs'
+import { useTranslation } from 'next-i18next'
+
+export const Author = ({ author = {} }) => {
+ const { t } = useTranslation(['posts'])
+ return (
+
+
+
+
+

+
+
+
+ )
+}
diff --git a/sites/org/components/sanity/mdx-wrapper.mjs b/sites/org/components/sanity/mdx-wrapper.mjs
new file mode 100644
index 00000000000..82350d5e937
--- /dev/null
+++ b/sites/org/components/sanity/mdx-wrapper.mjs
@@ -0,0 +1,29 @@
+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(() => {
+ ;(async () => {
+ const code = await compile(mdxStr, {
+ outputFormat: 'function-body',
+ development: false,
+ })
+ const evaled = await run(code, runtime)
+ setMdxModule(() => evaled.default)
+ })()
+ }, [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
new file mode 100644
index 00000000000..4a4951734c9
--- /dev/null
+++ b/sites/org/components/sanity/page-wrapper.mjs
@@ -0,0 +1,80 @@
+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/wrappers/mdx.mjs'
+import { SanityMdxWrapper } from './mdx-wrapper.mjs'
+import { useTranslation } from 'next-i18next'
+
+export const ns = ['common', 'posts', ...pageNs]
+
+export const SanityPageWrapper = ({
+ post = {},
+ author = {},
+ page = {},
+ namespaces = ['common'],
+}) => {
+ const { t } = useTranslation(namespaces)
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [{post.date}]
+
+
+ {post.designs?.map((design) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/sites/shared/sanity.mjs b/sites/org/components/sanity/utils.mjs
similarity index 85%
rename from sites/shared/sanity.mjs
rename to sites/org/components/sanity/utils.mjs
index 8838d17e4b5..9b43f773ccc 100644
--- a/sites/shared/sanity.mjs
+++ b/sites/org/components/sanity/utils.mjs
@@ -3,7 +3,7 @@ import { createClient, groq } from 'next-sanity'
const sanityId = process.env.SANITY_PROJECT || 'hl5bw8cj'
let sanityClient
-export const sanityLoader = ({ query, language, type, slug }) => {
+export const sanityLoader = ({ query, language, type, slug, order }) => {
sanityClient =
sanityClient ||
createClient({
@@ -20,6 +20,10 @@ export const sanityLoader = ({ query, language, type, slug }) => {
query += ']'
}
+ if (order) {
+ query += ` | order(${order})`
+ }
+
return sanityClient.fetch(query)
}
diff --git a/sites/org/pages/blog/[slug].mjs b/sites/org/pages/blog/[slug].mjs
index a4673379728..ac44335fabb 100644
--- a/sites/org/pages/blog/[slug].mjs
+++ b/sites/org/pages/blog/[slug].mjs
@@ -1,113 +1,12 @@
-import { useState, useEffect } from 'react'
-import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
-import { PlainMdxWrapper, TimeAgo } from 'shared/components/wrappers/mdx.mjs'
-import ReactMarkdown from 'react-markdown'
-import Head from 'next/head'
-import { Lightbox } from 'shared/components/lightbox.mjs'
-import { ImageWrapper } from 'shared/components/wrappers/img.mjs'
+import { SanityPageWrapper, ns as sanityNs } from 'site/components/sanity/page-wrapper.mjs'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
+import { sanityLoader, sanityImage } from 'site/components/sanity/utils.mjs'
import { useTranslation } from 'next-i18next'
-import { sanityLoader, sanityImage } from 'shared/strapi/loader.js'
-import { strapiImage } from 'shared/utils.mjs'
-const strapi = 'https://posts.freesewing.org'
+const namespaces = [...sanityNs]
-const Author = ({ author }) => {
- return (
-
-
-
-
-

-
-
-
- {author?.displayname}
- Wrote this
-
-
-
-
- )
-}
-
-const BlogPostPage = ({ post, author }) => {
- const { t } = useTranslation(['common'])
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
+const BlogPostPage = (props) => {
+ return
}
/*
@@ -122,7 +21,7 @@ const BlogPostPage = ({ post, author }) => {
*/
export async function getStaticProps({ params, locale }) {
const { slug } = params
- const post = await sanityLoader({ type: 'blog', language: locale, slug, withImage: true })
+ const post = await sanityLoader({ type: 'blog', language: locale, slug })
.then((data) => data[0])
.catch((err) => console.log(err))
@@ -144,7 +43,7 @@ export async function getStaticProps({ params, locale }) {
// image: strapiImage(post.author.picture, ['small']),
// about: post.author.about,
},
- ...(await serverSideTranslations(locale)),
+ ...(await serverSideTranslations(locale, namespaces)),
},
}
}
diff --git a/sites/org/pages/blog/index.mjs b/sites/org/pages/blog/index.mjs
index ac62e259cf1..ba6b5b2a2c9 100644
--- a/sites/org/pages/blog/index.mjs
+++ b/sites/org/pages/blog/index.mjs
@@ -1,6 +1,6 @@
// Dependencies
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
-import { sanityLoader, sanityImage } from 'shared/sanity.mjs'
+import { sanityLoader, sanityImage } from 'site/components/sanity/utils.mjs'
// Hooks
import { useTranslation } from 'next-i18next'
// Components
diff --git a/sites/org/pages/showcase/[slug].mjs b/sites/org/pages/showcase/[slug].mjs
new file mode 100644
index 00000000000..550eba68162
--- /dev/null
+++ b/sites/org/pages/showcase/[slug].mjs
@@ -0,0 +1,72 @@
+import { SanityPageWrapper, ns as sanityNs } from 'site/components/sanity/page-wrapper.mjs'
+import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
+import { sanityLoader, sanityImage } from 'site/components/sanity/utils.mjs'
+import { useTranslation } from 'next-i18next'
+
+const namespaces = [...sanityNs]
+
+const ShowcasePage = (props) => {
+ return
+}
+
+/*
+ * getStaticProps() is used to fetch data at build-time.
+ *
+ * On this page, it is loading the showcase content from strapi.
+ *
+ * This, in combination with getStaticPaths() below means this
+ * page will be used to render/generate all showcase content.
+ *
+ * To learn more, see: https://nextjs.org/docs/basic-features/data-fetching
+ */
+export async function getStaticProps({ params, locale }) {
+ const { slug } = params
+ const post = await sanityLoader({ type: 'showcase', language: locale, slug })
+ .then((data) => data[0])
+ .catch((err) => console.log(err))
+
+ const designs = [post.design1 || null]
+ if (post.design2 && post.design2.length > 2) designs.push(post.design2)
+ if (post.design3 && post.design3.length > 2) designs.push(post.design3)
+
+ return {
+ props: {
+ post: {
+ slug,
+ body: post.body,
+ title: post.title,
+ date: post.date,
+ caption: post.caption,
+ image: sanityImage(post.image[0]),
+ designs,
+ },
+ // FIXME load the author separately
+ author: {
+ displayname: post.maker,
+ // slug: post.maker.slug,
+ // image: strapiImage(post.maker.picture, ['small']),
+ // ...(await mdxCompiler(post.maker.about)),
+ },
+ ...(await serverSideTranslations(locale, namespaces)),
+ },
+ }
+}
+
+export const getStaticPaths = async () => {
+ const paths = await sanityLoader({ language: 'en', type: 'showcase' })
+ .then((data) => data.map((post) => `/showcase/${post.slug.current}`))
+ .catch((err) => console.log(err))
+
+ return {
+ paths: [
+ ...paths,
+ ...paths.map((p) => `/de${p}`),
+ ...paths.map((p) => `/es${p}`),
+ ...paths.map((p) => `/fr${p}`),
+ ...paths.map((p) => `/nl${p}`),
+ ],
+ fallback: false,
+ }
+}
+
+export default ShowcasePage
diff --git a/sites/org/pages/showcase/index.mjs b/sites/org/pages/showcase/index.mjs
index 8b39fb430d3..9a2e128d518 100644
--- a/sites/org/pages/showcase/index.mjs
+++ b/sites/org/pages/showcase/index.mjs
@@ -1,34 +1,99 @@
// Dependencies
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
+import { useTranslation } from 'next-i18next'
+import { useMemo } from 'react'
+import { sanityLoader, sanityImage } from 'site/components/sanity/utils.mjs'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
-import { V3Wip } from 'shared/components/v3-wip.mjs'
+import Link from 'next/link'
+import { TimeAgo } from 'shared/components/wrappers/mdx.mjs'
// Translation namespaces used on this page
-const namespaces = [...new Set(['showcase', ...pageNs])]
+const namespaces = [...new Set(['common', 'designs', ...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 DesignsPage = ({ page }) => (
-
-
-
-
-
+export const PreviewTile = ({ img, slug, title }) => (
+
+
+ {title}
+
)
-export default DesignsPage
+// const DesignPosts = ({ design, posts }) => {
+// const { t } = useTranslation(['patterns'])
+// return (
+//
+// )
+// }
+
+// FIXME paginate
+const Posts = ({ posts }) => (
+
+ {posts.map((post) => (
+
+ ))}
+
+)
+
+const ShowcaseIndexPage = (props) => {
+ const { t } = useTranslation()
+ const { posts } = props
+ // const designKeys = useMemo(() => Object.keys(designs).sort(), [designs])
+ return (
+
+
+
+ )
+}
+
+export default ShowcaseIndexPage
export async function getStaticProps({ locale }) {
+ const posts = await sanityLoader({
+ language: locale,
+ type: 'showcase',
+ order: 'date desc',
+ }).catch((err) => console.log(err))
+
+ const designs = {}
+ const propPosts = []
+ posts.forEach((post) => {
+ // for (const design of post.designs) {
+ // if (typeof designs[design] === 'undefined') designs[design] = []
+ // designs[design].push(post)
+ // }
+
+ propPosts.push({
+ slug: post.slug.current,
+ title: post.title,
+ date: post.date,
+ // FIXME get the authors separately
+ author: post.maker,
+ image: sanityImage(post.image[0]) + '?fit=clip&w=400',
+ })
+ })
+
return {
props: {
+ posts: propPosts,
+ designs,
...(await serverSideTranslations(locale, namespaces)),
page: {
locale,
+ // title: 'Freesewing Blog',
path: ['showcase'],
},
},
diff --git a/sites/shared/components/wrappers/mdx.mjs b/sites/shared/components/wrappers/mdx.mjs
index 20087f954b3..18634583c6c 100644
--- a/sites/shared/components/wrappers/mdx.mjs
+++ b/sites/shared/components/wrappers/mdx.mjs
@@ -102,20 +102,20 @@ const MetaData = ({ authors = [], maintainers = [], updated = '20220825', locale
)
-export const PlainMdxWrapper = ({ MDX = false, components = {}, compile, children }) => {
- const allComponents = { ...baseComponents, ...components }
- const compiledMdx = MDX ? (
-
- ) : compile ? (
- {children}
- ) : (
- children
- )
+export const PlainMdxWrapper = ({ MDX = false, components = {}, children, site = 'org' }) => {
+ const allComponents = { ...baseComponents(site), ...components }
+ const CompiledMdx = MDX ? : children || ''
- return {compiledMdx}
+ return {MDX ? : children}
}
-export const MdxWrapper = ({ MDX = false, frontmatter = {}, components = {}, children = [] }) => {
+export const MdxWrapper = ({
+ MDX = false,
+ frontmatter = {},
+ components = {},
+ children = [],
+ site = 'org',
+}) => {
const { t } = useTranslation('docs')
const { locale, slug } = useContext(NavigationContext)
diff --git a/sites/shared/hooks/use-evaled-mdx.mjs b/sites/shared/hooks/use-evaled-mdx.mjs
new file mode 100644
index 00000000000..09c8ebe89bb
--- /dev/null
+++ b/sites/shared/hooks/use-evaled-mdx.mjs
@@ -0,0 +1,21 @@
+import { compile, run } from '@mdx-js/mdx'
+import * as runtime from 'react/jsx-runtime' // Production.
+
+import { useState, useEffect, Fragment } from 'react'
+
+export const useEvaledMdx = (mdxStr = '') => {
+ const [mdxModule, setMdxModule] = useState(false)
+
+ useEffect(() => {
+ ;(async () => {
+ const code = await compile(mdxStr, {
+ outputFormat: 'function-body',
+ development: false,
+ })
+ const evaled = await run(code, runtime)
+ setMdxModule(() => evaled.default)
+ })()
+ }, [mdxStr])
+
+ return mdxModule
+}