VideoEmbed.tsx 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import React from "react"
  2. interface VideoEmbedProps {
  3. url: string
  4. title?: string
  5. caption?: string
  6. }
  7. function extractVideoId(url: string): string | null {
  8. const patterns = [
  9. /(?:youtube\.com\/watch\?v=)([^&\s]+)/,
  10. /(?:youtube\.com\/embed\/)([^?\s]+)/,
  11. /(?:youtu\.be\/)([^?\s]+)/,
  12. /(?:youtube\.com\/v\/)([^?\s]+)/,
  13. ]
  14. for (const pattern of patterns) {
  15. const match = url.match(pattern)
  16. if (match) {
  17. return match[1] ?? null
  18. }
  19. }
  20. return null
  21. }
  22. export function VideoEmbed({ url, title = "Video", caption }: VideoEmbedProps) {
  23. const videoId = extractVideoId(url)
  24. if (!videoId) {
  25. return (
  26. <div
  27. style={{
  28. padding: "1rem",
  29. backgroundColor: "var(--red-100, #fee2e2)",
  30. color: "var(--red-700, #b91c1c)",
  31. borderRadius: "0.5rem",
  32. margin: "1.5rem 0",
  33. }}
  34. >
  35. Invalid YouTube URL: {url}
  36. </div>
  37. )
  38. }
  39. return (
  40. <div
  41. style={{
  42. maxWidth: "640px",
  43. margin: "1.5rem 0",
  44. }}
  45. >
  46. <div
  47. style={{
  48. position: "relative",
  49. paddingBottom: "56.25%",
  50. height: 0,
  51. overflow: "hidden",
  52. borderRadius: "0.5rem",
  53. }}
  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. >
  80. {caption}
  81. </figcaption>
  82. )}
  83. </div>
  84. )
  85. }