Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import styled from 'styled-components';

export const WEBVIEW_BOTTOM_NAV_HEIGHT = 56;

export const BottomNavContainer = styled.nav`
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: calc(${WEBVIEW_BOTTOM_NAV_HEIGHT}px + env(safe-area-inset-bottom));
padding-bottom: env(safe-area-inset-bottom);
display: flex;
background-color: ${({ theme }) => theme.colors.base.white};
border-top: 1px solid ${({ theme }) => theme.colors.gray[300]};
z-index: 100;
`;

export const NavButton = styled.button<{ $isActive: boolean }>`
flex: 1;
display: flex;
align-items: center;
justify-content: center;
border: none;
background: none;
cursor: pointer;
font-size: 12px;
font-weight: ${({ $isActive }) => ($isActive ? 600 : 400)};
color: ${({ theme, $isActive }) =>
$isActive ? theme.colors.primary[900] : theme.colors.gray[600]};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useLocation, useNavigate } from 'react-router-dom';
import {
WEBVIEW_BOTTOM_NAV,
WebviewBottomNavPath,
} from '@/routes/webviewBottomNavConfig';
import * as Styled from './WebviewBottomNav.styles';

const WebviewBottomNav = () => {
const navigate = useNavigate();
const { pathname } = useLocation();

const isActive = (path: WebviewBottomNavPath) => {
// 홈 탭은 동아리 목록(/webview/main)과 홍보(/webview/promotions)에서 활성.
if (path === '/webview/main') {
return pathname === '/webview/main' || pathname === '/webview/promotions';
}
return pathname === path;
};

return (
<Styled.BottomNavContainer>
{WEBVIEW_BOTTOM_NAV.map((tab) => {
const active = isActive(tab.path);
return (
<Styled.NavButton
key={tab.path}
type='button'
$isActive={active}
aria-current={active ? 'page' : undefined}
onClick={() => navigate(tab.path)}
>
{tab.label}
</Styled.NavButton>
);
})}
</Styled.BottomNavContainer>
);
};

export default WebviewBottomNav;
9 changes: 9 additions & 0 deletions frontend/src/pages/WebviewLayout/WebviewLayout.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import styled from 'styled-components';
import { WEBVIEW_BOTTOM_NAV_HEIGHT } from '@/components/common/WebviewBottomNav/WebviewBottomNav.styles';

export const ContentArea = styled.div<{ $hideBottomNav: boolean }>`
padding-bottom: ${({ $hideBottomNav }) =>
$hideBottomNav
? '0'
: `calc(${WEBVIEW_BOTTOM_NAV_HEIGHT}px + env(safe-area-inset-bottom))`};
`;
13 changes: 11 additions & 2 deletions frontend/src/pages/WebviewLayout/WebviewLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { Outlet } from 'react-router-dom';
import { Outlet, useLocation } from 'react-router-dom';
import WebviewBottomNav from '@/components/common/WebviewBottomNav/WebviewBottomNav';
import WebviewGlobalStyles from '@/styles/WebviewGlobal.styles';
import * as Styled from './WebviewLayout.styles';

const WebviewLayout = () => {
const { pathname } = useLocation();
// 동아리 상세는 풀스크린 — 바텀바와 하단 패딩을 함께 숨긴다.
const hideBottomNav = pathname.startsWith('/webview/club');

return (
<>
<WebviewGlobalStyles />
<Outlet />
<Styled.ContentArea $hideBottomNav={hideBottomNav}>
<Outlet />
</Styled.ContentArea>
{!hideBottomNav && <WebviewBottomNav />}
</>
);
};
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/pages/WebviewMenuPage/WebviewMenuPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Placeholder — Sub-task 3(#1624)에서 메뉴 항목 + 앱 버전으로 구현 예정.
const WebviewMenuPage = () => {
return <div>메뉴</div>;
};

export default WebviewMenuPage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Placeholder — Sub-task 2(#1623)에서 구독 동아리 목록으로 구현 예정.
const WebviewSubscribedPage = () => {
return <div>구독</div>;
};

export default WebviewSubscribedPage;
9 changes: 9 additions & 0 deletions frontend/src/routes/webviewBottomNavConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 웹뷰 바텀 네비게이션 탭 정의
// 상단 필터칩(WEBVIEW_FILTER_CONFIG: 동아리/홍보)과는 별개의 리스트다.
export const WEBVIEW_BOTTOM_NAV = [
{ label: '홈', path: '/webview/main' },
{ label: '구독', path: '/webview/subscribed' },
{ label: '메뉴', path: '/webview/menu' },
] as const;

export type WebviewBottomNavPath = (typeof WEBVIEW_BOTTOM_NAV)[number]['path'];
18 changes: 18 additions & 0 deletions frontend/src/routes/webviewRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import ClubMapPage from '@/pages/ClubMapPage/ClubMapPage';
import PromotionListPage from '@/pages/PromotionPage/PromotionListPage';
import WebviewLayout from '@/pages/WebviewLayout/WebviewLayout';
import WebviewMainPage from '@/pages/WebviewMainPage/WebviewMainPage';
import WebviewMenuPage from '@/pages/WebviewMenuPage/WebviewMenuPage';
import WebviewSubscribedPage from '@/pages/WebviewSubscribedPage/WebviewSubscribedPage';
import {
WEBVIEW_FILTER_CONFIG,
WebviewFilterPath,
Expand All @@ -32,6 +34,22 @@ const webviewRoutes: RouteObject[] = [
),
};
}),
{
path: 'subscribed',
element: (
<ContentErrorBoundary>
<WebviewSubscribedPage />
</ContentErrorBoundary>
),
},
{
path: 'menu',
element: (
<ContentErrorBoundary>
<WebviewMenuPage />
</ContentErrorBoundary>
),
},
{
path: 'club/:clubId',
element: (
Expand Down