feat: Add video embedding for YouTube and Vimeo links in PostCard.
This commit is contained in:
@@ -338,6 +338,25 @@ a.btn-primary:visited {
|
|||||||
display: block;
|
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 {
|
.post-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import Link from 'next/link';
|
|||||||
import { HeartIcon, RepeatIcon, MessageIcon, FlagIcon, TrashIcon } from '@/components/Icons';
|
import { HeartIcon, RepeatIcon, MessageIcon, FlagIcon, TrashIcon } from '@/components/Icons';
|
||||||
import { Post } from '@/lib/types';
|
import { Post } from '@/lib/types';
|
||||||
import { useAuth } from '@/lib/contexts/AuthContext';
|
import { useAuth } from '@/lib/contexts/AuthContext';
|
||||||
|
import { VideoEmbed } from '@/components/VideoEmbed';
|
||||||
|
|
||||||
interface PostCardProps {
|
interface PostCardProps {
|
||||||
post: Post;
|
post: Post;
|
||||||
@@ -181,6 +182,10 @@ export function PostCard({ post, onLike, onRepost, onComment, onDelete, isDetail
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{post.linkPreviewUrl && (
|
{post.linkPreviewUrl && (
|
||||||
|
<VideoEmbed url={post.linkPreviewUrl} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{post.linkPreviewUrl && !post.linkPreviewUrl.match(/(youtube\.com|youtu\.be|vimeo\.com)/) && (
|
||||||
<a
|
<a
|
||||||
href={post.linkPreviewUrl}
|
href={post.linkPreviewUrl}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
interface VideoEmbedProps {
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VideoEmbed({ url }: VideoEmbedProps) {
|
||||||
|
const getYouTubeId = (url: string) => {
|
||||||
|
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 (
|
||||||
|
<div className="video-embed-container">
|
||||||
|
<iframe
|
||||||
|
src={`https://www.youtube.com/embed/${youtubeId}`}
|
||||||
|
title="YouTube video player"
|
||||||
|
frameBorder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
|
allowFullScreen
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vimeoId) {
|
||||||
|
return (
|
||||||
|
<div className="video-embed-container">
|
||||||
|
<iframe
|
||||||
|
src={`https://player.vimeo.com/video/${vimeoId}`}
|
||||||
|
title="Vimeo video player"
|
||||||
|
frameBorder="0"
|
||||||
|
allow="autoplay; fullscreen; picture-in-picture"
|
||||||
|
allowFullScreen
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user