Demo

Event Manager

This demo showcases an integrated event management system combining the Calendar and Timeline plugins. Schedule events, add milestones, and see your timeline come to life with real-time updates.


<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/index.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/style.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/style.min.css" />

<div id="root"></div>

<script>
function EventManager() {
    const self = this;

    // Sample events
    const initialEvents = [
        { date: new Date(2025, 0, 15), title: 'Project Kickoff', type: 'meeting', description: 'Initial planning and team assembly' },
        { date: new Date(2025, 1, 1), title: 'Design Review', type: 'review', description: 'UI/UX design presentation' },
        { date: new Date(2025, 1, 15), title: 'Sprint 1 Complete', type: 'milestone', description: 'Core features implemented' },
        { date: new Date(2025, 2, 1), title: 'QA Testing', type: 'testing', description: 'Comprehensive testing phase' },
        { date: new Date(2025, 2, 15), title: 'Launch Date', type: 'milestone', description: 'Product goes live!' }
    ];

    self.events = initialEvents;
    self.selectedDate = new Date().toISOString().split('T')[0];
    self.newEventTitle = '';
    self.newEventType = 'event';
    self.newEventDescription = '';

    // Stats as reactive properties
    self.totalEvents = initialEvents.length;
    self.milestonesCount = initialEvents.filter(e => e.type === 'milestone').length;
    self.meetingsCount = initialEvents.filter(e => e.type === 'meeting').length;

    // Reactive properties for calendar and timeline
    self.calendarEvents = initialEvents.map(e => ({
        date: e.date.toISOString().split('T')[0],
        title: e.title,
        color: e.type === 'milestone' ? '#e74c3c' : e.type === 'meeting' ? '#3498db' : e.type === 'review' ? '#f39c12' : '#2ecc71'
    }));

    // Timeline with date, title, subtitle (type) and description
    self.timelineData = [...initialEvents].sort((a, b) => a.date - b.date).map(e => ({
        date: e.date,
        title: e.title,
        subtitle: e.type.charAt(0).toUpperCase() + e.type.slice(1),
        description: e.description
    }));

    self.onDateChange = function(el, date) {
        if (date && date.length === 10 && self.selectedDate !== date) {
            self.selectedDate = date;
        }
    };

    self.updateViews = function() {
        // Update stats
        self.totalEvents = self.events.length;
        self.milestonesCount = self.events.filter(e => e.type === 'milestone').length;
        self.meetingsCount = self.events.filter(e => e.type === 'meeting').length;

        // Update calendar events
        self.calendarEvents = self.events.map(e => ({
            date: e.date.toISOString().split('T')[0],
            title: e.title,
            color: e.type === 'milestone' ? '#e74c3c' : e.type === 'meeting' ? '#3498db' : e.type === 'review' ? '#f39c12' : '#2ecc71'
        }));

        // Update timeline data
        self.timelineData = [...self.events].sort((a, b) => a.date - b.date).map(e => ({
            date: e.date,
            title: e.title,
            subtitle: e.type.charAt(0).toUpperCase() + e.type.slice(1),
            description: e.description
        }));
    };

    self.addEvent = function() {
        if (self.newEventTitle && self.selectedDate) {
            // Parse date correctly to avoid timezone issues
            const [year, month, day] = self.selectedDate.split('-').map(Number);
            self.events = [...self.events, {
                date: new Date(year, month - 1, day),
                title: self.newEventTitle,
                type: self.newEventType,
                description: self.newEventDescription || 'No description'
            }];
            self.newEventTitle = '';
            self.newEventType = 'event';
            self.newEventDescription = '';
            self.updateViews();
        }
    };

    return `<div style="padding: 20px;">
        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
            <h2 style="margin: 0;">Event Manager</h2>
            <div style="display: flex; gap: 30px;">
                <div style="text-align: center;">
                    <div style="font-size: 24px; font-weight: 700; color: #3498db;">{{self.totalEvents}}</div>
                    <div style="font-size: 12px; color: #64748b;">Total Events</div>
                </div>
                <div style="text-align: center;">
                    <div style="font-size: 24px; font-weight: 700; color: #e74c3c;">{{self.milestonesCount}}</div>
                    <div style="font-size: 12px; color: #64748b;">Milestones</div>
                </div>
                <div style="text-align: center;">
                    <div style="font-size: 24px; font-weight: 700; color: #2ecc71;">{{self.meetingsCount}}</div>
                    <div style="font-size: 12px; color: #64748b;">Meetings</div>
                </div>
            </div>
        </div>

        <div style="display: flex; gap: 20px;">
            <div style="flex: 1; display: flex; flex-direction: column;">
                <h3 style="margin: 0 0 16px 0; font-size: 18px;">Calendar View</h3>
                <div style="background: white; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0;">
                    <Calendar :events="self.calendarEvents" :onchange="self.onDateChange" type="inline" footer="false" />
                </div>
            </div>

            <div style="flex: 1; display: flex; flex-direction: column;">
                <h3 style="margin: 0 0 16px 0; font-size: 18px;">Add New Event</h3>
                <div style="background: white; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0;">
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Selected Date:</label>
                        <input type="date" :value="self.selectedDate" oninput="self.selectedDate = this.value" style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px;" />
                    </div>
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Event Title:</label>
                        <input type="text" :value="self.newEventTitle" oninput="self.newEventTitle = this.value" placeholder="Enter event name..." style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px;" />
                    </div>
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Event Type:</label>
                        <select :value="self.newEventType" onchange="self.newEventType = this.value" style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px;">
                            <option value="event">Event</option>
                            <option value="meeting">Meeting</option>
                            <option value="review">Review</option>
                            <option value="milestone">Milestone</option>
                            <option value="testing">Testing</option>
                        </select>
                    </div>
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Description:</label>
                        <textarea :value="self.newEventDescription" oninput="self.newEventDescription = this.value" placeholder="Enter description..." style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px; resize: none; height: 80px;"></textarea>
                    </div>
                    <button onclick="self.addEvent()" class="button primary" style="width: 100%;">Add Event</button>
                </div>
            </div>

            <div style="flex: 1; display: flex; flex-direction: column;">
                <h3 style="margin: 0 0 16px 0; font-size: 18px;">Timeline View</h3>
                <div style="background: white; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0; max-height: 450px; overflow-y: auto;">
                    <Timeline :data="self.timelineData" align="left" order="desc" />
                </div>
            </div>
        </div>
    </div>`;
}

lemonade.render(EventManager, document.getElementById('root'));
</script>
</html>
import lemonade from 'lemonadejs';
import Calendar from '@lemonadejs/calendar';
import Timeline from '@lemonadejs/timeline';

export default function EventManager() {
    const self = this;

    // Sample events
    const initialEvents = [
        { date: new Date(2025, 0, 15), title: 'Project Kickoff', type: 'meeting', description: 'Initial planning and team assembly' },
        { date: new Date(2025, 1, 1), title: 'Design Review', type: 'review', description: 'UI/UX design presentation' },
        { date: new Date(2025, 1, 15), title: 'Sprint 1 Complete', type: 'milestone', description: 'Core features implemented' },
        { date: new Date(2025, 2, 1), title: 'QA Testing', type: 'testing', description: 'Comprehensive testing phase' },
        { date: new Date(2025, 2, 15), title: 'Launch Date', type: 'milestone', description: 'Product goes live!' }
    ];

    self.events = initialEvents;
    self.selectedDate = new Date().toISOString().split('T')[0];
    self.newEventTitle = '';
    self.newEventType = 'event';
    self.newEventDescription = '';

    // Stats as reactive properties
    self.totalEvents = initialEvents.length;
    self.milestonesCount = initialEvents.filter(e => e.type === 'milestone').length;
    self.meetingsCount = initialEvents.filter(e => e.type === 'meeting').length;

    // Reactive properties for calendar and timeline
    self.calendarEvents = initialEvents.map(e => ({
        date: e.date.toISOString().split('T')[0],
        title: e.title,
        color: e.type === 'milestone' ? '#e74c3c' : e.type === 'meeting' ? '#3498db' : e.type === 'review' ? '#f39c12' : '#2ecc71'
    }));

    self.timelineData = [...initialEvents].sort((a, b) => a.date - b.date).map(e => ({
        date: e.date,
        title: e.title,
        subtitle: e.type.charAt(0).toUpperCase() + e.type.slice(1),
        description: e.description
    }));

    self.onDateChange = function(el, date) {
        if (date && date.length === 10 && self.selectedDate !== date) {
            self.selectedDate = date;
        }
    };

    self.updateViews = function() {
        self.totalEvents = self.events.length;
        self.milestonesCount = self.events.filter(e => e.type === 'milestone').length;
        self.meetingsCount = self.events.filter(e => e.type === 'meeting').length;

        self.calendarEvents = self.events.map(e => ({
            date: e.date.toISOString().split('T')[0],
            title: e.title,
            color: e.type === 'milestone' ? '#e74c3c' : e.type === 'meeting' ? '#3498db' : e.type === 'review' ? '#f39c12' : '#2ecc71'
        }));

        self.timelineData = [...self.events].sort((a, b) => a.date - b.date).map(e => ({
            date: e.date,
            title: e.title,
            subtitle: e.type.charAt(0).toUpperCase() + e.type.slice(1),
            description: e.description
        }));
    };

    self.addEvent = function() {
        if (self.newEventTitle && self.selectedDate) {
            const [year, month, day] = self.selectedDate.split('-').map(Number);
            self.events = [...self.events, {
                date: new Date(year, month - 1, day),
                title: self.newEventTitle,
                type: self.newEventType,
                description: self.newEventDescription || 'No description'
            }];
            self.newEventTitle = '';
            self.newEventType = 'event';
            self.newEventDescription = '';
            self.updateViews();
        }
    };

    return `<div style="padding: 20px;">
        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
            <h2 style="margin: 0;">Event Manager</h2>
            <div style="display: flex; gap: 30px;">
                <div style="text-align: center;">
                    <div style="font-size: 24px; font-weight: 700; color: #3498db;">{{self.totalEvents}}</div>
                    <div style="font-size: 12px; color: #64748b;">Total Events</div>
                </div>
                <div style="text-align: center;">
                    <div style="font-size: 24px; font-weight: 700; color: #e74c3c;">{{self.milestonesCount}}</div>
                    <div style="font-size: 12px; color: #64748b;">Milestones</div>
                </div>
                <div style="text-align: center;">
                    <div style="font-size: 24px; font-weight: 700; color: #2ecc71;">{{self.meetingsCount}}</div>
                    <div style="font-size: 12px; color: #64748b;">Meetings</div>
                </div>
            </div>
        </div>

        <div style="display: flex; gap: 20px;">
            <div style="flex: 1; display: flex; flex-direction: column;">
                <h3 style="margin: 0 0 16px 0; font-size: 18px;">Calendar View</h3>
                <div style="background: white; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0;">
                    <Calendar :events="self.calendarEvents" :onchange="self.onDateChange" type="inline" footer="false" />
                </div>
            </div>

            <div style="flex: 1; display: flex; flex-direction: column;">
                <h3 style="margin: 0 0 16px 0; font-size: 18px;">Add New Event</h3>
                <div style="background: white; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0;">
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Selected Date:</label>
                        <input type="date" :value="self.selectedDate" oninput="self.selectedDate = this.value" style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px;" />
                    </div>
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Event Title:</label>
                        <input type="text" :value="self.newEventTitle" oninput="self.newEventTitle = this.value" placeholder="Enter event name..." style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px;" />
                    </div>
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Event Type:</label>
                        <select :value="self.newEventType" onchange="self.newEventType = this.value" style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px;">
                            <option value="event">Event</option>
                            <option value="meeting">Meeting</option>
                            <option value="review">Review</option>
                            <option value="milestone">Milestone</option>
                            <option value="testing">Testing</option>
                        </select>
                    </div>
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Description:</label>
                        <textarea :value="self.newEventDescription" oninput="self.newEventDescription = this.value" placeholder="Enter description..." style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px; resize: none; height: 80px;"></textarea>
                    </div>
                    <button onclick="self.addEvent()" class="button primary" style="width: 100%;">Add Event</button>
                </div>
            </div>

            <div style="flex: 1; display: flex; flex-direction: column;">
                <h3 style="margin: 0 0 16px 0; font-size: 18px;">Timeline View</h3>
                <div style="background: white; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0; max-height: 450px; overflow-y: auto;">
                    <Timeline :data="self.timelineData" align="left" order="desc" />
                </div>
            </div>
        </div>
    </div>`;
}
import React, { useState } from 'react';
import { Calendar } from '@lemonadejs/calendar/react';
import { Timeline } from '@lemonadejs/timeline/react';
import '@lemonadejs/calendar/dist/style.min.css';
import '@lemonadejs/timeline/dist/style.min.css';

export default function EventManager() {
    const initialEvents = [
        { date: new Date(2025, 0, 15), title: 'Project Kickoff', type: 'meeting', description: 'Initial planning and team assembly' },
        { date: new Date(2025, 1, 1), title: 'Design Review', type: 'review', description: 'UI/UX design presentation' },
        { date: new Date(2025, 1, 15), title: 'Sprint 1 Complete', type: 'milestone', description: 'Core features implemented' },
        { date: new Date(2025, 2, 1), title: 'QA Testing', type: 'testing', description: 'Comprehensive testing phase' },
        { date: new Date(2025, 2, 15), title: 'Launch Date', type: 'milestone', description: 'Product goes live!' }
    ];

    const [events, setEvents] = useState(initialEvents);
    const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0]);
    const [newEventTitle, setNewEventTitle] = useState('');
    const [newEventType, setNewEventType] = useState('event');
    const [newEventDescription, setNewEventDescription] = useState('');

    const [totalEvents, setTotalEvents] = useState(initialEvents.length);
    const [milestonesCount, setMilestonesCount] = useState(initialEvents.filter(e => e.type === 'milestone').length);
    const [meetingsCount, setMeetingsCount] = useState(initialEvents.filter(e => e.type === 'meeting').length);

    const [calendarEvents, setCalendarEvents] = useState(
        initialEvents.map(e => ({
            date: e.date.toISOString().split('T')[0],
            title: e.title,
            color: e.type === 'milestone' ? '#e74c3c' : e.type === 'meeting' ? '#3498db' : e.type === 'review' ? '#f39c12' : '#2ecc71'
        }))
    );

    const [timelineData, setTimelineData] = useState(
        [...initialEvents].sort((a, b) => a.date - b.date).map(e => ({
            date: e.date,
            title: e.title,
            subtitle: e.type.charAt(0).toUpperCase() + e.type.slice(1),
            description: e.description
        }))
    );

    const handleDateChange = (el, date) => {
        if (date && date.length === 10 && selectedDate !== date) {
            setSelectedDate(date);
        }
    };

    const updateViews = (newEvents) => {
        setTotalEvents(newEvents.length);
        setMilestonesCount(newEvents.filter(e => e.type === 'milestone').length);
        setMeetingsCount(newEvents.filter(e => e.type === 'meeting').length);

        setCalendarEvents(
            newEvents.map(e => ({
                date: e.date.toISOString().split('T')[0],
                title: e.title,
                color: e.type === 'milestone' ? '#e74c3c' : e.type === 'meeting' ? '#3498db' : e.type === 'review' ? '#f39c12' : '#2ecc71'
            }))
        );

        setTimelineData(
            [...newEvents].sort((a, b) => a.date - b.date).map(e => ({
                date: e.date,
                title: e.title,
                subtitle: e.type.charAt(0).toUpperCase() + e.type.slice(1),
                description: e.description
            }))
        );
    };

    const addEvent = () => {
        if (newEventTitle && selectedDate) {
            const [year, month, day] = selectedDate.split('-').map(Number);
            const newEvents = [...events, {
                date: new Date(year, month - 1, day),
                title: newEventTitle,
                type: newEventType,
                description: newEventDescription || 'No description'
            }];
            setEvents(newEvents);
            setNewEventTitle('');
            setNewEventType('event');
            setNewEventDescription('');
            updateViews(newEvents);
        }
    };

    return (
        <div style={{ padding: '20px' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
                <h2 style={{ margin: 0 }}>Event Manager</h2>
                <div style={{ display: 'flex', gap: '30px' }}>
                    <div style={{ textAlign: 'center' }}>
                        <div style={{ fontSize: '24px', fontWeight: 700, color: '#3498db' }}>{totalEvents}</div>
                        <div style={{ fontSize: '12px', color: '#64748b' }}>Total Events</div>
                    </div>
                    <div style={{ textAlign: 'center' }}>
                        <div style={{ fontSize: '24px', fontWeight: 700, color: '#e74c3c' }}>{milestonesCount}</div>
                        <div style={{ fontSize: '12px', color: '#64748b' }}>Milestones</div>
                    </div>
                    <div style={{ textAlign: 'center' }}>
                        <div style={{ fontSize: '24px', fontWeight: 700, color: '#2ecc71' }}>{meetingsCount}</div>
                        <div style={{ fontSize: '12px', color: '#64748b' }}>Meetings</div>
                    </div>
                </div>
            </div>

            <div style={{ display: 'flex', gap: '20px' }}>
                <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
                    <h3 style={{ margin: '0 0 16px 0', fontSize: '18px' }}>Calendar View</h3>
                    <div style={{ background: 'white', padding: '20px', borderRadius: '10px', border: '1px solid #e2e8f0' }}>
                        <Calendar events={calendarEvents} onchange={handleDateChange} type="inline" footer={false} />
                    </div>
                </div>

                <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
                    <h3 style={{ margin: '0 0 16px 0', fontSize: '18px' }}>Add New Event</h3>
                    <div style={{ background: 'white', padding: '20px', borderRadius: '10px', border: '1px solid #e2e8f0' }}>
                        <div style={{ marginBottom: '12px' }}>
                            <label style={{ display: 'block', marginBottom: '6px', fontSize: '14px', fontWeight: 500 }}>Selected Date:</label>
                            <input type="date" value={selectedDate} onChange={(e) => setSelectedDate(e.target.value)} style={{ width: '100%', padding: '8px', border: '1px solid #cbd5e1', borderRadius: '6px' }} />
                        </div>
                        <div style={{ marginBottom: '12px' }}>
                            <label style={{ display: 'block', marginBottom: '6px', fontSize: '14px', fontWeight: 500 }}>Event Title:</label>
                            <input type="text" value={newEventTitle} onChange={(e) => setNewEventTitle(e.target.value)} placeholder="Enter event name..." style={{ width: '100%', padding: '8px', border: '1px solid #cbd5e1', borderRadius: '6px' }} />
                        </div>
                        <div style={{ marginBottom: '12px' }}>
                            <label style={{ display: 'block', marginBottom: '6px', fontSize: '14px', fontWeight: 500 }}>Event Type:</label>
                            <select value={newEventType} onChange={(e) => setNewEventType(e.target.value)} style={{ width: '100%', padding: '8px', border: '1px solid #cbd5e1', borderRadius: '6px' }}>
                                <option value="event">Event</option>
                                <option value="meeting">Meeting</option>
                                <option value="review">Review</option>
                                <option value="milestone">Milestone</option>
                                <option value="testing">Testing</option>
                            </select>
                        </div>
                        <div style={{ marginBottom: '12px' }}>
                            <label style={{ display: 'block', marginBottom: '6px', fontSize: '14px', fontWeight: 500 }}>Description:</label>
                            <textarea value={newEventDescription} onChange={(e) => setNewEventDescription(e.target.value)} placeholder="Enter description..." style={{ width: '100%', padding: '8px', border: '1px solid #cbd5e1', borderRadius: '6px', resize: 'none', height: '80px' }}></textarea>
                        </div>
                        <button onClick={addEvent} className="button primary" style={{ width: '100%' }}>Add Event</button>
                    </div>
                </div>

                <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
                    <h3 style={{ margin: '0 0 16px 0', fontSize: '18px' }}>Timeline View</h3>
                    <div style={{ background: 'white', padding: '20px', borderRadius: '10px', border: '1px solid #e2e8f0', maxHeight: '450px', overflowY: 'auto' }}>
                        <Timeline data={timelineData} align="left" order="desc" />
                    </div>
                </div>
            </div>
        </div>
    );
}
<template>
    <div style="padding: 20px;">
        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
            <h2 style="margin: 0;">Event Manager</h2>
            <div style="display: flex; gap: 30px;">
                <div style="text-align: center;">
                    <div style="font-size: 24px; font-weight: 700; color: #3498db;">{{ totalEvents }}</div>
                    <div style="font-size: 12px; color: #64748b;">Total Events</div>
                </div>
                <div style="text-align: center;">
                    <div style="font-size: 24px; font-weight: 700; color: #e74c3c;">{{ milestonesCount }}</div>
                    <div style="font-size: 12px; color: #64748b;">Milestones</div>
                </div>
                <div style="text-align: center;">
                    <div style="font-size: 24px; font-weight: 700; color: #2ecc71;">{{ meetingsCount }}</div>
                    <div style="font-size: 12px; color: #64748b;">Meetings</div>
                </div>
            </div>
        </div>

        <div style="display: flex; gap: 20px;">
            <div style="flex: 1; display: flex; flex-direction: column;">
                <h3 style="margin: 0 0 16px 0; font-size: 18px;">Calendar View</h3>
                <div style="background: white; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0;">
                    <Calendar :events="calendarEvents" @change="handleDateChange" type="inline" :footer="false" />
                </div>
            </div>

            <div style="flex: 1; display: flex; flex-direction: column;">
                <h3 style="margin: 0 0 16px 0; font-size: 18px;">Add New Event</h3>
                <div style="background: white; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0;">
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Selected Date:</label>
                        <input type="date" v-model="selectedDate" style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px;" />
                    </div>
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Event Title:</label>
                        <input type="text" v-model="newEventTitle" placeholder="Enter event name..." style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px;" />
                    </div>
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Event Type:</label>
                        <select v-model="newEventType" style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px;">
                            <option value="event">Event</option>
                            <option value="meeting">Meeting</option>
                            <option value="review">Review</option>
                            <option value="milestone">Milestone</option>
                            <option value="testing">Testing</option>
                        </select>
                    </div>
                    <div style="margin-bottom: 12px;">
                        <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500;">Description:</label>
                        <textarea v-model="newEventDescription" placeholder="Enter description..." style="width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 6px; resize: none; height: 80px;"></textarea>
                    </div>
                    <button @click="addEvent" class="button primary" style="width: 100%;">Add Event</button>
                </div>
            </div>

            <div style="flex: 1; display: flex; flex-direction: column;">
                <h3 style="margin: 0 0 16px 0; font-size: 18px;">Timeline View</h3>
                <div style="background: white; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0; max-height: 450px; overflow-y: auto;">
                    <Timeline :data="timelineData" align="left" order="desc" />
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import { Calendar } from '@lemonadejs/calendar/vue';
import { Timeline } from '@lemonadejs/timeline/vue';
import '@lemonadejs/calendar/dist/style.min.css';
import '@lemonadejs/timeline/dist/style.min.css';

export default {
    name: 'EventManager',
    components: {
        Calendar,
        Timeline
    },
    data() {
        const initialEvents = [
            { date: new Date(2025, 0, 15), title: 'Project Kickoff', type: 'meeting', description: 'Initial planning and team assembly' },
            { date: new Date(2025, 1, 1), title: 'Design Review', type: 'review', description: 'UI/UX design presentation' },
            { date: new Date(2025, 1, 15), title: 'Sprint 1 Complete', type: 'milestone', description: 'Core features implemented' },
            { date: new Date(2025, 2, 1), title: 'QA Testing', type: 'testing', description: 'Comprehensive testing phase' },
            { date: new Date(2025, 2, 15), title: 'Launch Date', type: 'milestone', description: 'Product goes live!' }
        ];

        return {
            events: initialEvents,
            selectedDate: new Date().toISOString().split('T')[0],
            newEventTitle: '',
            newEventType: 'event',
            newEventDescription: '',
            totalEvents: initialEvents.length,
            milestonesCount: initialEvents.filter(e => e.type === 'milestone').length,
            meetingsCount: initialEvents.filter(e => e.type === 'meeting').length,
            calendarEvents: initialEvents.map(e => ({
                date: e.date.toISOString().split('T')[0],
                title: e.title,
                color: e.type === 'milestone' ? '#e74c3c' : e.type === 'meeting' ? '#3498db' : e.type === 'review' ? '#f39c12' : '#2ecc71'
            })),
            timelineData: [...initialEvents].sort((a, b) => a.date - b.date).map(e => ({
                date: e.date,
                title: e.title,
                subtitle: e.type.charAt(0).toUpperCase() + e.type.slice(1),
                description: e.description
            }))
        };
    },
    methods: {
        handleDateChange(el, date) {
            if (date && date.length === 10 && this.selectedDate !== date) {
                this.selectedDate = date;
            }
        },
        updateViews() {
            this.totalEvents = this.events.length;
            this.milestonesCount = this.events.filter(e => e.type === 'milestone').length;
            this.meetingsCount = this.events.filter(e => e.type === 'meeting').length;

            this.calendarEvents = this.events.map(e => ({
                date: e.date.toISOString().split('T')[0],
                title: e.title,
                color: e.type === 'milestone' ? '#e74c3c' : e.type === 'meeting' ? '#3498db' : e.type === 'review' ? '#f39c12' : '#2ecc71'
            }));

            this.timelineData = [...this.events].sort((a, b) => a.date - b.date).map(e => ({
                date: e.date,
                title: e.title,
                subtitle: e.type.charAt(0).toUpperCase() + e.type.slice(1),
                description: e.description
            }));
        },
        addEvent() {
            if (this.newEventTitle && this.selectedDate) {
                const [year, month, day] = this.selectedDate.split('-').map(Number);
                this.events = [...this.events, {
                    date: new Date(year, month - 1, day),
                    title: this.newEventTitle,
                    type: this.newEventType,
                    description: this.newEventDescription || 'No description'
                }];
                this.newEventTitle = '';
                this.newEventType = 'event';
                this.newEventDescription = '';
                this.updateViews();
            }
        }
    }
}
</script>