fix(blog): optimize component share logic, typography, and modal layouts
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🏗️ Build (push) Failing after 14s
Build & Deploy / 🧪 QA (push) Failing after 1m48s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🏗️ Build (push) Failing after 14s
Build & Deploy / 🧪 QA (push) Failing after 1m48s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
This commit is contained in:
88
apps/web/src/components/LinkedInEmbed.tsx
Normal file
88
apps/web/src/components/LinkedInEmbed.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
|
||||
interface LinkedInEmbedProps {
|
||||
/** The post URL, e.g. "https://www.linkedin.com/posts/xyz" or raw URN */
|
||||
url: string;
|
||||
className?: string;
|
||||
width?: string | number;
|
||||
}
|
||||
|
||||
export function LinkedInEmbed({
|
||||
url,
|
||||
className = "",
|
||||
width = 504
|
||||
}: LinkedInEmbedProps) {
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
|
||||
// Extract the 19-digit ID from the URL or URN
|
||||
const match = url.match(/(\d{19})/);
|
||||
const embedId = match ? match[1] : null;
|
||||
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
}, []);
|
||||
|
||||
if (!isMounted || !embedId) return null;
|
||||
|
||||
// LinkedIn technically supports share, ugcPost, and activity. We start with share and natively cycle.
|
||||
const initialSrc = `https://www.linkedin.com/embed/feed/update/urn:li:share:${embedId}`;
|
||||
|
||||
const handleError = () => {
|
||||
if (!iframeRef.current) return;
|
||||
const currentSrc = iframeRef.current.src;
|
||||
|
||||
// If the 'share' URN 404s (e.g., restricted post type), fallback to 'activity', then 'ugcPost'
|
||||
if (currentSrc.includes('urn:li:share:')) {
|
||||
iframeRef.current.src = `https://www.linkedin.com/embed/feed/update/urn:li:activity:${embedId}`;
|
||||
} else if (currentSrc.includes('urn:li:activity:')) {
|
||||
iframeRef.current.src = `https://www.linkedin.com/embed/feed/update/urn:li:ugcPost:${embedId}`;
|
||||
} else {
|
||||
// All fallbacks exhausted. The post is truly dead or private.
|
||||
setHasError(true);
|
||||
}
|
||||
};
|
||||
|
||||
if (hasError) {
|
||||
return (
|
||||
<div className={`not-prose flex w-full justify-center my-8 ${className}`}>
|
||||
<div
|
||||
className="flex flex-col items-center justify-center text-center p-8 w-full max-w-[504px] border border-slate-200 border-dashed rounded-lg bg-slate-50 text-slate-500"
|
||||
style={{ minHeight: '150px' }}
|
||||
>
|
||||
<svg className="w-8 h-8 mb-3 text-slate-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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 className="text-sm font-medium">Beitrag nicht verfügbar</span>
|
||||
<span className="text-xs mt-1 text-slate-400">Dieser LinkedIn-Post wurde gelöscht oder die Privatsphäre-Einstellungen verhindern eine Einbettung.</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`not-prose flex w-full justify-center my-8 ${className}`}>
|
||||
<div
|
||||
className="linkedin-embed-container w-full max-w-[504px] border border-slate-200 rounded-lg overflow-hidden shadow-sm bg-white"
|
||||
style={{ width, minHeight: '500px' }}
|
||||
>
|
||||
{/* We use onLoad to detect successful rendering, relying on onError for explicit iframe load crashes */}
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
src={initialSrc}
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameBorder="0"
|
||||
allowFullScreen
|
||||
title="Embedded post"
|
||||
className="w-full min-h-[500px]"
|
||||
onError={handleError}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user