diff --git a/package-lock.json b/package-lock.json index 0587ad123a5ab693e30a8168764441543924f147..d9e2f700f0999bf6cc4313a56b7fb75f079efc4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,10 +11,13 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.28.0", "react-scripts": "5.0.1", + "tailwind-merge": "^2.5.4", "web-vitals": "^2.1.4", "workbox-background-sync": "^6.6.0", "workbox-broadcast-update": "^6.6.0", @@ -5425,6 +5428,25 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==" }, + "node_modules/class-variance-authority": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", + "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", + "dependencies": { + "clsx": "2.0.0" + }, + "funding": { + "url": "https://joebell.co.uk" + } + }, + "node_modules/class-variance-authority/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", @@ -5454,6 +5476,14 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -14799,6 +14829,15 @@ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, + "node_modules/tailwind-merge": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.4.tgz", + "integrity": "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "3.4.15", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz", diff --git a/package.json b/package.json index fa49f4d88adbf18e752078d781b84039c3cf030e..032f68fa9ef89e510c9866671e6153657088fa8c 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,13 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.28.0", "react-scripts": "5.0.1", + "tailwind-merge": "^2.5.4", "web-vitals": "^2.1.4", "workbox-background-sync": "^6.6.0", "workbox-broadcast-update": "^6.6.0", diff --git a/src/App.js b/src/App.js index b6a8f89f5d9794f96f3e21c1f7e1e231e506a18f..689e5d3f3195325f0db5445bac6ddb09b0dd5817 100644 --- a/src/App.js +++ b/src/App.js @@ -7,19 +7,28 @@ import HomePage from "./pages/HomePage"; import TimeTablePage from "./pages/TimeTablePage"; import ChattingListPage from "./pages/Chatting/ChattingListPage"; import MyPage from "./pages/Mypage"; +import HeaderNav from "./components/layout/HeaderNav"; +import Footer from "./components/layout/Footer"; +import BodyLayout from "./components/layout/BodyLayout"; +import HeaderLogoBar from "./components/layout/HeaderLogoBar"; const App = () => { return ( <Router> <div className="min-h-screen bg-gray-100"> - <Routes className> - <Route path="/" element={<HomePage />} /> - <Route path="/timetable" element={<TimeTablePage />} /> - <Route path="/chattinglist" element={<ChattingListPage />} /> - <Route path="/mypage" element={<MyPage />} /> - <Route path="/login" element={<LoginPage />} /> - <Route path="/signup" element={<SignupPage />} /> - </Routes> + <HeaderLogoBar /> + <HeaderNav /> + <BodyLayout> + <Routes> + <Route path="/" element={<HomePage />} /> + <Route path="/timetable" element={<TimeTablePage />} /> + <Route path="/chattinglist" element={<ChattingListPage />} /> + <Route path="/mypage" element={<MyPage />} /> + <Route path="/login" element={<LoginPage />} /> + <Route path="/signup" element={<SignupPage />} /> + </Routes> + </BodyLayout> + <Footer /> </div> </Router> ); diff --git a/src/components/Button.jsx b/src/components/Button.jsx index ac67c66328b0babd8ce708fa03ad8ba32261ea9d..01714b52b16896a90affc0bea394812f0396156c 100644 --- a/src/components/Button.jsx +++ b/src/components/Button.jsx @@ -60,11 +60,15 @@ export default function Button({ : "flex h-[1.5rem] w-[1.5rem] items-center justify-center" } > - <img - src={icon} - alt="icon" - className={children ? "w-5 h-5" : "w-6 h-6"} - /> + <div + className={ + children + ? "flex items-center justify-center w-6 h-6" + : "flex items-center justify-center w-7 h-7" + } + > + {icon} + </div> </div> )} {children} diff --git a/src/components/icons/LogoIcon.jsx b/src/components/icons/LogoIcon.jsx new file mode 100644 index 0000000000000000000000000000000000000000..398fc137463bb2b70f7c2d9baeb9558c20d51eff --- /dev/null +++ b/src/components/icons/LogoIcon.jsx @@ -0,0 +1,40 @@ +import React from "react"; +import clsx from "clsx"; + +export default function LogoIcon({ + className = "", + width = 24, + height = 24, + fillColor, +}) { + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + className={clsx("inline-block", className)} + width={width} + height={height} + viewBox="0 0 24 24" + fill="none" + aria-hidden="true" + > + <path + d="M11.5 13.8H10.1299C8.72143 13.8 8.01721 13.8 7.72228 13.3385C7.42735 12.8769 7.72321 12.2379 8.31493 10.9597L11.0463 5.06006C11.4205 4.25182 11.6075 3.8477 11.8038 3.89091C12 3.93413 12 4.37946 12 5.27013V9.7C12 9.9357 12 10.0536 12.0732 10.1268C12.1464 10.2 12.2643 10.2 12.5 10.2H13.8701C15.2786 10.2 15.9828 10.2 16.2777 10.6615C16.5726 11.1231 16.2768 11.7621 15.6851 13.0402L12.9537 18.9399C12.5795 19.7482 12.3925 20.1523 12.1962 20.1091C12 20.0659 12 19.6205 12 18.7299V14.3C12 14.0643 12 13.9464 11.9268 13.8732C11.8536 13.8 11.7357 13.8 11.5 13.8Z" + fill={fillColor ? fillColor : "url(#paint0_linear_2165_2529)"} + /> + <defs> + <linearGradient + id="paint0_linear_2165_2529" + x1="12" + y1="3" + x2="12" + y2="21" + gradientUnits="userSpaceOnUse" + > + <stop stopColor="#6366F1" /> + <stop offset="0.5" stopColor="#A855F7" /> + <stop offset="1" stopColor="#EC4899" /> + </linearGradient> + </defs> + </svg> + ); +} diff --git a/src/components/layout/BodyLayout.jsx b/src/components/layout/BodyLayout.jsx new file mode 100644 index 0000000000000000000000000000000000000000..c29db0603765038f077bbe42523dbc30b0027485 --- /dev/null +++ b/src/components/layout/BodyLayout.jsx @@ -0,0 +1,14 @@ +// Layout.jsx +import React from "react"; + +const BodyLayout = ({ children }) => { + return ( + <div className="w-full mt-3"> + <main className="px-4 py-6 mx-auto bg-white max-w-[768px] tablet:rounded-2xl"> + {children} + </main> + </div> + ); +}; + +export default BodyLayout; diff --git a/src/components/layout/ContentContainer.jsx b/src/components/layout/ContentContainer.jsx deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/components/layout/Footer.jsx b/src/components/layout/Footer.jsx index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..24a676ab199029f89e3114d4d9118ef6bee5da76 100644 --- a/src/components/layout/Footer.jsx +++ b/src/components/layout/Footer.jsx @@ -0,0 +1,11 @@ +const Footer = () => { + return ( + <footer className="mt-4 bg-gray-200"> + <div className="container max-w-5xl px-4 py-2 mx-auto text-center"> + <p className="text-sm">© yoonseokchan. All rights reserved.</p> + </div> + </footer> + ); +}; + +export default Footer; diff --git a/src/components/layout/HeaderLogoBar.jsx b/src/components/layout/HeaderLogoBar.jsx new file mode 100644 index 0000000000000000000000000000000000000000..0b8aef801a89cb09855afc002deaa5380165a417 --- /dev/null +++ b/src/components/layout/HeaderLogoBar.jsx @@ -0,0 +1,14 @@ +import LogoIcon from "../icons/LogoIcon"; + +const HeaderLogoBar = () => { + return ( + <div className="flex items-center justify-start w-full h-16 px-4 bg-white"> + <div className="flex items-center"> + <LogoIcon width={32} height={32} /> + <span className="title-1">YANAWA</span> + </div> + </div> + ); +}; + +export default HeaderLogoBar; diff --git a/src/components/layout/HeaderNav.jsx b/src/components/layout/HeaderNav.jsx index 96db4ba63d8ae07c237ce08b901aa0127de38c96..e1d5d5d0752f038959b76dfb78d7b77e78e5d0c0 100644 --- a/src/components/layout/HeaderNav.jsx +++ b/src/components/layout/HeaderNav.jsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import Button from "../Button"; +import LogoIcon from "../icons/LogoIcon"; export default function HeaderNav() { const navigate = useNavigate(); @@ -19,78 +20,80 @@ export default function HeaderNav() { const navigateToLogin = () => navigate("/login"); return ( - <div className="fixed z-30 flex items-center justify-center w-full p-1 bg-white border-b-[1px] border-grayscale-400 desktop:h-[6rem] tablet:h-[5rem] mobile:h-[4rem]"> - <div className="flex items-center space-x-6"> - {isMobile ? ( - <> - <Button - size="icon" - theme="pink" - icon="https://i.namu.wiki/i/TH3mmCfG6-vJG_dFJ4pvAO7wQx4ibyHMuXFWodRXXVOmsxKbWkC1hXDoY_FfhSxxN4pgX0pIrQJTy6gK8-yhDA.svg" - onClick={navigateToHome} - /> - <Button - size="icon" - theme="purple" - icon="https://i.namu.wiki/i/TH3mmCfG6-vJG_dFJ4pvAO7wQx4ibyHMuXFWodRXXVOmsxKbWkC1hXDoY_FfhSxxN4pgX0pIrQJTy6gK8-yhDA.svg" - onClick={navigateToTimeTable} - /> - <Button - size="icon" - theme="mix" - icon="https://i.namu.wiki/i/TH3mmCfG6-vJG_dFJ4pvAO7wQx4ibyHMuXFWodRXXVOmsxKbWkC1hXDoY_FfhSxxN4pgX0pIrQJTy6gK8-yhDA.svg" - onClick={navigateToChattingList} - /> - <Button - size="icon" - theme="black" - icon="https://i.namu.wiki/i/TH3mmCfG6-vJG_dFJ4pvAO7wQx4ibyHMuXFWodRXXVOmsxKbWkC1hXDoY_FfhSxxN4pgX0pIrQJTy6gK8-yhDA.svg" - onClick={navigateToLogin} - /> - </> - ) : ( - <> - <Button - size="icon" - theme="pink" - icon="https://i.namu.wiki/i/TH3mmCfG6-vJG_dFJ4pvAO7wQx4ibyHMuXFWodRXXVOmsxKbWkC1hXDoY_FfhSxxN4pgX0pIrQJTy6gK8-yhDA.svg" - onClick={navigateToHome} - /> - <Button - size="lg" - theme="purple" - icon="https://i.namu.wiki/i/TH3mmCfG6-vJG_dFJ4pvAO7wQx4ibyHMuXFWodRXXVOmsxKbWkC1hXDoY_FfhSxxN4pgX0pIrQJTy6gK8-yhDA.svg" - onClick={navigateToHome} - > - 홈 - </Button> - <Button - size="lg" - theme="indigo" - icon="https://i.namu.wiki/i/TH3mmCfG6-vJG_dFJ4pvAO7wQx4ibyHMuXFWodRXXVOmsxKbWkC1hXDoY_FfhSxxN4pgX0pIrQJTy6gK8-yhDA.svg" - onClick={navigateToTimeTable} - > - 캘린더 - </Button> - <Button - size="lg" - theme="mix" - icon="https://i.namu.wiki/i/TH3mmCfG6-vJG_dFJ4pvAO7wQx4ibyHMuXFWodRXXVOmsxKbWkC1hXDoY_FfhSxxN4pgX0pIrQJTy6gK8-yhDA.svg" - onClick={navigateToChattingList} - > - 번개채팅방 - </Button> - <Button - size="lg" - theme="black" - icon="https://i.namu.wiki/i/TH3mmCfG6-vJG_dFJ4pvAO7wQx4ibyHMuXFWodRXXVOmsxKbWkC1hXDoY_FfhSxxN4pgX0pIrQJTy6gK8-yhDA.svg" - onClick={navigateToLogin} - > - 로그인 - </Button> - </> - )} + <header className="bg-white shadow-md"> + <div className="flex items-center justify-center w-full h-16 px-4 bg-white"> + <div className="flex items-center space-x-6"> + {isMobile ? ( + <> + <Button + size="icon" + theme="pink" + icon={<LogoIcon fillColor="#ffffff" />} + onClick={navigateToHome} + /> + <Button + size="icon" + theme="purple" + icon={<LogoIcon fillColor="#ffffff" />} + onClick={navigateToTimeTable} + /> + <Button + size="icon" + theme="mix" + icon={<LogoIcon fillColor="#ffffff" />} + onClick={navigateToChattingList} + /> + <Button + size="icon" + theme="black" + icon={<LogoIcon fillColor="#ffffff" />} + onClick={navigateToLogin} + /> + </> + ) : ( + <> + <Button + size="icon" + theme="pink" + icon={<LogoIcon fillColor="#ffffff" />} + onClick={navigateToHome} + /> + <Button + size="lg" + theme="purple" + icon={<LogoIcon fillColor="#ffffff" />} + onClick={navigateToHome} + > + 홈 + </Button> + <Button + size="lg" + theme="indigo" + icon={<LogoIcon fillColor="#ffffff" />} + onClick={navigateToTimeTable} + > + 캘린더 + </Button> + <Button + size="lg" + theme="mix" + icon={<LogoIcon fillColor="#ffffff" />} + onClick={navigateToChattingList} + > + 번개채팅방 + </Button> + <Button + size="lg" + theme="black" + icon={<LogoIcon fillColor="#ffffff" />} + onClick={navigateToLogin} + > + 로그인 + </Button> + </> + )} + </div> </div> - </div> + </header> ); } diff --git a/src/components/layout/ImageContainer.jsx b/src/components/layout/ImageContainer.jsx deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/tailwind.config.js b/tailwind.config.js index 42e2f8678d624476d9e1eaf2084189f7b63c9146..38492ecf47de3a43fccee32a0de977eec2206aa4 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -11,7 +11,7 @@ module.exports = { }, screens: { mobile: "320px", - tablet: "600px", + tablet: "768px", notebook: "1024px", desktop: "1440px", },