Troubleshooting custom preview of YouTube video in Sanity.io

3 replies
Last updated: Mar 30, 2023
Hello everyone! πŸ™‚
Im trying to make a custom preview of a embed youtube video but it doesnt work. What am i doing wrong? Its version 3.


import { defineField, defineType } from "sanity";
import getYouTubeId from "get-youtube-id";

interface Youtube {
  _type: "youtube";
  url: string;
}

interface PreviewProps {
  media: React.ReactNode;
  title: string;
}

const YoutubePreview: React.FC<PreviewProps> = ({ media, title }) => {
  const id = getYouTubeId(media as string);
  const embedUrl = `<https://www.youtube.com/embed/${id}>`;
  return (
    <div>
      <h2>{title}</h2>
      <iframe
        width="560"
        height="315"
        src={embedUrl}
        title="YouTube video player"
        frameBorder="0"
        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
        allowFullScreen
      ></iframe>
    </div>
  );
};

export default defineType({
  name: "youtube",
  type: "object",
  fields: [
    {
      name: "url",
      title: "URL",
      type: "url",
      validation: (Rule) => Rule.required(),
    },
  ],
  preview: {
    select: {
      url: "url",
    },
    prepare(selection) {
      const { url } = selection;
      if (!url) {
        return {
          title: "Missing YouTube URL",
          media: <div>Missing YouTube URL</div>,
        };
      }
      const id = getYouTubeId(url);
      const media = (
        <img
          src={`<https://i.ytimg.com/vi/${id}/hqdefault.jpg>`}
          alt="Video thumbnail"
        />
      );
      return {
        title: "YouTube Video",
        media,
      };
    },
    component: YoutubePreview,
  },
}) as unknown as Youtube;
Mar 21, 2023, 11:22 AM
Ah you dont want to just define the preview.media (but as you can see it does work in general πŸ˜‰ ), but define the preview component for the whole type. At the moment you’re only defining a custom component for media.you need to define this on the type bot in the preview, but I would still select and prepare values as do
πŸ™‚
components:{
  preview: YoutubePreview,
}
Mar 21, 2023, 12:05 PM
HI, is there a full example of this ? All examples i found are on v2 😞
Mar 30, 2023, 6:10 PM
ok got it`Μ€`import {defineType, defineArrayMember} from 'sanity'

/**
* This is the schema definition for the rich text fields used for
* for this blog studio. When you import it in schemas.js it can be
* reused in other parts of the studio with:
* {
* name: 'someName',
* title: 'Some title',
* type: 'blockContent'
* }
*/
export default defineType({
title: 'Block Content',
name: 'blockContent',
type: 'array',
of: [
defineArrayMember({
title: 'Block',
type: 'block',
// Styles let you set what your user can mark up blocks with. These
// correspond with HTML tags, but you can set any title or value
// you want and decide how you want to deal with it where you want to
// use your content.
styles: [
{title: 'Normal', value: 'normal'},
{title: 'H1', value: 'h1'},
{title: 'H2', value: 'h2'},
{title: 'H3', value: 'h3'},
{title: 'H4', value: 'h4'},
{title: 'Quote', value: 'blockquote'},
],
lists: [{title: 'Bullet', value: 'bullet'}],
// Marks let you mark up inline text in the block editor.
marks: {
// Decorators usually describe a single property – e.g. a typographic
// preference or highlighting by editors.
decorators: [
{title: 'Strong', value: 'strong'},
{title: 'Emphasis', value: 'em'},
],

// Annotations can be any object structure – e.g. a link or a footnote.
annotations: [
{
name: 'link',
type: 'object',
title: 'External link',
fields: [
{
name: 'href',
type: 'url',
title: 'URL',
},
{
title: 'Ouvrir dans un nouvel onglet',
name: 'blank',

type: 'boolean',
},
{
title: 'Nofollow',
name: 'nofollow',

type: 'boolean',
},
{
title: 'Sponsored',
name: 'sponsored',

type: 'boolean',
},
{
title: 'User generated content',
name: 'ugc',
type: 'boolean',
},
{
title: 'Cloaked',
name: 'cloaked',
type: 'boolean',
},
],
},
{
name: 'internalLink',
type: 'object',
title: 'Internal link',
fields: [
{
name: 'reference',
type: 'reference',
title: 'Reference',
to: [
{type: 'post'},
// other types you may want to link to
],
},
{
name: 'obfuscation',
title: 'obfuscation',
type: 'boolean',
},
],
},
],
},
}),
// You can add additional types here. Note that you can't use
// primitive types such as 'string' and 'number' in the same array
// as a block type.
defineArrayMember({
type: 'image',
options: {hotspot: true},
}),
defineArrayMember({
type: 'youtube',
}),
],
})
Mar 30, 2023, 6:21 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?