Files
MOPC-Portal/src/components/shared/resource-renderer.tsx

72 lines
1.7 KiB
TypeScript
Raw Normal View History

'use client'
import dynamic from 'next/dynamic'
const BlockViewer = dynamic(
() => import('@/components/shared/block-editor').then((mod) => mod.BlockViewer),
{
ssr: false,
loading: () => (
<div className="min-h-[200px] rounded-lg border bg-muted/20 animate-pulse" />
),
}
)
interface ResourceRendererProps {
title: string
description?: string | null
contentJson: unknown // BlockNote PartialBlock[] stored as JSON
coverImageUrl?: string | null
className?: string
}
export function ResourceRenderer({
title,
description,
contentJson,
coverImageUrl,
className,
}: ResourceRendererProps) {
const contentString =
typeof contentJson === 'string' ? contentJson : JSON.stringify(contentJson)
return (
<article className={`mx-auto max-w-3xl ${className ?? ''}`}>
{/* Cover image */}
{coverImageUrl && (
<div className="mb-8 overflow-hidden rounded-lg">
<img
src={coverImageUrl}
alt=""
className="h-auto w-full object-cover"
/>
</div>
)}
{/* Title */}
<h1 className="text-3xl font-bold tracking-tight text-foreground sm:text-4xl">
{title}
</h1>
{/* Description */}
{description && (
<p className="mt-3 text-lg text-muted-foreground leading-relaxed">
{description}
</p>
)}
{/* Divider */}
<hr className="my-6 border-border" />
{/* Content */}
{contentJson ? (
<div className="prose-renderer">
<BlockViewer content={contentString} />
</div>
) : (
<p className="text-muted-foreground italic">No content</p>
)}
</article>
)
}