-
Notifications
You must be signed in to change notification settings - Fork 13
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
[3주차] 정대헌 미션 제출합니다. #21
base: master
Are you sure you want to change the base?
Changes from all commits
84b702d
97c1885
e34cea1
8873d43
4750dae
e99b667
0775348
4148872
d379344
6c4147b
b967efe
3e1d890
621b438
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import React from "react"; | ||
|
||
import { GlobalProvider } from "./context/GlobalContext"; | ||
import InputContainer from "./containers/InputContainer"; | ||
import ListItemContainer from "./containers/ListItemContainer"; | ||
import GlobalStyle from "./GlobalStyles"; | ||
import { ItemType } from "./Objects"; | ||
|
||
function App() { | ||
return ( | ||
<GlobalProvider> | ||
<GlobalStyle /> | ||
<div className="background"> | ||
<div className="container"> | ||
<InputContainer /> | ||
<ListItemContainer title={"해야할 일"} listType={ItemType.Todo} /> | ||
<ListItemContainer title={"완료한 일"} listType={ItemType.Done} /> | ||
</div> | ||
</div> | ||
</GlobalProvider> | ||
); | ||
} | ||
|
||
export default App; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { createGlobalStyle } from "styled-components"; | ||
|
||
export default createGlobalStyle` | ||
/* fonts */ | ||
|
||
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+KR&display=swap"); | ||
|
||
:root { | ||
--ff-main: "Noto Sans KR", sans-serif; | ||
} | ||
|
||
/* global attributes */ | ||
|
||
*, | ||
::after, | ||
::before { | ||
margin: 0; | ||
padding: 0; | ||
box-sizing: border-box; | ||
} | ||
|
||
/* tags */ | ||
|
||
p { | ||
line-height: 1.5; | ||
font-size: 1rem; | ||
display: inline; | ||
} | ||
|
||
/* classes */ | ||
|
||
.background { | ||
min-height: 100vh; | ||
display: grid; | ||
place-items: center; | ||
background-color: #fa8bff; | ||
background-image: linear-gradient(120deg, #fccb90 0%, #d57eeb 100%); | ||
font-family: var(--ff-main); | ||
color: white; | ||
} | ||
.container { | ||
display: flex; | ||
justify-content: center; | ||
flex-direction: column; | ||
align-items: center; | ||
border-radius: 2rem; | ||
border-color: black; | ||
padding: 1rem; | ||
background-color: rgba(255, 255, 255, 0.3); | ||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); | ||
min-width: 30rem; | ||
} | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
export type Item = { | ||
id: string, | ||
type?: ItemType, | ||
content?: string, | ||
} | ||
|
||
export enum ItemType {Todo, Done} | ||
|
||
export type Action = {type: ActionType, payload: Item} | ||
|
||
export enum ActionType {DELETE, ADD, MODIFY } | ||
|
||
export type State = Item[] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import React, { useContext } from "react"; | ||
import { FaTrash } from "react-icons/fa"; | ||
import styled from "styled-components"; | ||
|
||
import { DispatchContext} from "../context/GlobalContext"; | ||
import { Item, ActionType, ItemType } from "../Objects"; | ||
|
||
const ItemDiv = styled.div` | ||
display: flex; | ||
width: "100%"; | ||
justify-content: space-between; | ||
align-items: center; | ||
margin-bottom: 1rem; | ||
border-radius: 2rem; | ||
background-color: white; | ||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); | ||
padding: 0.75rem; | ||
&:hover { | ||
box-shadow: 0 0 10px rgba(255, 255, 255, 0.6); | ||
} | ||
`; | ||
|
||
const ItemScrollDiv = styled.div` | ||
width: 23rem; | ||
display: flex; | ||
align-items: center; | ||
`; | ||
|
||
const ItemTitle = styled.div` | ||
margin-left: 0.5rem; | ||
margin-right: 0.5rem; | ||
font-family: var(--ff-main); | ||
line-height: 1.5; | ||
text-align: left; | ||
word-wrap: break-word; | ||
word-break: break-all; | ||
text-align-last: left; | ||
font-size: 1rem; | ||
display: inline; | ||
line-height: 1.5; | ||
`; | ||
|
||
const ItemFinishButton = styled.button` | ||
background-color: transparent; | ||
border-color: transparent; | ||
cursor: pointer; | ||
border-radius: 1.3rem; | ||
&:hover { | ||
background-color: lightgray; | ||
} | ||
`; | ||
|
||
const ItemDeleteButton = styled.button` | ||
width: 2rem; | ||
height: 2rem; | ||
border-color: transparent; | ||
background-color: transparent; | ||
border-radius: 10rem; | ||
margin-right: 0.2rem; | ||
padding: 0 0.2rem 0 0.2rem; | ||
cursor: pointer; | ||
&:hover { | ||
background-color: lightgray; | ||
} | ||
`; | ||
const DeleteIcon = styled.p` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
size: 1.5rem; | ||
color: gray; | ||
`; | ||
|
||
const ListItem = ({ item }: {item: Item}) => { | ||
const dispatch = useContext(DispatchContext); | ||
Comment on lines
+74
to
+75
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.
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. 말씀하신 대로 수정해보았는데, prop를 2개를 받고 있어서 오류가 나는 것 같아요! |
||
|
||
const moveItem = (uid: string) => { | ||
dispatch({ | ||
type: ActionType.MODIFY, | ||
payload: { | ||
id: uid, | ||
}, | ||
}); | ||
}; | ||
|
||
const deleteItem = (uid: string) => { | ||
dispatch({ | ||
type: ActionType.DELETE, | ||
payload: { | ||
id: uid, | ||
}, | ||
}); | ||
}; | ||
|
||
return ( | ||
<ItemDiv> | ||
<ItemScrollDiv> | ||
<ItemFinishButton | ||
type="button" | ||
onClick={() => { | ||
moveItem(item.id); | ||
}} | ||
> | ||
<ItemTitle> | ||
{/* listType의 done/todo에 따라 del 태그 삽입 */} | ||
{item.type === ItemType.Done ? <del>{item.content}</del> : item.content} | ||
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. 태그로 감싸는것도 새로운 방법이네요. 하지만 실제로는 css로 처리하는게 렌더링 성능에서 더 유리하다고 합니다! 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. 조언 감사합니다~ 저는 오히려 css로 처리하는 방법을 생각하지 못했네요, 참고하겠습니다. |
||
</ItemTitle> | ||
</ItemFinishButton> | ||
</ItemScrollDiv> | ||
<ItemDeleteButton | ||
type="button" | ||
onClick={() => { | ||
deleteItem(item.id); | ||
}} | ||
> | ||
<DeleteIcon> | ||
<FaTrash /> | ||
</DeleteIcon> | ||
</ItemDeleteButton> | ||
</ItemDiv> | ||
); | ||
}; | ||
|
||
export default ListItem; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import React, { useState, useContext } from "react"; | ||
import styled from "styled-components"; | ||
|
||
import { DispatchContext } from "../context/GlobalContext"; | ||
import { ActionType, ItemType } from "../Objects"; | ||
|
||
const AppInput = styled.div` | ||
width: 28rem; | ||
margin-bottom: 1rem; | ||
`; | ||
|
||
const FormControl = styled.form` | ||
display: flex; | ||
justify-content: space-between; | ||
width: 100%; | ||
`; | ||
|
||
const FormInput = styled.input` | ||
width: 23rem; | ||
padding: 0.75rem; | ||
font-size: 1rem; | ||
border-radius: 2rem; | ||
border-color: transparent; | ||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); | ||
padding-left: 1.2rem; | ||
font-family: var(--ff-main); | ||
outline: none; | ||
&:hover { | ||
box-shadow: 0 0 10px rgba(255, 255, 255, 0.6); | ||
} | ||
Comment on lines
+28
to
+30
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. 역시 디테일 최고네요 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 AppTitle = styled.div` | ||
font-size: 1.7rem; | ||
display: flex; | ||
text-align: center; | ||
justify-content: center; | ||
margin: 1.5rem 0; | ||
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); | ||
`; | ||
|
||
const SubmitBtn = styled.button` | ||
display: flex; | ||
align-items: center; | ||
background-color: white; | ||
border-color: transparent; | ||
color: grey; | ||
padding: 0.25rem; | ||
cursor: pointer; | ||
border-radius: 2rem; | ||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); | ||
&:hover { | ||
background-color: rgba(0, 0, 0, 0.3); | ||
color: white; | ||
} | ||
& p { | ||
font-size: 2rem; | ||
width: 3rem; | ||
} | ||
`; | ||
|
||
const InputContainer = () => { | ||
const [text, setText] = useState(""); | ||
const dispatch = useContext(DispatchContext); | ||
|
||
const addItem = (uid:string, itemType: ItemType, itemContent: string) => { | ||
dispatch({ | ||
type: ActionType.ADD, | ||
payload: { id: uid, type: itemType, content: itemContent }, | ||
}); | ||
}; | ||
|
||
Comment on lines
+66
to
+72
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. 리덕스 적용하신 것까지 멋있어요 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 submitHandler = (e:React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
if (text !== "") { | ||
const uid = new Date().getTime().toString(); | ||
addItem(uid, ItemType.Todo, text); | ||
setText(""); | ||
} | ||
}; | ||
|
||
return ( | ||
<AppInput> | ||
<AppTitle> | ||
<h3>투두 투두</h3> | ||
</AppTitle> | ||
<FormControl onSubmit={(e) => submitHandler(e)}> | ||
<FormInput | ||
type="text" | ||
id="todoItem" | ||
placeholder="오늘은 행복하길 바래" | ||
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. 깨알 감동 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. 하하 알아봐주시다니🙊💗 |
||
onChange={(e) => setText(e.target.value)} | ||
value={text} | ||
/> | ||
<SubmitBtn type="submit"> | ||
<p>+</p> | ||
</SubmitBtn> | ||
</FormControl> | ||
</AppInput> | ||
); | ||
}; | ||
|
||
export default InputContainer; |
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.
구조가 깔끔해서 보기 좋네요
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.
감사합니다 :)