-
Notifications
You must be signed in to change notification settings - Fork 10
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
[2주차] 김서연 미션 제출합니다! #6
base: master
Are you sure you want to change the base?
Changes from all commits
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,6 @@ | ||
{ | ||
"trailingComma": "es5", | ||
"tabWidth": 2, | ||
"semi": true, | ||
"singleQuote": true | ||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,107 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import styled from 'styled-components'; | ||
import { Font } from './styles/font'; | ||
import DateBox from './components/DateBox'; | ||
import TodayGoal from './components/TodayGoal'; | ||
import TodoInput from './components/TodoInput'; | ||
import Tasks from './components/Tasks'; | ||
function App() { | ||
const TODO = 0; | ||
const DONE = 1; | ||
Comment on lines
+9
to
+10
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. state를 0 1대신 이름을 적용해서 더 알아보기 좋은 것 같아요! |
||
const [tasks, setTasks] = useState({ | ||
12345678: { | ||
id: '12345678', | ||
state: TODO, | ||
text: 'CEOS 1주차 과제 : JS로 Todo 구현하기', | ||
}, | ||
12345679: { | ||
id: '12345679', | ||
state: TODO, | ||
text: 'CEOS 2주차 과제 : React로 Todo 구현하기', | ||
}, | ||
}); | ||
const _saveTasks = (tasks) => { | ||
setTasks(tasks); | ||
localStorage.setItem('tasks', tasks); | ||
}; | ||
|
||
const _loadTasks = () => { | ||
var tasks = JSON.parse(localStorage.getItem('tasks') || `{}`); // 저장된 tasks 정보 불러오기 | ||
// 저장된 tasks가 없을 경우 비어있는 객체 불러올 수 있도록 | ||
setTasks(tasks); | ||
}; | ||
const _toggleTask = (id) => { | ||
var newTasks = { ...tasks }; | ||
|
||
newTasks[id].state = 1 - newTasks[id].state; // TODO <-> DONE 상태 전환 | ||
console.log(newTasks); | ||
_saveTasks(newTasks); | ||
}; | ||
|
||
const _deleteTask = (id) => { | ||
var newTasks = { ...tasks }; | ||
delete newTasks[id]; //id가 key값인 객체 삭제 | ||
_saveTasks(newTasks); | ||
}; | ||
const _addTask = (text) => { | ||
if (text.trim() === '') { | ||
return; | ||
} | ||
var newId = Date.now(); | ||
Comment on lines
+41
to
+50
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. 혹시 여기서 |
||
|
||
/* 변수의 value값을 JS의 key값으로 사용하는 방법 | ||
https://koonsland.tistory.com/146 */ | ||
|
||
_saveTasks({ | ||
...tasks, | ||
[newId]: { | ||
id: [newId], | ||
state: TODO, | ||
text: text, | ||
}, | ||
}); | ||
}; | ||
useEffect(() => { | ||
//_loadTasks(); | ||
}, []); | ||
|
||
console.log(tasks); | ||
return ( | ||
<div> | ||
<h1>17기 프론트 화이팅~ 우하하</h1> | ||
</div> | ||
<Background> | ||
<MainBox> | ||
<DateBox /> | ||
<TodayGoal /> | ||
<TodoInput _addTask={_addTask} /> | ||
<Tasks | ||
tasks={tasks} | ||
_toggleTask={_toggleTask} | ||
_deleteTask={_deleteTask} | ||
/> | ||
</MainBox> | ||
</Background> | ||
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. 전 이번 과제하면서 컴포넌트를 어떻게 나눌까 고민이 많았는데 |
||
); | ||
} | ||
const Background = styled.div` | ||
display: flex; | ||
flex-direction: row; | ||
justify-content: center; | ||
align-items: center; | ||
height: 100%; | ||
width: 100vw; | ||
`; | ||
|
||
const MainBox = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: flex-start; | ||
align-items: center; | ||
|
||
padding: 5vh 5vw; | ||
box-shadow: 0px 4px 4px rgba(45, 45, 45, 0.45); | ||
width: 90vw; | ||
height: 100vh; | ||
|
||
max-width: 600px; | ||
`; | ||
|
||
export default App; | ||
export default App; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import styled from 'styled-components'; | ||
import { Font } from '../styles/font'; | ||
export default function DateBox() { | ||
let days = [ | ||
'SUNDAY', | ||
'MONDAY', | ||
'TUESDAY', | ||
'WEDNESDAY', | ||
'THURSDAY', | ||
'FRIDAY', | ||
'SATURDAY', | ||
]; | ||
|
||
let months = [ | ||
'', | ||
'JANUARY', | ||
'FEBRUARY', | ||
'MARCH', | ||
'APRILL', | ||
'MAY', | ||
'JUNE', | ||
'JULY', | ||
'AUGUST', | ||
'SEMTEMBER', | ||
'OCTOBER', | ||
'NOBEMBER', | ||
'DESEMBER', | ||
]; | ||
|
||
const [currentMonthText, setCurrentMonthText] = useState('MARCH'); | ||
const [currentMonth, setCurrentMonth] = useState(0); | ||
const [currentDate, setCurrentDate] = useState(0); | ||
const [currentDay, setCurrentDay] = useState('MON'); | ||
|
||
useEffect(() => { | ||
let today = new Date(); | ||
|
||
setCurrentMonth(today.getMonth() + 1); | ||
setCurrentDate(today.getDate()); | ||
|
||
let currentDayIdx = today.getDay(); | ||
setCurrentDay(days[currentDayIdx]); | ||
setCurrentMonthText(months[currentMonth]); | ||
}, []); | ||
return ( | ||
<Col> | ||
<HeadLine fontSize={'var(--font-size-lg)'} color={`var(--pink)`}> | ||
{currentMonthText} | ||
</HeadLine> | ||
<Row> | ||
<Font fontSize={'var(--font-size-ml)'} color={`var(--gray)`}> | ||
{currentMonth}.{currentDate} | ||
</Font> | ||
| ||
<Font fontSize={'var(--font-size-ml)'} color={`var(--gray)`}> | ||
{currentDay} | ||
</Font> | ||
</Row> | ||
</Col> | ||
); | ||
} | ||
|
||
const Row = styled.div` | ||
display: flex; | ||
flex-direction: row; | ||
justify-content: center; | ||
align-content: center; | ||
`; | ||
|
||
const Col = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-content: center; | ||
margin: 10px; | ||
`; | ||
const HeadLine = styled(Font)` | ||
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.
|
||
letter-spacing: 3px; | ||
display: flex; | ||
flex-direction: row; | ||
justify-content: center; | ||
align-content: center; | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { Font } from '../styles/font'; | ||
import CheckIconSrc from '../assets/images/check.svg'; | ||
import DeleteIconSrc from '../assets/images/delete.svg'; | ||
import UnCheckIconSrc from '../assets/images/uncheck.svg'; | ||
export default function Tasks({ tasks, _toggleTask, _deleteTask }) { | ||
return ( | ||
<TasksLayout> | ||
<TaskBox> | ||
<Font fontSize={'var(--font-size-md)'}>TO DO</Font> | ||
<TaskContent> | ||
{Object.values(tasks) | ||
.filter((task) => task.state === 0) | ||
.map(({ text, id }) => ( | ||
<TaskContentItem fontSize="var(--font-size-sm)"> | ||
<SvgIcon src={UnCheckIconSrc} onClick={() => _toggleTask(id)} /> | ||
{text} | ||
<SvgIcon src={DeleteIconSrc} onClick={() => _deleteTask(id)} /> | ||
</TaskContentItem> | ||
))} | ||
</TaskContent> | ||
</TaskBox> | ||
|
||
<TaskBox> | ||
<Font fontSize={'var(--font-size-md)'}>DONE</Font> | ||
<TaskContent> | ||
{' '} | ||
{Object.values(tasks) | ||
.filter((task) => task.state === 1) | ||
.map(({ text, id }) => ( | ||
<Font fontSize="var(--font-size-sm)"> | ||
<SvgIcon | ||
src={CheckIconSrc} | ||
onClick={() => _toggleTask(id)} | ||
width={'var(--font-size-sm)'} | ||
/> | ||
|
||
{text} | ||
<SvgIcon | ||
src={DeleteIconSrc} | ||
onClick={() => _deleteTask(id)} | ||
width={'var(--font-size-sm)'} | ||
/> | ||
</Font> | ||
))} | ||
</TaskContent> | ||
</TaskBox> | ||
</TasksLayout> | ||
); | ||
} | ||
const TasksLayout = styled.div` | ||
display: flex; | ||
gap: 20px; | ||
height: 100%; | ||
width: 100%; | ||
|
||
@media (max-width: 767px) { | ||
//모바일 | ||
|
||
flex-direction: column; | ||
justify-content: space-between; | ||
} | ||
|
||
@media (min-width: 1200px) { | ||
// 데스크탑 일반 | ||
flex-direction: row; | ||
|
||
justify-content: space-between; | ||
} | ||
`; | ||
Comment on lines
+58
to
+71
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. 오오 pc와 mobile 반응형 따로 구현해주신 디테일~!!👏🏻👏🏻👏🏻 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. 모바일과 웹 반응형을 고려해주신 디테일에 감탄하고 갑니다.. 😭
Comment on lines
+52
to
+71
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. 왜인지 모르겠는데 입력할 때 긴 문장이 들어가면 TODO width가 content내용만큼 늘어나더라고요 ..?? 저는 이부분 |
||
|
||
const TaskContent = styled.ul` | ||
display: flex; | ||
flex-direction: column; | ||
gap: 20px; | ||
border: 3px solid var(--medium-pink); | ||
width: 100%; | ||
height: 100%; | ||
padding: 10px; | ||
overflow-y: scroll; | ||
list-style: none; | ||
`; | ||
|
||
const TaskContentItem = styled.div` | ||
display: flex; | ||
gap: 5px; | ||
`; | ||
|
||
const TaskBox = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
width: 100%; | ||
@media (max-width: 767px) { | ||
//모바일 | ||
|
||
height: 50%; | ||
} | ||
|
||
@media (min-width: 1200px) { | ||
// 데스크탑 일반 | ||
height: 50vh; | ||
} | ||
`; | ||
|
||
const SvgIcon = styled.img` | ||
cursor: pointer; | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { Font } from '../styles/font'; | ||
export default function TodayGoal() { | ||
return ( | ||
<Box> | ||
<Label fontSize={'var(--font-size-md)'} color={'var(--darken-pink)'}> | ||
TODAY GOAL | ||
</Label> | ||
<TextInput type="text" /> | ||
</Box> | ||
); | ||
} | ||
|
||
const Box = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: flex-start; | ||
align-content: center; | ||
background-color: var(--light-pink); | ||
width: 100%; | ||
height: 30%; | ||
padding: 10px; | ||
`; | ||
/* 상속 받아서 사용하기 */ | ||
const TextInput = styled.input` | ||
border: none; | ||
background: transparent; | ||
height: 100%; | ||
font-size: var(--font-size-md); | ||
`; | ||
Comment on lines
+26
to
+31
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. |
||
|
||
const Label = styled(Font)` | ||
font-weight: 500; | ||
letter-spacing: 3px; | ||
|
||
align-self: center; | ||
`; |
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.
저도 이렇게 사용했었는데
React
를 적어주지 않아도 되는 걸 이번 코드 리뷰 하면서 처음 알게 됐어요!!예린님 과제에서 문기님이 코드 리뷰 해주신 부분 참고하시면 도움 되실 것 같아요!!! 코드 리뷰