feat: Enhance calendar component with glassmorphism design and modular architecture
- Refactored Calendar.tsx into modular component structure - Added glassmorphism theming with CSS custom properties - Implemented reusable calendar subcomponents: - CalendarGrid: Month view with improved day/event display - CalendarHeader: Navigation and view controls - EventList: List view for events - TrendingEvents: Location-based trending events - UpcomingEvents: Quick upcoming events preview - Enhanced responsive design for mobile devices - Added Playwright testing framework for automated testing - Updated Docker development commands in CLAUDE.md - Improved accessibility and user experience 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
78
src/components/calendar/EventList.tsx
Normal file
78
src/components/calendar/EventList.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import React from 'react';
|
||||
import { EventListProps } from './types';
|
||||
import { groupEventsByDate, sortEventsByDate, getFutureEvents, getRelativeDateText } from './utils';
|
||||
import { EventCard } from './EventCard';
|
||||
|
||||
/**
|
||||
* Event list component showing events grouped by date
|
||||
*/
|
||||
export const EventList: React.FC<EventListProps> = ({
|
||||
events,
|
||||
onEventClick,
|
||||
showDistance = false
|
||||
}) => {
|
||||
const futureEvents = getFutureEvents(events);
|
||||
const sortedEvents = sortEventsByDate(futureEvents);
|
||||
const groupedEvents = groupEventsByDate(sortedEvents);
|
||||
const sortedDates = Object.keys(groupedEvents).sort((a, b) => new Date(a).getTime() - new Date(b).getTime());
|
||||
|
||||
if (sortedEvents.length === 0) {
|
||||
return (
|
||||
<div className="p-3 md:p-6">
|
||||
<div className="text-center py-16">
|
||||
<div className="w-24 h-24 mx-auto mb-6 rounded-full flex items-center justify-center"
|
||||
style={{ background: 'linear-gradient(to bottom right, var(--ui-bg-secondary), var(--ui-bg-elevated))' }}>
|
||||
<svg className="w-12 h-12" style={{ color: 'var(--ui-text-muted)' }} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold mb-2" style={{ color: 'var(--ui-text-primary)' }}>
|
||||
No Upcoming Events
|
||||
</h3>
|
||||
<p style={{ color: 'var(--ui-text-secondary)' }}>
|
||||
Check back later for new events or adjust your filters.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-3 md:p-6">
|
||||
<div className="space-y-6">
|
||||
{sortedDates.map(dateKey => {
|
||||
const date = new Date(dateKey);
|
||||
const dateEvents = groupedEvents[dateKey];
|
||||
const dateText = getRelativeDateText(date);
|
||||
|
||||
return (
|
||||
<div key={dateKey} className="animate-fade-in-up">
|
||||
{/* Date Header */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-lg font-semibold mb-1" style={{ color: 'var(--ui-text-primary)' }}>
|
||||
{dateText}
|
||||
</h3>
|
||||
<div className="w-16 h-1 rounded-full"
|
||||
style={{ background: 'linear-gradient(to right, rgb(37, 99, 235), rgb(147, 51, 234))' }}>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Events for this date */}
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{dateEvents.map(event => (
|
||||
<EventCard
|
||||
key={event.id}
|
||||
event={event}
|
||||
onClick={onEventClick}
|
||||
variant="list"
|
||||
showDistance={showDistance}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user