HyeonJun Jeon

[Implement] Header component, Calendar grid

......@@ -13,6 +13,7 @@
"@testing-library/user-event": "^13.5.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
......@@ -8061,6 +8062,14 @@
"he": "bin/he"
}
},
"node_modules/history": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
"dependencies": {
"@babel/runtime": "^7.7.6"
}
},
"node_modules/hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
......@@ -13462,6 +13471,30 @@
"node": ">=0.10.0"
}
},
"node_modules/react-router": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
"integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==",
"dependencies": {
"history": "^5.2.0"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/react-router-dom": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz",
"integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==",
"dependencies": {
"history": "^5.2.0",
"react-router": "6.3.0"
},
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
}
},
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
......@@ -21987,6 +22020,14 @@
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"history": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
"requires": {
"@babel/runtime": "^7.7.6"
}
},
"hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
......@@ -25751,6 +25792,23 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
},
"react-router": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
"integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==",
"requires": {
"history": "^5.2.0"
}
},
"react-router-dom": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz",
"integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==",
"requires": {
"history": "^5.2.0",
"react-router": "6.3.0"
}
},
"react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
......
......@@ -8,6 +8,7 @@
"@testing-library/user-event": "^13.5.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
......
......@@ -29,15 +29,5 @@
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
......
import "./styles/App.css";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Calendar from "./pages/Calendar";
import Home from "./pages/Home";
function App() {
return <div className="App"></div>;
return (
<BrowserRouter>
<div className="App">
<Routes>
<Route path="/calendar/*" element={<Calendar />} />
<Route exact path="/login" element={<></>} />
<Route exact path="/setting" element={<></>} />
<Route path="*" element={<Home />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
......
import "../styles/Grid.css";
import GridHead from "./GridHead.js";
import GridRow from "./GridRow.js";
import React from "react";
const Grid = () => {
const renderRows = () => {
const rows = [];
for (let i = 0; i < 5; i++) {
rows.push(<GridRow key={i} />);
}
return rows;
};
return (
<div className="Grid">
<GridHead />
{renderRows()}
</div>
);
};
export default Grid;
const GridHead = () => {
const days = ["일", "월", "화", "수", "목", "금", "토"];
const renderItems = () => {
const items = [];
for (let i = 0; i < 7; i++) {
items.push(
<div className="GridHeadItem" key={i}>
{days[i]}
</div>
);
}
return items;
};
return <div className="GridHead">{renderItems()}</div>;
};
export default GridHead;
const GridItem = () => {
return <div className="GridItem"></div>;
};
export default GridItem;
import GridItem from "./GridItem";
const GridRow = () => {
const renderItems = () => {
const items = [];
for (let i = 0; i < 7; i++) {
items.push(<GridItem key={i} />);
}
return items;
};
return <div className="GridRow">{renderItems()}</div>;
};
export default GridRow;
import { useContext } from "react";
import { CalendarStateContext } from "../pages/Calendar";
import "../styles/Header.css";
const Header = () => {
const [state, setState] = useContext(CalendarStateContext);
const handleChangeState = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
};
const gotoToday = () => {
const scope = state.scope;
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth() + 1;
const date = today.getDate();
setState({ scope, year, month, date });
};
const move = (e) => {
const scope = state.scope;
const current = new Date(state.year, state.month - 1, state.date);
switch (scope) {
case "month":
current.setMonth(current.getMonth() + Number(e.target.value));
break;
case "week":
current.setDate(current.getDate() + Number(e.target.value) * 7);
break;
case "day":
current.setDate(current.getDate() + Number(e.target.value));
break;
default:
}
const year = current.getFullYear();
const month = current.getMonth() + 1;
const date = current.getDate();
setState({ scope, year, month, date });
};
let headLabel;
switch (state.scope) {
case "month":
case "week":
headLabel = state.year + "년 " + state.month + "월";
break;
case "day":
headLabel = state.year + "년 " + state.month + "월 " + state.date + "일";
break;
default:
headLabel = "unexpected scope";
}
return (
<header>
<div className="hl">
<span className="hls">확장 캘린더</span>
</div>
<div className="hc">
<button className="hcb" onClick={gotoToday}>
오늘
</button>
<div className="hcd">
<button onClick={move} value={-1}>
{"ᐸ"}
</button>
<button onClick={move} value={+1}>
{"ᐳ"}
</button>
</div>
<span className="hcs">{headLabel}</span>
</div>
<div className="hr">
<div className="hrd">
<button
disabled={state.scope === "day"}
onClick={handleChangeState}
name="scope"
value="day"
>
</button>
<button
disabled={state.scope === "week"}
onClick={handleChangeState}
name="scope"
value="week"
>
</button>
<button
disabled={state.scope === "month"}
onClick={handleChangeState}
name="scope"
value="month"
>
</button>
</div>
</div>
</header>
);
};
export default Header;
File mode changed
import React, { useState } from "react";
import { Route, Routes } from "react-router-dom";
import Grid from "../components/Grid";
import Header from "../components/Header";
import "../styles/Home.css";
export const CalendarStateContext = React.createContext();
const Calendar = () => {
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth() + 1;
const date = today.getDate();
//const day = today.getDay();
//scope는 day, state는 date
const [state, setState] = useState({
scope: "month",
year: year,
month: month,
date: date,
});
return (
<CalendarStateContext.Provider value={[state, setState]}>
<div className="Calendar">
<Header />
<Routes>
<Route path="/month/*" element={<Grid />} />
<Route path="/week/*" element={<></>} />
<Route path="/day/*" element={<></>} />
</Routes>
</div>
</CalendarStateContext.Provider>
);
};
export default Calendar;
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
const Home = () => {
const navigate = useNavigate();
useEffect(() => navigate("/calendar/month"), [navigate]);
};
export default Home;
h1,
h2 {
margin: 0;
}
......
.GridItem,
.GridHeadItem {
border-style: solid;
border-width: thin;
height: 150px;
flex-basis: 100px;
flex-grow: 1;
}
.GridHeadItem {
height: 30px;
text-align: center;
line-height: 30px;
padding: 10px 5px 10px 5px;
}
.GridRow,
.GridHead {
display: flex;
}
.Grid {
display: flex;
flex-direction: column;
}
header {
background-color: rgba(255, 255, 255, 1);
display: flex;
padding: 8px;
justify-content: space-between;
align-items: center;
}
.hl {
padding-right: 50px;
}
.hls {
padding-left: 8px;
font-size: x-large;
}
.hc {
height: 48px;
align-items: center;
display: flex;
justify-content: left;
flex-grow: 1;
}
.hcb {
height: 34px;
margin: 10px;
}
.hcd {
margin: 10px;
}
.hcd > button {
font-size: large;
}
.hcs {
font-size: x-large;
margin: 10px;
}
.hrd > button {
padding: 8px 14px 8px 14px;
font-size: medium;
}
File mode changed