Approve blog post migration

This commit is contained in:
gpt-engineer-app[bot]
2025-10-10 22:55:46 +00:00
parent 7ce82e9e71
commit 5f3ff2c9e9
6 changed files with 232 additions and 1 deletions

View File

@@ -0,0 +1,88 @@
import { Link } from 'react-router-dom';
import { Card } from '@/components/ui/card';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Eye, Calendar } from 'lucide-react';
import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils';
import { formatDistanceToNow } from 'date-fns';
interface BlogPostCardProps {
slug: string;
title: string;
content: string;
featuredImageId?: string;
author: {
username: string;
displayName?: string;
avatarUrl?: string;
};
publishedAt: string;
viewCount: number;
}
export function BlogPostCard({
slug,
title,
content,
featuredImageId,
author,
publishedAt,
viewCount,
}: BlogPostCardProps) {
const excerpt = content.substring(0, 150) + (content.length > 150 ? '...' : '');
return (
<Link to={`/blog/${slug}`}>
<Card className="overflow-hidden hover:scale-[1.02] hover:shadow-xl transition-all duration-300 group">
<div className="aspect-[16/9] overflow-hidden bg-gradient-to-br from-primary/20 to-secondary/20">
{featuredImageId ? (
<img
src={getCloudflareImageUrl(featuredImageId, 'public')}
alt={title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
loading="lazy"
/>
) : (
<div className="w-full h-full flex items-center justify-center">
<span className="text-6xl opacity-20">📝</span>
</div>
)}
</div>
<div className="p-6 space-y-3">
<h3 className="text-xl font-bold line-clamp-2 group-hover:text-primary transition-colors">
{title}
</h3>
<p className="text-sm text-muted-foreground line-clamp-3">
{excerpt}
</p>
<div className="flex items-center justify-between pt-3 border-t">
<div className="flex items-center gap-2">
<Avatar className="w-6 h-6">
<AvatarImage src={author.avatarUrl} />
<AvatarFallback>
{author.displayName?.[0] || author.username[0]}
</AvatarFallback>
</Avatar>
<span className="text-xs text-muted-foreground">
{author.displayName || author.username}
</span>
</div>
<div className="flex items-center gap-3 text-xs text-muted-foreground">
<div className="flex items-center gap-1">
<Calendar className="w-3 h-3" />
{formatDistanceToNow(new Date(publishedAt), { addSuffix: true })}
</div>
<div className="flex items-center gap-1">
<Eye className="w-3 h-3" />
{viewCount}
</div>
</div>
</div>
</div>
</Card>
</Link>
);
}

View File

@@ -0,0 +1,31 @@
import ReactMarkdown from 'react-markdown';
import { cn } from '@/lib/utils';
interface MarkdownRendererProps {
content: string;
className?: string;
}
export function MarkdownRenderer({ content, className }: MarkdownRendererProps) {
return (
<ReactMarkdown
className={cn(
'prose dark:prose-invert max-w-none',
'prose-headings:font-bold prose-headings:tracking-tight',
'prose-h1:text-4xl prose-h2:text-3xl prose-h3:text-2xl',
'prose-p:text-base prose-p:leading-relaxed',
'prose-a:text-primary prose-a:no-underline hover:prose-a:underline',
'prose-strong:text-foreground prose-strong:font-semibold',
'prose-code:bg-muted prose-code:px-1.5 prose-code:py-0.5 prose-code:rounded prose-code:text-sm',
'prose-pre:bg-muted prose-pre:border prose-pre:border-border',
'prose-blockquote:border-l-4 prose-blockquote:border-primary prose-blockquote:italic',
'prose-img:rounded-lg prose-img:shadow-lg',
'prose-hr:border-border',
'prose-ul:list-disc prose-ol:list-decimal',
className
)}
>
{content}
</ReactMarkdown>
);
}

View File

@@ -1,4 +1,4 @@
import { LayoutDashboard, FileText, Flag, Users, Settings, ArrowLeft, ScrollText } from 'lucide-react';
import { LayoutDashboard, FileText, Flag, Users, Settings, ArrowLeft, ScrollText, BookOpen } from 'lucide-react';
import { NavLink } from 'react-router-dom';
import { useUserRole } from '@/hooks/useUserRole';
import { useSidebar } from '@/hooks/useSidebar';
@@ -47,6 +47,11 @@ export function AdminSidebar() {
url: '/admin/users',
icon: Users,
},
{
title: 'Blog',
url: '/admin/blog',
icon: BookOpen,
},
...(isSuperuser ? [{
title: 'Settings',
url: '/admin/settings',

View File

@@ -27,6 +27,12 @@ export function Footer() {
>
Submission Guidelines
</Link>
<Link
to="/blog"
className="hover:text-foreground transition-colors"
>
Blog
</Link>
</div>
</div>
</div>