I added custom block YouTube block using this tutorial. I have problem with render the YouTube embed in a frontend. [slug].tsx file:
import { GetStaticProps } from 'next';
import Header from '../../components/Header';
import { sanityClient, urlFor } from '../../sanity';
import { Post } from '../../typings';
import PortableText from "react-portable-text";
import YouTube from "react-youtube";
import getYouTubeID from "get-youtube-id";
interface Props {
post: Post;
}
const serializers = {
block: ({node}: any) => {
if (node._type === 'youtube') {
console.log(`NODE: ${JSON.stringify(node)}`)
const {url} = node
const id = getYouTubeID(url)
return (<YouTube videoId={id}/>)
}
},
normal: (props: any) => (
<p className=""> {props.children}</p>
),
h1: (props: any) => (
<h1 className="text-2xl font-bold my-5"> {props.children}</h1>
),
h2: (props: any) => (
<h2 className="text-xl font-bold my-5"> {props.children}</h2>
),
h3: (props: any) => (
<h3 className="text-xl font-bold my-5"> {props.children}</h3>
),
h4: (props: any) => (
<h4 className="text-lg font-bold my-5"> {props.children}</h4>
),
h5: (props: any) => (
<h5 className="text-base font-bold my-5"> {props.children}</h5>
),
h6: (props: any) => (
<h6 className="text-sm font-bold my-5"> {props.children}</h6>
),
blockquote: ({children}: any) => (
<blockquote className="p-4 my-4 bg-gray-50 border-l-4 border-gray-300 dark:border-gray-500 dark:bg-gray-300">
<p className="text-xl italic font-medium leading-relaxed text-gray-900 dark:text-white">{children}</p>
</blockquote>
),
li: ({children}: any) => (
<li className="ml-4 list-disc"> {children}</li>
),
link: ({href, children}: any) => (
<a href={href} className="text-blue-500 hover:underline">
{children}
</a>
),
}
function Posts({post}: Props) {
console.log(post);
return (
<main>
<Header/>
<img src={urlFor(post.mainImage).url()!} alt="" className="w-full h-40 object-cover"/>
<article className="max-w-3xl mx-auto p-5">
<h1 className="text-3xl mt-10 mb-3">{post.title}</h1>
<h2 className="text-xl font-light text-gray-500 mb-2">{post.description}</h2>
<div className="flex items-center space-x-2">
<img className="h-10 w-10 rounded-full" src={urlFor(post.author.image).url()!} alt=""/>
<p className="font-extralight text-sm">
<span className="text-green-600">Blog post by {post.author.name} </span> - Published at {" "}
{new Date(post._createdAt).toLocaleString()}
</p>
</div>
<div className="mt-10">
<PortableText dataset={process.env.NEXT_PUBLIC_SANITY_DATASET!}
projectId={process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!}
content={post.body}
serializers={serializers}
/>
</div>
</article>
</main>
);
}
export default Posts;
export const getStaticPaths = async () => {
const query = `*[_type == "post"]{
_id,
slug {
current
}
}`;
const posts = await sanityClient.fetch(query);
const paths = posts.map((post: Post) => ({
params: {
slug: post.slug.current,
},
}));
return {
paths,
fallback: 'blocking',
};
};
export const getStaticProps: GetStaticProps = async ({params}) => {
const query = `*[_type == "post" && slug.current == $slug][0]{
_id,
_createdAt,
title,
author-> {
name,
image
},
'comments' : *[_type == "comment" &&
post._ref == ^._id &&
approved== true],
description,
mainImage,
slug,
body
}`;
const post = await sanityClient.fetch(query, {
slug: params?.slug,
});
if (!post) {
return {
notFound: true,
};
}
return {
props: {
post,
},
revalidate: 60
};
};
The problem is that block overwrites the default serializer. Because of this, it only renders my YouTube video, but no longer renders my headlines, block quotes, etc. screenshot of the problem.
How to properly display video, headlines and block quotes?
I used @portabletext/react instead of react-portable-text. For customizing individual block styles, I was helped by this example from migration notes.