Troubleshooting custom preview of YouTube video in Sanity.io
3 replies
Last updated: Mar 30, 2023
C
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.
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
S
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
J
HI, is there a full example of this ? All examples i found are on v2 π
Mar 30, 2023, 6:10 PM
J
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',
}),
],
})
/**
* 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
The Sanity Composable Content Cloud is the headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.