diff --git a/frontend/.storybook/preview.ts b/frontend/.storybook/preview.ts index a9a9b4fb..767db400 100644 --- a/frontend/.storybook/preview.ts +++ b/frontend/.storybook/preview.ts @@ -1,15 +1,5 @@ import type { Preview } from '@storybook/react'; import '../src/index.css'; -// 우선은 폰트 다 포함시켰는데, 나중에 사용할 것들만 따로 뺴자. -import '@fontsource/pretendard/100.css'; -import '@fontsource/pretendard/200.css'; -import '@fontsource/pretendard/300.css'; -import '@fontsource/pretendard/400.css'; -import '@fontsource/pretendard/500.css'; -import '@fontsource/pretendard/600.css'; -import '@fontsource/pretendard/700.css'; -import '@fontsource/pretendard/800.css'; -import '@fontsource/pretendard/900.css'; const preview: Preview = { parameters: { diff --git a/frontend/package.json b/frontend/package.json index d5fe6de4..268c3601 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,7 +19,6 @@ "build-storybook": "storybook build" }, "dependencies": { - "@fontsource/pretendard": "^5.1.0", "axios": "^1.7.7", "lz-string": "^1.5.0", "react": "^18.3.1", diff --git a/frontend/src/App.css b/frontend/src/App.css index 12c5704e..77787acb 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,6 +1,6 @@ #root { touch-action: pan-y; - font-family: Pretendard, 'Pretendard Variable', sans-serif; + font-family: Pretendard, 'Pretendard Variable', sans-serif !important; } .logo { @@ -40,10 +40,10 @@ } .disable-drag { - -webkit-user-select:none; - -moz-user-select:none; - -ms-user-select:none; - user-select:none + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } .overlay { diff --git a/frontend/src/component/content/Content.tsx b/frontend/src/component/content/Content.tsx index d3f505d5..6bc807a3 100644 --- a/frontend/src/component/content/Content.tsx +++ b/frontend/src/component/content/Content.tsx @@ -4,6 +4,7 @@ import { getChannelInfo } from '@/api/channel.api'; import { useContext } from 'react'; import { ChannelContext } from '@/context/ChannelContext'; import { Dropdown } from '../common/dropdown/Dropdown'; +import { FooterContext } from '../layout/footer/LayoutFooterProvider'; interface IContentProps { title: string; @@ -35,6 +36,7 @@ interface IContentProps { */ export const Content = (props: IContentProps) => { + const { resetFooterContext } = useContext(FooterContext); const formattedDate = new Date(props.time).toLocaleDateString('ko-KR', { year: 'numeric', month: '2-digit', @@ -61,9 +63,15 @@ export const Content = (props: IContentProps) => { const goToChannelInfoPage = () => { if (channelInfo?.id) { navigate(`/channelInfo/${channelInfo.id}`); + resetFooterContext(); } }; + const goToHostViewPage = () => { + navigate(props.link); + resetFooterContext(); + }; + const handleUpdate = () => { getUpdateChannelInfo(); goToChannelInfoPage(); @@ -85,7 +93,7 @@ export const Content = (props: IContentProps) => { {props.person > 0 && ( <> - {props.person}명 + {props.person}명 )} @@ -101,10 +109,15 @@ export const Content = (props: IContentProps) => { - + 공유하기 - 삭제하기 + + 삭제하기 + diff --git a/frontend/src/component/header/HeaderLayout.tsx b/frontend/src/component/header/HeaderLayout.tsx new file mode 100644 index 00000000..136f4b96 --- /dev/null +++ b/frontend/src/component/header/HeaderLayout.tsx @@ -0,0 +1,42 @@ +import { ReactNode } from 'react'; +import classNames from 'classnames'; + +interface IHeaderProps { + leftItems?: ReactNode[]; + rightItems?: ReactNode[]; + title?: ReactNode; + subtitle?: string; + className?: string; + userName?: string; +} + +export const HeaderLayout = (props: IHeaderProps) => { + return ( +
+
+
+ {props.leftItems && + props.leftItems.map(item => ( +
{item}
+ ))} +
+
{props.userName}
+
{props.title}
+
+
+
+ {props.rightItems && + props.rightItems.map(item => ( +
{item}
+ ))} +
+
+
{props.subtitle}
+
+ ); +}; diff --git a/frontend/src/component/layout/constant/HeaderConst.ts b/frontend/src/component/layout/constant/HeaderConst.ts index 44d1002c..7092bb40 100644 --- a/frontend/src/component/layout/constant/HeaderConst.ts +++ b/frontend/src/component/layout/constant/HeaderConst.ts @@ -1,3 +1,7 @@ +import { HeaderBackButton } from '@/component/header/HeaderBackButton'; +import { HeaderDropdown } from '@/component/header/HeaderDropdown'; +import React, { ReactNode } from 'react'; + export const HEADER_TITLE: Record = { '/add-channel/:user/draw': '에 따른 경로 설정', }; @@ -6,17 +10,17 @@ export const HEADER_SUBTITLE: Record = { '/add-channel/:user/draw': '사용자 별로 출발지/도착지(마커), 경로(그림)을 설정할 수 있습니다', }; -export const HEADER_LEFTBUTTON: Record = { - '/add-channel': 'back', - '/add-channel/:user': 'back', - '/add-channel/:user/draw': 'back', - '/channel/:channelId/host': 'back', - '/update-channel': 'back', - '/register': 'back', - '/channelInfo/:channelId': 'back', - '/guest-add-channel/:channelId': 'back', +export const HEADER_LEFTITEMS: Record = { + '/add-channel': [React.createElement(HeaderBackButton)], + '/add-channel/:user': [React.createElement(HeaderBackButton)], + '/add-channel/:user/draw': [React.createElement(HeaderBackButton)], + '/channel/:channelId/host': [React.createElement(HeaderBackButton)], + '/update-channel': [React.createElement(HeaderBackButton)], + '/register': [React.createElement(HeaderBackButton)], + '/channelInfo/:channelId': [React.createElement(HeaderBackButton)], + '/guest-add-channel/:channelId': [React.createElement(HeaderBackButton)], }; -export const HEADER_RIGHTBUTTON: Record = { - '/channel/:channelId/host': 'dropdown', +export const HEADER_RIGHTITEMS: Record = { + '/channel/:channelId/host': [React.createElement(HeaderDropdown)], }; diff --git a/frontend/src/component/layout/header/LayoutHeader.tsx b/frontend/src/component/layout/header/LayoutHeader.tsx index 69168592..6214d645 100644 --- a/frontend/src/component/layout/header/LayoutHeader.tsx +++ b/frontend/src/component/layout/header/LayoutHeader.tsx @@ -1,25 +1,19 @@ -import { Header } from '@/component/header/Header'; -import { NoticeText } from '@/component/text/NoticeText'; import { useLocation, useParams } from 'react-router-dom'; import { getHeaderInfo } from '@/utils/mapping/HeaderMapping'; +import { HeaderLayout } from '@/component/header/HeaderLayout'; export const LayoutHeader = () => { const params = useParams>(); const urlPath = useLocation(); const headerOption = getHeaderInfo(urlPath.pathname); - return ( -
- - {headerOption.subtitle && ( - - {headerOption.subtitle} - - )} -
+ ); }; diff --git a/frontend/src/index.css b/frontend/src/index.css index 9983d0f2..03968b36 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -20,19 +20,87 @@ box-sizing: border-box; /* padding과 border를 box 크기에 포함 */ } -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { margin: 0; padding: 0; border: 0; @@ -43,22 +111,35 @@ time, mark, audio, video { } /* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { display: block; } body { line-height: 1; - font-family: Pretendard, 'Pretendard Variable', sans-serif; + font-family: Pretendard, 'Pretendard Variable', sans-serif !important; } -ol, ul { +ol, +ul { list-style: none; } -blockquote, q { +blockquote, +q { quotes: none; } -blockquote:before, blockquote:after, -q:before, q:after { +blockquote:before, +blockquote:after, +q:before, +q:after { content: ''; content: none; } @@ -66,9 +147,11 @@ table { border-collapse: collapse; border-spacing: 0; } -span, a, img { - -webkit-user-select:none; - -moz-user-select:none; - -ms-user-select:none; - user-select:none +span, +a, +img { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } diff --git a/frontend/src/pages/AddChannel.tsx b/frontend/src/pages/AddChannel.tsx index a9937e8e..7ee3febc 100644 --- a/frontend/src/pages/AddChannel.tsx +++ b/frontend/src/pages/AddChannel.tsx @@ -47,6 +47,11 @@ export const AddChannel = () => { resetFooterContext, } = useContext(FooterContext); const navigate = useNavigate(); + const goToMainPage = () => { + navigate('/'); + resetFooterContext(); + resetUsers(); + }; /** * 사용자 추가 함수 @@ -172,11 +177,7 @@ export const AddChannel = () => { console.error('채널 생성 실패:', error); } }; - const goToMainPage = () => { - navigate('/'); - resetFooterContext(); - resetUsers(); - }; + useEffect(() => { setFooterOnClick(() => { createChannelAPI(); diff --git a/frontend/src/pages/AddGuestPage.tsx b/frontend/src/pages/AddGuestPage.tsx index 7cfce20c..7bd53cb7 100644 --- a/frontend/src/pages/AddGuestPage.tsx +++ b/frontend/src/pages/AddGuestPage.tsx @@ -30,9 +30,10 @@ export const AddGuestPage = () => { resetFooterContext, footerOption, } = useContext(FooterContext); + const navigate = useNavigate(); const goToMainPage = () => { - navigate('/', { replace: true }); + navigate('/'); resetFooterContext(); resetUsers(); }; diff --git a/frontend/src/pages/DrawRoute.tsx b/frontend/src/pages/DrawRoute.tsx index 1bd17afc..ab16dd54 100644 --- a/frontend/src/pages/DrawRoute.tsx +++ b/frontend/src/pages/DrawRoute.tsx @@ -10,13 +10,15 @@ import { getAddressFromCoordinates } from '@/utils/map/getAddress'; export const DrawRoute = () => { const { users, setUsers } = useContext(UserContext); - const { setFooterTitle, setFooterActive, setFooterOnClick } = useContext(FooterContext); + const { setFooterTitle, setFooterActive, setFooterOnClick, resetFooterContext } = + useContext(FooterContext); const { currentUser, setCurrentUser } = useContext(CurrentUserContext); - const params = useParams>(); // userName을 URL 파라미터로 가져옴 + const params = useParams>(); const navigate = useNavigate(); const goToRoutePage = () => { navigate(-1); + resetFooterContext(); }; const getUser = () => { diff --git a/frontend/src/pages/HostView.tsx b/frontend/src/pages/HostView.tsx index 481e32b3..3a40aeab 100644 --- a/frontend/src/pages/HostView.tsx +++ b/frontend/src/pages/HostView.tsx @@ -130,7 +130,6 @@ export const HostView = () => { useEffect(() => { headerDropdownContext.setItems([{ name: '사용자 1', id: '1', markerStyle: { color: '#000' } }]); - fetchChannelInfo(location.pathname.split('/')[2]); }, []); diff --git a/frontend/src/routes/IndexRoutes.tsx b/frontend/src/routes/IndexRoutes.tsx index 52a290d5..6f5fe5e6 100644 --- a/frontend/src/routes/IndexRoutes.tsx +++ b/frontend/src/routes/IndexRoutes.tsx @@ -20,37 +20,22 @@ export const IndexRoutes = () => ( }> } /> - - - - - } - /> - - - - - } - /> - - - - {/* channelInfo 페이지 경로 설정 */} - + + + } + /> + + } /> - ( } /> - + + + + } + /> ( /> } /> - - {/* 정의되지 않은 경로 라우팅 */} - } /> + + {/* 정의되지 않은 경로 라우팅 */} + } /> diff --git a/frontend/src/utils/mapping/HeaderMapping.ts b/frontend/src/utils/mapping/HeaderMapping.ts index a803f36d..238601c4 100644 --- a/frontend/src/utils/mapping/HeaderMapping.ts +++ b/frontend/src/utils/mapping/HeaderMapping.ts @@ -1,6 +1,6 @@ import { - HEADER_LEFTBUTTON, - HEADER_RIGHTBUTTON, + HEADER_LEFTITEMS, + HEADER_RIGHTITEMS, HEADER_SUBTITLE, HEADER_TITLE, } from '@/component/layout/constant/HeaderConst'; @@ -20,13 +20,13 @@ export const getHeaderInfo = (path: string) => { const normalizedPath = normalizePath(path); const title = HEADER_TITLE[normalizedPath] || ''; const subtitle = HEADER_SUBTITLE[normalizedPath] || ''; - const leftButton = HEADER_LEFTBUTTON[normalizedPath] || ''; - const rightButton = HEADER_RIGHTBUTTON[normalizedPath] || ''; + const leftItems = HEADER_LEFTITEMS[normalizedPath] || ''; + const rightItems = HEADER_RIGHTITEMS[normalizedPath] || ''; return { title, subtitle, - leftButton, - rightButton, + leftItems, + rightItems, }; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 662a3794..c2b23bf0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -202,9 +202,6 @@ importers: frontend: dependencies: - '@fontsource/pretendard': - specifier: ^5.1.0 - version: 5.1.0 axios: specifier: ^1.7.7 version: 1.7.7 @@ -1581,9 +1578,6 @@ packages: resolution: {integrity: sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@fontsource/pretendard@5.1.0': - resolution: {integrity: sha512-aUkTiTYKDX/919OJqKKyly4cuoets76Cwjqw1qNTCFpIdVMpOm5uGEpreIPabDdp1ReYdeVfB94Wxyn5Q9jrBQ==} - '@hapi/hoek@9.3.0': resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} @@ -9969,8 +9963,6 @@ snapshots: dependencies: levn: 0.4.1 - '@fontsource/pretendard@5.1.0': {} - '@hapi/hoek@9.3.0': {} '@hapi/topo@5.1.0':