45 lines
1.2 KiB
TypeScript
45 lines
1.2 KiB
TypeScript
"use client"
|
|
|
|
import { useMemo } from "react"
|
|
|
|
interface YouTubeEmbedProps {
|
|
url: string
|
|
title?: string
|
|
}
|
|
|
|
function extractVideoId(url: string): string | null {
|
|
// Handle various YouTube URL formats
|
|
const patterns = [
|
|
/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&?/]+)/,
|
|
/youtube\.com\/v\/([^&?/]+)/,
|
|
/youtube\.com\/shorts\/([^&?/]+)/
|
|
]
|
|
|
|
for (const pattern of patterns) {
|
|
const match = url.match(pattern)
|
|
if (match && match[1]) {
|
|
return match[1]
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
export function YouTubeEmbed({ url, title = "YouTube video" }: YouTubeEmbedProps) {
|
|
const videoId = useMemo(() => extractVideoId(url), [url])
|
|
|
|
if (!videoId) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<div className="relative w-full aspect-video rounded-lg overflow-hidden bg-muted">
|
|
<iframe
|
|
src={`https://www.youtube.com/embed/${videoId}`}
|
|
title={title}
|
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
allowFullScreen
|
|
className="absolute inset-0 w-full h-full"
|
|
/>
|
|
</div>
|
|
)
|
|
}
|