YouTube.tsx 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import React from "react"
  2. interface YouTubeProps {
  3. url: string
  4. title?: string
  5. caption?: string
  6. }
  7. /**
  8. * Extracts the YouTube video ID from various URL formats
  9. */
  10. function extractVideoId(url: string): string | null {
  11. const patterns = [
  12. /(?:youtube\.com\/watch\?v=)([^&\s]+)/,
  13. /(?:youtube\.com\/embed\/)([^?\s]+)/,
  14. /(?:youtu\.be\/)([^?\s]+)/,
  15. /(?:youtube\.com\/v\/)([^?\s]+)/,
  16. ]
  17. for (const pattern of patterns) {
  18. const match = url.match(pattern)
  19. if (match) {
  20. return match[1]
  21. }
  22. }
  23. return null
  24. }
  25. export function YouTube({ url, title = "YouTube video", caption }: YouTubeProps) {
  26. const videoId = extractVideoId(url)
  27. if (!videoId) {
  28. return (
  29. <div
  30. style={{
  31. padding: "1rem",
  32. backgroundColor: "var(--red-100, #fee2e2)",
  33. color: "var(--red-700, #b91c1c)",
  34. borderRadius: "0.5rem",
  35. margin: "1.5rem 0",
  36. }}>
  37. Invalid YouTube URL: {url}
  38. </div>
  39. )
  40. }
  41. return (
  42. <div
  43. style={{
  44. maxWidth: "640px",
  45. margin: "1.5rem 0",
  46. }}>
  47. <div
  48. style={{
  49. position: "relative",
  50. paddingBottom: "56.25%", // 16:9 aspect ratio
  51. height: 0,
  52. overflow: "hidden",
  53. borderRadius: "0.5rem",
  54. }}>
  55. <iframe
  56. src={`https://www.youtube.com/embed/${videoId}`}
  57. title={title}
  58. style={{
  59. position: "absolute",
  60. top: 0,
  61. left: 0,
  62. width: "100%",
  63. height: "100%",
  64. border: "none",
  65. borderRadius: "0.5rem",
  66. }}
  67. allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
  68. allowFullScreen
  69. />
  70. </div>
  71. {caption && (
  72. <figcaption
  73. style={{
  74. fontStyle: "italic",
  75. textAlign: "center",
  76. marginTop: "0.5rem",
  77. color: "var(--gray-600, #6b7280)",
  78. }}>
  79. {caption}
  80. </figcaption>
  81. )}
  82. </div>
  83. )
  84. }