diff --git a/packages/freesewing.org/pages/showcase/index.js b/packages/freesewing.org/pages/showcase/index.js
new file mode 100644
index 00000000000..813ee0e6e38
--- /dev/null
+++ b/packages/freesewing.org/pages/showcase/index.js
@@ -0,0 +1,117 @@
+import Page from 'site/components/wrappers/page.js'
+import useApp from 'site/hooks/useApp.js'
+import Link from 'next/link'
+import PageLink from 'shared/components/page-link.js'
+import TimeAgo from 'react-timeago'
+import { strapiHost } from 'shared/config/freesewing.mjs'
+import { strapiImage } from 'shared/utils.js'
+import { useTranslation } from 'next-i18next'
+import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
+
+const PreviewTile = ({ img, slug, title }) => (
+
+)
+
+const DesignPosts = ({ design, posts }) => {
+ const { t } = useTranslation(['patterns'])
+ return (
+
+
+
+
+
+ {posts.slice(0, 10).map(post =>
)}
+
+
+ )
+}
+const ShowcaseIndexPage = (props) => {
+ const app = useApp()
+ const { t } = useTranslation()
+
+ const designs = {}
+ for (const post of props.posts) {
+ for (const design of post.designs) {
+ if (typeof designs[design] === 'undefined') designs[design] = []
+ designs[design].push(post)
+ }
+ }
+
+ return (
+
+
+ {Object.keys(designs).sort().map(design => )}
+
+
+ )
+}
+
+export default ShowcaseIndexPage
+
+/*
+ * 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 posts = await fetch(
+ `${strapiHost}/showcaseposts?_locale=${locale}&_sort=date:DESC&_limit=-1`
+ )
+ .then(response => response.json())
+ .then(data => data)
+ .catch(err => console.log(err))
+
+ return {
+ props: {
+ posts: posts.map(post => {
+ const designs = [post.design1]
+ if (post.design2 && post.design2.length > 2) designs.push(post.design2)
+ if (post.design3 && post.design3.length > 2) designs.push(post.design3)
+ return {
+ slug: post.slug,
+ title: post.title,
+ date: post.date,
+ maker: post.maker.displayname,
+ image: strapiImage(post.image, ['medium']),
+ designs
+ }
+ }),
+ ...(await serverSideTranslations(locale)),
+ }
+ }
+}
+
diff --git a/packages/freesewing.shared/utils.js b/packages/freesewing.shared/utils.js
index 1360b7c8b91..9e4394cee54 100644
--- a/packages/freesewing.shared/utils.js
+++ b/packages/freesewing.shared/utils.js
@@ -78,7 +78,7 @@ export const capitalize = string => string.charAt(0).toUpperCase() + string.slic
export const strapiImage = (img, sizes=['thumbnail', 'xlarge', 'large', 'medium', 'small', 'xsmall']) => {
const image = {
- caption: img.caption,
+ caption: img?.caption || '',
w: img.width,
h: img.height,
url: img.url,