From 163951a7e93e259f5f9be3f9f4938f7336970dcc Mon Sep 17 00:00:00 2001 From: Jeje Date: Tue, 10 Sep 2024 02:59:36 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat(Header):=20=EC=9D=BC=EB=8B=A8=20?= =?UTF-8?q?=ED=97=A4=EB=8D=94=20=EB=8B=AC=EC=95=84=EB=B4=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Header/.css.ts | 81 +++++++++++++++++++++++++++++++++ src/components/Header/index.tsx | 31 +++++++++++++ src/components/Layout/index.tsx | 2 + 3 files changed, 114 insertions(+) create mode 100644 src/components/Header/.css.ts create mode 100644 src/components/Header/index.tsx diff --git a/src/components/Header/.css.ts b/src/components/Header/.css.ts new file mode 100644 index 0000000..32694b7 --- /dev/null +++ b/src/components/Header/.css.ts @@ -0,0 +1,81 @@ +import { style } from '@vanilla-extract/css'; + +export const headerContainer = style({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '10px 20px', + backgroundColor: '#fff', + boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)', + + '@media': { + 'screen and (max-width: 768px)': { + flexDirection: 'row', + alignItems: 'flex-start', + }, + }, +}); + +export const logoStyle = style({ + fontSize: '1.5rem', + fontWeight: 'bold', + color: '#333', + + '@media': { + 'screen and (max-width: 768px)': { + fontSize: '1.2rem', + }, + }, +}); + +export const navStyle = style({ + display: 'flex', + gap: '15px', + + '@media': { + 'screen and (max-width: 768px)': { + flexDirection: 'column', + gap: '10px', + display: 'none', // 처음에는 숨김 + }, + }, +}); + +export const navVisible = style({ + '@media': { + 'screen and (max-width: 768px)': { + display: 'flex', // 토글로 보임 처리 + }, + }, +}); + +export const navItem = style({ + color: '#333', + textDecoration: 'none', + fontSize: '1rem', + flexDirection: 'column', + + ':hover': { + color: '#0070f3', + }, + + '@media': { + 'screen and (max-width: 768px)': { + fontSize: '0.9rem', + }, + }, +}); + +export const menuButton = style({ + display: 'none', + background: 'none', + border: 'none', + fontSize: '1.5rem', + + '@media': { + 'screen and (max-width: 768px)': { + display: 'block', + cursor: 'pointer', + }, + }, +}); diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx new file mode 100644 index 0000000..4c2999c --- /dev/null +++ b/src/components/Header/index.tsx @@ -0,0 +1,31 @@ +import React, { useState } from 'react'; +import * as styles from '.css.ts'; + +const Header: React.FC = () => { + const [isMenuOpen, setIsMenuOpen] = useState(false); + + const toggleMenu = () => { + setIsMenuOpen(!isMenuOpen); + }; + + return ( +
+
My Website
+ + {/* 모바일 메뉴 버튼 */} + + + {/* 내비게이션 메뉴: 768px 이하에서는 토글로 표시 */} + +
+ ); +}; + +export default Header; diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index c4dce47..91c978c 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -1,9 +1,11 @@ import { Outlet } from "react-router-dom"; +import Header from "../Header"; // TODO: 모든 페이지에 공통으로 들어가는 레이아웃을 작성합니다. 필요 없으면 삭제해주세요 export default function Layout() { return (
+
); From 7a5ade748075a995fce8d7427d24540c3ef241b9 Mon Sep 17 00:00:00 2001 From: Jeje Date: Wed, 11 Sep 2024 11:17:09 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat(Header):=20=EB=B0=98=EC=9D=91?= =?UTF-8?q?=ED=98=95=20=EC=A0=9C=EC=9E=91=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Header/.css.ts | 94 +++++++++++++++++---------------- src/components/Header/index.tsx | 42 ++++++++------- 2 files changed, 72 insertions(+), 64 deletions(-) diff --git a/src/components/Header/.css.ts b/src/components/Header/.css.ts index 32694b7..2033321 100644 --- a/src/components/Header/.css.ts +++ b/src/components/Header/.css.ts @@ -1,81 +1,85 @@ import { style } from '@vanilla-extract/css'; -export const headerContainer = style({ +export const headerStyles = style({ display: 'flex', justifyContent: 'space-between', alignItems: 'center', - padding: '10px 20px', - backgroundColor: '#fff', - boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)', - + backgroundColor: 'beige', + padding: '8px 12px', '@media': { - 'screen and (max-width: 768px)': { - flexDirection: 'row', + 'screen and (max-width: 600px)': { + flexDirection: 'column', alignItems: 'flex-start', + padding: '8px 24px', }, }, }); -export const logoStyle = style({ - fontSize: '1.5rem', - fontWeight: 'bold', - color: '#333', - - '@media': { - 'screen and (max-width: 768px)': { - fontSize: '1.2rem', - }, - }, +export const logoStyles = style({ + fontSize: '24px', + color: 'violet', }); -export const navStyle = style({ +export const menuStyles = style({ display: 'flex', - gap: '15px', - + listStyle: 'none', + paddingLeft: 0, '@media': { - 'screen and (max-width: 768px)': { + 'screen and (max-width: 600px)': { + display: 'none', flexDirection: 'column', - gap: '10px', - display: 'none', // 처음에는 숨김 + alignItems: 'center', + width: '100%', + selectors: { + '&.active': { + display: 'flex', + }, + }, }, }, }); -export const navVisible = style({ +export const menuItemStyles = style({ + padding: '8px 12px', + ':hover': { + backgroundColor: 'grey', + borderRadius: '4px', + }, '@media': { - 'screen and (max-width: 768px)': { - display: 'flex', // 토글로 보임 처리 + 'screen and (max-width: 600px)': { + width: '100%', + textAlign: 'center', }, }, }); -export const navItem = style({ - color: '#333', - textDecoration: 'none', - fontSize: '1rem', - flexDirection: 'column', - - ':hover': { - color: '#0070f3', - }, - +export const linksStyles = style({ + listStyle: 'none', + paddingLeft: 0, + color: 'teal', + display: 'flex', '@media': { - 'screen and (max-width: 768px)': { - fontSize: '0.9rem', + 'screen and (max-width: 600px)': { + display: 'none', + justifyContent: 'center', + width: '100%', + selectors: { + '&.active': { + display: 'flex', + }, + }, }, }, }); -export const menuButton = style({ +export const toggleBtnStyles = style({ display: 'none', - background: 'none', - border: 'none', - fontSize: '1.5rem', - + position: 'absolute', + right: '32px', + fontSize: '24px', '@media': { - 'screen and (max-width: 768px)': { + 'screen and (max-width: 600px)': { display: 'block', - cursor: 'pointer', }, }, }); diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx index 4c2999c..592eb4a 100644 --- a/src/components/Header/index.tsx +++ b/src/components/Header/index.tsx @@ -1,31 +1,35 @@ import React, { useState } from 'react'; -import * as styles from '.css.ts'; +import { headerStyles, menuStyles, linksStyles, toggleBtnStyles, logoStyles, menuItemStyles } from './.css.ts'; -const Header: React.FC = () => { - const [isMenuOpen, setIsMenuOpen] = useState(false); +export const Header: React.FC = () => { + const [isActive, setIsActive] = useState(false); - const toggleMenu = () => { - setIsMenuOpen(!isMenuOpen); + const handleToggle = () => { + setIsActive(!isActive); }; return ( -
-
My Website
- - {/* 모바일 메뉴 버튼 */} - - - {/* 내비게이션 메뉴: 768px 이하에서는 토글로 표시 */} -
); }; -export default Header; +export default Header \ No newline at end of file From 0459d1316bc214bcaa8579409e5f4a49e6ee39fd Mon Sep 17 00:00:00 2001 From: Jeje Date: Sat, 14 Sep 2024 16:26:10 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat(Router):=20=EB=9D=BC=EC=9A=B0?= =?UTF-8?q?=ED=84=B0=20=EA=B0=9D=EC=B2=B4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 62 +++++---------------------------- src/RouterInfo.tsx | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 53 deletions(-) create mode 100644 src/RouterInfo.tsx diff --git a/src/App.tsx b/src/App.tsx index 9d9b1dd..ec62270 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,59 +1,15 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import Layout from "./components/Layout"; +import RouterInfo from "./RouterInfo.tsx"; -import Layout from "./components/Layout/index.tsx"; -import Main from "./pages/Main/index.tsx"; -import Artist from "./pages/Artist/index.tsx"; -import Booth from "./pages/Booth/index.tsx"; -import BoothNFoodList from "./pages/BoothNFoodList/index.tsx"; -import Foodtruck from "./pages/Foodtruck/index.tsx"; -import Makers from "./pages/Makers/index.tsx"; -import Map from "./pages/Map/index.tsx"; -import Notice from "./pages/Notice/index.tsx"; -import QnA from "./pages/QnA/index.tsx"; -import Timetable from "./pages/Timetable/index.tsx"; -const RouterPath = [ - { - path: "", - element:
, - }, - { - path: "artist/:id", - element: , - }, - { - path: "booth/:id", - element: , - }, - { - path: "booth_foodtruck_list", - element: , - }, - { - path: "foodtruck/:id", - element: , - }, - { - path: "makers", - element: , - }, - { - path: "map", - element: , - }, - { - path: "notice", - element: , - }, - { - path: "QnA", - element: , - }, - { - path: "timetable", - element: , - }, -]; +const RouterPath = RouterInfo.map((info) => { + return { + path: info.path, + element: info.element, + } +}); + const router = createBrowserRouter([ { path: "/", diff --git a/src/RouterInfo.tsx b/src/RouterInfo.tsx new file mode 100644 index 0000000..a38fbfb --- /dev/null +++ b/src/RouterInfo.tsx @@ -0,0 +1,86 @@ +import Layout from "./components/Layout/index.tsx"; +import Main from "./pages/Main/index.tsx"; +import Artist from "./pages/Artist/index.tsx"; +import Booth from "./pages/Booth/index.tsx"; +import BoothNFoodList from "./pages/BoothNFoodList/index.tsx"; +import Foodtruck from "./pages/Foodtruck/index.tsx"; +import Makers from "./pages/Makers/index.tsx"; +import Map from "./pages/Map/index.tsx"; +import Notice from "./pages/Notice/index.tsx"; +import QnA from "./pages/QnA/index.tsx"; +import Timetable from "./pages/Timetable/index.tsx"; + +export const RouterInfo = [ + { + path: "", + element:
, + english: "Main", + korean: "메인", + expose: true, + }, + { + path: "artist/:id", + element: , + english: "Artist", + korean: "아티스트", + expose: false, + }, + { + path: "booth/:id", + element: , + english: "Booth", + korean: "부스", + expose: false, + }, + { + path: "booth_foodtruck_list", + element: , + english: "Booth & Foodtruck List", + korean: "부스 & 푸드트럭 리스트", + expose: true, + }, + { + path: "foodtruck/:id", + element: , + english: "Foodtruck", + korean: "푸드트럭", + expose: false, + }, + { + path: "makers", + element: , + english: "Makers", + korean: "메이커스", + expose: false, + }, + { + path: "map", + element: , + english: "Map", + korean: "지도", + expose: true, + }, + { + path: "notice", + element: , + english: "Notice", + korean: "공지사항", + expose: true, + }, + { + path: "QnA", + element: , + english: "QnA", + korean: "QnA", + expose: true, + }, + { + path: "timetable", + element: , + english: "Timetable", + korean: "타임테이블", + expose: true, + }, +]; + +export default RouterInfo; \ No newline at end of file From 65451bd3814f05d039fda9cf0cad32575ad28af5 Mon Sep 17 00:00:00 2001 From: jjh4450 Date: Sun, 15 Sep 2024 19:01:56 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat(Header):=201=EC=B0=A8=20=EC=99=84?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 +- src/assets/logo.svg | 161 +++++++++++++++++++++++ src/assets/menu_buton.json | 1 + src/components/Header/.css.ts | 167 ++++++++++++++---------- src/components/Header/index.tsx | 112 ++++++++++++---- src/components/Layout/index.tsx | 2 + src/{ => shared/routing}/RouterInfo.tsx | 28 ++-- src/shared/types/Route.ts | 9 ++ 8 files changed, 373 insertions(+), 109 deletions(-) create mode 100644 src/assets/logo.svg create mode 100644 src/assets/menu_buton.json rename src/{ => shared/routing}/RouterInfo.tsx (71%) create mode 100644 src/shared/types/Route.ts diff --git a/src/App.tsx b/src/App.tsx index ec62270..b550d03 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,6 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom"; import Layout from "./components/Layout"; -import RouterInfo from "./RouterInfo.tsx"; +import RouterInfo from "./shared/routing/RouterInfo.tsx"; const RouterPath = RouterInfo.map((info) => { diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..08c652d --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1,161 @@ + + + + + + + + + + + + diff --git a/src/assets/menu_buton.json b/src/assets/menu_buton.json new file mode 100644 index 0000000..cf5bf59 --- /dev/null +++ b/src/assets/menu_buton.json @@ -0,0 +1 @@ +{"v":"5.4.4","fr":60,"ip":0,"op":140,"w":100,"h":100,"nm":"Menu","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Buttom","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":40,"s":[0],"e":[-45]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[-45],"e":[-45]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":85,"s":[-45],"e":[0]},{"t":105}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[51,70,0],"e":[51,78,0],"to":[0,1.333,0],"ti":[0,3.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":23,"s":[51,78,0],"e":[51,50,0],"to":[0,-3.333,0],"ti":[0,4.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[51,50,0],"e":[51,50,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":110,"s":[51,50,0],"e":[51,78,0],"to":[0,4.667,0],"ti":[0,-3.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":123,"s":[51,78,0],"e":[51,70,0],"to":[0,3.333,0],"ti":[0,1.333,0]},{"t":136}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[31,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[200,200],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Buttom","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":331,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Center","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":40,"s":[0],"e":[45]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[45],"e":[45]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":85,"s":[45],"e":[0]},{"t":105}],"ix":10},"p":{"a":0,"k":[51,50,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[31,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[200,200],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Center","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":331,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Upper","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":40,"s":[0],"e":[-45]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[-45],"e":[-45]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":85,"s":[-45],"e":[0]},{"t":105}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[51,30,0],"e":[51,22,0],"to":[0,-1.333,0],"ti":[0,-3.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":23,"s":[51,22,0],"e":[51,50,0],"to":[0,3.333,0],"ti":[0,-4.667,0]},{"i":{"x":0.831,"y":0.831},"o":{"x":0.165,"y":0.165},"t":36,"s":[51,50,0],"e":[51,50,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":110,"s":[51,50,0],"e":[51,22,0],"to":[0,-4.667,0],"ti":[0,3.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":123,"s":[51,22,0],"e":[51,30,0],"to":[0,-3.333,0],"ti":[0,-1.333,0]},{"t":136}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[31,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[200,200],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Upper","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":331,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/components/Header/.css.ts b/src/components/Header/.css.ts index 2033321..eda661f 100644 --- a/src/components/Header/.css.ts +++ b/src/components/Header/.css.ts @@ -1,85 +1,120 @@ -import { style } from '@vanilla-extract/css'; +import { style } from "@vanilla-extract/css"; +import { vars } from "../../shared/styles/vars.css"; + +const mobileBreakpoint = "1000px"; export const headerStyles = style({ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - backgroundColor: 'beige', - padding: '8px 12px', - '@media': { - 'screen and (max-width: 600px)': { - flexDirection: 'column', - alignItems: 'flex-start', - padding: '8px 24px', - }, - }, + display: "flex", + justifyContent: "space-between", + alignItems: "center", + padding: "10px 20px", + backgroundColor: "none", + position: "relative", }); export const logoStyles = style({ - fontSize: '24px', - color: 'violet', + width: "4em", + height: "auto", + fill: vars.color.green2, + ":hover": { + fill: vars.color.green1, + }, }); -export const menuStyles = style({ - display: 'flex', - listStyle: 'none', - paddingLeft: 0, - '@media': { - 'screen and (max-width: 600px)': { - display: 'none', - flexDirection: 'column', - alignItems: 'center', - width: '100%', - selectors: { - '&.active': { - display: 'flex', - }, - }, - }, +export const currentPageStyles = style({ + color: "white", + fontSize: "16px", + fontWeight: "bold", +}); + +export const toggleBtnStyles = style({ + background: "none", + border: "none", + color: "white", + fontSize: "24px", + cursor: "pointer", + display: "block", + height: "1.5em", + "@media": { + [`(min-width: ${mobileBreakpoint})`]: { + display: "none", }, + }, }); -export const menuItemStyles = style({ - padding: '8px 12px', - ':hover': { - backgroundColor: 'grey', - borderRadius: '4px', +export const menuStyles = style({ + flexDirection: "column", + position: "absolute", + top: "100%", + left: 0, + right: 0, + padding: "20px", + boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)", + transform: "translateX(-100%)", + opacity: 0, + pointerEvents: "none", + transition: "transform 0.3s ease-out, opacity 0.3s ease-out", + selectors: { + "&.active": { + transform: "translateX(0)", + opacity: 1, + pointerEvents: "auto", + backdropFilter: "blur(5px)", }, - '@media': { - 'screen and (max-width: 600px)': { - width: '100%', - textAlign: 'center', - }, + }, + "@media": { + [`(min-width: ${mobileBreakpoint})`]: { + display: "flex", + position: "static", + flexDirection: "row", + boxShadow: "none", + padding: 0, + transform: "none", + opacity: 1, + pointerEvents: "auto", + transition: "none", }, + }, }); -export const linksStyles = style({ - listStyle: 'none', - paddingLeft: 0, - color: 'teal', - display: 'flex', - '@media': { - 'screen and (max-width: 600px)': { - display: 'none', - justifyContent: 'center', - width: '100%', - selectors: { - '&.active': { - display: 'flex', - }, - }, - }, +export const menuListStyles = style({ + listStyle: "none", + padding: 0, + margin: 0, + display: "flex", + flexDirection: "column", + alignItems: "flex-end", + "@media": { + [`(min-width: ${mobileBreakpoint})`]: { + flexDirection: "row", + alignItems: "center", }, + }, }); -export const toggleBtnStyles = style({ - display: 'none', - position: 'absolute', - right: '32px', - fontSize: '24px', - '@media': { - 'screen and (max-width: 600px)': { - display: 'block', - }, +export const menuItemStyles = style({ + marginBottom: "10px", + margin: "16px", + fontSize: "large", + "@media": { + [`(min-width: ${mobileBreakpoint})`]: { + marginBottom: 0, + marginLeft: "20px", }, + }, +}); + +export const menuItemLinkStyles = style({ + color: "white", + textDecoration: "none", + fontSize: "16px", + ":hover": { + textDecoration: "underline", + backgroundColor: "rgba(255, 255, 255, 0.1)", + }, +}); + +export const highlightStyles = style({ + fontWeight: "bold", + textDecoration: "underline", }); diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx index 592eb4a..420cff8 100644 --- a/src/components/Header/index.tsx +++ b/src/components/Header/index.tsx @@ -1,35 +1,91 @@ -import React, { useState } from 'react'; -import { headerStyles, menuStyles, linksStyles, toggleBtnStyles, logoStyles, menuItemStyles } from './.css.ts'; +import React, { useEffect, useRef, useState } from "react"; +import { Link, matchPath, useLocation } from "react-router-dom"; +import RouterInfo from "../../shared/routing/RouterInfo.tsx"; +import Logo from "../../assets/logo.svg?react"; +import Menu from "../../assets/menu_buton.json"; +import { + currentPageStyles, + headerStyles, + highlightStyles, + logoStyles, + menuItemLinkStyles, + menuItemStyles, + menuListStyles, + menuStyles, + toggleBtnStyles, +} from "./.css.ts"; +import { RouterInfoType } from "../../shared/types/Route"; +import Lottie, { LottieRefCurrentProps } from "lottie-react"; export const Header: React.FC = () => { - const [isActive, setIsActive] = useState(false); + const [isActive, setIsActive] = useState(false); + const [currentPage, setCurrentPage] = useState("/"); + const location = useLocation(); + const lottieRef = useRef(null); - const handleToggle = () => { - setIsActive(!isActive); - }; + const handleToggle = () => { + setIsActive((prevState) => { + const newState = !prevState; + if (lottieRef.current) { + if (newState) { + lottieRef.current.playSegments([0, 60], true); + } else { + lottieRef.current.playSegments([60, 120], true); + } + } + return newState; + }); + }; - return ( -
- - -
    -
  • -
  • -
- -
+ useEffect(() => { + const currentRoute = RouterInfo.find((route) => + matchPath({ path: route.path, end: true }, location.pathname) ); + setCurrentPage(currentRoute ? currentRoute.korean : "/"); + setIsActive(false); + lottieRef.current?.setSpeed(1.2); + }, [location.pathname]); + + return ( +
+ + + + {currentPage} + + +
+ ); }; -export default Header \ No newline at end of file +export default Header; \ No newline at end of file diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 3c8f64a..78fb21f 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -1,11 +1,13 @@ import { Outlet } from "react-router-dom"; import "../../shared/styles/globalStyle.css"; import backgroundImg from "../../assets/background.png"; +import Header from "../Header"; // TODO: 모든 페이지에 공통으로 들어가는 레이아웃을 작성합니다. 필요 없으면 삭제해주세요 export default function Layout() { return (
+
background
diff --git a/src/RouterInfo.tsx b/src/shared/routing/RouterInfo.tsx similarity index 71% rename from src/RouterInfo.tsx rename to src/shared/routing/RouterInfo.tsx index a38fbfb..d956816 100644 --- a/src/RouterInfo.tsx +++ b/src/shared/routing/RouterInfo.tsx @@ -1,18 +1,18 @@ -import Layout from "./components/Layout/index.tsx"; -import Main from "./pages/Main/index.tsx"; -import Artist from "./pages/Artist/index.tsx"; -import Booth from "./pages/Booth/index.tsx"; -import BoothNFoodList from "./pages/BoothNFoodList/index.tsx"; -import Foodtruck from "./pages/Foodtruck/index.tsx"; -import Makers from "./pages/Makers/index.tsx"; -import Map from "./pages/Map/index.tsx"; -import Notice from "./pages/Notice/index.tsx"; -import QnA from "./pages/QnA/index.tsx"; -import Timetable from "./pages/Timetable/index.tsx"; +import { RouterInfoType } from "../types/Route.ts"; +import Main from "../../pages/Main"; +import Artist from "../../pages/Artist"; +import Booth from "../../pages/Booth"; +import BoothNFoodList from "../../pages/BoothNFoodList"; +import Foodtruck from "../../pages/Foodtruck"; +import Makers from "../../pages/Makers"; +import Map from "../../pages/Map"; +import Notice from "../../pages/Notice"; +import QnA from "../../pages/QnA"; +import Timetable from "../../pages/Timetable"; -export const RouterInfo = [ +export const RouterInfo: RouterInfoType [] = [ { - path: "", + path: "/", element:
, english: "Main", korean: "메인", @@ -83,4 +83,4 @@ export const RouterInfo = [ }, ]; -export default RouterInfo; \ No newline at end of file +export default RouterInfo; diff --git a/src/shared/types/Route.ts b/src/shared/types/Route.ts new file mode 100644 index 0000000..abe742d --- /dev/null +++ b/src/shared/types/Route.ts @@ -0,0 +1,9 @@ + +// 라우팅 정보 객체 타입 +export interface RouterInfoType { + path: string; + element: React.ReactElement; + english: string; + korean: string; + expose: boolean; +} \ No newline at end of file From c1f1682cc74ea224cbb9af642ca0d38a3f16c157 Mon Sep 17 00:00:00 2001 From: jjh4450 Date: Sun, 15 Sep 2024 19:59:54 +0900 Subject: [PATCH 05/12] =?UTF-8?q?refactor(Header):=20=EB=A6=AC=ED=92=B1?= =?UTF-8?q?=ED=89=88=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Header/.css.ts | 12 +++----- src/components/Header/index.tsx | 54 ++++++++++++++++----------------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/components/Header/.css.ts b/src/components/Header/.css.ts index eda661f..e404e20 100644 --- a/src/components/Header/.css.ts +++ b/src/components/Header/.css.ts @@ -8,7 +8,6 @@ export const headerStyles = style({ justifyContent: "space-between", alignItems: "center", padding: "10px 20px", - backgroundColor: "none", position: "relative", }); @@ -42,8 +41,9 @@ export const toggleBtnStyles = style({ }, }); +const menuTransition = "transform 0.3s ease-out, opacity 0.3s ease-out"; + export const menuStyles = style({ - flexDirection: "column", position: "absolute", top: "100%", left: 0, @@ -53,7 +53,7 @@ export const menuStyles = style({ transform: "translateX(-100%)", opacity: 0, pointerEvents: "none", - transition: "transform 0.3s ease-out, opacity 0.3s ease-out", + transition: menuTransition, selectors: { "&.active": { transform: "translateX(0)", @@ -64,8 +64,8 @@ export const menuStyles = style({ }, "@media": { [`(min-width: ${mobileBreakpoint})`]: { - display: "flex", position: "static", + display: "flex", flexDirection: "row", boxShadow: "none", padding: 0, @@ -93,13 +93,11 @@ export const menuListStyles = style({ }); export const menuItemStyles = style({ - marginBottom: "10px", margin: "16px", fontSize: "large", "@media": { [`(min-width: ${mobileBreakpoint})`]: { - marginBottom: 0, - marginLeft: "20px", + margin: "0 0 0 20px", }, }, }); diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx index 420cff8..915080a 100644 --- a/src/components/Header/index.tsx +++ b/src/components/Header/index.tsx @@ -1,6 +1,6 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useRef, useState, useCallback } from "react"; import { Link, matchPath, useLocation } from "react-router-dom"; -import RouterInfo from "../../shared/routing/RouterInfo.tsx"; +import RouterInfo from "../../shared/routing/RouterInfo"; import Logo from "../../assets/logo.svg?react"; import Menu from "../../assets/menu_buton.json"; import { @@ -17,13 +17,16 @@ import { import { RouterInfoType } from "../../shared/types/Route"; import Lottie, { LottieRefCurrentProps } from "lottie-react"; +const isCurrentPath = (path: string, pathname: string): boolean => + !!matchPath({ path, end: true }, pathname); + export const Header: React.FC = () => { const [isActive, setIsActive] = useState(false); const [currentPage, setCurrentPage] = useState("/"); const location = useLocation(); const lottieRef = useRef(null); - const handleToggle = () => { + const handleToggle = useCallback(() => { setIsActive((prevState) => { const newState = !prevState; if (lottieRef.current) { @@ -35,15 +38,15 @@ export const Header: React.FC = () => { } return newState; }); - }; + }, []); useEffect(() => { const currentRoute = RouterInfo.find((route) => - matchPath({ path: route.path, end: true }, location.pathname) + isCurrentPath(route.path, location.pathname) ); - setCurrentPage(currentRoute ? currentRoute.korean : "/"); + setCurrentPage(currentRoute?.korean ?? "/"); setIsActive(false); - lottieRef.current?.setSpeed(1.2); + lottieRef.current?.setSpeed(1.5); }, [location.pathname]); return ( @@ -62,26 +65,23 @@ export const Header: React.FC = () => { /> From 1aeaa752db8386174003cecf2e3f7d0be7993bd0 Mon Sep 17 00:00:00 2001 From: jjh4450 Date: Sun, 15 Sep 2024 22:42:35 +0900 Subject: [PATCH 06/12] =?UTF-8?q?feat(Header):=20nav=20=EC=86=8D=20Link?= =?UTF-8?q?=ED=83=9C=EA=B7=B8=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Header/.css.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/Header/.css.ts b/src/components/Header/.css.ts index e404e20..c394562 100644 --- a/src/components/Header/.css.ts +++ b/src/components/Header/.css.ts @@ -103,16 +103,20 @@ export const menuItemStyles = style({ }); export const menuItemLinkStyles = style({ + display: "inline-block", + padding: "10px 15px", color: "white", textDecoration: "none", fontSize: "16px", + borderRadius: "20px", + backgroundColor: "rgba(255, 255, 255, 0.1)", + transition: "background-color 0.3s ease", ":hover": { - textDecoration: "underline", - backgroundColor: "rgba(255, 255, 255, 0.1)", + backgroundColor: "rgba(255, 255, 255, 0.2)", }, }); export const highlightStyles = style({ fontWeight: "bold", - textDecoration: "underline", -}); + backgroundColor: "rgba(255, 255, 255, 0.3)", +}); \ No newline at end of file From 213727f23129a996c96681b10046585d05bda701 Mon Sep 17 00:00:00 2001 From: jjh4450 Date: Sun, 15 Sep 2024 22:53:04 +0900 Subject: [PATCH 07/12] =?UTF-8?q?docs(Header):=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Header/index.tsx | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx index 915080a..9444b19 100644 --- a/src/components/Header/index.tsx +++ b/src/components/Header/index.tsx @@ -17,15 +17,33 @@ import { import { RouterInfoType } from "../../shared/types/Route"; import Lottie, { LottieRefCurrentProps } from "lottie-react"; +/** + * 현재 경로인지 확인하는 함수 + * @param path 비교할 경로 + * @param pathname 현재 경로(useLocation().pathname) + * @return boolean + */ const isCurrentPath = (path: string, pathname: string): boolean => !!matchPath({ path, end: true }, pathname); +/** + * Header 컴포넌트 + * @component + * @returns {React.ReactElement} Header 컴포넌트 요소 + */ export const Header: React.FC = () => { const [isActive, setIsActive] = useState(false); const [currentPage, setCurrentPage] = useState("/"); const location = useLocation(); + + // lottie 애니메이션을 제어하기 위한 ref | 참고: https://lottiereact.com/#calling-the-methods const lottieRef = useRef(null); + /** + * 토글 버튼 클릭 이벤트 핸들러 + * @function handleToggle + * @return {void} + */ const handleToggle = useCallback(() => { setIsActive((prevState) => { const newState = !prevState; @@ -40,6 +58,9 @@ export const Header: React.FC = () => { }); }, []); + /** + * 컴포넌트가 마운트될 때 현재 페이지를 설정하고, isActive를 false로 초기화함 + */ useEffect(() => { const currentRoute = RouterInfo.find((route) => isCurrentPath(route.path, location.pathname) @@ -51,10 +72,15 @@ export const Header: React.FC = () => { return (
+ {/*로고 부분*/} + + {/*현재 페이지 출력 부분*/} {currentPage} + + {/*토글 버튼 (lottie)*/} { autoplay={false} loop={false} /> + + {/*페이지 메뉴*/}