Skip to content
Open
53 changes: 53 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메타 뷰포트 태그를 이용해서 반응형으로 화면이 브라우저 사이즈에 따라 표시되도록 한 점이 좋은 거 같아요..! 저는 사용하지 않았는데 다음에 는 사용해보고 싶습니당,,!

<title>vainilla todo</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header class="header">
<!-- <img src="menu-bar.svg" alt="menu-bar"> -->
<h1>CEOS vanilla-todo</h1>
</header>
<!-- 사이드바 2주차 과제때 추가 예정 -->
<aside></aside>
<main>
<div class="calendarContainer">
<div class="calendarHeader">
<button id="prevMonth">◀️</button>
<h2 id="currentMonth">2025년 9월</h2>
<button id="nextMonth">▶️</button>
</div>
<div class="weekdays">
<div>일</div>
<div>월</div>
<div>화</div>
<div>수</div>
<div>목</div>
<div>금</div>
<div>토</div>
</div>
<div class="dates" id="calendarDates"></div>
</div>
Comment on lines +17 to +33

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주로 div 태그 위주로 사용하셨는데, semantic tag로
section, li 등 쓰면 더 구조가 보기 좋을거 같아요..!

</main>
<!-- 할일 추가 모달 -->
<div id="todoModal" class="modal">
<div class="modalContent">
<div class="modalHeader">
<h3 id="modalDate">날짜</h3>
<span class="close">x</span>
</div>
<div class="modalBody">
<div id="todoList" class="todoList"></div>
<div class="inputContainer">
<input type="text" id="todoInput" placeholder="할 일을 입력하세요">
<button id="addTodoBtn">추가</button>
</div>
</div>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
220 changes: 220 additions & 0 deletions main.js

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전체적으로 꼼꼼한 주석 덕분에 코드를 파악하기 수월한 것 같아요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
let todos = {}; // 할 일을 저장할 객체
let selectedDay = null; // 현재 선택된 날짜 저장
let currentDate = new Date(); // 현재 표시할 년월을 저장

// localStorage에서 할 일 불러오는 함수
function loadTodos() {
const savedTodos = localStorage.getItem('todos');
if (savedTodos) {
todos = JSON.parse(savedTodos);
}
}

// localStorage에 할 일 저장하는 함수
function saveTodos() {
localStorage.setItem('todos', JSON.stringify(todos));
}


// 모달 내 할 일 목록 표시
function renderTodoList() {
const todoListElement = document.getElementById('todoList');
todoListElement.innerHTML = '';

// 등록된 할 일이 없으면 "할 일이 없습니다" 메시지 표시
if (!todos[selectedDay] || todos[selectedDay].length === 0) {
todoListElement.innerHTML = '<p style="text-align: center; color: #666;">할 일이 없습니다.</p>';
return;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가된 할일이 없을 때 빈 화면만 보여주지 않고 "할 일이 없습니다" 라고 보여주는게 좋은 것 같습니다!


// 할 일 목록 표시
todos[selectedDay].forEach((todo, index) => {
const todoItem = document.createElement('div');
// 완료된 할 일 className에 'completed' 추가
todoItem.className = `todoItem ${todo.completed ? 'completed' : ''}`;

todoItem.innerHTML = `
<div class="todoText">${todo.text}</div>
<div class="todoActions">
<button class="complete" onclick="toggleTodo('${selectedDay}', ${index})">
${todo.completed ? '취소' : '완료'}
</button>
<button onclick="deleteTodo('${selectedDay}', ${index})">삭제</button>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

할일을 저장할 때, selectedDay를 id로 사용하고, index로 삭제, 완료 등 모든 것을 수행하는데 코드적으로는 간편하고 좋지만 확장성을 고려하였을 때는 uuid를 활용하는 것이 유지보수 측면에서 더 좋다고 고려됩니다!

</div>
`;

todoListElement.appendChild(todoItem);
});
}

// 할 일 완료/취소 토글
function toggleTodo(day, index) {
todos[day][index].completed = !todos[day][index].completed;
saveTodos();
renderTodoList();
showCalendar();
}

// 할 일 삭제
function deleteTodo(day, index) {
todos[day].splice(index, 1);
if (todos[day].length === 0) {
delete todos[day];
}
saveTodos();
renderTodoList();
showCalendar();
}


// 모달 열기 함수
function openModal(day) {
const year = currentDate.getFullYear();
const month = currentDate.getMonth() + 1;
selectedDay = `${year}-${month}-${day}`; // 년-월-일 형태로 저장

document.getElementById('modalDate').textContent = `${year}년 ${month}월 ${day}일`;
document.getElementById('todoInput').value = '';
document.getElementById('todoModal').style.display = 'block';
renderTodoList();
}

// 모달 닫기 함수
function closeModal() {
document.getElementById('todoModal').style.display = 'none';
selectedDay = null;
}

// 달력 표시 함수
function showCalendar() {
const calendarDates = document.getElementById('calendarDates');

// 기존 내용 지우고 다시 그리기
calendarDates.innerHTML = '';

const year = currentDate.getFullYear();
const month = currentDate.getMonth(); // 0부터 시작 (0=1월)

// 달력 헤더 업데이트
document.getElementById('currentMonth').textContent =
`${year}년 ${month + 1}월`;
Comment on lines +95 to +100
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위의 openModal 함수에서는 const monthcurrentDate.getMonth() + 1이었다면, 여기서는 따로 ${month+1}로 처리하고 있습니다. 이 변수 선언을 일치시켜서 따로 함수로 빼서 재사용 하다면 좋을 것 같습니다.


// 해당 월의 첫날과 마지막날
const firstDay = new Date(year, month, 1).getDay(); // 첫날이 무슨 요일인지
const daysInMonth = new Date(year, month + 1, 0).getDate(); // 해당 월의 총 일수

// 이전 달의 마지막 날짜들 표시
const prevMonth = new Date(year, month - 1, 0).getDate();
for (let i = firstDay - 1; i >= 0; i--) {
const dateElement = createDateElement(prevMonth - i, year, month - 1, true);
calendarDates.appendChild(dateElement);
}

// 현재 달의 날짜들 표시
for (let day = 1; day <= daysInMonth; day++) {
const dateElement = createDateElement(day, year, month, false);
calendarDates.appendChild(dateElement);
}

// 다음 달의 첫 날짜들로 나머지 칸 채우기
const remainingCells = 42 - (firstDay + daysInMonth); // 최대 6주 x 7일 = 42칸
for (let day = 1; day <= remainingCells; day++) {
const dateElement = createDateElement(day, year, month + 1, true);
calendarDates.appendChild(dateElement);
}
}

// 날짜 요소 생성 함수
function createDateElement(day, year, month, isOtherMonth) {
const dateElement = document.createElement('div');
dateElement.className = 'date';
dateElement.textContent = day;

if (isOtherMonth) {
dateElement.classList.add('otherMonth');
}

// 오늘 날짜 확인 -> 초록색으로 표시
const today = new Date();
if (year === today.getFullYear() &&
month === today.getMonth() &&
day === today.getDate() &&
!isOtherMonth) {
dateElement.classList.add('today');
}

// 할 일이 있는 날짜 확인 -> 노란색으로 표시
const dateKey = `${year}-${month + 1}-${day}`;
if (todos[dateKey] && todos[dateKey].length > 0) {
dateElement.classList.add('hasTodos');
}

// 날짜 클릭 시 모달 오픈
if (!isOtherMonth) {
dateElement.addEventListener('click', function() {
openModal(day);
});
}

return dateElement;
}

// 이전/다음 달 이동 함수들
function goToPrevMonth() {
currentDate.setMonth(currentDate.getMonth() - 1);
showCalendar();
}

function goToNextMonth() {
currentDate.setMonth(currentDate.getMonth() + 1);
showCalendar();
}

// 모달 관련 이벤트 리스너 함수
function setupModalEvents() {
// X 버튼 클릭시 모달 닫기
document.querySelector('.close').addEventListener('click', closeModal);

// 모달 외부 클릭시 닫기
document.getElementById('todoModal').addEventListener('click', function(e) {
if (e.target === this) {
closeModal();
}
});

// 할 일 추가 버튼
document.getElementById('addTodoBtn').addEventListener('click', function() {

const todoText = document.getElementById('todoInput').value.trim();

if (todoText && selectedDay) {
if (!todos[selectedDay]) {
todos[selectedDay] = [];
}
todos[selectedDay].push({
text: todoText,
completed: false
});
Comment on lines +194 to +197

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 작동은 아무 문제 없이 되는 거 같은데 나중에 서버와 연동이나 다른 기능 추가를 생각하면 각 todo 당 id를 사용하는 것도 좋을 것 같아요..!

saveTodos();
document.getElementById('todoInput').value = '';
renderTodoList();
showCalendar();
}
});

// Enter로 할 일 추가 가능하게
document.getElementById('todoInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
document.getElementById('addTodoBtn').click();
}
});

// 달력 네비게이션 버튼
document.getElementById('prevMonth').addEventListener('click', goToPrevMonth);
document.getElementById('nextMonth').addEventListener('click', goToNextMonth);
}

// 페이지 시작할 때 실행
loadTodos(); // 저장된 할 일 불러오기
showCalendar(); // 달력 표시
setupModalEvents();
3 changes: 3 additions & 0 deletions menu-bar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading