Skip to content
2 changes: 1 addition & 1 deletion packages/blog-kit-react/src/components/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type BadgeProps = {
export function Badge({ children, className }: BadgeProps) {
return (
<span
className={`inline-flex items-center rounded-full border border-transparent bg-orange-100 px-2.5 py-0.5 text-xs font-semibold text-orange-500 ${className}`}
className={`inline-flex items-center rounded-full border border-transparent bg-orange-100 dark:bg-orange-900/30 px-2.5 py-0.5 text-xs font-semibold text-orange-500 dark:text-orange-300 ${className}`}
>
{children}
</span>
Expand Down
12 changes: 7 additions & 5 deletions packages/blog-kit-react/src/components/BlogCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ export function BlogCard({

return (
<article
className={`rounded-lg border border-gray-200 hover:border-gray-300 p-6 transition-colors ${className}`}
className={`rounded-lg border border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600 bg-white dark:bg-gray-800 p-6 transition-colors ${className}`}
>
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-3">
{showCategory && metadata.category && <Badge>{metadata.category}</Badge>}
{(showReadingTime || showDate) && (
<div className="flex items-center gap-2 text-sm text-gray-500">
<div className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
{showReadingTime && <span>{metadata.readingTime}</span>}
{showReadingTime && showDate && <span>•</span>}
{showDate && (
Expand All @@ -52,16 +52,18 @@ export function BlogCard({

{Link(
href,
<h2 className="font-semibold text-xl text-gray-700 mb-2 hover:underline transition-colors">
<h2 className="font-semibold text-xl text-gray-700 dark:text-gray-100 mb-2 hover:underline transition-colors">
{metadata.title}
</h2>
)}

<p className="text-sm text-gray-500 leading-6 mb-4">{metadata.description}</p>
<p className="text-sm text-gray-500 dark:text-gray-300 leading-6 mb-4">
{metadata.description}
</p>

{Link(
href,
<span className="inline-flex items-center text-blue-600 hover:text-blue-700 font-medium text-sm">
<span className="inline-flex items-center text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 font-medium text-sm">
Read more →
</span>
)}
Expand Down
6 changes: 5 additions & 1 deletion packages/blog-kit-react/src/components/BlogList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export function BlogList({
cardProps,
}: BlogListProps) {
if (metadata.length === 0) {
return <div className={`text-center text-gray-500 py-12 ${className}`}>{emptyMessage}</div>;
return (
<div className={`text-center text-gray-500 dark:text-gray-400 py-12 ${className}`}>
{emptyMessage}
</div>
);
}

return (
Expand Down
11 changes: 7 additions & 4 deletions packages/blog-kit-react/src/components/BlogPlaceholder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ export function BlogPlaceholder({ count = 3, className = '' }: BlogPlaceholderPr
return (
<div className={`space-y-6 ${className}`}>
{Array.from({ length: count }).map((_, i) => (
<div key={i} className="bg-white rounded-lg border border-gray-200 p-6 animate-pulse">
<div className="h-4 bg-gray-200 rounded mb-3"></div>
<div className="h-6 bg-gray-200 rounded mb-2"></div>
<div className="h-4 bg-gray-200 rounded w-3/4"></div>
<div
key={i}
className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-6 animate-pulse"
>
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded mb-3"></div>
<div className="h-6 bg-gray-200 dark:bg-gray-700 rounded mb-2"></div>
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-3/4"></div>
</div>
))}
</div>
Expand Down
81 changes: 59 additions & 22 deletions packages/blog-kit-react/src/components/BlogRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,46 @@ export interface BlogRendererProps {
export function BlogRenderer({ content, metadata, className = '', components }: BlogRendererProps) {
const defaultComponents = {
h1: ({ ...props }: any) => (
<h1 className="text-4xl font-bold mb-4 mt-8 text-gray-800" {...props} />
<h1 className="text-4xl font-bold mb-4 mt-8 text-gray-800 dark:text-gray-100" {...props} />
),
h2: ({ ...props }: any) => (
<h2 className="text-3xl font-bold mb-3 mt-6 text-gray-800" {...props} />
<h2 className="text-3xl font-bold mb-3 mt-6 text-gray-800 dark:text-gray-100" {...props} />
),
h3: ({ ...props }: any) => (
<h3 className="text-2xl font-semibold mb-2 mt-4 text-gray-800" {...props} />
<h3
className="text-2xl font-semibold mb-2 mt-4 text-gray-800 dark:text-gray-100"
{...props}
/>
),
h4: ({ ...props }: any) => (
<h4 className="text-xl font-semibold mb-2 mt-4 text-gray-800" {...props} />
<h4 className="text-xl font-semibold mb-2 mt-4 text-gray-800 dark:text-gray-100" {...props} />
),
h5: ({ ...props }: any) => (
<h5 className="text-lg font-semibold mb-2 mt-3 text-gray-800" {...props} />
<h5 className="text-lg font-semibold mb-2 mt-3 text-gray-800 dark:text-gray-100" {...props} />
),
h6: ({ ...props }: any) => (
<h6 className="text-base font-semibold mb-2 mt-3 text-gray-800" {...props} />
<h6
className="text-base font-semibold mb-2 mt-3 text-gray-800 dark:text-gray-100"
{...props}
/>
),
p: ({ ...props }: any) => (
<p className="mb-4 leading-7 text-gray-600 dark:text-gray-300" {...props} />
),
ul: ({ ...props }: any) => (
<ul className="mb-4 ml-6 list-disc text-gray-600 dark:text-gray-300" {...props} />
),
ol: ({ ...props }: any) => (
<ol className="mb-4 ml-6 list-decimal text-gray-600 dark:text-gray-300" {...props} />
),
p: ({ ...props }: any) => <p className="mb-4 leading-7 text-gray-600" {...props} />,
ul: ({ ...props }: any) => <ul className="mb-4 ml-6 list-disc text-gray-600" {...props} />,
ol: ({ ...props }: any) => <ol className="mb-4 ml-6 list-decimal text-gray-600" {...props} />,
li: ({ ...props }: any) => <li className="mb-2" {...props} />,
code: ({ className: codeClassName, children, ...props }: any) => {
const isInline = !codeClassName;
return isInline ? (
<code className="px-1.5 py-0.5 bg-gray-100 rounded text-sm text-red-600" {...props}>
<code
className="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 rounded text-sm text-red-600 dark:text-red-400"
{...props}
>
{children}
</code>
) : (
Expand All @@ -65,31 +80,53 @@ export function BlogRenderer({ content, metadata, className = '', components }:
},
blockquote: ({ ...props }: any) => (
<blockquote
className="border-l-4 border-blue-500 pl-4 italic my-4 text-gray-600"
className="border-l-4 border-blue-500 dark:border-blue-400 pl-4 italic my-4 text-gray-600 dark:text-gray-400"
{...props}
/>
),
a: ({ ...props }: any) => (
<a className="text-blue-600 hover:text-blue-800 underline" {...props} />
<a
className="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline"
{...props}
/>
),
strong: ({ ...props }: any) => (
<strong className="font-semibold text-gray-800 dark:text-gray-100" {...props} />
),
strong: ({ ...props }: any) => <strong className="font-semibold text-gray-800" {...props} />,
em: ({ ...props }: any) => <em className="italic" {...props} />,
del: ({ ...props }: any) => <del className="line-through text-gray-500" {...props} />,
hr: ({ ...props }: any) => <hr className="my-8 border-gray-300" {...props} />,
del: ({ ...props }: any) => (
<del className="line-through text-gray-500 dark:text-gray-400" {...props} />
),
hr: ({ ...props }: any) => (
<hr className="my-8 border-gray-300 dark:border-gray-700" {...props} />
),
br: ({ ...props }: any) => <br {...props} />,
img: ({ ...props }: any) => <img className="max-w-full h-auto rounded-lg my-4" {...props} />,
table: ({ ...props }: any) => (
<div className="overflow-x-auto my-4">
<table className="min-w-full border border-gray-300 rounded" {...props} />
<table
className="min-w-full border border-gray-300 dark:border-gray-700 rounded"
{...props}
/>
</div>
),
thead: ({ ...props }: any) => <thead className="bg-gray-50" {...props} />,
thead: ({ ...props }: any) => <thead className="bg-gray-50 dark:bg-gray-800" {...props} />,
tbody: ({ ...props }: any) => <tbody {...props} />,
tr: ({ ...props }: any) => <tr className="border-b border-gray-300" {...props} />,
tr: ({ ...props }: any) => (
<tr className="border-b border-gray-300 dark:border-gray-700" {...props} />
),
th: ({ ...props }: any) => (
<th className="px-4 py-2 text-left font-semibold border border-gray-300" {...props} />
<th
className="px-4 py-2 text-left font-semibold border border-gray-300 dark:border-gray-700 dark:text-gray-100"
{...props}
/>
),
td: ({ ...props }: any) => (
<td
className="px-4 py-2 border border-gray-300 dark:border-gray-700 dark:text-gray-300"
{...props}
/>
),
td: ({ ...props }: any) => <td className="px-4 py-2 border border-gray-300" {...props} />,
input: ({ ...props }: any) => <input className="mr-2" type="checkbox" disabled {...props} />,
};

Expand All @@ -99,7 +136,7 @@ export function BlogRenderer({ content, metadata, className = '', components }:
<>
<div className="flex items-center gap-3 mb-4">
{metadata.category && <Badge>{metadata.category}</Badge>}
<div className="flex items-center gap-2 text-sm text-gray-500">
<div className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
<span>{metadata.readingTime}</span>
<span>•</span>
<time dateTime={metadata.date}>
Expand All @@ -112,7 +149,7 @@ export function BlogRenderer({ content, metadata, className = '', components }:
</div>
</div>

<div className={`prose prose-slate max-w-none ${className}`}>
<div className={`prose prose-slate dark:prose-invert max-w-none ${className}`}>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw, rehypePrismPlus]}
Expand Down