-
Notifications
You must be signed in to change notification settings - Fork 10
[2주차] 백승선 과제 제출합니다. #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
7ea841a
7cb5201
b4192a1
f8979fe
2592124
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "singleQuote": true, | ||
| "semi": true, | ||
| "trailingComma": "all", | ||
| "printWidth": 100, | ||
| "tabWidth": 3 | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 파일 1주차 과제 더미 데이터로 보이는 데 맞을까요 ?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3주차 과제부터는 코딩 중간중간 / 제출 직전에 폴더 구조나 파일 구성 점검해보는 습관을 들이는 걸 추천드립니다
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,233 @@ | ||
| document.addEventListener('DOMContentLoaded', () => { | ||
| //menu tab | ||
| const menuTab = document.getElementById('menuTab'); | ||
| const openBtn = document.querySelector('.menu'); | ||
| const closeBtn = document.getElementById('closeMenu'); | ||
|
|
||
| //open and close menu drawer | ||
| const openDrawer = () => { | ||
| menuTab.classList.add('active'); | ||
| }; | ||
| const closeDrawer = () => { | ||
| menuTab.classList.remove('active'); | ||
| }; | ||
|
|
||
| openBtn.addEventListener('click', openDrawer); | ||
| closeBtn.addEventListener('click', closeDrawer); | ||
|
|
||
| //close menu when clicked outside of menu tab | ||
| document.addEventListener('click', (e) => { | ||
| if ( | ||
| menuTab.classList.contains('active') && | ||
| !menuTab.contains(e.target) && | ||
| !openBtn.contains(e.target) | ||
| ) { | ||
| closeDrawer(); | ||
| } | ||
| }); | ||
|
|
||
| //close menu when user presses esc | ||
| document.addEventListener('keydown', (e) => { | ||
| if (e.key === 'Escape' && menuTab.classList.contains('active')) closeDrawer(); | ||
| }); | ||
|
|
||
| //define date manipulating buttons | ||
| const today = document.querySelector('.today'); | ||
| const prevBtn = document.getElementById('yesterday'); | ||
| const nextBtn = document.getElementById('tomorrow'); | ||
|
|
||
| //get date | ||
| let current = new Date(); | ||
| const fmt = { year: 'numeric', month: 'long', day: 'numeric' }; | ||
|
|
||
| //Date manipulation | ||
| function render() { | ||
| today.textContent = current.toLocaleDateString(undefined, fmt); | ||
| } | ||
| render(); | ||
|
|
||
| //define next and last week buttons in menu | ||
| const nWeek = document.querySelector('.nWeek'); | ||
| const lWeek = document.querySelector('.lWeek'); | ||
|
|
||
| //피드백 주신 대로 changWeek함수를 만들고 +7/-7을 인자로 남겨 처리했습니다 | ||
| function changeDays(offSetDays) { | ||
| current.setDate(current.getDate() + offSetDays); | ||
| render(); | ||
| loadList(current); | ||
| ifNoEvents(); | ||
| } | ||
| nWeek.addEventListener('click', () => { | ||
| changeDays(7); | ||
| }); | ||
| lWeek.addEventListener('click', () => { | ||
| changeDays(-7); | ||
| }); | ||
|
|
||
| prevBtn.addEventListener('click', () => { | ||
| changeDays(-1); | ||
| }); | ||
|
|
||
| nextBtn.addEventListener('click', () => { | ||
| changeDays(1); | ||
| }); | ||
|
|
||
| //when the date is clicked on, change current date to today | ||
| today.addEventListener('click', () => { | ||
| current = new Date(); | ||
| render(); | ||
| loadList(current); | ||
| }); | ||
|
|
||
| const dateKey = (d) => new Date(d).toLocaleDateString('en-CA'); | ||
| // "YYYY-MM-DD" in local time | ||
| const storageKey = (d) => `${dateKey(d)}`; | ||
|
|
||
| const numEvent = document.querySelector('.numEvent'); | ||
|
|
||
| //saves the events for a date | ||
| function saveList(date) { | ||
| const dateData = { | ||
| dateTodoEl: todoEl.innerHTML, | ||
| dateTodos: todos, | ||
| }; | ||
| sessionStorage.setItem(storageKey(date), JSON.stringify(dateData)); | ||
| } | ||
|
|
||
| //loads the events for a date | ||
| function loadList(date) { | ||
| const raw = sessionStorage.getItem(storageKey(date) || ''); | ||
| if (raw) { | ||
| const parsed = JSON.parse(raw); | ||
| todoEl.innerHTML = parsed.dateTodoEl; | ||
| todos = parsed.dateTodos; | ||
| } else { | ||
| todos = []; | ||
| todoEl.innerHTML = ''; | ||
| } | ||
| getNumEvent(); | ||
| } | ||
|
|
||
| const input = document.querySelector('.input'); | ||
| const add = document.querySelector('.register'); | ||
| const todoEl = document.querySelector('.todoEl'); | ||
| const clearAll = document.querySelector('.clearAll'); | ||
|
|
||
| let todos = []; | ||
|
|
||
| //event listener that is restored once loaded from storage | ||
| todoEl.addEventListener('click', (e) => { | ||
| //선택된 li | ||
| const li = e.target.closest('li'); | ||
| //선택된 li의 index number을 idx라 명명 | ||
| const id = li.dataset.id; | ||
| const idx = todos.findIndex((t) => t.id === id); | ||
|
|
||
| //delete button | ||
| if (e.target && e.target.classList.contains('delEvent')) { | ||
| todos.splice(idx, 1); | ||
| } | ||
|
|
||
| //done button | ||
| if (e.target && e.target.classList.contains('doneEvent')) { | ||
| todos[idx].done = !todos[idx].done; | ||
| console.log('done'); | ||
| } | ||
| //pin and unpin events | ||
| if (e.target && e.target.classList.contains('pinEvent')) { | ||
| todos[idx].pinned = !todos[idx].pinned; | ||
| } | ||
|
|
||
| renderTodos(); | ||
| saveList(current); | ||
| ifNoEvents(); | ||
| getNumEvent(); | ||
| }); | ||
|
|
||
| //add event using enter and button click | ||
| add.addEventListener('click', () => { | ||
| if (input.value !== '') { | ||
| addToList(input.value); | ||
| input.value = ''; | ||
| saveList(current); | ||
| } | ||
| }); | ||
| input.addEventListener('keydown', (e) => { | ||
| if (e.key === 'Enter' && input.value !== '') { | ||
| addToList(input.value); | ||
| input.value = ''; | ||
| saveList(current); | ||
| } | ||
| }); | ||
|
|
||
| function addToList(text) { | ||
| const newTodo = { | ||
| id: crypto.randomUUID(), | ||
| done: false, | ||
| pinned: false, | ||
| text: text, | ||
| }; | ||
| todos.push(newTodo); | ||
| saveList(); | ||
| renderTodos(); | ||
| } | ||
|
|
||
| function renderTodos() { | ||
| const sorted = [...todos].sort((a, b) => b.pinned - a.pinned); | ||
| todoEl.innerHTML = ''; | ||
|
|
||
| for (const t of sorted) { | ||
| const li = document.createElement('li'); | ||
| li.dataset.id = t.id; | ||
| li.className = t.pinned ? 'pinned' : ''; | ||
| li.innerHTML = ` | ||
| <button class="doneEvent">${t.done ? 'Undone' : 'Done'}</button> | ||
| <span class="text ${t.done ? 'markDone' : ''}">${t.text}</span> | ||
| <button class="pinEvent ${t.pinned ? 'markPin' : ''}"> | ||
| ${t.pinned ? 'Unpin' : 'Pin'} | ||
| </button> | ||
| <button class="delEvent">Delete</button> | ||
| `; | ||
| todoEl.appendChild(li); | ||
| } | ||
| getNumEvent(); | ||
| } | ||
|
|
||
| //clear all events for a date | ||
| function clearALlEvents(date) { | ||
| todos = []; | ||
| renderTodos(); | ||
| saveList(current); | ||
| ifNoEvents(); | ||
| } | ||
| clearAll.addEventListener('click', () => { | ||
| clearALlEvents(current); | ||
| getNumEvent(); | ||
| }); | ||
|
|
||
| function ifNoEvents() { | ||
| if (todos.length === 0) { | ||
| sessionStorage.removeItem(storageKey(current)); | ||
| } | ||
| } | ||
|
|
||
| //get the number of Events | ||
| function getNumEvent() { | ||
| numEvent.textContent = 'To-do: ' + todoEl.children.length; | ||
| } | ||
|
|
||
| //calendar manipulation | ||
| const menuContent = document.getElementById('menuContent'); | ||
| const datePickerEl = document.createElement('input'); | ||
| datePickerEl.type = 'date'; | ||
| datePickerEl.className = 'menuDatePicker'; // make it obvious | ||
| menuContent.appendChild(datePickerEl); | ||
| datePickerEl.addEventListener('change', () => { | ||
| if (!datePickerEl.value) return; | ||
| const [y, m, d] = datePickerEl.value.split('-').map(Number); | ||
| saveList(current); | ||
| current = new Date(y, m - 1, d); | ||
| render(); | ||
| loadList(current); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| <!doctype html> | ||
| <html lang="en"> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 추후 프로젝트 진행하시게 되면 높은 확률로 대상 국가가 대한민국일텐데요. 검색 엔진 최적화 등 다양한 요소를 고려하였을 때 lang="ko" 로 지정하시면 좀 더 완성도 높은 결과물이 나올 거 같아요
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 개인적으로는 이런 사소한 것 하나하나부터 확실히 이해하는 게 중요하다고 생각합니다 |
||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <title>react-todo 백승선</title> | ||
| </head> | ||
| <body> | ||
| <!-- React가 붙을 자리 --> | ||
| <div id="root"></div> | ||
|
|
||
| <!-- Vite 권장: 루트 기준 절대 경로 --> | ||
| <script type="module" src="src/main.jsx"></script> | ||
| </body> | ||
| </html> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tabWidth를 3으로 설정하신 이유가 있을까요 ? 일반적으로 html, js 같은 프론트엔드 기술 스택에서는 2를 주로 사용합니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prettier 설정하실 때도 각 속성이 어떤 역할을 하는지 명확히 이해하신 후 사용하시는 걸 추천드립니다.