-
Notifications
You must be signed in to change notification settings - Fork 10
[2주차] 정인영 미션 제출합니다. #11
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
0b5d67d
24cdd48
a7e893b
037a8a3
1d2e02f
8efadb4
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 |
|---|---|---|
| @@ -1,9 +1,19 @@ | ||
| import { GlobalStyle } from "./style/GlobalStyle"; | ||
| import Template from "./components/template/Template"; | ||
| import Background from "./components/organism/Background"; | ||
| import { RecoilRoot } from "recoil"; | ||
|
|
||
| function App() { | ||
| return ( | ||
| <div> | ||
| <h1>18기 프론트 화이팅~ 푸하항ㅋ</h1> | ||
| </div> | ||
| ); | ||
| return ( | ||
| <RecoilRoot> | ||
| <GlobalStyle /> | ||
| <> | ||
| {/* three.js 을 사용한 우주 배경 */} | ||
| <Background /> | ||
| <Template /> | ||
| </> | ||
| </RecoilRoot> | ||
| ); | ||
| } | ||
|
|
||
| export default App; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { styled } from "styled-components"; | ||
|
|
||
| export const Button = styled.div` | ||
| display: flex; | ||
| width: 67px; | ||
| height: 27px; | ||
| align-items: center; | ||
| justify-content: center; | ||
| background-color: var(--lightGray); | ||
| border: 2px solid var(--black); | ||
| border-radius: 10px; | ||
| font-weight: 600; | ||
| font-size: 13px; | ||
|
Comment on lines
+3
to
+13
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. px 단위의 작업도 좋지만 모바일에서의 사용성도 고려하여 media-query 와 rem 작업 단위로 작업하는 것을 습관화 하시면 좋을 거 같습니다 ㅎㅎ |
||
| `; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import { styled } from "styled-components"; | ||
| export const H1 = styled.h1` | ||
| font-size: 24px; | ||
| color: ${(props) => props.color || "var(--white)"}; | ||
| `; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import { styled } from "styled-components"; | ||
|
|
||
| export const ImageButton = styled.img` | ||
| height: 70%; | ||
| `; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { styled } from "styled-components"; | ||
|
|
||
| export const Input = styled.input` | ||
| width: 70%; | ||
| background-color: var(--white); | ||
| font-size: 12px; | ||
| border: none; | ||
| outline: none; | ||
| `; | ||
|
rmdnps10 marked this conversation as resolved.
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import { styled } from "styled-components"; | ||
| export const Span = styled.div` | ||
| font-size: 15px; | ||
| padding: 5px; | ||
| color: ${(props) => props.color || "var(--white)"}; | ||
| `; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import React from "react"; | ||
| import { styled } from "styled-components"; | ||
| import { ImageButton } from "../atoms/ImageButton"; | ||
| import { Button } from "../atoms/Button"; | ||
| import { Input } from "../atoms/Input"; | ||
| import logo from "../../image/galaxy-icon.svg"; | ||
| import { useRecoilState } from "recoil"; | ||
|
rmdnps10 marked this conversation as resolved.
|
||
| import { nowTodoList } from "../../recoil/atom.ts"; | ||
| import useInput from "../../hooks/useTextInput"; | ||
|
|
||
| function TextInput() { | ||
| const { input, handleChange, handleKeyPress, setInput } = useInput(""); // 키 입력 할 때를 따로 커스텀 훅으로 분리함 | ||
| const [nowTodo, setNowTodoList] = useRecoilState(nowTodoList); | ||
|
|
||
| const buttonClick = () => { | ||
| if (input.length < 5 || input.length > 30) { | ||
| alert("할 일은 5자 이상 30자 이하로 작성해주세요."); | ||
| return; | ||
| } | ||
| setNowTodoList([...nowTodo, input]); | ||
| setInput(""); | ||
| }; | ||
|
|
||
| return ( | ||
| <StyledInput> | ||
| <ImageButton src={logo} alt="로고" /> | ||
| <Input | ||
| type="text" | ||
| placeholder="화면 중앙을 드래그하거나 포커스 한 후 마우스 휠을 움직여보세요." | ||
| value={input} | ||
| onChange={handleChange} | ||
| onKeyPress={(e) => handleKeyPress(e, buttonClick)} | ||
| /> | ||
| <Button onClick={buttonClick}>Submit</Button> | ||
|
rmdnps10 marked this conversation as resolved.
|
||
| </StyledInput> | ||
| ); | ||
| } | ||
|
|
||
| const StyledInput = styled.div` | ||
| display: flex; | ||
| gap: 20px; | ||
| align-items: center; | ||
| justify-content: center; | ||
| height: 45px; | ||
| width: 45%; | ||
| border-radius: 20px; | ||
| background-color: var(--white); | ||
| `; | ||
|
|
||
| export default TextInput; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| import React from "react"; | ||
| import { Span } from "../atoms/Span"; | ||
| import { styled } from "styled-components"; | ||
| import { ImageButton } from "../atoms/ImageButton"; | ||
| import deleteButton from "../../image/delete.png"; | ||
| import backButton from "../../image/restore.png"; | ||
| import { useRecoilState } from "recoil"; | ||
| import { nowTodoList, solvedTodoList } from "../../recoil/atom.ts"; | ||
| function ToDoItem({ todo, isSolved }) { | ||
| const [nowTodo, setNowTodo] = useRecoilState(nowTodoList); | ||
| const [solvedTodo, setSolvedTodo] = useRecoilState(solvedTodoList); | ||
| const deleteButtonClick = () => { | ||
| const newSolvedList = solvedTodo.filter((item) => item !== todo); | ||
| setSolvedTodo(newSolvedList); | ||
| }; | ||
| const backButtonClick = () => { | ||
| const newSolvedList = solvedTodo.filter((item) => item !== todo); | ||
| setSolvedTodo(newSolvedList); | ||
| setNowTodo([...nowTodo, todo]); | ||
| }; | ||
| const clickNowToDo = (e) => { | ||
| // SolvedToDo 아이템 클릭했을 경우, 아무 일도 발생하지 않기하기 | ||
| if (isSolved) { | ||
| return; | ||
| } else { | ||
| const targetTodo = e.target.innerText; | ||
| const newNowTodoList = nowTodo.filter((item) => item !== targetTodo); | ||
| setNowTodo(newNowTodoList); | ||
| setSolvedTodo([...solvedTodo, targetTodo]); | ||
| } | ||
|
rmdnps10 marked this conversation as resolved.
|
||
| }; | ||
|
Comment on lines
+12
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. 지극히 제 개인적인 의견입니다만, todo를 삭제하거나 옮기는 과정에서 filter 를 사용하면 현재 있는 todo를 전부 탐색하여 비교하는 과정을 거쳐야하므로 todo가 많이 생긴다면 살짝 비효율적인 면이 있지 않을까 생각합니다. 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. 오 좋은 방법 같아요 저도 배워갑니당
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. todo 가 많이 생긴다면 분명히 splice 함수로 처리하는 게 좋은 방법일 것 같네요... 감사합니다! |
||
| return ( | ||
| <> | ||
| <StyledItem isSolved={isSolved}> | ||
| <Span onClick={clickNowToDo}>{todo}</Span> | ||
|
|
||
| {isSolved ? ( | ||
| <ButtonWrapper> | ||
| <ImageButton src={deleteButton} onClick={deleteButtonClick} /> | ||
| <ImageButton src={backButton} onClick={backButtonClick} /> | ||
| </ButtonWrapper> | ||
| ) : ( | ||
| "" | ||
| )} | ||
|
rmdnps10 marked this conversation as resolved.
|
||
| </StyledItem> | ||
| </> | ||
| ); | ||
| } | ||
|
|
||
| const StyledItem = styled.div` | ||
| display: flex; | ||
| justify-content: center; | ||
| gap: 20px; | ||
| align-items: center; | ||
| border-radius: 20px; | ||
| padding: 20px 14px; | ||
| height: 45px; | ||
| background: var(--gradient); | ||
| cursor: pointer; | ||
| transition: 1s; | ||
| // 그림자 잘리는 것 방지를 위한 margin 설정 | ||
| margin: 10px; | ||
| ${(props) => | ||
| props.isSolved | ||
| ? "" | ||
| : ` | ||
| box-shadow: 0px 0px 20px white; | ||
| &:hover { | ||
| background: yellow; | ||
| > ${Span} { | ||
| color: black; /* 호버 시 Span의 텍스트 색상을 검은색으로 변경 */ | ||
| } | ||
| }`} | ||
| `; | ||
| const ButtonWrapper = styled.div` | ||
| display: flex; | ||
| align-items: center; | ||
| height: 40px; | ||
| `; | ||
|
|
||
| export default ToDoItem; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import { Canvas } from "@react-three/fiber"; | ||
| import { OrbitControls, Stars } from "@react-three/drei"; | ||
|
rmdnps10 marked this conversation as resolved.
|
||
|
|
||
| export default function Background() { | ||
| return ( | ||
| <div | ||
| style={{ | ||
| width: "100%", | ||
| height: "100vh", | ||
| position: "absolute", | ||
| top: "0px", | ||
| zIndex: "-999", | ||
| }} | ||
| > | ||
| {/* three.js 라이브러리에서 가져온 컴포넌트 */} | ||
| <Canvas resize={{ polyfill: false }}> | ||
| <OrbitControls /> | ||
| <Stars /> | ||
| <ambientLight intensity={0.5} /> | ||
| <spotLight position={[10, 15, 10]} angle={0.3} /> | ||
| </Canvas> | ||
| </div> | ||
| ); | ||
| } | ||
|
rmdnps10 marked this conversation as resolved.
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import React, { useEffect, useRef } from "react"; | ||
| import { styled } from "styled-components"; | ||
| import TextInput from "../molecules/TextInput"; | ||
| import { Span } from "../atoms/Span"; | ||
|
|
||
| function Header({}) { | ||
|
rmdnps10 marked this conversation as resolved.
|
||
| return ( | ||
| <StyledHeader> | ||
| <TextInput /> | ||
| <Span>"Carl Seagan - 소멸은 법칙이다."</Span> | ||
| </StyledHeader> | ||
| ); | ||
| } | ||
|
|
||
| const StyledHeader = styled.header` | ||
| display: flex; | ||
| height: 250px; | ||
| align-items: center; | ||
| justify-content: center; | ||
| flex-direction: column; | ||
| gap: 26px; | ||
| `; | ||
|
|
||
| export default Header; | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,48 @@ | ||||||||||||||||||||||||||||||
| import React from "react"; | ||||||||||||||||||||||||||||||
| import { H1 } from "../atoms/H1"; | ||||||||||||||||||||||||||||||
| import { Span } from "../atoms/Span"; | ||||||||||||||||||||||||||||||
| import ToDoItem from "../molecules/ToDoItem"; | ||||||||||||||||||||||||||||||
| import { styled } from "styled-components"; | ||||||||||||||||||||||||||||||
| import { useRecoilValue, useRecoilState } from "recoil"; | ||||||||||||||||||||||||||||||
| import { nowTodoList, solvedTodoList } from "../../recoil/atom.ts"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| function NowTodo() { | ||||||||||||||||||||||||||||||
| const nowTodo = useRecoilValue(nowTodoList); | ||||||||||||||||||||||||||||||
| const [solvedToDo, setSolvedTodo] = useRecoilState(solvedTodoList); | ||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||
| <StyledNowTodo> | ||||||||||||||||||||||||||||||
| <H1>✔ 지금 당장 해결하세요.</H1> | ||||||||||||||||||||||||||||||
| <Span color="var(--lightWhite)"> | ||||||||||||||||||||||||||||||
| 총 {nowTodo.length} 개의 할 일이 있어요. | ||||||||||||||||||||||||||||||
| </Span> | ||||||||||||||||||||||||||||||
| <StyledList> | ||||||||||||||||||||||||||||||
| {nowTodo.map((todo, idx) => ( | ||||||||||||||||||||||||||||||
| <ToDoItem | ||||||||||||||||||||||||||||||
| isSolved={false} | ||||||||||||||||||||||||||||||
| todo={todo} | ||||||||||||||||||||||||||||||
| setSolvedTodo={setSolvedTodo} | ||||||||||||||||||||||||||||||
| key={idx} | ||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||
|
Comment on lines
+19
to
+25
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. map 함수 사용 시 key 를 index 로 설정하는 것은 권장하지 않는다고 합니다.
Suggested change
|
||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||
| </StyledList> | ||||||||||||||||||||||||||||||
| </StyledNowTodo> | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // SolvedTodo.js에서 사용하기 위함 | ||||||||||||||||||||||||||||||
| export const StyledList = styled.div` | ||||||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||||||
| margin-top: 20px; | ||||||||||||||||||||||||||||||
| overflow: scroll; | ||||||||||||||||||||||||||||||
| flex-direction: column; | ||||||||||||||||||||||||||||||
| align-items: start; | ||||||||||||||||||||||||||||||
| gap: 15px; | ||||||||||||||||||||||||||||||
| height: 500px; | ||||||||||||||||||||||||||||||
| `; | ||||||||||||||||||||||||||||||
|
Comment on lines
+33
to
+41
Collaborator
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. 이렇게 export하는 것보단 따로 component를 만들고 NowTodo, SolvedTodo에서 사용하는건 어떨까요 ?? |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const StyledNowTodo = styled.div` | ||||||||||||||||||||||||||||||
| position: absolute; | ||||||||||||||||||||||||||||||
| top: 170px; | ||||||||||||||||||||||||||||||
| left: 50px; | ||||||||||||||||||||||||||||||
| `; | ||||||||||||||||||||||||||||||
| export default NowTodo; | ||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.