티스토리 뷰

통합 달력 스크립트 (년월 이동 오늘 일정 자동 표시).html
0.01MB

 

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS 일정 관리 달력</title>
    <style>
        :root {
            --primary-color: #4a90e2;
            --event-dot-color: #ff4d4d;
            --today-bg: #fff9c4;
        }

        body { font-family: 'Pretendard', sans-serif; display: flex; justify-content: center; padding: 20px; background-color: #f5f5f5; }
        
        .calendar-container { 
            width: 400px; 
            background: #fff; 
            padding: 20px; 
            border-radius: 12px; 
            box-shadow: 0 10px 25px rgba(0,0,0,0.1); 
        }

        /* 헤더 스타일 */
        .calendar-header { 
            display: flex; 
            justify-content: space-between; 
            align-items: center; 
            margin-bottom: 20px; 
        }
        .nav-buttons { display: flex; gap: 8px; align-items: center; }
        select { padding: 5px; border-radius: 4px; border: 1px solid #ddd; cursor: pointer; }
        button { 
            background: var(--primary-color); 
            color: white; border: none; 
            padding: 5px 12px; border-radius: 4px; cursor: pointer; 
        }
        button:hover { opacity: 0.8; }

        /* 달력 그리드 */
        .weekdays { 
            display: grid; 
            grid-template-columns: repeat(7, 1fr); 
            font-weight: bold; 
            text-align: center; 
            color: #666;
            margin-bottom: 10px;
        }
        .calendar-grid { 
            display: grid; 
            grid-template-columns: repeat(7, 1fr); 
            gap: 5px; 
        }

        .day { 
            aspect-ratio: 1 / 1; 
            display: flex; 
            align-items: center; 
            justify-content: center; 
            cursor: pointer; 
            border-radius: 8px;
            position: relative;
            transition: 0.2s;
            font-size: 14px;
        }
        .day:hover { background: #eef2ff; }
        .day.today { background: var(--today-bg); font-weight: bold; color: #d4a017; border: 1px solid #fbc02d; }

        /* 일정 점 표시 */
        .has-event::after {
            content: '';
            position: absolute;
            bottom: 6px;
            width: 5px;
            height: 5px;
            background-color: var(--event-dot-color);
            border-radius: 50%;
        }

        /* 하단 일정 리스트 */
        .event-section { 
            margin-top: 25px; 
            padding-top: 15px; 
            border-top: 1px dashed #ddd; 
        }
        .event-section h3 { font-size: 16px; margin-bottom: 10px; color: #333; }
        #eventList { list-style: none; padding: 0; margin: 0; }
        #eventList li { 
            padding: 8px 12px; 
            background: #f9f9f9; 
            margin-bottom: 5px; 
            border-radius: 6px; 
            font-size: 14px;
            border-left: 3px solid var(--primary-color);
        }
        .no-event { color: #999; font-style: italic; border-left: none !important; background: none !important; }
    </style>
</head>
<body>

<div class="calendar-container">
    <div class="calendar-header">
        <div class="nav-buttons">
            <button id="prevMonth">&lt;</button>
            <select id="yearSelect"></select>
            <select id="monthSelect"></select>
            <button id="nextMonth">&gt;</button>
        </div>
        <button onclick="goToToday()">오늘</button>
    </div>
    
    <div class="weekdays">
        <div style="color:red">일</div><div>월</div><div>화</div><div>수</div><div>목</div><div>금</div><div style="color:blue">토</div>
    </div>

    <div id="calendarGrid" class="calendar-grid"></div>
    
    <div class="event-section">
        <h3 id="selectedDateTitle">날짜를 선택하세요</h3>
        <ul id="eventList"></ul>
    </div>
</div>

<script>
    // 1. 가상 일정 데이터 (테스트용)
    const scheduleData = {
        "2026-03-03": ["오늘은 서비스 오픈일!", "팀 회식 19:00"],
        "2026-03-05": ["프로젝트 마감일"],
        "2026-03-14": ["화이트데이 캔들 만들기"],
        "2026-04-01": ["만우절 장난 준비"]
    };

    let viewDate = new Date(); // 현재 화면에 보이는 기준 날짜

    const yearSelect = document.getElementById('yearSelect');
    const monthSelect = document.getElementById('monthSelect');
    const grid = document.getElementById('calendarGrid');
    const listEl = document.getElementById('eventList');
    const titleEl = document.getElementById('selectedDateTitle');

    // 초기화 함수
    function init() {
        const currentYear = new Date().getFullYear();
        // 년도 선택 범위: 현재 기준 ±5년
        for (let i = currentYear - 5; i <= currentYear + 5; i++) {
            const opt = document.createElement('option');
            opt.value = i; opt.innerText = i + "년";
            yearSelect.appendChild(opt);
        }
        // 월 선택
        for (let i = 0; i < 12; i++) {
            const opt = document.createElement('option');
            opt.value = i; opt.innerText = (i + 1) + "월";
            monthSelect.appendChild(opt);
        }

        renderCalendar();
        
        // [핵심] 로딩 시 오늘 날짜 일정 바로 표시
        const todayStr = formatDate(new Date());
        showEvents(todayStr);
    }

    // 날짜 포맷팅 유틸리티 (YYYY-MM-DD)
    function formatDate(date) {
        const y = date.getFullYear();
        const m = String(date.getMonth() + 1).padStart(2, '0');
        const d = String(date.getDate()).padStart(2, '0');
        return `${y}-${m}-${d}`;
    }

    // 달력 그리기
    function renderCalendar() {
        const year = viewDate.getFullYear();
        const month = viewDate.getMonth();

        yearSelect.value = year;
        monthSelect.value = month;
        grid.innerHTML = '';

        const firstDay = new Date(year, month, 1).getDay();
        const lastDate = new Date(year, month + 1, 0).getDate();
        const todayStr = formatDate(new Date());

        // 시작 요일 맞추기 위한 빈칸
        for (let i = 0; i < firstDay; i++) grid.innerHTML += `<div></div>`;

        // 날짜 생성
        for (let d = 1; d <= lastDate; d++) {
            const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
            const dayDiv = document.createElement('div');
            dayDiv.className = 'day';
            
            if (dateStr === todayStr) dayDiv.classList.add('today');
            if (scheduleData[dateStr]) dayDiv.classList.add('has-event');

            dayDiv.innerText = d;
            dayDiv.onclick = () => showEvents(dateStr);
            grid.appendChild(dayDiv);
        }
    }

    // 일정 리스트 업데이트
    function showEvents(dateStr) {
        const isToday = dateStr === formatDate(new Date());
        titleEl.innerText = isToday ? `오늘 (${dateStr})` : dateStr;
        
        const events = scheduleData[dateStr] || [];
        if (events.length > 0) {
            listEl.innerHTML = events.map(e => `<li>${e}</li>`).join('');
        } else {
            listEl.innerHTML = `<li class="no-event">일정이 없습니다.</li>`;
        }
    }

    // 오늘로 이동 버튼
    function goToToday() {
        viewDate = new Date();
        renderCalendar();
        showEvents(formatDate(viewDate));
    }

    // 이벤트 리스너
    yearSelect.onchange = () => { viewDate.setFullYear(yearSelect.value); renderCalendar(); };
    monthSelect.onchange = () => { viewDate.setMonth(monthSelect.value); renderCalendar(); };
    
    document.getElementById('prevMonth').onclick = () => {
        viewDate.setMonth(viewDate.getMonth() - 1);
        renderCalendar();
    };
    document.getElementById('nextMonth').onclick = () => {
        viewDate.setMonth(viewDate.getMonth() + 1);
        renderCalendar();
    };

    init();
</script>

</body>
</html>

 

※ 해당 내용은 Google Gmini3.0에서 작성되었습니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함