프로젝트

프젝)체크리스트+메모장+캘린더

연습노트 2024. 8. 30. 21:07
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>할일, 메모장, 캘린더</title>
    <style>
        :root {
            --primary-color: #4a90e2;
            --secondary-color: #f5a623;
            --background-color: #f0f4f8;
            --text-color: #333;
            --task-bg-color: #ffffff;
            --task-border-color: #dee2e6;
        }
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 0;
            background-color: var(--background-color);
            color: var(--text-color);
        }
        .container {
            max-width: 800px;
            margin: 50px auto;
            padding: 20px;
            background-color: var(--task-bg-color);
            border: 1px solid var(--task-border-color);
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }
        .tabs {
            display: flex;
            justify-content: space-around;
            margin-bottom: 20px;
        }
        .tabs div {
            flex: 1;
            text-align: center;
            padding: 10px;
            background-color: #f1f3f5;
            border-radius: 8px;
            cursor: pointer;
            margin: 0 5px;
            font-weight: bold;
            color: var(--text-color);
            transition: background-color 0.3s, color 0.3s;
        }
        .tabs div.active {
            background-color: var(--primary-color);
            color: white;
        }
        .tabs div:hover {
            background-color: var(--primary-color);
            color: white;
        }
        .date-selector {
            display: flex;
            justify-content: space-around;
            margin-bottom: 20px;
            font-size: 18px;
        }
        .date-selector div {
            cursor: pointer;
            padding: 5px 10px;
            background-color: #f1f3f5;
            border-radius: 8px;
            transition: background-color 0.3s;
        }
        .date-selector div:hover {
            background-color: var(--secondary-color);
            color: white;
        }
        .tasks {
            margin-bottom: 20px;
            padding: 10px;
            border-radius: 8px;
            background-color: var(--task-bg-color);
        }
        .tasks div {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 10px;
            padding: 10px;
            background-color: var(--task-bg-color);
            border: 1px solid var(--task-border-color);
            border-radius: 8px;
            transition: background-color 0.3s;
        }
        .tasks div:hover {
            background-color: #e9ecef;
        }
        .tasks input[type="checkbox"] {
            margin-right: 10px;
        }
        .tasks div.completed {
            text-decoration: line-through;
            color: #868e96;
            background-color: #e9ecef;
        }
        .tasks div button {
            background-color: transparent;
            border: none;
            font-size: 16px;
            cursor: pointer;
            margin-left: 10px;
        }
        .tasks div button.add {
            color: var(--primary-color);
            font-size: 20px;
            margin-left: auto;
        }
        .tasks div button.delete {
            color: #fa5252;
        }
        .tasks div button.editable {
            flex: 1;
            margin-left: 10px;
            font-size: 14px;
            color: var(--text-color);
            background-color: transparent;
            border: none;
            cursor: text;
            outline: none;
        }
        .date {
            font-size: 24px;
            margin-bottom: 20px;
            font-weight: bold;
            color: var(--text-color);
            text-align: center;
        }
        .add {
            margin-left: 93%;
        }
        #memopad {
            width: 100%;
            height: 200px;
            margin-bottom: 20px;
            padding: 10px;
            border: 1px solid var(--task-border-color);
            border-radius: 8px;
            resize: vertical;
            background-color: var(--task-bg-color);
            color: var(--text-color);
        }
        #calendar {
            display: none;
        }
        .calendar-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
        }
        .calendar-grid {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 5px;
        }
        .calendar-day {
            text-align: center;
            padding: 5px;
            background-color: #f1f3f5;
            border-radius: 4px;
            cursor: pointer;
        }
        .calendar-day:hover {
            background-color: var(--secondary-color);
            color: white;
        }
        .calendar-day.has-tasks {
            background-color: var(--secondary-color);
        }
        .calendar-day.today {
            border: 2px solid var(--primary-color);
            font-weight: bold;
        }
        .calendar-day.weekday {
            font-weight: bold;
            background-color: var(--primary-color);
            color: white;
        }
        #dayTasks {
            margin-top: 20px;
        }
        @media (max-width: 600px) {
            .container {
                margin: 20px 10px;
                padding: 10px;
            }
            .tabs div {
                font-size: 14px;
            }
            .calendar-grid {
                font-size: 12px;
            }
        }
        #savedMemos {
            margin-top: 20px;
            border-top: 1px solid #ccc;
            padding-top: 20px;
        }
        .saved-memo {
            background-color: #f9f9f9;
            border: 1px solid #ddd;
            padding: 10px;
            margin-bottom: 10px;
            border-radius: 5px;
        }
        .memo-actions {
            margin-top: 10px;
        }
        .memo-actions button {
            margin-right: 5px;
        }
    </style>
</head>
<body>

<div class="container">
    <div class="tabs">
        <div class="tab active" onclick="switchTab('todo')">할일</div>
        <div class="tab" onclick="switchTab('memo')">메모장</div>
        <div class="tab" onclick="switchTab('calendar')">캘린더</div>
    </div>
   
    <div id="todoContent">
        <div class="date-selector">
            <div onclick="switchList('주')"></div>
            <div onclick="switchList('월')"></div>
            <div onclick="switchList('년')"></div>
        </div>
       
        <div class="tasks" id="taskList"></div>
       
        <div class="date" id="today"></div>
       
        <div class="tasks" id="todayTaskList">
            <button class="add" onclick="addTodayTask()">+</button>
        </div>
    </div>

    <div id="memoContent" style="display:none;">
        <textarea id="memopad">Welcome to TinyMCE!</textarea>
        <button id="saveMemo">메모 저장</button>
       
        <div id="savedMemos">
            <h3>저장된 메모</h3>
            <!-- 저장된 메모가 여기에 표시됩니다 -->
        </div>
    </div>
   
    <div id="calendar" style="display:none;">
        <div class="calendar-header">
            <button onclick="changeMonth(-1)">이전</button>
            <span id="currentMonth"></span>
            <button onclick="changeMonth(1)">다음</button>
        </div>
        <div class="calendar-grid" id="calendarGrid"></div>
        <div id="dayTasks"></div>
    </div>
</div>

<script>
    tinymce.init({
        selector: '#memopad',
        plugins: 'anchor autolink charmap codesample emoticons image link lists media searchreplace table visualblocks wordcount',
        toolbar: 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table | align lineheight | numlist bullist indent outdent | emoticons charmap | removeformat',
    });

    const tasks = {
        '주': ['주 할일 1', '주 할일 2','주 할일 3'],
        '월': ['월 할일 1', '월 할일 2', '월 할일 3'],
        '년': ['년 할일 1', '년 할일 2', '년 할일 3']
    };

    let calendarTasks = {};

    function switchList(period) {
        const taskList = document.getElementById('taskList');
        taskList.innerHTML = '';

        tasks[period].forEach(task => {
            taskList.innerHTML += `
                <div>
                    <input type="checkbox" onclick="toggleComplete(this)">
                    <span class="editable" contenteditable="true">${task}</span>
                    <button onclick="deleteTask(this)">-</button>
                </div>`;
        });

        taskList.innerHTML += '<button class="add" onclick="addTask(\'taskList\')">+</button>';
    }

    function toggleComplete(checkbox) {
        const taskDiv = checkbox.parentElement;
        if (checkbox.checked) {
            taskDiv.classList.add('completed');
        } else {
            taskDiv.classList.remove('completed');
        }
    }

    function deleteTask(button) {
        const taskDiv = button.parentElement;
        taskDiv.remove();
    }

    function addTask(listId) {
        const taskList = document.getElementById(listId);
        const newTaskDiv = document.createElement('div');
        newTaskDiv.innerHTML = `
            <input type="checkbox" onclick="toggleComplete(this)">
            <span class="editable" contenteditable="true">새 할일</span>
            <button onclick="deleteTask(this)">-</button>`;
        taskList.insertBefore(newTaskDiv, taskList.querySelector('button.add'));
    }

    function switchTab(tab) {
        document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
        document.querySelector(`.tab:nth-child(${tab === 'todo' ? 1 : tab === 'memo' ? 2 : 3})`).classList.add('active');
       
        document.getElementById('todoContent').style.display = tab === 'todo' ? 'block' : 'none';
        document.getElementById('memoContent').style.display = tab === 'memo' ? 'block' : 'none';
        document.getElementById('calendar').style.display = tab === 'calendar' ? 'block' : 'none';
       
        if (tab === 'calendar') {
            renderCalendar();
        }
    }

    let currentDate = new Date();

    function updateToday() {
        const today = new Date();
        const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
        document.getElementById('today').textContent = today.toLocaleDateString('ko-KR', options);
    }

    function addTodayTask() {
        const todayTaskList = document.getElementById('todayTaskList');
        const newTaskDiv = document.createElement('div');
        newTaskDiv.innerHTML = `
            <input type="checkbox" onclick="toggleComplete(this)">
            <span class="editable" contenteditable="true" onblur="updateCalendarTask(this)">새 할일</span>
            <button onclick="deleteTodayTask(this)">-</button>`;
        todayTaskList.insertBefore(newTaskDiv, todayTaskList.querySelector('button.add'));
    }

    function deleteTodayTask(button) {
        const taskDiv = button.parentElement;
        const taskText = taskDiv.querySelector('span').textContent;
        taskDiv.remove();
        removeFromCalendar(taskText);
    }

    function updateCalendarTask(span) {
        const taskText = span.textContent;
        const today = new Date();
        const dateString = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;
       
        if (!calendarTasks[dateString]) {
            calendarTasks[dateString] = [];
        }
        calendarTasks[dateString].push({ text: taskText, completed: false });
        renderCalendar();
    }

    function removeFromCalendar(taskText) {
        const today = new Date();
        const dateString = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;
       
        if (calendarTasks[dateString]) {
            calendarTasks[dateString] = calendarTasks[dateString].filter(task => task.text !== taskText);
            renderCalendar();
        }
    }

    function renderCalendar() {
        const year = currentDate.getFullYear();
        const month = currentDate.getMonth();
       
        document.getElementById('currentMonth').textContent = `${year}${month + 1}월`;
       
        const firstDay = new Date(year, month, 1);
        const lastDay = new Date(year, month + 1, 0);
       
        const calendarGrid = document.getElementById('calendarGrid');
        calendarGrid.innerHTML = '';

        const weekdays = ['일', '월', '화', '수', '목', '금', '토'];
        weekdays.forEach(day => {
            const dayElement = document.createElement('div');
            dayElement.textContent = day;
            dayElement.classList.add('calendar-day', 'weekday');
            calendarGrid.appendChild(dayElement);
        });
       
        for (let i = 0; i < firstDay.getDay(); i++) {
            calendarGrid.appendChild(document.createElement('div'));
        }
       
        for (let i = 1; i <= lastDay.getDate(); i++) {
            const dayElement = document.createElement('div');
            dayElement.textContent = i;
            dayElement.classList.add('calendar-day');
            const dateString = `${year}-${month + 1}-${i}`;
            if (calendarTasks[dateString] && calendarTasks[dateString].length > 0) {
                dayElement.classList.add('has-tasks');
            }
            if (i === new Date().getDate() && month === new Date().getMonth() && year === new Date().getFullYear()) {
                dayElement.classList.add('today');
            }
            dayElement.onclick = () => showDayTasks(dateString);
            calendarGrid.appendChild(dayElement);
        }
    }

    function showDayTasks(dateString) {
        const dayTasks = document.getElementById('dayTasks');
        dayTasks.innerHTML = `<h3>${dateString} 할일</h3>`;
        if (calendarTasks[dateString]) {
            calendarTasks[dateString].forEach((task, index) => {
                dayTasks.innerHTML += `
                    <div>
                        <input type="checkbox" ${task.completed ? 'checked' : ''} onchange="toggleCalendarTask('${dateString}', ${index})">
                        <span>${task.text}</span>
                        <button onclick="deleteCalendarTask('${dateString}', ${index})">삭제</button>
                    </div>
                `;
            });
        }
    }

    function toggleCalendarTask(dateString, index) {
        calendarTasks[dateString][index].completed = !calendarTasks[dateString][index].completed;
        showDayTasks(dateString);
    }

    function deleteCalendarTask(dateString, index) {
        calendarTasks[dateString].splice(index, 1);
        showDayTasks(dateString);
        renderCalendar();
    }

    function changeMonth(delta) {
        currentDate.setMonth(currentDate.getMonth() + delta);
        renderCalendar();
    }

    document.getElementById('saveMemo').addEventListener('click', function() {
        const content = tinymce.get('memopad').getContent();
        const timestamp = new Date().toLocaleString('ko-KR');
        const memoObj = { id: Date.now(), content, timestamp };
       
        let memos = JSON.parse(localStorage.getItem('memos')) || [];
        memos.unshift(memoObj);
       
        localStorage.setItem('memos', JSON.stringify(memos));
       
        displayMemos();
        tinymce.get('memopad').setContent('');
    });

    function displayMemos() {
        const savedMemosDiv = document.getElementById('savedMemos');
        const memos = JSON.parse(localStorage.getItem('memos')) || [];
       
        let memosHTML = '<h3>저장된 메모</h3>';
        memos.forEach((memo) => {
            memosHTML += `
                <div class="saved-memo" id="memo-${memo.id}">
                    <p><strong>저장 시간:</strong> ${memo.timestamp}</p>
                    <div>${memo.content}</div>
                    <div class="memo-actions">
                        <button onclick="editMemo(${memo.id})">수정</button>
                        <button onclick="deleteMemo(${memo.id})">삭제</button>
                    </div>
                </div>
            `;
        });
       
        savedMemosDiv.innerHTML = memosHTML;
    }

    function editMemo(id) {
        const memos = JSON.parse(localStorage.getItem('memos')) || [];
        const memo = memos.find(m => m.id === id);
        if (memo) {
            tinymce.get('memopad').setContent(memo.content);
            deleteMemo(id);
        }
    }

    function deleteMemo(id) {
        let memos = JSON.parse(localStorage.getItem('memos')) || [];
        memos = memos.filter(m => m.id !== id);
        localStorage.setItem('memos', JSON.stringify(memos));
        displayMemos();
    }

    window.addEventListener('load', () => {
        updateToday();
        switchList('주');
        switchTab('todo');
        displayMemos();
    });
</script>

</body>
</html>

'프로젝트' 카테고리의 다른 글

팀 프로젝트) 해당 글만 필터하기  (1) 2024.09.24
프로젝트>카풀 _ 보완점  (9) 2024.09.03
프로젝트 > OTT 업데이트  (0) 2024.08.24
간단 게임>비행기  (0) 2024.08.13
프로젝트> ott 로그인버튼  (0) 2024.08.12