Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions Week1/dist/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use strict";
// 1. DOM 요소 가져오기 (타입 단언 사용)
const todoInput = document.getElementById('todo-input');
const todoForm = document.getElementById('todo-form');
const todoList = document.getElementById('todo-list');
const doneList = document.getElementById('done-list');
// 상태 관리 배열
let todos = [];
let doneTasks = [];
// 3. 텍스트 입력 처리 함수 (공백 제거)
const getTodoText = () => {
return todoInput.value.trim();
};
// 4. 할 일 추가 함수
const addTodo = (text) => {
const newTodo = {
id: Date.now(), // 고유 ID로 현재 시간 사용
text: text,
};
todos.push(newTodo);
todoInput.value = ''; // 입력창 초기화
};
// 5. 할 일 상태 변경 (할 일 -> 완료)
const completeTask = (todo) => {
todos = todos.filter((t) => t.id !== todo.id); // 기존 리스트에서 제거
doneTasks.push(todo); // 완료 리스트에 추가
renderTasks();
};
// 6. 완료된 할 일 삭제 함수
const deleteTodo = (todo) => {
doneTasks = doneTasks.filter((t) => t.id !== todo.id);
renderTasks();
};
// 7. 리스트 아이템 DOM 생성 함수
const createTodoElement = (todo, isDone) => {
const li = document.createElement('li');
li.classList.add('render__container__item');
// 텍스트 추가
const textNode = document.createTextNode(todo.text);
li.appendChild(textNode);
// 버튼 추가
const button = document.createElement('button');
button.classList.add('render__container__item__button');
if (isDone) {
button.textContent = '삭제';
button.style.backgroundColor = '#dc3545'; // 삭제는 빨간색
button.addEventListener('click', () => deleteTodo(todo));
}
else {
button.textContent = '완료';
button.style.backgroundColor = '#28a745'; // 완료는 초록색
button.addEventListener('click', () => completeTask(todo));
}
li.appendChild(button);
return li; // HTML 태그 노드 반환
};
// 8. 화면 렌더링 함수
const renderTasks = () => {
// 화면 초기화
todoList.innerHTML = '';
doneList.innerHTML = '';
// 진행 중인 할 일 렌더링
todos.forEach((todo) => {
const li = createTodoElement(todo, false);
todoList.appendChild(li);
});
// 완료된 할 일 렌더링
doneTasks.forEach((doneTask) => {
const li = createTodoElement(doneTask, true);
doneList.appendChild(li);
});
};
// 9. 폼 이벤트 리스너 연결
todoForm.addEventListener('submit', (e) => {
e.preventDefault(); // 기본 폼 제출(새로고침) 방지
const text = getTodoText();
if (text) {
addTodo(text);
renderTasks();
}
});
34 changes: 34 additions & 0 deletions Week1/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dori Todo</title>
<link rel="stylesheet" href="style.css">
<script defer src="dist/script.js"></script>
</head>
<body>
<div class="todo__container">
<div class="todo__container__header">
<h1>Dori Todo</h1>
</div>

<form id="todo-form" class="todo__container__form">
<input type="text" id="todo-input" class="todo__container__input" placeholder="할 일을 입력해주세요" required>
<button type="submit" class="todo__container__button">할 일 추가</button>
</form>

<div class="render__container">
<section class="render__container__section">
<h2 class="render__container__title">할 일</h2>
<ul id="todo-list" class="render__container__list"></ul>
</section>

<section class="render__container__section">
<h2 class="render__container__title">완료</h2>
<ul id="done-list" class="render__container__list"></ul>
</section>
</div>
</div>
</body>
</html>
100 changes: 100 additions & 0 deletions Week1/src/script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// 1. DOM 요소 가져오기 (타입 단언 사용)
const todoInput = document.getElementById('todo-input') as HTMLInputElement;
const todoForm = document.getElementById('todo-form') as HTMLFormElement;
const todoList = document.getElementById('todo-list') as HTMLUListElement;
const doneList = document.getElementById('done-list') as HTMLUListElement;

// 2. 할 일 타입 정의
type Todo = {
id: number;
text: string;
};

// 상태 관리 배열
let todos: Todo[] = [];
let doneTasks: Todo[] = [];

// 3. 텍스트 입력 처리 함수 (공백 제거)
const getTodoText = (): string => {
return todoInput.value.trim();
};

// 4. 할 일 추가 함수
const addTodo = (text: string): void => {
const newTodo: Todo = {
id: Date.now(), // 고유 ID로 현재 시간 사용
text: text,
};
todos.push(newTodo);
todoInput.value = ''; // 입력창 초기화
};

// 5. 할 일 상태 변경 (할 일 -> 완료)
const completeTask = (todo: Todo): void => {
todos = todos.filter((t) => t.id !== todo.id); // 기존 리스트에서 제거
doneTasks.push(todo); // 완료 리스트에 추가
renderTasks();
};

// 6. 완료된 할 일 삭제 함수
const deleteTodo = (todo: Todo): void => {
doneTasks = doneTasks.filter((t) => t.id !== todo.id);
renderTasks();
};

// 7. 리스트 아이템 DOM 생성 함수
const createTodoElement = (todo: Todo, isDone: boolean): HTMLLIElement => {
const li = document.createElement('li');
li.classList.add('render__container__item');

// 텍스트 추가
const textNode = document.createTextNode(todo.text);
li.appendChild(textNode);

// 버튼 추가
const button = document.createElement('button');
button.classList.add('render__container__item__button');

if (isDone) {
button.textContent = '삭제';
button.style.backgroundColor = '#dc3545'; // 삭제는 빨간색
button.addEventListener('click', () => deleteTodo(todo));
} else {
button.textContent = '완료';
button.style.backgroundColor = '#28a745'; // 완료는 초록색
button.addEventListener('click', () => completeTask(todo));
}

li.appendChild(button);
return li; // HTML 태그 노드 반환
};

// 8. 화면 렌더링 함수
const renderTasks = (): void => {
// 화면 초기화
todoList.innerHTML = '';
doneList.innerHTML = '';

// 진행 중인 할 일 렌더링
todos.forEach((todo) => {
const li = createTodoElement(todo, false);
todoList.appendChild(li);
});

// 완료된 할 일 렌더링
doneTasks.forEach((doneTask) => {
const li = createTodoElement(doneTask, true);
doneList.appendChild(li);
});
};

// 9. 폼 이벤트 리스너 연결
todoForm.addEventListener('submit', (e: Event) => {
e.preventDefault(); // 기본 폼 제출(새로고침) 방지
const text = getTodoText();

if (text) {
addTodo(text);
renderTasks();
}
});
97 changes: 97 additions & 0 deletions Week1/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: 'Roboto', sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f5f5;
}

.todo__container {
background-color: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
width: 350px;
text-align: center;
}

.todo__container__header {
font-size: 24px;
margin-bottom: 16px;
}

.todo__container__form {
display: flex;
gap: 10px;
margin-bottom: 20px;
}

.todo__container__input {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 14px;
}

.todo__container__button {
background-color: #28a745;
color: white;
border: none;
padding: 8px 12px;
cursor: pointer;
border-radius: 6px;
transition: background-color 0.3s;
}

.todo__container__button:hover {
background-color: #218838;
}

.render__container {
display: flex;
justify-content: space-between;
gap: 20px;
}

.render__container__section {
width: 100%;
}

.render__container__title {
font-size: 18px;
margin-bottom: 10px;
text-align: center;
}

.render__container__list {
list-style: none;
}

.render__container__item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px;
border-bottom: 1px solid #ddd;
margin-bottom: 6px;
background-color: #fff;
border-radius: 6px;
}

.render__container__item__button {
border: none;
padding: 6px 10px;
cursor: pointer;
border-radius: 6px;
font-size: 12px;
color: white;
transition: background-color 0.3s;
}
11 changes: 11 additions & 0 deletions Week1/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "ES2016",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
}
}