Refactor project structure: update Astro configuration, integrate Tailwind CSS, enhance ContactForm with validation, and improve layout for various pages. Add new Donate and Orphanage pages, and implement responsive design adjustments across components.

This commit is contained in:
2025-06-27 22:49:11 +02:00
parent 81f637b317
commit 9f6fa46227
23 changed files with 2721 additions and 3058 deletions

View File

@@ -0,0 +1,82 @@
import React, { useState, useEffect } from 'react';
export default function EventFilterSearch({ events }) {
const [searchTerm, setSearchTerm] = useState('');
const [selectedCategory, setSelectedCategory] = useState('All');
const [filteredEvents, setFilteredEvents] = useState(events);
const categories = ['All', ...new Set(events.map(event => event.frontmatter.category))];
useEffect(() => {
let tempEvents = events;
// Filter by category
if (selectedCategory !== 'All') {
tempEvents = tempEvents.filter(event => event.frontmatter.category === selectedCategory);
}
// Filter by search term
if (searchTerm) {
tempEvents = tempEvents.filter(event =>
event.frontmatter.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
event.frontmatter.description.toLowerCase().includes(searchTerm.toLowerCase())
);
}
setFilteredEvents(tempEvents);
}, [searchTerm, selectedCategory, events]);
return (
<div className="container mx-auto px-4 py-8">
<div className="flex flex-col md:flex-row gap-4 mb-8">
{/* Search Input */}
<input
type="text"
placeholder="Search events..."
className="flex-grow p-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-nigerian-green-500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
{/* Category Filter */}
<select
className="p-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-nigerian-green-500"
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)}
>
{categories.map(category => (
<option key={category} value={category}>{category}</option>
))}
</select>
</div>
{/* Event List */}
<section className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{filteredEvents.length > 0 ? (
filteredEvents.map(event => (
<article key={event.url} className="card bg-base-100 shadow-lg rounded-xl overflow-hidden transform transition-transform duration-300 hover:scale-105 hover:shadow-xl">
<figure className="relative h-48 w-full overflow-hidden">
<img src={event.frontmatter.image} alt={event.frontmatter.title} className="w-full h-full object-cover" />
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent"></div>
<span className="absolute bottom-3 left-3 badge badge-secondary bg-kente-gold-500 text-white px-3 py-1 rounded-full text-sm font-semibold">{event.frontmatter.category}</span>
</figure>
<div className="card-body p-6">
<h2 className="card-title text-xl font-bold text-nigerian-green-700 mb-2">{event.frontmatter.title}</h2>
<p className="text-sm text-gray-600 mb-3">{new Date(event.frontmatter.date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}</p>
<p className="text-gray-700 leading-relaxed text-sm mb-4">{event.frontmatter.description}</p>
<a href={event.url} className="inline-flex items-center text-nigerian-green-600 hover:text-nigerian-green-800 font-semibold transition-colors duration-200">
Read More
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7" />
</svg>
</a>
</div>
</article>
))
) : (
<p className="text-center text-gray-500 text-lg col-span-full">No events found matching your criteria.</p>
)}
</section>
</div>
);
}