Skip to content

Commit

Permalink
feat: add templating to netlify partials
Browse files Browse the repository at this point in the history
  • Loading branch information
johnathonroach committed Dec 31, 2022
1 parent cf43a2d commit 67ec624
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 22 deletions.
115 changes: 106 additions & 9 deletions packages/website/components/netlifyPartial.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,119 @@
import { MDXRemote } from 'next-mdx-remote'
import { useState, useEffect } from 'react'
import React, { useState, useEffect } from 'react'
import Loading from './loading'
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'

/*
* There are two ways we can load content from the CMS as a partial
*
* Compiled Content
* This takes compiled JSX from the CMS and plugs it into the <MDXRemote/> component as is.
*
* Templates with Metadata and Compiled Content
* For more complex content that needs more control and styling, we can use a template while passing in
* metadata from the frontmatter section of the CMS markdown into a custom React component.
*
* Template Naming Convention
* The template name corresponds to the content type from the CMS. For the image-grids content
* found at the api URI of https://blog.nft.storage/api/partials/image-grids/my-md-content,
* the template name would be 'image-grids' and should be added to the templates object
* as templates['image-grids']. Other content type examples could be
* templates['faq'], templates['my-new-type']
*
* All data from the frontmatter can be found in the meta property as well as the
* main body content that can be found in meta.body. The body content can be
* rendered like <MDXRemote {...meta.body} />
*/

/**
* Templates
* @template {Object<string,any>} T
* @param {T} obj
*/

/** @type {any} */
const templates = {}
/**
* Image Grid Template
* @param {Object} meta
*/
templates['image-grids'] = function (
/** @type {{
description: String | undefined;
images: [];
footer: String | undefined
}} */ meta
) {
return (
<div className="max-w-4xl mx-auto py-8 px-6 sm:px-16">
{meta.description && (
<ReactMarkdown
children={meta.description}
remarkPlugins={[remarkGfm]}
className="text-center mt-0 chicagoflf"
/>
)}
<div className="grid grid-cols-2 sm:grid-cols-[repeat(auto-fit,_minmax(150px,_1fr))] gap-4 p-5 justify-center mx-auto">
{meta.images.map(
(/** @type {{ src: string; alt: string | undefined; }} */ image) => (
<img
className="w-full h-[80px] object-contain object-center !border !border-solid !border-gray-200 rounded !py-4 !px-6 select-none mx-auto"
src={`${image.src}`}
alt={image.alt}
width="100%"
height={80}
/>
)
)}
</div>
{meta.footer && (
<ReactMarkdown
children={meta.footer}
remarkPlugins={[remarkGfm]}
className="text-center chicagoflf"
/>
)}
{/* For future reference, you can render main body content like so */}
{/*
{meta.body &&
<MDXRemote {...meta.body} />
}
*/}
</div>
)
}

/**
* @typedef {Object} NetlifyPartialProps
* @prop {string} [route]
* @prop {string} [template]
* @prop {string} [className]
* @prop {JSX.Element} [fallback]
*/

/**
*
* @param {NetlifyPartialProps} props
* @returns {JSX.Element}
*/
export default function NetlifyPartial({ route, className, fallback }) {
export default function NetlifyPartial({
route,
template,
className,
fallback,
}) {
/** @type [any, null | any] */
const [content, setContent] = useState()
/** @type [any, null | any] */
const [meta, setMeta] = useState()
const [error, setError] = useState(false)
useEffect(() => {
// TODO: Update fallback when we have the blog in production.
const host =
process.env.NEXT_PUBLIC_NETLIFY_CMS_ENDPOINT || 'https://blog.nft.storage'
const host = process.env.NEXT_PUBLIC_NETLIFY_CMS_ENDPOINT
fetch(`${host}/api/partials/${route}`)
.then(async (response) => {
return await response.text()
})
.then((text) => {
const obj = JSON.parse(text)
setMeta(obj.props.partial.meta)
setContent(obj.props.partial.content)
})
.catch((e) => {
Expand All @@ -41,7 +127,7 @@ export default function NetlifyPartial({ route, className, fallback }) {
}
return (
<div className={className}>
<p>An unexpected error occured.</p>
<p>An unexpected error occurred.</p>
</div>
)
}
Expand All @@ -54,6 +140,17 @@ export default function NetlifyPartial({ route, className, fallback }) {
)
}

{
if (meta && template && templates[template]) {
let TemplateComponent = templates[template]
return (
<div className={className}>
<TemplateComponent {...meta} body={content} />
</div>
)
}
}

return (
content && (
<div className={className}>
Expand Down
1 change: 1 addition & 0 deletions packages/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"react-dom": "17.0.2",
"react-icons": "^4.3.1",
"react-if": "4.0.1",
"react-markdown": "^8.0.4",
"react-query": "^3.34.15",
"react-tiny-popover": "^7.0.1",
"swagger-ui-react": "^4.1.3",
Expand Down
6 changes: 6 additions & 0 deletions packages/website/pages/stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,12 @@ export default function Stats({ logos }) {
className="netlify-partial-trusted-by-stats-page max-w-4xl mx-auto py-8 px-6 sm:px-16 text-center chicagoflf"
fallback={<TrustedBy logos={logos} />}
/>
{/* <NetlifyPartial
route="image-grids/trusted-by-home-page"
template="image-grids"
className="netlify-partial-trusted-by-stats-page max-w-4xl mx-auto py-8 px-6 sm:px-16 text-center chicagoflf"
fallback={<TrustedBy logos={logos} />}
/> */}
</div>
</div>
</div>
Expand Down
37 changes: 24 additions & 13 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4875,7 +4875,7 @@
resolved "https://registry.yarnpkg.com/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz#72a26101dc567b0d68fd956cf42314556e42d601"
integrity sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==

"@types/prop-types@*":
"@types/prop-types@*", "@types/prop-types@^15.0.0":
version "15.7.5"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
Expand Down Expand Up @@ -16834,16 +16834,11 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"

[email protected], prettier@^2.5.1:
[email protected], "prettier@>=2.2.1 <=2.3.0", prettier@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==

"prettier@>=2.2.1 <=2.3.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18"
integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==

pretty-error@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6"
Expand Down Expand Up @@ -17384,6 +17379,27 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==

react-markdown@^8.0.4:
version "8.0.4"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.4.tgz#b5ff1f0f29ead71a7a6f98815eb1a70bcc2a036e"
integrity sha512-2oxHa6oDxc1apg/Gnc1Goh06t3B617xeywqI/92wmDV9FELI6ayRkwge7w7DoEqM0gRpZGTNU6xQG+YpJISnVg==
dependencies:
"@types/hast" "^2.0.0"
"@types/prop-types" "^15.0.0"
"@types/unist" "^2.0.0"
comma-separated-tokens "^2.0.0"
hast-util-whitespace "^2.0.0"
prop-types "^15.0.0"
property-information "^6.0.0"
react-is "^18.0.0"
remark-parse "^10.0.0"
remark-rehype "^10.0.0"
space-separated-tokens "^2.0.0"
style-to-object "^0.3.0"
unified "^10.0.0"
unist-util-visit "^4.0.0"
vfile "^5.0.0"

react-merge-refs@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-1.1.0.tgz#73d88b892c6c68cbb7a66e0800faa374f4c38b06"
Expand Down Expand Up @@ -20016,12 +20032,7 @@ typedoc@^0.22.14:
minimatch "^5.1.0"
shiki "^0.10.1"

[email protected]:
version "4.4.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c"
integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==

[email protected]:
[email protected], [email protected]:
version "4.5.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.3.tgz#afaa858e68c7103317d89eb90c5d8906268d353c"
integrity sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ==
Expand Down

0 comments on commit 67ec624

Please sign in to comment.