Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Event Management System</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
.custom-checkbox:checked { | |
background-color: #4f46e5; | |
} | |
#eventModal { | |
transition: all 0.3s ease; | |
} | |
.month-nav:hover { | |
background-color: #4f46e5; | |
color: white; | |
} | |
.event-day { | |
background-color: #e0e7ff; | |
} | |
.has-event { | |
position: relative; | |
} | |
.has-event::after { | |
content: ''; | |
position: absolute; | |
bottom: 5px; | |
left: 50%; | |
transform: translateX(-50%); | |
width: 6px; | |
height: 6px; | |
background-color: #4f46e5; | |
border-radius: 50%; | |
} | |
.floating-btn { | |
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); | |
transition: all 0.3s ease; | |
} | |
.floating-btn:hover { | |
transform: translateY(-3px); | |
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); | |
} | |
.event-card:hover { | |
transform: translateY(-3px); | |
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); | |
} | |
</style> | |
</head> | |
<body class="bg-gray-50"> | |
<!-- Header --> | |
<header class="bg-indigo-600 text-white shadow-lg"> | |
<div class="container mx-auto px-4 py-6"> | |
<div class="flex justify-between items-center"> | |
<h1 class="text-2xl md:text-3xl font-bold">Local Event Calendar</h1> | |
<div class="hidden md:block"> | |
<input type="text" placeholder="Search events..." class="px-4 py-2 rounded-full text-gray-800 focus:outline-none focus:ring-2 focus:ring-indigo-300"> | |
</div> | |
</div> | |
<div class="flex mt-4 space-x-4"> | |
<button class="px-4 py-2 rounded-full bg-indigo-700 hover:bg-indigo-800 transition">All Events</button> | |
<button class="px-4 py-2 rounded-full hover:bg-indigo-700 transition">Music</button> | |
<button class="px-4 py-2 rounded-full hover:bg-indigo-700 transition">Sports</button> | |
<button class="px-4 py-2 rounded-full hover:bg-indigo-700 transition">Art</button> | |
</div> | |
</div> | |
</header> | |
<!-- Main Content --> | |
<main class="container mx-auto px-4 py-8"> | |
<div class="flex flex-col lg:flex-row gap-8"> | |
<!-- Calendar Section --> | |
<div class="lg:w-2/3"> | |
<div class="bg-white rounded-lg shadow-md p-6 mb-8"> | |
<div class="flex justify-between items-center mb-6"> | |
<h2 class="text-xl font-bold text-gray-800">Event Calendar</h2> | |
<div class="flex space-x-2"> | |
<button onclick="previousMonth()" class="month-nav px-3 py-1 rounded-lg bg-indigo-100 text-indigo-600"><i class="fas fa-chevron-left"></i></button> | |
<h3 id="currentMonthYear" class="px-4 py-1 font-semibold text-gray-700">June 2023</h3> | |
<button onclick="nextMonth()" class="month-nav px-3 py-1 rounded-lg bg-indigo-100 text-indigo-600"><i class="fas fa-chevron-right"></i></button> | |
</div> | |
</div> | |
<div class="grid grid-cols-7 gap-2 mb-2"> | |
<div class="text-center font-semibold text-gray-500 py-2">Sun</div> | |
<div class="text-center font-semibold text-gray-500 py-2">Mon</div> | |
<div class="text-center font-semibold text-gray-500 py-2">Tue</div> | |
<div class="text-center font-semibold text-gray-500 py-2">Wed</div> | |
<div class="text-center font-semibold text-gray-500 py-2">Thu</div> | |
<div class="text-center font-semibold text-gray-500 py-2">Fri</div> | |
<div class="text-center font-semibold text-gray-500 py-2">Sat</div> | |
</div> | |
<div id="calendarDays" class="grid grid-cols-7 gap-2"> | |
<!-- Calendar days will be populated by JavaScript --> | |
</div> | |
</div> | |
<!-- Events List Section --> | |
<div id="eventsList" class="space-y-4"> | |
<!-- Events will be displayed here --> | |
</div> | |
</div> | |
<!-- Sidebar --> | |
<div class="lg:w-1/3"> | |
<div class="bg-white rounded-lg shadow-md p-6 mb-6"> | |
<h2 class="text-xl font-bold text-gray-800 mb-4">Featured Venues</h2> | |
<div class="space-y-4"> | |
<div class="flex items-center space-x-3"> | |
<div class="w-12 h-12 rounded-full bg-indigo-100 flex items-center justify-center"> | |
<i class="fas fa-music text-indigo-600"></i> | |
</div> | |
<div> | |
<h3 class="font-semibold">The Jazz Club</h3> | |
<p class="text-sm text-gray-500">Live music venue</p> | |
</div> | |
</div> | |
<div class="flex items-center space-x-3"> | |
<div class="w-12 h-12 rounded-full bg-indigo-100 flex items-center justify-center"> | |
<i class="fas fa-theater-masks text-indigo-600"></i> | |
</div> | |
<div> | |
<h3 class="font-semibold">City Theater</h3> | |
<p class="text-sm text-gray-500">Drama & plays</p> | |
</div> | |
</div> | |
<div class="flex items-center space-x-3"> | |
<div class="w-12 h-12 rounded-full bg-indigo-100 flex items-center justify-center"> | |
<i class="fas fa-futbol text-indigo-600"></i> | |
</div> | |
<div> | |
<h3 class="font-semibold">Sports Arena</h3> | |
<p class="text-sm text-gray-500">Athletic events</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="bg-white rounded-lg shadow-md p-6"> | |
<h2 class="text-xl font-bold text-gray-800 mb-4">Recently Added</h2> | |
<div id="recentEvents" class="space-y-4"> | |
<!-- Recent events will be shown here --> | |
</div> | |
</div> | |
</div> | |
</div> | |
</main> | |
<!-- Floating Add Event Button --> | |
<div id="addEventBtn" class="fixed bottom-6 right-6 bg-indigo-600 text-white rounded-full w-16 h-16 flex items-center justify-center cursor-pointer shadow-lg floating-btn z-50"> | |
<i class="fas fa-plus text-2xl"></i> | |
</div> | |
<!-- Event Form Modal --> | |
<div id="eventModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
<div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4"> | |
<div class="flex justify-between items-center border-b px-6 py-4"> | |
<h3 class="text-lg font-semibold text-gray-800">Add New Event</h3> | |
<button id="closeModal" class="text-gray-500 hover:text-gray-700"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<div class="p-6"> | |
<form id="eventForm" class="space-y-4"> | |
<div> | |
<label for="eventName" class="block text-sm font-medium text-gray-700 mb-1">Event Name</label> | |
<input type="text" id="eventName" class="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" required> | |
</div> | |
<div> | |
<label for="artistName" class="block text-sm font-medium text-gray-700 mb-1">Performer/Artist</label> | |
<input type="text" id="artistName" class="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" required> | |
</div> | |
<div> | |
<label for="eventDate" class="block text-sm font-medium text-gray-700 mb-1">Date & Time</label> | |
<input type="datetime-local" id="eventDate" class="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" required> | |
</div> | |
<div> | |
<label for="venueName" class="block text-sm font-medium text-gray-700 mb-1">Venue Name</label> | |
<input type="text" id="venueName" class="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" required> | |
</div> | |
<div> | |
<label for="ticketPrice" class="block text-sm font-medium text-gray-700 mb-1">Ticket Price ($)</label> | |
<input type="number" id="ticketPrice" min="0" step="0.01" class="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
</div> | |
<div> | |
<label for="eventUrl" class="block text-sm font-medium text-gray-700 mb-1">Event Website URL</label> | |
<input type="url" id="eventUrl" class="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
</div> | |
<div class="flex items-center space-x-4"> | |
<div class="flex items-center"> | |
<input type="radio" id="statusActive" name="eventStatus" value="active" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500" checked> | |
<label for="statusActive" class="ml-2 block text-sm text-gray-700">Active</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="radio" id="statusCancelled" name="eventStatus" value="cancelled" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500"> | |
<label for="statusCancelled" class="ml-2 block text-sm text-gray-700">Cancelled</label> | |
</div> | |
</div> | |
<div class="flex justify-end space-x-3 pt-4"> | |
<button type="button" id="cancelBtn" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50">Cancel</button> | |
<button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">Add Event</button> | |
</div> | |
</form> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Sample events data | |
let events = [ | |
{ | |
id: 1, | |
name: "Jazz Night with Sarah Smith", | |
artist: "Sarah Smith Quartet", | |
date: "2023-06-15T20:00:00", | |
venue: "The Jazz Club", | |
price: 25.00, | |
status: "active", | |
url: "https://thejazzclub.com/events" | |
}, | |
{ | |
id: 2, | |
name: "Rock Festival 2023", | |
artist: "Various Artists", | |
date: "2023-06-22T15:00:00", | |
venue: "City Park", | |
price: 45.00, | |
status: "active", | |
url: "https://rockfest.city" | |
}, | |
{ | |
id: 3, | |
name: "Modern Art Exhibition", | |
artist: "Contemporary Artists", | |
date: "2023-06-10T10:00:00", | |
venue: "City Art Gallery", | |
price: 12.50, | |
status: "active", | |
url: "https://cityartgallery.net" | |
}, | |
{ | |
id: 4, | |
name: "Cancelled: Summer Poetry Slam", | |
artist: "Local Poets", | |
date: "2023-06-08T19:30:00", | |
venue: "Downtown Books", | |
price: 10.00, | |
status: "cancelled", | |
url: "https://dtbooks.com/events" | |
} | |
]; | |
// DOM elements | |
const calendarDays = document.getElementById('calendarDays'); | |
const currentMonthYear = document.getElementById('currentMonthYear'); | |
const eventsList = document.getElementById('eventsList'); | |
const recentEvents = document.getElementById('recentEvents'); | |
const addEventBtn = document.getElementById('addEventBtn'); | |
const eventModal = document.getElementById('eventModal'); | |
const closeModal = document.getElementById('closeModal'); | |
const cancelBtn = document.getElementById('cancelBtn'); | |
const eventForm = document.getElementById('eventForm'); | |
// Calendar variables | |
let currentDate = new Date(); | |
let currentMonth = currentDate.getMonth(); | |
let currentYear = currentDate.getFullYear(); | |
// Initialize app | |
document.addEventListener('DOMContentLoaded', () => { | |
renderCalendar(); | |
displayEvents(); | |
displayRecentEvents(); | |
// Event listeners | |
addEventBtn.addEventListener('click', () => { | |
eventModal.classList.remove('hidden'); | |
}); | |
closeModal.addEventListener('click', () => { | |
eventModal.classList.add('hidden'); | |
}); | |
cancelBtn.addEventListener('click', () => { | |
eventModal.classList.add('hidden'); | |
}); | |
eventForm.addEventListener('submit', addNewEvent); | |
}); | |
// Render calendar | |
function renderCalendar() { | |
// Clear previous calendar | |
calendarDays.innerHTML = ''; | |
// Set month and year display | |
const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; | |
currentMonthYear.textContent = `${monthNames[currentMonth]} ${currentYear}`; | |
// Get first day of month and total days | |
const firstDay = new Date(currentYear, currentMonth, 1).getDay(); | |
const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate(); | |
// Get days from previous month | |
const daysInPrevMonth = new Date(currentYear, currentMonth, 0).getDate(); | |
// Get days from next month | |
const totalCells = Math.ceil((daysInMonth + firstDay) / 7) * 7; | |
const daysFromNextMonth = totalCells - (daysInMonth + firstDay); | |
// Previous month days | |
for (let i = 0; i < firstDay; i++) { | |
const day = daysInPrevMonth - firstDay + i + 1; | |
const dayElement = document.createElement('div'); | |
dayElement.className = 'text-center py-2 text-gray-400'; | |
dayElement.textContent = day; | |
calendarDays.appendChild(dayElement); | |
} | |
// Current month days | |
for (let i = 1; i <= daysInMonth; i++) { | |
const dayElement = document.createElement('div'); | |
dayElement.className = 'text-center py-2 cursor-pointer rounded-lg'; | |
// Check if this is today | |
const today = new Date(); | |
if (currentYear === today.getFullYear() && currentMonth === today.getMonth() && i === today.getDate()) { | |
dayElement.classList.add('bg-indigo-100', 'font-semibold', 'text-indigo-700'); | |
} | |
// Check if there are events on this day | |
const hasEvent = events.some(event => { | |
const eventDate = new Date(event.date); | |
return eventDate.getFullYear() === currentYear && | |
eventDate.getMonth() === currentMonth && | |
eventDate.getDate() === i; | |
}); | |
if (hasEvent) { | |
dayElement.classList.add('has-event', 'event-day', 'hover:bg-indigo-200'); | |
} else { | |
dayElement.classList.add('hover:bg-gray-100'); | |
} | |
dayElement.textContent = i; | |
dayElement.dataset.day = i; | |
dayElement.dataset.month = currentMonth; | |
dayElement.dataset.year = currentYear; | |
dayElement.addEventListener('click', () => { | |
showEventsForDay(i, currentMonth, currentYear); | |
}); | |
calendarDays.appendChild(dayElement); | |
} | |
// Next month days | |
for (let i = 1; i <= daysFromNextMonth; i++) { | |
const dayElement = document.createElement('div'); | |
dayElement.className = 'text-center py-2 text-gray-400'; | |
dayElement.textContent = i; | |
calendarDays.appendChild(dayElement); | |
} | |
} | |
// Navigate to previous month | |
function previousMonth() { | |
currentMonth--; | |
if (currentMonth < 0) { | |
currentMonth = 11; | |
currentYear--; | |
} | |
renderCalendar(); | |
displayEvents(); // Update events display for the new month | |
} | |
// Navigate to next month | |
function nextMonth() { | |
currentMonth++; | |
if (currentMonth > 11) { | |
currentMonth = 0; | |
currentYear++; | |
} | |
renderCalendar(); | |
displayEvents(); // Update events display for the new month | |
} | |
// Display all events for current month | |
function displayEvents() { | |
eventsList.innerHTML = ''; | |
const filteredEvents = events.filter(event => { | |
const eventDate = new Date(event.date); | |
return eventDate.getFullYear() === currentYear && eventDate.getMonth() === currentMonth; | |
}); | |
if (filteredEvents.length === 0) { | |
eventsList.innerHTML = '<p class="text-gray-500 text-center py-4">No events scheduled for this month.</p>'; | |
return; | |
} | |
// Sort events by date | |
filteredEvents.sort((a, b) => new Date(a.date) - new Date(b.date)); | |
filteredEvents.forEach(event => { | |
const eventCard = createEventCard(event); | |
eventsList.appendChild(eventCard); | |
}); | |
} | |
// Show events for a specific day | |
function showEventsForDay(day, month, year) { | |
eventsList.innerHTML = ''; | |
const filteredEvents = events.filter(event => { | |
const eventDate = new Date(event.date); | |
return eventDate.getFullYear() == year && | |
eventDate.getMonth() == month && | |
eventDate.getDate() == day; | |
}); | |
if (filteredEvents.length === 0) { | |
const date = new Date(year, month, day); | |
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; | |
eventsList.innerHTML = ` | |
<div class="bg-white rounded-lg shadow-md p-6 text-center"> | |
<h3 class="text-xl font-semibold text-gray-800 mb-2">No Events Scheduled</h3> | |
<p class="text-gray-500">${date.toLocaleDateString('en-US', options)}</p> | |
</div> | |
`; | |
return; | |
} | |
filteredEvents.forEach(event => { | |
const eventCard = createEventCard(event); | |
eventsList.appendChild(eventCard); | |
}); | |
} | |
// Display recent events in sidebar | |
function displayRecentEvents() { | |
recentEvents.innerHTML = ''; | |
const now = new Date(); | |
const recent = events.filter(event => { | |
const eventDate = new Date(event.date); | |
return eventDate > now && event.status === 'active'; | |
}).sort((a, b) => new Date(a.date) - new Date(b.date)); | |
const maxRecent = 3; | |
const displayCount = Math.min(recent.length, maxRecent); | |
if (displayCount === 0) { | |
recentEvents.innerHTML = '<p class="text-gray-500">No upcoming events</p>'; | |
return; | |
} | |
for (let i = 0; i < displayCount; i++) { | |
const eventCard = document.createElement('div'); | |
eventCard.className = 'bg-gray-50 rounded-lg p-4 event-card transition cursor-pointer'; | |
const eventDate = new Date(recent[i].date); | |
const options = { month: 'short', day: 'numeric' }; | |
eventCard.innerHTML = ` | |
<div class="flex justify-between items-start"> | |
<div> | |
<h3 class="font-semibold text-gray-800">${recent[i].name}</h3> | |
<p class="text-sm text-indigo-600">${recent[i].artist}</p> | |
</div> | |
<div class="bg-indigo-100 text-indigo-800 text-xs font-medium px-2 py-1 rounded-lg"> | |
${eventDate.toLocaleDateString('en-US', options)} | |
</div> | |
</div> | |
<div class="mt-2 text-sm text-gray-600"> | |
<p>${recent[i].venue} • $${recent[i].price.toFixed(2)}</p> | |
</div> | |
`; | |
eventCard.addEventListener('click', () => { | |
// Scroll to the event in the main list | |
const eventElement = document.querySelector(`[data-event-id="${recent[i].id}"]`); | |
if (eventElement) { | |
eventElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); | |
eventElement.classList.add('ring-2', 'ring-indigo-500'); | |
setTimeout(() => { | |
eventElement.classList.remove('ring-2', 'ring-indigo-500'); | |
}, 2000); | |
} | |
}); | |
recentEvents.appendChild(eventCard); | |
} | |
} | |
// Create event card element | |
function createEventCard(event) { | |
const eventDate = new Date(event.date); | |
const eventDay = eventDate.getDate(); | |
const eventMonth = eventDate.toLocaleString('default', { month: 'short' }); | |
const eventTime = eventDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); | |
const fullDate = eventDate.toLocaleString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }); | |
const eventCard = document.createElement('div'); | |
eventCard.className = `bg-white rounded-lg shadow-md overflow-hidden event-card transition ${event.status === 'cancelled' ? 'opacity-70' : ''}`; | |
eventCard.dataset.eventId = event.id; | |
eventCard.innerHTML = ` | |
<div class="p-6"> | |
<div class="flex items-start justify-between"> | |
<div class="flex items-start space-x-4"> | |
<div class="bg-indigo-100 text-indigo-800 p-3 rounded-lg text-center"> | |
<div class="font-bold text-xl">${eventDay}</div> | |
<div class="text-sm uppercase">${eventMonth}</div> | |
</div> | |
<div> | |
<h3 class="text-xl font-bold text-gray-800 ${event.status === 'cancelled' ? 'line-through' : ''}">${event.name}</h3> | |
<p class="text-indigo-600">${event.artist}</p> | |
<p class="text-gray-500 text-sm mt-1">${fullDate} at ${eventTime}</p> | |
<div class="flex items-center mt-2 space-x-4"> | |
<span class="text-gray-700">${event.venue}</span> | |
<span class="text-gray-700">$${event.price.toFixed(2)}</span> | |
${event.status === 'cancelled' ? | |
'<span class="bg-red-100 text-red-800 text-xs font-medium px-2 py-0.5 rounded">Cancelled</span>' : | |
'<span class="bg-green-100 text-green-800 text-xs font-medium px-2 py-0.5 rounded">Active</span>'} | |
</div> | |
${event.url ? `<a href="${event.url}" target="_blank" class="inline-block mt-3 text-sm text-indigo-600 hover:underline">More info & tickets →</a>` : ''} | |
</div> | |
</div> | |
</div> | |
</div> | |
`; | |
return eventCard; | |
} | |
// Add new event | |
function addNewEvent(e) { | |
e.preventDefault(); | |
// Get form values | |
const eventName = document.getElementById('eventName').value; | |
const artistName = document.getElementById('artistName').value; | |
const eventDate = document.getElementById('eventDate').value; | |
const venueName = document.getElementById('venueName').value; | |
const ticketPrice = parseFloat(document.getElementById('ticketPrice').value) || 0; | |
const eventUrl = document.getElementById('eventUrl').value; | |
const eventStatus = document.querySelector('input[name="eventStatus"]:checked').value; | |
// Create new event object | |
const newEvent = { | |
id: events.length > 0 ? Math.max(...events.map(e => e.id)) + 1 : 1, | |
name: eventName, | |
artist: artistName, | |
date: eventDate, | |
venue: venueName, | |
price: ticketPrice, | |
status: eventStatus, | |
url: eventUrl | |
}; | |
// Add to events array | |
events.push(newEvent); | |
// Reset form and close modal | |
eventForm.reset(); | |
eventModal.classList.add('hidden'); | |
// Update UI | |
renderCalendar(); | |
displayEvents(); | |
displayRecentEvents(); | |
// For demo purposes, show success message | |
alert('Event added successfully!'); | |
} | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=privateuserh/chandelier-events" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |