diff --git a/components/Feed/ArticleReader/ArticleReader.css b/components/Feed/ArticleReader/ArticleReader.css index 2264d1f..e33a7a0 100644 --- a/components/Feed/ArticleReader/ArticleReader.css +++ b/components/Feed/ArticleReader/ArticleReader.css @@ -118,7 +118,8 @@ /* Embedded content */ .reader-view-article-content iframe, -.reader-view-page-content iframe { +.reader-view-page-content iframe, +.reader-view-article iframe { width: 100%; max-height: 450px; height: 100%; @@ -129,6 +130,13 @@ aspect-ratio: 16/9; } +/* YouTube embed specific styling */ +.reader-view-article iframe[src*="youtube.com/embed"] { + min-height: 315px; + max-height: 500px; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); +} + /* Article container */ .reader-view-article-content { position: relative; diff --git a/components/Feed/ArticleReader/ArticleReader.tsx b/components/Feed/ArticleReader/ArticleReader.tsx index bfd4150..d36abda 100644 --- a/components/Feed/ArticleReader/ArticleReader.tsx +++ b/components/Feed/ArticleReader/ArticleReader.tsx @@ -22,6 +22,43 @@ import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import rehypeRaw from "rehype-raw"; +// YouTube helper functions +const isYouTubeEmbedUrl = (url: string): boolean => { + return url.includes('youtube.com/embed/') || url.includes('youtu.be/'); +}; + +const extractYouTubeVideoId = (url: string): string | null => { + try { + const urlObj = new URL(url); + + // Handle youtube.com/embed/VIDEO_ID format + if (urlObj.hostname === 'www.youtube.com' || urlObj.hostname === 'youtube.com') { + const embedMatch = urlObj.pathname.match(/^\/embed\/([a-zA-Z0-9_-]+)/); + if (embedMatch) { + return embedMatch[1]; + } + + // Handle youtube.com/watch?v=VIDEO_ID format + const watchMatch = urlObj.searchParams.get('v'); + if (watchMatch) { + return watchMatch; + } + } + + // Handle youtu.be/VIDEO_ID format + if (urlObj.hostname === 'youtu.be') { + const shortMatch = urlObj.pathname.match(/^\/([a-zA-Z0-9_-]+)/); + if (shortMatch) { + return shortMatch[1]; + } + } + + return null; + } catch { + return null; + } +}; + export const ArticleImage = memo( ({ src, @@ -677,17 +714,40 @@ export const ArticleContent = memo( li: ({ children }: { children: React.ReactNode }) => (