user13680445
user13680445

Reputation:

Contentful richText with next.js

Im trying to integrate contentful rich text in my blog and its only working with bold, paragraphs and italics. I cant make the images and embedded things appear.

First i have this component:

const Content = ({ content }) => {
  return (
    <div className="content-body-contentful">
      {documentToReactComponents(content)}
    </div>
  )
}

Then, in the post page, i import that component and pass de data like this:

<Content content={article.fields.body} />

Any answer to this problem?

Upvotes: 0

Views: 3124

Answers (2)

Hi @user13680445 the Richtext field in contentful always return something like this at least as a Graphql response

"richTextResponse": {
  // JSON structure of the Rich Text field
  "json": {
    # ...
  }
  // all referenced assets/entries
  "links": {
    # ...
  }
}

in the links field you get all the assets and entries you are embedded in your Richtext

Here I have an example in Typescript of how to add assets

    export const renderOptions = (links: Links): Options => {
      const assetMap = getAssets(links.assets.block);
      const entryMap = getEntries(links.entries.block);
    
      return {
        renderNode: {
          [BLOCKS.HEADING_1]: renderHeading,
          [BLOCKS.PARAGRAPH]: renderParagraph,
          [BLOCKS.EMBEDDED_ENTRY]: renderEntry(entryMap),
          [BLOCKS.EMBEDDED_ASSET]: renderAsset(assetMap),
        },
      };
    };
    
const renderAsset =
  (assetMap: Map<string, ContentfulImage>): NodeRenderer =>
  (node) => {
    const asset = assetMap.get(node.data.target.sys.id);
    if (!asset) {
      return <></>;
    }
    switch (asset.contentType) {
      case "video/mp4":
        return (
          <VideoAsset
            url={asset.url}
            width={asset.width}
            height={asset.height}
          />
        );
      case "image/png":
      case "image/jpeg":
        return (
          <ImageAsset
            url={asset.url}
            width={600}
            height={450}
            description={asset.description}
            quality={75}
          />
        );
      default:
        return "Nothing to see here...";
    }
  };

and then you can call that function like this:

{documentToReactComponents(json, renderOptions(links))}

it's a rudimentary way to do it but Contentful at the moment doesn't have a better way to do it.

there we got the asset data matching the sys.id in the nodeType and the sys.id in your asset link for example:

RichText Object

{
  "nodeType": "embedded-asset-block",
  "content": [],
  "data": {
    "target": {
      "sys": {
        "id": "2DdSHQJA8zoumehPzqWZrs",
        "type": "Link",
        "linkType": "Asset"
      }
    }
  }
}

links object

"links": {
  "assets": {
    "block": [
      {
        "sys": {
          "id": "2DdSHQJA8zoumehPzqWZrs"
        },
        "fileName": "GOPR0511.JPG",
        "url": "https://images.ctfassets.net/",
        "title": "GOPR0511"
      }
    ]
  }
}

we are connecting both based on the sys.id, in this case, is 2DdSHQJA8zoumehPzqWZrs

Upvotes: 1

Sawan Patodia
Sawan Patodia

Reputation: 839

Below is a sample for using image with Next.js via Contentful. You can implement rest of the items similarly.

import Image from 'next/image'

const renderProps = {
    renderNode: {
        [BLOCKS.EMBEDDED_ASSET]: node => {
            let { description, file } = node.data.target.fields

            return (
                <picture>
                    <Image src={file.url} alt={description} />
                </picture>
            )
        },
    },
}
const Content = ({ content }) => {
    return <div className="content-body-contentful">{documentToReactComponents(content, renderProps)}</div>
}

Upvotes: -1

Related Questions