wwww_3node_tenstorrent/src/components/Blog.jsx
2025-07-24 09:38:35 +02:00

122 lines
5.1 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import matter from 'gray-matter';
function Blog() {
const [posts, setPosts] = useState([]);
const [searchTerm, setSearchTerm] = useState('');
const [selectedTag, setSelectedTag] = useState('');
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchPosts() {
try {
const postFiles = import.meta.glob('../blogs/*.md', { query: '?raw', import: 'default', eager: true });
const loadedPosts = [];
for (const path in postFiles) {
const content = postFiles[path];
const { data } = matter(content);
const slug = path.split('/').pop().replace('.md', '');
loadedPosts.push({ slug, ...data });
}
loadedPosts.sort((a, b) => new Date(b.date) - new Date(a.date));
setPosts(loadedPosts);
} catch (error) {
console.error("Error fetching blog posts:", error);
} finally {
setLoading(false);
}
}
fetchPosts();
}, []);
const allTags = [...new Set(posts.flatMap(post => post.tags || []))];
const filteredPosts = posts
.filter(post => {
const title = post.title || '';
const author = post.author || '';
return title.toLowerCase().includes(searchTerm.toLowerCase()) ||
author.toLowerCase().includes(searchTerm.toLowerCase());
})
.filter(post =>
selectedTag ? (post.tags || []).includes(selectedTag) : true
);
return (
<div className="container mx-auto px-4 py-12 max-w-5xl">
<div className="text-center mb-12">
<h1 className="text-5xl font-extrabold text-gray-900 leading-tight">OurWorld Blog</h1>
<p className="mt-4 text-xl text-gray-600 max-w-2xl mx-auto">
Insights, stories, and updates from the OurWorld Cooperative.
</p>
</div>
<div className="mb-8 flex flex-col md:flex-row gap-4 items-center">
<input
type="text"
placeholder="Search articles..."
className="flex-grow w-full md:w-auto px-4 py-2 border border-gray-300 rounded-full focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-shadow"
value={searchTerm}
onChange={e => setSearchTerm(e.target.value)}
/>
<div className="relative w-full md:w-auto">
<select
className="w-full appearance-none bg-white border border-gray-300 rounded-full px-4 py-2 pr-8 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-shadow"
value={selectedTag}
onChange={e => setSelectedTag(e.target.value)}
>
<option value="">All Topics</option>
{allTags.map(tag => (
<option key={tag} value={tag}>{tag}</option>
))}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
<svg className="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
</div>
</div>
</div>
<div>
{loading ? (
<div className="text-center text-gray-500">Loading posts...</div>
) : filteredPosts.length > 0 ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
{filteredPosts.map(post => (
<Link to={`/blog/${post.slug}`} key={post.slug} className="group block bg-white rounded-xl shadow-lg hover:shadow-2xl transition-all duration-300 overflow-hidden transform hover:-translate-y-1">
{post.cover_image && (
<img src={post.cover_image} alt={post.title} className="w-full h-48 object-cover" />
)}
<div className="p-6">
<div className="flex items-center gap-2 mb-4">
{post.tags && post.tags.map(tag => (
<span key={tag} className="bg-blue-100 text-blue-800 text-xs font-semibold px-3 py-1 rounded-full">
{tag}
</span>
))}
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2 group-hover:text-blue-600 transition-colors">
{post.title}
</h2>
<p className="text-gray-500 text-sm mb-4">
By {post.author} on {new Date(post.date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}
</p>
<p className="text-gray-700 leading-relaxed">
{post.summary && post.summary.length > 200 ? `${post.summary.substring(0, 200)}...` : post.summary}
</p>
</div>
</Link>
))}
</div>
) : (
<div className="text-center text-gray-500 py-16">
<h2 className="text-2xl font-semibold mb-2">No posts found</h2>
<p>Try adjusting your search or filters.</p>
</div>
)}
</div>
</div>
);
}
export default Blog;