Skip to content
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주차] 김문기 미션 제출합니다. #4

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 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
Binary file added .DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules

.env
302 changes: 295 additions & 7 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"recoil": "^0.7.7",
"styled-components": "^5.3.9",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
Binary file added public/Link.cur
Binary file not shown.
Binary file added public/Text.cur
Binary file not shown.
Binary file modified public/favicon.ico
Binary file not shown.
Binary file added public/icon_100.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/icon_100.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
Expand All @@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>MY_TODO</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
Binary file removed public/logo192.png
Binary file not shown.
Binary file removed public/logo512.png
Binary file not shown.
14 changes: 2 additions & 12 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "MY_TODO",
"name": "Simple Todo Planner",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
Expand Down
Binary file added src/.DS_Store
Binary file not shown.
39 changes: 34 additions & 5 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
import { useEffect, useState } from "react";
import Mainpage from "./pages/Mainpage/Mainpage";

function App() {
return (
<div>
<h1>17기 프론트 화이팅~ 우하하</h1>
</div>
const [clickedIcon, setClickedIcon] = useState("");
const [mainIconPosition, setMainIconPosition] = useState(
JSON.parse(localStorage.getItem("mainIconPosition")) ?? {
top: 30,
left: 30,
}
);
const [textIconPosition, setTextIconPosition] = useState(
JSON.parse(localStorage.getItem("textIconPosition")) ?? {
top: 160,
left: 30,
}
);
Comment on lines +6 to 17
Copy link
Member

Choose a reason for hiding this comment

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

그동안 style에 대한 값은 state로 지정해본 적이 없었는데 좋은 방법인 것 같아요! 배워갑니다. ㅎㅎ


useEffect(() => {
if (!localStorage.getItem("mainIconPosition")) {
localStorage.setItem(
"mainIconPosition",
JSON.stringify(mainIconPosition)
);
}
if (!localStorage.getItem("textIconPosition")) {
localStorage.setItem(
"textIconPosition",
JSON.stringify(textIconPosition)
);
}
}, [mainIconPosition, textIconPosition]);

useEffect(() => {});
return <Mainpage clickedIcon={clickedIcon} setClickedIcon={setClickedIcon} />;
}

export default App;
export default App;
Binary file added src/assets/.DS_Store
Binary file not shown.
Binary file added src/assets/Link.cur
Binary file not shown.
Binary file added src/assets/Normal.cur
Binary file not shown.
Binary file added src/assets/background_image.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icon_main.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icon_text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions src/components/card/Card.element.js
Copy link
Member

Choose a reason for hiding this comment

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

styled-components를 선언하는 파일과 사용하는 파일을 분리해서 사용하시네요! 이렇게 사용하는 게 더 가독성이나 유지보수에 편리하겠군용... 👀 배워갑니당

Copy link
Member

Choose a reason for hiding this comment

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

저도 styled-components 사용 시 코드가 위아래로 길어지는 게 너무 불편했는데 파일 분리 배워갑니다. ㅎㅎ

Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import styled from "styled-components";

export const CardContainer = styled.div`
width: ${(props) => (props.display ? "max(300px, 30vw)" : "0")};
height: ${(props) => (props.display ? "max(500px, 50vw)" : "0")};
position: ${(props) => (props.display ? "initial" : "fixed")};
top: ${(props) => props.position.top};
left: ${(props) => props.position.left};
Comment on lines +4 to +8
Copy link
Member

Choose a reason for hiding this comment

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

props를 이용한 효율적인 코드 좋네요!

Copy link
Member

Choose a reason for hiding this comment

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

문기님 styled-components 에서 props 활용을 잘 하시는 것 같아요!! 저도 다음 과제에 적용해보고 싶습니다 👍

margin: 0 auto;
background-color: #1e1e1e;
border-radius: 12px;
z-index: 2;
visibility: ${(props) => (props.display ? "visible" : "hidden")};
box-shadow: 0 0 10px 0px #000000;
transition: width 0.2s, height 0.2s, visibility 0.05s linear 0.15s;
Copy link
Member

Choose a reason for hiding this comment

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

transition 까지.. 쩌는 디테일

Copy link
Member Author

Choose a reason for hiding this comment

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

옆에 맥 켜놓고 최대한 비슷하게 만드려고 노력했습니다 ㅎㅎ

Copy link
Member

Choose a reason for hiding this comment

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

우와........ 진짜 감탄만.........

`;

export const CardToolBar = styled.div`
display: flex;
align-items: center;
height: 40px;
padding: 12px;
background-color: #312f34;
border-radius: 12px 12px 0 0;
box-sizing: border-box;
position: relative;
visibility: ${(props) => (props.display ? "visible" : "hidden")};
`;

export const CardPlusBtn = styled.div`
width: 20px;
height: 20px;
color: white;
display: flex;
justify-content: center;
font-size: 24px;
border-radius: 4px;
position: absolute;
right: 12px;
padding: 2px;
&:hover {
background-color: #656565;
cursor: url(Link.cur) 0 0, pointer;
/* cursor: url(../../assets/Link.cur) 0 0, pointer; */
}
Comment on lines +41 to +45
Copy link
Member

Choose a reason for hiding this comment

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

와 이런 디테일!

&::before {
content: "+";
}
`;

export const NotHoverDiv = styled.div`
opacity: ${(props) => (props.hoverRender ? 0 : 1)};
display: ${(props) => (props.render ? "flex" : "none")};
flex-direction: column;
height: 100%;
transition: opacity 0.1s;
`;

export const CardMainDiv = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: calc(100% - 40px);
border-radius: 0 0 12px 12px;
position: relative;
`;

export const CardTodoText = styled.h1`
color: white;
font-weight: 800;
font-size: 20px;
display: flex;
width: 100%;
text-align: left;
box-sizing: border-box;
padding: 8px 0 0 12px;
margin-bottom: 8px;
`;

export const CardTodoDiv = styled.div`
display: flex;
flex-wrap: wrap;
height: 100%;
flex-direction: row;
justify-content: center;
overflow-y: auto;
position: relative;
align-content: flex-start;
overflow-x: hidden;
width: 100%;
`;
95 changes: 95 additions & 0 deletions src/components/card/Card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useEffect, useState } from "react";
import CircleBtn from "../circleBtn/CircleBtn";

import HoverDiv from "../hoverDiv/HoverDiv";
import Todo from "../todo/Todo";
import {
CardContainer,
CardToolBar,
CardPlusBtn,
CardMainDiv,
CardTodoDiv,
CardTodoText,
NotHoverDiv,
} from "./Card.element";

const Card = ({ render, setRender }) => {
useEffect(() => {
setHoverDivRender(false);
}, [render]);
const [hoverDivRender, setHoverDivRender] = useState(false);

const [allList, setAllList] = useState([]);
const todoList = allList ? allList.filter((item) => item.done === false) : [];
const doneList = allList ? allList.filter((item) => item.done === true) : [];

useEffect(() => {
setAllList(JSON.parse(localStorage.getItem("todoList")) || []);
}, [hoverDivRender]);
return (
<CardContainer
display={render}
position={{
top: "50px",
left: "50px",
}}
>
<CardToolBar display={render}>
<CircleBtn
color="red"
type="button"
render={render}
setRender={setRender}
/>
<CircleBtn color="yellow" type="button" />
<CircleBtn color="green" type="button" />
<CardPlusBtn onClick={() => setHoverDivRender(!hoverDivRender)} />
</CardToolBar>
<CardMainDiv>
<HoverDiv
hoverDivRender={hoverDivRender && render}
setHoverDivRender={setHoverDivRender}
/>
<NotHoverDiv render={render} hoverRender={hoverDivRender}>
<CardTodoText>TODO [{todoList.length}개]</CardTodoText>
<CardTodoDiv>
{todoList.length > 0 &&
todoList.map((item) => {
return (
<Todo
key={item.id}
id={item.id}
content={item.content}
tag={item.tag}
done={item.done}
setAllList={setAllList}
allList={allList}
/>
);
})}
{todoList.length === 0 && <Todo tag={-1} />}
</CardTodoDiv>
<CardTodoText>DONE [{doneList.length}개]</CardTodoText>
<CardTodoDiv>
{doneList.length > 0 &&
doneList.map((item) => {
return (
<Todo
key={item.id}
id={item.id}
content={item.content}
tag={item.tag}
done={item.done}
setAllList={setAllList}
/>
);
})}
{doneList.length === 0 && <Todo tag={-2} />}
</CardTodoDiv>
</NotHoverDiv>
</CardMainDiv>
</CardContainer>
);
};

export default Card;
33 changes: 33 additions & 0 deletions src/components/circleBtn/CircleBtn.element.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import styled from "styled-components";

export const CardCircle = styled.div`
display: inline-block;
margin: 0 4px;
align-items: center;
width: 10px;
height: 10px;
padding: 1px;
border-radius: 50%;
background-color: ${(props) => `var(--${props.color}-${props.type})`};
&:hover {
cursor: url(Link.cur) 0 0, pointer;
}
`;

export const InputCircle = styled.input`
appearance: none;
display: inline-block;
margin: 0 4px;
align-items: center;
width: max(12px, 1.2vw);
height: max(12px, 1.2vw);
padding: 1px;
border-radius: 50%;
background-color: ${(props) => `var(--${props.color}-${props._type})`};
&:hover {
cursor: url(Link.cur) 0 0, pointer;
}
border: ${(props) =>
props.selectedTag === props.value ? "1px solid white" : "none"};
transition: border 0.3s ease-in-out;
`;
39 changes: 39 additions & 0 deletions src/components/circleBtn/CircleBtn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { CardCircle, InputCircle } from "./CircleBtn.element";

const CircleBtn = ({
color,
type,
render,
setRender,
name,
value,
selectedTag,
handleTagChange,
}) => {
if (type === "tag") {
// using type as _type since 'type' is reserved word in input
return (
<InputCircle
type="radio"
color={color}
_type={type}
name={name}
value={value}
selectedTag={selectedTag}
onClick={handleTagChange}
/>
);
} else if (color === "red" && type === "button") {
return (
<CardCircle
color={color}
type={type}
onClick={() => setRender(!render)}
/>
);
} else {
return <CardCircle color={color} type={type} />;
}
};

export default CircleBtn;
Loading