Files
mintel.me/apps/web/src/components/GenericEmbed.tsx
Marc Mintel 103d71851c
Some checks failed
🧪 CI (QA) / 🧪 Quality Assurance (push) Failing after 1m3s
chore: overhaul infrastructure and integrate @mintel packages
- Restructure to pnpm monorepo (site moved to apps/web)
- Integrate @mintel/tsconfig, @mintel/eslint-config, @mintel/husky-config
- Implement Docker service architecture (Varnish, Directus, Gatekeeper)
- Setup environment-aware Gitea Actions deployment
2026-02-05 14:18:51 +01:00

99 lines
3.0 KiB
TypeScript

import React from 'react';
interface GenericEmbedProps {
url: string;
className?: string;
maxWidth?: string;
type?: 'video' | 'article' | 'rich';
}
export const GenericEmbed: React.FC<GenericEmbedProps> = ({
url,
className = "",
maxWidth = "100%",
type = 'rich'
}) => {
let embedUrl: string | null = null;
let provider = 'unknown';
try {
const urlObj = new URL(url);
const hostname = urlObj.hostname.replace('www.', '');
if (hostname.includes('youtube.com') || hostname.includes('youtu.be')) {
const videoId = urlObj.searchParams.get('v') || urlObj.pathname.split('/').pop();
if (videoId) {
embedUrl = `https://www.youtube.com/embed/${videoId}`;
provider = 'youtube.com';
}
}
else if (hostname.includes('vimeo.com')) {
const videoId = urlObj.pathname.split('/').filter(Boolean)[0];
if (videoId) {
embedUrl = `https://player.vimeo.com/video/${videoId}`;
provider = 'vimeo.com';
}
}
else if (hostname.includes('codepen.io')) {
const penPath = urlObj.pathname.replace('/pen/', '/');
embedUrl = `https://codepen.io${penPath}?default-tab=html,result`;
provider = 'codepen.io';
}
else if (hostname.includes('gist.github.com')) {
const gistPath = urlObj.pathname;
embedUrl = `https://gist.github.com${gistPath}.js`;
provider = 'gist.github.com';
}
} catch (e) {
console.warn('GenericEmbed: Failed to parse URL', e);
}
const hasEmbed = embedUrl !== null;
return (
<div
className={`generic-embed not-prose ${className}`}
data-provider={provider}
data-type={type}
style={{ '--max-width': maxWidth } as React.CSSProperties}
>
{hasEmbed ? (
<div className="embed-wrapper">
{type === 'video' ? (
<iframe
src={embedUrl!}
width="100%"
height="100%"
style={{ border: 'none', width: '100%', height: '100%' }}
allowFullScreen
loading="lazy"
title={`${provider} embed`}
/>
) : (
<iframe
src={embedUrl!}
width="100%"
height="400"
style={{ border: 'none' }}
loading="lazy"
title={`${provider} embed`}
/>
)}
</div>
) : (
<div className="embed-fallback">
<div className="fallback-content">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>Unable to embed this URL</span>
<a href={url} target="_blank" rel="noopener noreferrer" className="fallback-link">
Open link
</a>
</div>
</div>
)}
</div>
);
};