From 59ba9f7d8b3e2eb29006063637987e3f01102186 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 22 Jan 2026 18:40:26 -0800 Subject: [PATCH] feat: Add video embedding for YouTube and Vimeo links in PostCard. --- src/app/globals.css | 19 +++++++++++++ src/components/PostCard.tsx | 5 ++++ src/components/VideoEmbed.tsx | 52 +++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/components/VideoEmbed.tsx diff --git a/src/app/globals.css b/src/app/globals.css index dfd1b05..6d32303 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -338,6 +338,25 @@ a.btn-primary:visited { display: block; } +.video-embed-container { + position: relative; + padding-bottom: 56.25%; /* 16:9 aspect ratio */ + height: 0; + overflow: hidden; + border-radius: var(--radius-md); + margin-bottom: 12px; + border: 1px solid var(--border); + background: #000; +} + +.video-embed-container iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + .post-actions { display: flex; gap: 24px; diff --git a/src/components/PostCard.tsx b/src/components/PostCard.tsx index ae89e73..e653491 100644 --- a/src/components/PostCard.tsx +++ b/src/components/PostCard.tsx @@ -5,6 +5,7 @@ import Link from 'next/link'; import { HeartIcon, RepeatIcon, MessageIcon, FlagIcon, TrashIcon } from '@/components/Icons'; import { Post } from '@/lib/types'; import { useAuth } from '@/lib/contexts/AuthContext'; +import { VideoEmbed } from '@/components/VideoEmbed'; interface PostCardProps { post: Post; @@ -181,6 +182,10 @@ export function PostCard({ post, onLike, onRepost, onComment, onDelete, isDetail )} {post.linkPreviewUrl && ( + + )} + + {post.linkPreviewUrl && !post.linkPreviewUrl.match(/(youtube\.com|youtu\.be|vimeo\.com)/) && ( { + const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/; + const match = url.match(regExp); + return (match && match[2].length === 11) ? match[2] : null; + }; + + const getVimeoId = (url: string) => { + const regExp = /(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/(?:[^\/]*)\/videos\/|album\/(?:\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)/; + const match = url.match(regExp); + return match ? match[1] : null; + }; + + const youtubeId = getYouTubeId(url); + const vimeoId = getVimeoId(url); + + if (youtubeId) { + return ( +
+ +
+ ); + } + + if (vimeoId) { + return ( +
+ +
+ ); + } + + return null; +}