diff --git a/frontend/.prettierrc b/frontend/.prettierrc
index 10f39c8d9..0a14f71df 100644
--- a/frontend/.prettierrc
+++ b/frontend/.prettierrc
@@ -10,6 +10,5 @@
"arrowParens": "always",
"endOfLine": "auto",
"prefer-const": true,
- "singleAttributePerLine": false,
- "bracketSameLine": true
-}
\ No newline at end of file
+ "singleAttributePerLine": false
+}
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index b2ef24986..d1dcb0967 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -6,10 +6,11 @@ import { AdminClubProvider } from '@/context/AdminClubContext';
import GlobalStyles from '@/styles/Global.styles';
import MainPage from '@/pages/MainPage/MainPage';
import ClubDetailPage from '@/pages/ClubDetailPage/ClubDetailPage';
-import AdminPage from './pages/AdminPage/AdminPage';
+import AdminPage from '@/pages/AdminPage/AdminPage';
+import IntroducePage from '@/pages/IntroducePage/IntroducePage';
import ClubInfoEditTab from '@/pages/AdminPage/tabs/ClubInfoEditTab/ClubInfoEditTab';
-import RecruitEditTab from './pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab';
-import AccountEditTab from './pages/AdminPage/tabs/AccountEditTab/AccountEditTab';
+import RecruitEditTab from '@/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab';
+import AccountEditTab from '@/pages/AdminPage/tabs/AccountEditTab/AccountEditTab';
import LoginTab from '@/pages/AdminPage/auth/LoginTab/LoginTab';
import PrivateRoute from '@/pages/AdminPage/auth/PrivateRoute/PrivateRoute';
import PhotoEditTab from '@/pages/AdminPage/tabs/PhotoEditTab/PhotoEditTab';
@@ -41,6 +42,7 @@ const App = () => {
}
/>
+ } />
} />
`
+ position: fixed;
+ top: ${({ isOpen }) => (isOpen ? '0' : '-175px')};
+ height: 175px;
+ left: 0;
+ right: 0;
+ border-radius: 0px 0px 20px 20px;
+ background: #fff;
+ box-shadow: 0px 20px 30px 0px rgba(0, 0, 0, 0.25);
+ transition: top 0.2s ease-in-out;
+ z-index: 2;
+ padding: 20px;
+
+ visibility: ${({ isOpen }) => (isOpen ? 'visible' : 'hidden')};
+`;
+
+export const DrawerWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 34.75px;
+`;
+
+export const DrawerHeader = styled.div`
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ gap: 150px;
+`;
+
+export const DrawerMainIcon = styled.img`
+ width: 158px;
+ height: 32.25px;
+ flex-shrink: 0;
+ cursor: pointer;
+`;
+
+export const DrawerDeleteIcon = styled.img`
+ width: 17px;
+ height: 17px;
+ flex-shrink: 0;
+`;
+
+export const MenubarIntroduceBox = styled.div`
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ padding: 6px 36px;
+ border-radius: 52px;
+ background: rgba(255, 84, 20, 0.08);
+ cursor: pointer;
+`;
diff --git a/frontend/src/components/common/Header/Header.tsx b/frontend/src/components/common/Header/Header.tsx
index f9e8fa837..428c6a918 100644
--- a/frontend/src/components/common/Header/Header.tsx
+++ b/frontend/src/components/common/Header/Header.tsx
@@ -3,10 +3,12 @@ import { useLocation } from 'react-router-dom';
import * as Styled from './Header.styles';
import SearchBox from '@/components/common/SearchBox/SearchBox';
import useHeaderService from '@/services/header/useHeaderService';
+import useMobileMenu from '@/services/header/useMobileMenu';
import useIsMobile from '@/hooks/useIsMobile';
import DesktopMainIcon from '@/assets/images/moadong_name_logo.svg';
import MobileMainIcon from '@/assets/images/logos/moadong_mobile_logo.svg';
import MenuBar from '@/assets/images/icons/menu_button_icon.svg';
+import DeleteIcon from '@/assets/images/introduce/delete.png';
interface MobileHeaderProps {
handleHomeClick: (device: 'mobile' | 'desktop') => void;
@@ -19,6 +21,42 @@ interface DesktopHeaderProps {
handleIntroduceClick: () => void;
}
+interface MobileMenuProp {
+ isOpen: boolean;
+ onClose: () => void;
+ handleHomeClick: (device: 'mobile' | 'desktop') => void;
+ handleIntroduceClick: () => void;
+}
+
+const MobileMenuDrawer = ({
+ isOpen,
+ onClose,
+ handleHomeClick,
+ handleIntroduceClick,
+}: MobileMenuProp) => {
+ return (
+
+
+
+ handleHomeClick('mobile')}
+ />
+
+
+
+ 모아동 소개
+
+
+
+ );
+};
+
const MobileHeader = ({
handleHomeClick,
handleMenuClick,
@@ -56,11 +94,7 @@ const DesktopHeader = ({
/>
{!isAdminPage && (
-
+
모아동 소개
)}
@@ -78,11 +112,23 @@ const Header = () => {
const { handleHomeClick, handleIntroduceClick, handleMenuClick } =
useHeaderService();
+ const { isMenuOpen, openMenu, closeMenu } = useMobileMenu({
+ handleMenuClick,
+ });
+
return isMobile ? (
-
+ <>
+
+
+ >
) : (
(
+
+
+
+);
+
+export default Spinner;
diff --git a/frontend/src/pages/IntroducePage/IntroducePage.styles.ts b/frontend/src/pages/IntroducePage/IntroducePage.styles.ts
new file mode 100644
index 000000000..361c0029e
--- /dev/null
+++ b/frontend/src/pages/IntroducePage/IntroducePage.styles.ts
@@ -0,0 +1,21 @@
+import styled from 'styled-components';
+import { HeaderStyles } from '@/components/common/Header/Header.styles';
+import { FooterContainer } from '@/components/common/Footer/Footer.styles';
+
+export const IntroducePageHeader = styled(HeaderStyles)`
+ max-width: none;
+
+ @media (max-width: 500px) {
+ display: flex;
+ }
+`;
+
+export const IntroducePageFooter = styled(FooterContainer)`
+ margin-top: -50px;
+`;
+
+export const IntroduceImage = styled.img`
+ width: 100vw;
+ height: auto;
+ margin-top: 62px;
+`;
diff --git a/frontend/src/pages/IntroducePage/IntroducePage.tsx b/frontend/src/pages/IntroducePage/IntroducePage.tsx
new file mode 100644
index 000000000..2ec91fe04
--- /dev/null
+++ b/frontend/src/pages/IntroducePage/IntroducePage.tsx
@@ -0,0 +1,30 @@
+import React, { useState } from 'react';
+import * as Styled from './IntroducePage.styles';
+import Header from '@/components/common/Header/Header';
+import Footer from '@/components/common/Footer/Footer';
+import Spinner from '@/components/common/Spinner/Spinner';
+import IntroduceImage from '@/assets/images/introduce/Introduce.png';
+
+const IntroducePage = () => {
+ const [loading, setLoading] = useState(true);
+
+ return (
+ <>
+
+
+
+ {loading && }
+ setLoading(false)}
+ />
+
+
+
+ >
+ );
+};
+
+export default IntroducePage;
diff --git a/frontend/src/services/header/useHeaderService.ts b/frontend/src/services/header/useHeaderService.ts
index f7715bad7..bc0dface0 100644
--- a/frontend/src/services/header/useHeaderService.ts
+++ b/frontend/src/services/header/useHeaderService.ts
@@ -20,6 +20,7 @@ const useHeaderService = () => {
};
const goIntroducePage = () => {
+ navigate('/introduce');
trackEvent('Introduce Button Clicked');
};
diff --git a/frontend/src/services/header/useMobileMenu.ts b/frontend/src/services/header/useMobileMenu.ts
new file mode 100644
index 000000000..be849b594
--- /dev/null
+++ b/frontend/src/services/header/useMobileMenu.ts
@@ -0,0 +1,33 @@
+import { useCallback, useEffect, useState } from 'react';
+import useMixpanelTrack from '@/hooks/useMixpanelTrack';
+
+interface MobileMenuProp {
+ handleMenuClick: () => void;
+}
+
+const useMobileMenu = ({ handleMenuClick }: MobileMenuProp) => {
+ const trackEvent = useMixpanelTrack();
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
+
+ const openMenu = () => {
+ handleMenuClick();
+ setIsMenuOpen((prev) => !prev);
+ };
+
+ const closeMenu = useCallback(() => {
+ setIsMenuOpen(false);
+ trackEvent('Mobile Menubar delete Button Clicked');
+ }, []);
+
+ useEffect(() => {
+ const handleEsc = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') closeMenu();
+ };
+ if (isMenuOpen) window.addEventListener('keydown', handleEsc);
+ return () => window.removeEventListener('keydown', handleEsc);
+ }, [isMenuOpen, closeMenu]);
+
+ return { isMenuOpen, openMenu, closeMenu };
+};
+
+export default useMobileMenu;