PaperStack / components /BlogSection.tsx
Akhil-Theerthala's picture
checkpoint-2
ade3003 verified
raw
history blame
7.98 kB
import React from 'react';
import ReactMarkdown from 'react-markdown';
import { BlogSection as BlogSectionType } from '../types';
import MermaidDiagram from './MermaidDiagram';
import InteractiveChart from './InteractiveChart';
import EquationBlock from './EquationBlock';
import Collapsible from './Collapsible';
import Tooltip from './Tooltip';
import { Info, Lightbulb, AlertTriangle, BookOpen } from 'lucide-react';
interface Props {
section: BlogSectionType;
theme: 'light' | 'dark';
index: number;
}
const BlogSectionComponent: React.FC<Props> = ({ section, theme, index }) => {
const getMarginNoteIcon = (icon?: 'info' | 'warning' | 'tip' | 'note') => {
switch (icon) {
case 'warning':
return <AlertTriangle size={14} className="text-amber-500" />;
case 'tip':
return <Lightbulb size={14} className="text-green-500" />;
case 'info':
return <Info size={14} className="text-blue-500" />;
default:
return <BookOpen size={14} className="text-gray-400" />;
}
};
// Apply tooltips to content
const renderContent = () => {
if (!section.technicalTerms || section.technicalTerms.length === 0) {
return <ReactMarkdown>{section.content}</ReactMarkdown>;
}
// For complex tooltip integration, we'll render ReactMarkdown
// and let users hover on specially marked terms
return (
<div className="relative">
<ReactMarkdown>{section.content}</ReactMarkdown>
{/* Technical Terms Legend */}
{section.technicalTerms.length > 0 && (
<div className="mt-6 p-4 bg-gray-50 dark:bg-gray-800/50 rounded-xl border border-gray-200 dark:border-gray-700">
<h5 className="text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-3">
Key Terms
</h5>
<div className="flex flex-wrap gap-2">
{section.technicalTerms.map((term, idx) => (
<Tooltip key={idx} term={term.term} definition={term.definition}>
<span className="inline-flex items-center px-2.5 py-1 rounded-lg bg-brand-50 dark:bg-brand-900/20 text-brand-700 dark:text-brand-300 text-sm font-medium cursor-help">
{term.term}
</span>
</Tooltip>
))}
</div>
</div>
)}
</div>
);
};
return (
<section
id={`section-${section.id}`}
className="relative scroll-mt-32 animate-in fade-in slide-in-from-bottom-4 duration-700"
style={{ animationDelay: `${index * 100}ms` }}
>
<div className="flex gap-8">
{/* Main Content */}
<article className="flex-1 min-w-0">
{/* Section Header */}
<header className="mb-8">
<div className="flex items-center gap-4 mb-4">
<span className="flex-shrink-0 w-10 h-10 rounded-xl bg-gradient-to-br from-brand-500 to-purple-600 flex items-center justify-center text-white font-bold text-lg shadow-lg shadow-brand-500/20">
{index + 1}
</span>
<h2 className="text-2xl md:text-3xl font-display font-bold text-gray-900 dark:text-gray-50 leading-tight">
{section.title}
</h2>
</div>
<div className="w-20 h-1 bg-gradient-to-r from-brand-500 to-purple-500 rounded-full" />
</header>
{/* Content */}
<div className="prose prose-lg dark:prose-invert max-w-none
prose-headings:font-display prose-headings:font-bold
prose-h3:text-xl prose-h3:mt-8 prose-h3:mb-4
prose-p:text-gray-700 prose-p:dark:text-gray-300 prose-p:leading-relaxed
prose-strong:text-gray-900 prose-strong:dark:text-white
prose-a:text-brand-600 prose-a:dark:text-brand-400 prose-a:no-underline hover:prose-a:underline
prose-blockquote:border-l-brand-500 prose-blockquote:bg-gray-50 prose-blockquote:dark:bg-gray-800/50 prose-blockquote:py-2 prose-blockquote:px-4 prose-blockquote:rounded-r-lg prose-blockquote:not-italic
prose-code:bg-gray-100 prose-code:dark:bg-gray-800 prose-code:px-1.5 prose-code:py-0.5 prose-code:rounded prose-code:text-sm prose-code:before:content-none prose-code:after:content-none
prose-pre:bg-gray-900 prose-pre:dark:bg-black prose-pre:border prose-pre:border-gray-800
prose-li:text-gray-700 prose-li:dark:text-gray-300
">
{renderContent()}
</div>
{/* Visualization */}
{section.visualizationType && section.visualizationType !== 'none' && (
<div className="my-10">
<div className="p-6 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 shadow-lg shadow-gray-200/50 dark:shadow-none">
{section.visualizationType === 'mermaid' && section.visualizationData && (
<div className="min-h-[200px]">
<MermaidDiagram chart={section.visualizationData} theme={theme} />
</div>
)}
{section.visualizationType === 'chart' && section.chartData && (
<InteractiveChart data={section.chartData} theme={theme} />
)}
{section.visualizationType === 'equation' && section.visualizationData && (
<EquationBlock equation={section.visualizationData} label={`${index + 1}`} />
)}
</div>
</div>
)}
{/* Collapsible Deep Dives */}
{section.collapsibleSections && section.collapsibleSections.length > 0 && (
<div className="mt-8 space-y-4">
{section.collapsibleSections.map((collapsible, idx) => (
<Collapsible
key={collapsible.id}
title={collapsible.title}
variant={idx === 0 ? 'deep-dive' : 'default'}
>
<ReactMarkdown>{collapsible.content}</ReactMarkdown>
</Collapsible>
))}
</div>
)}
</article>
{/* Margin Notes */}
{section.marginNotes && section.marginNotes.length > 0 && (
<aside className="hidden xl:block w-64 flex-shrink-0">
<div className="sticky top-32 space-y-4">
{section.marginNotes.map((note, idx) => (
<div
key={note.id}
className="p-4 rounded-xl bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-gray-700 animate-in fade-in slide-in-from-right-4 duration-500"
style={{ animationDelay: `${(index * 100) + (idx * 50)}ms` }}
>
<div className="flex items-start gap-3">
<div className="flex-shrink-0 mt-0.5">
{getMarginNoteIcon(note.icon)}
</div>
<p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
{note.text}
</p>
</div>
</div>
))}
</div>
</aside>
)}
</div>
{/* Section Divider */}
<div className="my-16 flex items-center gap-4">
<div className="flex-1 h-px bg-gradient-to-r from-transparent via-gray-300 dark:via-gray-700 to-transparent" />
<div className="flex gap-1">
<div className="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700" />
<div className="w-1.5 h-1.5 rounded-full bg-gray-400 dark:bg-gray-600" />
<div className="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700" />
</div>
<div className="flex-1 h-px bg-gradient-to-r from-transparent via-gray-300 dark:via-gray-700 to-transparent" />
</div>
</section>
);
};
export default BlogSectionComponent;