Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@

## ⏰ 스터디 시간

**매주 월요일 10:00**
~~매주 월요일 10:00~~

**월요일 16:00**

<br/>

Expand All @@ -31,9 +33,8 @@
## ⚙️ 컨벤션

* 본인 이름의 브랜치에 정리 파일 및 실습 파일 올리고 PR 보내기
* 파일명 규칙
* 본인 이름 폴더 / 챕터 {번호 및 제목} / {정리}.md
* 본인 이름 폴더 / 챕터 {번호 및 제목} / Practice / {문제}.ts
* 파일업로드
* `본인 이름 폴더` / 내에 정리 md 파일, 예제문제 풀이 ts파일

<br/>

Expand All @@ -43,5 +44,9 @@
| 회차 | 일시 | 스터디 내용 |
| ---- | -------- | -------- |
| 1 | 23.11.13 월 | CHAPTER 1, 2, 3, 4 |
| 2 | 23.11.20 월 | CHAPTER 5, 6, 7 ,10 |
| 3 | 23.11.27 월 | CHAPTER 8,9 + type-challenges 워밍업(1) & 쉬움(13) |
| 4 | 23.12.04 월 | CHAPTER 15, Vue+TS 과제 중 이슈 공유 |
| 5 | 23.12.11 월 | TodoList 과제 TS 전환 |


16 changes: 16 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0" />
<title>h0ber Ts</title>
</head>
<body>
<main id="app"></main>
<script
type="module"
src="./src/main.js"></script>
</body>
</html>
29 changes: 29 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "fedc5_learningts_study",
"version": "1.0.0",
"description": "[러닝 타입스크립트](https://www.yes24.com/Product/Goods/116585556)로 타입스크립트 뿌시기 !",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"typescript": "^5.3.3"
}
}
45 changes: 45 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Header from './components/Header.js';
import createTodo from './components/createTodoInput.js';
import TodoList from './components/TodoList.js';
import TodoCounter from './components/TodoCounter.js';
const HEADER_TITLE = 'TODO LIST';
export default class App {
constructor({ $app, initialState }) {
this.$app = $app;
this.state = initialState;
new Header({
$app: this.$app,
title: HEADER_TITLE,
});
new createTodo({
$app: this.$app,
onSubmit: (text) => {
const nextState = this.makeNextState(text);
this.state = nextState;
todoList.setState(nextState);
},
});
const todoList = new TodoList({
$app: this.$app,
todoInitialState: this.state,
updateTodoCounter: (nextState) => {
todoCounter.setState(nextState);
},
});
const todoCounter = new TodoCounter({
$app: this.$app,
initialState: this.state,
});
}
makeNextState(text) {
const nextState = [
...this.state,
{
isCompleted: false,
title: text,
id: new Date().getTime().toString(),
},
];
return nextState;
}
}
57 changes: 57 additions & 0 deletions src/App.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Todo, AppProps } from './util/types.js';

import Header from './components/Header.js';
import createTodo from './components/createTodoInput.js';
import TodoList from './components/TodoList.js';
import TodoCounter from './components/TodoCounter.js';

const HEADER_TITLE = 'TODO LIST';

export default class App {
$app: HTMLDivElement;
state: Todo[];

constructor({ $app, initialState }: AppProps) {
this.$app = $app;
this.state = initialState;

new Header({
$app: this.$app,
title: HEADER_TITLE,
});

new createTodo({
$app: this.$app,
onSubmit: (text: string) => {
const nextState = this.makeNextState(text);
this.state = nextState;
todoList.setState(nextState);
},
});

const todoList = new TodoList({
$app: this.$app,
todoInitialState: this.state,
updateTodoCounter: (nextState: Todo[]) => {
todoCounter.setState(nextState);
},
});

const todoCounter = new TodoCounter({
$app: this.$app,
initialState: this.state,
});
}

makeNextState(text: string): Todo[] {
const nextState = [
...this.state,
{
isCompleted: false,
title: text,
id: new Date().getTime().toString(),
Copy link
Member

Choose a reason for hiding this comment

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

id를 따로 날짜로 주셨군요? 좋은 방법이라고 생각됩니다!

},
];
return nextState;
}
}
12 changes: 12 additions & 0 deletions src/components/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default class Header {
constructor({ $app, title }) {
this.$header = document.createElement('h1');
this.$app = $app;
this.title = title;
this.render();
}
render() {
this.$header.textContent = this.title;
this.$app.appendChild(this.$header);
}
}
19 changes: 19 additions & 0 deletions src/components/Header.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { HeaderProps } from '../util/types.js';

export default class Header {
$app: HTMLDivElement;
title: string;
$header: HTMLHeadElement;

constructor({ $app, title }: HeaderProps) {
this.$header = document.createElement('h1');
this.$app = $app;
this.title = title;
this.render();
}

render(): void {
this.$header.textContent = this.title;
this.$app.appendChild(this.$header);
}
}
18 changes: 18 additions & 0 deletions src/components/TodoCounter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default class TodoCounter {
constructor({ $app, initialState }) {
this.$counter = document.createElement('div');
$app.appendChild(this.$counter);
this.state = initialState;
this.render();
}
setState(nextState) {
this.state = nextState;
this.render();
}
render() {
this.$counter.innerHTML = `
<div class="todo-counter">Total: ${this.state.length}</div>
<div class="done-counter">Done: ${this.state.filter((e) => e.isCompleted).length}</div>
`;
}
}
27 changes: 27 additions & 0 deletions src/components/TodoCounter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Todo, TodoCounterProps } from '../util/types.js';

export default class TodoCounter {
state: Todo[];
$counter: HTMLDivElement;

constructor({ $app, initialState }: TodoCounterProps) {
this.$counter = document.createElement('div');
$app.appendChild(this.$counter);
this.state = initialState;
this.render();
}

setState(nextState: Todo[]): void {
this.state = nextState;
this.render();
}

render(): void {
this.$counter.innerHTML = `
<div class="todo-counter">Total: ${this.state.length}</div>
<div class="done-counter">Done: ${
this.state.filter((e) => e.isCompleted).length
}</div>
`;
}
}
63 changes: 63 additions & 0 deletions src/components/TodoList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { setItem } from '../util/storage.js';
const STORAGE_KEY = 'todo';
export default class TodoList {
constructor({ $app, todoInitialState, updateTodoCounter }) {
this.$todoList = document.createElement('div');
$app.appendChild(this.$todoList);
this.updateTodoCounter = updateTodoCounter;
this.state = todoInitialState;
this.setEvent();
this.render();
}
completedTodo(id) {
const nextState = this.state.map((todo) => {
if (todo.id === id) {
return {
...todo,
isCompleted: !todo.isCompleted,
};
}
return todo;
});
this.setState(nextState);
}
removeTodo(id) {
const nextState = this.state.filter((todo) => todo.id !== id);
this.setState(nextState);
}
setState(nextState) {
setItem(STORAGE_KEY, JSON.stringify(nextState));
this.updateTodoCounter(nextState);
this.state = nextState;
this.render();
}
render() {
this.$todoList.innerHTML = `
<ul>
${this.state
.map(({ title, isCompleted, id }) => {
return `
<li class="toggled-text" data-id="${id}"
style="text-decoration: ${isCompleted ? 'line-through' : 'none'}">
${title}
<button class="remove-button" data-id="${id}">
Remove
</button>
</li>
`;
})
.join('')}
</ul>
`;
}
setEvent() {
this.$todoList.addEventListener('click', (event) => {
const target = event.target;
const id = target.dataset.id;
if (id !== null) {
target.className === 'toggled-text' && this.completedTodo(id);
target.className === 'remove-button' && this.removeTodo(id);
}
});
}
}
Loading