.calendar-container {
max-width: 1400px;
margin: 0 auto;
padding: 32px 24px;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: #f8fafc;
min-height: 100vh;
}
.calendar-header {
text-align: center;
margin-bottom: 32px;
}
.calendar-title {
font-size: 36px;
font-weight: 700;
color: #1a202c;
margin: 0 0 12px 0;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.calendar-subtitle {
font-size: 16px;
color: #6b7280;
margin: 0;
}
.calendar-widget {
background: white;
border-radius: 16px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
overflow: hidden;
}
.calendar-controls {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24px 32px;
border-bottom: 1px solid #e5e7eb;
background: #fafbfc;
}
.calendar-nav {
display: flex;
align-items: center;
gap: 16px;
}
.nav-btn {
width: 40px;
height: 40px;
border: none;
border-radius: 8px;
background: #f3f4f6;
color: #6b7280;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
}
.nav-btn:hover {
background: #e5e7eb;
color: #374151;
}
.nav-btn svg {
width: 20px;
height: 20px;
}
.current-month {
display: flex;
align-items: center;
gap: 16px;
}
.current-month h2 {
font-size: 24px;
font-weight: 600;
color: #1a202c;
margin: 0;
min-width: 200px;
}
.today-btn {
padding: 8px 16px;
background: #3b82f6;
color: white;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.today-btn:hover {
background: #2563eb;
}
.view-controls {
display: flex;
align-items: center;
gap: 16px;
}
.view-buttons {
display: flex;
background: #f3f4f6;
border-radius: 8px;
padding: 4px;
}
.view-btn {
padding: 8px 16px;
border: none;
background: none;
color: #6b7280;
font-size: 14px;
font-weight: 500;
cursor: pointer;
border-radius: 6px;
transition: all 0.2s ease;
}
.view-btn.active {
background: white;
color: #1a202c;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.add-event-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 16px;
background: #10b981;
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.add-event-btn:hover {
background: #059669;
transform: translateY(-1px);
}
.add-event-btn svg {
width: 16px;
height: 16px;
}
.calendar-main {
display: grid;
grid-template-columns: 1fr 300px;
min-height: 600px;
}
.calendar-grid {
padding: 24px;
}
.weekdays {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 1px;
margin-bottom: 8px;
}
.weekday {
padding: 12px;
text-align: center;
font-size: 14px;
font-weight: 600;
color: #6b7280;
background: #f8fafc;
}
.calendar-days {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 1px;
background: #e5e7eb;
}
.calendar-day {
min-height: 100px;
background: white;
padding: 8px;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
border: 2px solid transparent;
}
.calendar-day:hover {
background: #f8fafc;
}
.calendar-day.selected {
border-color: #3b82f6;
background: #eff6ff;
}
.calendar-day.other-month {
color: #d1d5db;
background: #f9fafb;
}
.calendar-day.today {
background: #fef3c7;
border-color: #f59e0b;
}
.day-number {
font-size: 14px;
font-weight: 600;
margin-bottom: 4px;
}
.day-events {
display: flex;
flex-direction: column;
gap: 2px;
}
.event-item {
padding: 2px 6px;
border-radius: 3px;
font-size: 11px;
font-weight: 500;
color: white;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.event-item.work {
background: #3b82f6;
}
.event-item.personal {
background: #10b981;
}
.event-item.meeting {
background: #f59e0b;
}
.event-item.reminder {
background: #8b5cf6;
}
.event-item.holiday {
background: #ef4444;
}
.calendar-sidebar {
background: #fafbfc;
border-left: 1px solid #e5e7eb;
padding: 24px;
display: flex;
flex-direction: column;
gap: 24px;
}
.calendar-sidebar h3 {
font-size: 16px;
font-weight: 600;
color: #1a202c;
margin: 0 0 16px 0;
}
.mini-months {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.mini-month {
padding: 8px;
text-align: center;
font-size: 12px;
font-weight: 500;
color: #6b7280;
background: white;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
}
.mini-month:hover {
background: #e5e7eb;
}
.mini-month.current {
background: #3b82f6;
color: white;
}
.events-list {
max-height: 200px;
overflow-y: auto;
}
.event-preview {
padding: 12px;
background: white;
border-radius: 8px;
margin-bottom: 8px;
cursor: pointer;
transition: all 0.2s ease;
border-left: 4px solid;
}
.event-preview:hover {
transform: translateX(4px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.event-preview.work {
border-left-color: #3b82f6;
}
.event-preview.personal {
border-left-color: #10b981;
}
.event-preview.meeting {
border-left-color: #f59e0b;
}
.event-preview.reminder {
border-left-color: #8b5cf6;
}
.event-preview.holiday {
border-left-color: #ef4444;
}
.event-preview-title {
font-size: 14px;
font-weight: 600;
color: #1a202c;
margin-bottom: 4px;
}
.event-preview-time {
font-size: 12px;
color: #6b7280;
}
.stats-grid {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
}
.stat-item {
text-align: center;
padding: 16px;
background: white;
border-radius: 8px;
}
.stat-number {
display: block;
font-size: 24px;
font-weight: 700;
color: #1a202c;
margin-bottom: 4px;
}
.stat-label {
font-size: 12px;
color: #6b7280;
font-weight: 500;
}
/* Modal Styles */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.modal-overlay.active {
opacity: 1;
visibility: visible;
}
.modal-content {
background: white;
border-radius: 12px;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
transform: scale(0.9);
transition: transform 0.3s ease;
}
.modal-overlay.active .modal-content {
transform: scale(1);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24px 24px 0 24px;
}
.modal-header h3 {
font-size: 20px;
font-weight: 600;
color: #1a202c;
margin: 0;
}
.modal-close {
width: 32px;
height: 32px;
border: none;
background: #f3f4f6;
border-radius: 6px;
color: #6b7280;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
}
.modal-close:hover {
background: #e5e7eb;
}
.modal-close svg {
width: 16px;
height: 16px;
}
.event-form {
padding: 24px;
}
.form-group {
margin-bottom: 20px;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.form-group label {
display: block;
font-size: 14px;
font-weight: 500;
color: #374151;
margin-bottom: 8px;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 12px;
border: 1px solid #d1d5db;
border-radius: 8px;
font-size: 14px;
transition: all 0.2s ease;
box-sizing: border-box;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.form-group textarea {
resize: vertical;
min-height: 80px;
}
.form-actions {
display: flex;
gap: 12px;
justify-content: flex-end;
margin-top: 24px;
}
.btn-primary,
.btn-secondary,
.btn-danger {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-primary {
background: #3b82f6;
color: white;
}
.btn-primary:hover {
background: #2563eb;
}
.btn-secondary {
background: #f3f4f6;
color: #6b7280;
}
.btn-secondary:hover {
background: #e5e7eb;
}
.btn-danger {
background: #ef4444;
color: white;
}
.btn-danger:hover {
background: #dc2626;
}
/* Responsive Design */
@media (max-width: 1024px) {
.calendar-main {
grid-template-columns: 1fr;
}
.calendar-sidebar {
border-left: none;
border-top: 1px solid #e5e7eb;
}
}
@media (max-width: 768px) {
.calendar-container {
padding: 24px 16px;
}
.calendar-title {
font-size: 28px;
}
.calendar-controls {
flex-direction: column;
gap: 16px;
padding: 16px;
}
.calendar-nav {
justify-content: center;
}
.current-month h2 {
font-size: 20px;
min-width: auto;
}
.calendar-grid {
padding: 16px;
}
.calendar-day {
min-height: 80px;
}
.form-row {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.weekday {
padding: 8px 4px;
font-size: 12px;
}
.calendar-day {
min-height: 60px;
padding: 4px;
}
.day-number {
font-size: 12px;
}
.event-item {
font-size: 10px;
}
.view-buttons {
width: 100%;
}
.view-btn {
flex: 1;
}
}
document.addEventListener('DOMContentLoaded', () => {
const currentMonthEl = document.getElementById('currentMonth');
const calendarDaysEl = document.getElementById('calendarDays');
const prevMonthBtn = document.getElementById('prevMonth');
const nextMonthBtn = document.getElementById('nextMonth');
const todayBtn = document.getElementById('todayBtn');
const addEventBtn = document.getElementById('addEventBtn');
const eventModal = document.getElementById('eventModal');
const modalClose = document.getElementById('modalClose');
const eventForm = document.getElementById('eventForm');
const viewButtons = document.querySelectorAll('.view-btn');
const eventsListEl = document.getElementById('eventsList');
const miniMonthsEl = document.getElementById('miniMonths');
// Statistics elements
const totalEventsEl = document.getElementById('totalEvents');
const thisMonthEl = document.getElementById('thisMonth');
const todayEventsEl = document.getElementById('todayEvents');
let currentDate = new Date();
let selectedDate = null;
let currentView = 'month';
let editingEvent = null;
// Sample events data
let events = [
{
id: 1,
title: 'Team Meeting',
date: '2025-01-15',
time: '10:00',
description: 'Weekly team sync meeting',
category: 'meeting',
priority: 'high'
},
{
id: 2,
title: 'Project Deadline',
date: '2025-01-20',
time: '17:00',
description: 'Submit final project deliverables',
category: 'work',
priority: 'high'
},
{
id: 3,
title: 'Doctor Appointment',
date: '2025-01-18',
time: '14:30',
description: 'Annual checkup',
category: 'personal',
priority: 'medium'
},
{
id: 4,
title: 'Birthday Party',
date: '2025-01-25',
time: '19:00',
description: 'Sarah\'s birthday celebration',
category: 'personal',
priority: 'medium'
},
{
id: 5,
title: 'New Year Holiday',
date: '2025-01-01',
time: '',
description: 'Public holiday',
category: 'holiday',
priority: 'low'
}
];
// Month names
const monthNames = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
];
// Initialize calendar
function init() {
renderCalendar();
renderMiniMonths();
renderUpcomingEvents();
updateStatistics();
}
// Render calendar grid
function renderCalendar() {
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
currentMonthEl.textContent = `${monthNames[month]} ${year}`;
// Clear previous days
calendarDaysEl.innerHTML = '';
// Get first day of month and number of days
const firstDay = new Date(year, month, 1).getDay();
const daysInMonth = new Date(year, month + 1, 0).getDate();
const daysInPrevMonth = new Date(year, month, 0).getDate();
// Add previous month's trailing days
for (let i = firstDay - 1; i >= 0; i--) {
const dayNum = daysInPrevMonth - i;
const dayEl = createDayElement(dayNum, true, new Date(year, month - 1, dayNum));
calendarDaysEl.appendChild(dayEl);
}
// Add current month's days
for (let day = 1; day <= daysInMonth; day++) {
const date = new Date(year, month, day);
const dayEl = createDayElement(day, false, date);
calendarDaysEl.appendChild(dayEl);
}
// Add next month's leading days
const totalCells = calendarDaysEl.children.length;
const remainingCells = 42 - totalCells; // 6 rows × 7 days
for (let day = 1; day <= remainingCells; day++) {
const dayEl = createDayElement(day, true, new Date(year, month + 1, day));
calendarDaysEl.appendChild(dayEl);
}
}
// Create day element
function createDayElement(dayNum, isOtherMonth, date) {
const dayEl = document.createElement('div');
dayEl.className = 'calendar-day';
if (isOtherMonth) {
dayEl.classList.add('other-month');
}
// Check if it's today
const today = new Date();
if (date.toDateString() === today.toDateString()) {
dayEl.classList.add('today');
}
// Check if it's selected
if (selectedDate && date.toDateString() === selectedDate.toDateString()) {
dayEl.classList.add('selected');
}
const dayNumberEl = document.createElement('div');
dayNumberEl.className = 'day-number';
dayNumberEl.textContent = dayNum;
dayEl.appendChild(dayNumberEl);
// Add events for this day
const dayEventsEl = document.createElement('div');
dayEventsEl.className = 'day-events';
const dayEvents = getEventsForDate(date);
dayEvents.forEach(event => {
const eventEl = document.createElement('div');
eventEl.className = `event-item ${event.category}`;
eventEl.textContent = event.title;
eventEl.addEventListener('click', (e) => {
e.stopPropagation();
editEvent(event);
});
dayEventsEl.appendChild(eventEl);
});
dayEl.appendChild(dayEventsEl);
// Add click handler
dayEl.addEventListener('click', () => {
selectedDate = date;
renderCalendar();
});
// Add double-click handler for new event
dayEl.addEventListener('dblclick', () => {
selectedDate = date;
showEventModal(date);
});
return dayEl;
}
// Get events for specific date
function getEventsForDate(date) {
const dateStr = date.toISOString().split('T')[0];
return events.filter(event => event.date === dateStr);
}
// Show event modal
function showEventModal(date = null, event = null) {
editingEvent = event;
if (event) {
document.getElementById('modalTitle').textContent = 'Edit Event';
document.getElementById('eventTitle').value = event.title;
document.getElementById('eventDate').value = event.date;
document.getElementById('eventTime').value = event.time;
document.getElementById('eventDescription').value = event.description;
document.getElementById('eventCategory').value = event.category;
document.getElementById('eventPriority').value = event.priority;
document.getElementById('deleteBtn').style.display = 'block';
} else {
document.getElementById('modalTitle').textContent = 'Add New Event';
eventForm.reset();
if (date) {
document.getElementById('eventDate').value = date.toISOString().split('T')[0];
}
document.getElementById('deleteBtn').style.display = 'none';
}
eventModal.classList.add('active');
}
// Hide event modal
function hideEventModal() {
eventModal.classList.remove('active');
editingEvent = null;
}
// Edit event
function editEvent(event) {
showEventModal(null, event);
}
// Save event
function saveEvent(eventData) {
if (editingEvent) {
// Update existing event
const index = events.findIndex(e => e.id === editingEvent.id);
if (index !== -1) {
events[index] = { ...editingEvent, ...eventData };
}
} else {
// Add new event
const newEvent = {
id: Date.now(),
...eventData
};
events.push(newEvent);
}
renderCalendar();
renderUpcomingEvents();
updateStatistics();
hideEventModal();
}
// Delete event
function deleteEvent() {
if (editingEvent && confirm('Are you sure you want to delete this event?')) {
events = events.filter(e => e.id !== editingEvent.id);
renderCalendar();
renderUpcomingEvents();
updateStatistics();
hideEventModal();
}
}
// Render mini months
function renderMiniMonths() {
miniMonthsEl.innerHTML = '';
for (let i = 0; i < 12; i++) {
const monthEl = document.createElement('div');
monthEl.className = 'mini-month';
monthEl.textContent = monthNames[i].substr(0, 3);
if (i === currentDate.getMonth()) {
monthEl.classList.add('current');
}
monthEl.addEventListener('click', () => {
currentDate.setMonth(i);
renderCalendar();
renderMiniMonths();
});
miniMonthsEl.appendChild(monthEl);
}
}
// Render upcoming events
function renderUpcomingEvents() {
const today = new Date();
const upcomingEvents = events
.filter(event => new Date(event.date) >= today)
.sort((a, b) => new Date(a.date) - new Date(b.date))
.slice(0, 5);
eventsListEl.innerHTML = '';
if (upcomingEvents.length === 0) {
eventsListEl.innerHTML = '<p style="color: #6b7280; text-align: center; padding: 20px;">No upcoming events</p>';
return;
}
upcomingEvents.forEach(event => {
const eventEl = document.createElement('div');
eventEl.className = `event-preview ${event.category}`;
const titleEl = document.createElement('div');
titleEl.className = 'event-preview-title';
titleEl.textContent = event.title;
const timeEl = document.createElement('div');
timeEl.className = 'event-preview-time';
const eventDate = new Date(event.date);
const timeStr = event.time ? ` at ${event.time}` : '';
timeEl.textContent = `${eventDate.toLocaleDateString()}${timeStr}`;
eventEl.appendChild(titleEl);
eventEl.appendChild(timeEl);
eventEl.addEventListener('click', () => {
editEvent(event);
});
eventsListEl.appendChild(eventEl);
});
}
// Update statistics
function updateStatistics() {
const today = new Date();
const currentMonth = currentDate.getMonth();
const currentYear = currentDate.getFullYear();
// Total events
totalEventsEl.textContent = events.length;
// Events this month
const thisMonthEvents = events.filter(event => {
const eventDate = new Date(event.date);
return eventDate.getMonth() === currentMonth && eventDate.getFullYear() === currentYear;
});
thisMonthEl.textContent = thisMonthEvents.length;
// Events today
const todayStr = today.toISOString().split('T')[0];
const todayEvents = events.filter(event => event.date === todayStr);
todayEventsEl.textContent = todayEvents.length;
}
// Navigate to previous month
function prevMonth() {
currentDate.setMonth(currentDate.getMonth() - 1);
renderCalendar();
renderMiniMonths();
updateStatistics();
}
// Navigate to next month
function nextMonth() {
currentDate.setMonth(currentDate.getMonth() + 1);
renderCalendar();
renderMiniMonths();
updateStatistics();
}
// Go to today
function goToToday() {
currentDate = new Date();
selectedDate = new Date();
renderCalendar();
renderMiniMonths();
updateStatistics();
}
// Event listeners
prevMonthBtn.addEventListener('click', prevMonth);
nextMonthBtn.addEventListener('click', nextMonth);
todayBtn.addEventListener('click', goToToday);
addEventBtn.addEventListener('click', () => showEventModal(selectedDate));
modalClose.addEventListener('click', hideEventModal);
// View buttons
viewButtons.forEach(btn => {
btn.addEventListener('click', () => {
viewButtons.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentView = btn.dataset.view;
// Note: Different views would require additional implementation
});
});
// Event form submission
eventForm.addEventListener('submit', (e) => {
e.preventDefault();
const eventData = {
title: document.getElementById('eventTitle').value,
date: document.getElementById('eventDate').value,
time: document.getElementById('eventTime').value,
description: document.getElementById('eventDescription').value,
category: document.getElementById('eventCategory').value,
priority: document.getElementById('eventPriority').value
};
saveEvent(eventData);
});
// Cancel button
document.getElementById('cancelBtn').addEventListener('click', hideEventModal);
// Delete button
document.getElementById('deleteBtn').addEventListener('click', deleteEvent);
// Close modal on overlay click
eventModal.addEventListener('click', (e) => {
if (e.target === eventModal) {
hideEventModal();
}
});
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
hideEventModal();
} else if (e.key === 'n' && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
showEventModal(selectedDate);
} else if (e.key === 'ArrowLeft' && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
prevMonth();
} else if (e.key === 'ArrowRight' && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
nextMonth();
} else if (e.key === 't' && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
goToToday();
}
});
// Initialize the calendar
init();
});