Skip to content

Commit e490fde

Browse files
authored
[feat] 헤더 & 푸터 구현
* feat: Header 구현 * feat: 모바일 반응형 수정 * refactor: 폰트 크기 수정 * feat: footer구현
1 parent a03f7f1 commit e490fde

File tree

8 files changed

+196
-165
lines changed

8 files changed

+196
-165
lines changed

src/App.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ import {
3434
SomkatonApplicants,
3535
RecruitInfo,
3636
} from './pages'
37-
import { Header } from './components/UI/Header'
37+
import Header from './components/layout/Header'
38+
import Footer from './components/layout/Footer'
3839
import ProtectedRoute from './components/layout/ProtectRoute'
3940

4041
function App() {
@@ -49,12 +50,12 @@ function App() {
4950

5051
function AppContent() {
5152
const location = useLocation()
52-
const hideHeader = ['/login'] // 헤더를 숨길 페이지
53+
const hideHeaderFooter = ['/login'] // 헤더와 푸터를 숨길 페이지
5354

5455
return (
5556
<>
5657
{/* 지정한 페이지 header 숨기기 */}
57-
{!hideHeader.includes(location.pathname) && <Header />}
58+
{!hideHeaderFooter.includes(location.pathname) && <Header />}
5859
<Routes>
5960
<Route path='/' element={<Main />} />
6061
<Route path='/login' element={<Login />} />
@@ -151,6 +152,7 @@ function AppContent() {
151152
}
152153
/>
153154
</Routes>
155+
{!hideHeaderFooter.includes(location.pathname) && <Footer />}
154156
</>
155157
)
156158
}

src/components/UI/Header.tsx

Lines changed: 0 additions & 156 deletions
This file was deleted.

src/components/layout/Footer.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react'
2+
import { Github, Instagram } from 'lucide-react'
3+
import { Link } from 'react-router-dom'
4+
5+
const Footer = () => {
6+
return (
7+
<footer className="bg-mainColor text-white font-pretendardRegular h-auto md:h-[140px] py-7">
8+
<div className="w-full max-w-screen-xl mx-auto flex flex-col justify-center h-full px-4 md:px-12">
9+
<div className="flex flex-col md:flex-row justify-between md:items-center gap-4">
10+
<p className="text-xs md:text-lg font-normal">© 2025 DASOM. ALL RIGHTS RESERVED.</p>
11+
<div className="flex space-x-2">
12+
<Link to="https://www.instagram.com/dasom___official/" target="_blank" rel="noopener noreferrer">
13+
<Instagram className="size-6" />
14+
</Link>
15+
<Link to="https://github.com/DASOM-GitHub" target="_blank" rel="noopener noreferrer">
16+
<Github className="size-6" />
17+
</Link>
18+
</div>
19+
</div>
20+
21+
<div className="w-full my-4 border-t border-white" />
22+
23+
<div className="flex flex-col md:flex-row justify-between w-full gap-4">
24+
<p className="text-sm md:text-lg font-bold">Made by DASOM Makers</p>
25+
<div className="text-left md:text-right">
26+
<p className="text-[10px] md:text-sm font-normal">서울특별시 구로구 경인로 445, 3호관 511호</p>
27+
<a href="mailto:[email protected]" className="text-[10px] md:text-sm font-normal underline">
28+
29+
</a>
30+
</div>
31+
</div>
32+
</div>
33+
</footer>
34+
)
35+
}
36+
37+
export default Footer

src/components/layout/Header.tsx

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import React, { useState } from 'react'
2+
import { Link } from 'react-router-dom'
3+
import { Menu } from 'lucide-react'
4+
import MobileNav from './MobileNav'
5+
6+
const Header = () => {
7+
const [activeMenu, setActiveMenu] = useState<string | null>(null)
8+
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
9+
10+
const toggleMobileMenu = () => {
11+
setIsMobileMenuOpen(!isMobileMenuOpen)
12+
}
13+
14+
const navItems = [
15+
{
16+
title: 'About',
17+
links: [
18+
{ name: '소개', path: '/about/introduction' },
19+
{ name: '조직도', path: '/about/organization' },
20+
],
21+
},
22+
{
23+
title: '활동 기록',
24+
links: [
25+
{ name: '활동 현황', path: '/activities/status' },
26+
{ name: '다솜 소식', path: '/activities/news' },
27+
],
28+
},
29+
{
30+
title: '가입안내',
31+
links: [{ name: '지원하기', path: '/join/apply' }],
32+
},
33+
]
34+
35+
return (
36+
<header
37+
onMouseLeave={() => setActiveMenu(null)}
38+
className={`w-full relative shadow-[2px_6px_11px_0px_rgba(0,0,0,0.25)] bg-mainBlack text-white transition-all duration-300 ease-in-out ${activeMenu ? 'md:h-[120px]' : 'md:h-[56px]'} h-[56px]`}>
39+
40+
<div className="w-full max-w-screen-xl mx-auto px-4">
41+
{/* 모바일 헤더 */}
42+
<div className="w-full h-[56px] flex md:hidden items-center justify-between">
43+
<Link to="/" className="text-mainColor text-2xl font-pretendardBlack">
44+
DASOM
45+
</Link>
46+
<button onClick={toggleMobileMenu} className="text-3xl hover:text-mainColor transition-colors duration-300">
47+
<Menu />
48+
</button>
49+
</div>
50+
51+
{/* 데탑용 헤더 */}
52+
<div className="w-full hidden md:block">
53+
<div className="flex items-center justify-between h-[56px]">
54+
<Link to="/" className="text-mainColor text-2xl font-pretendardBlack">DASOM</Link>
55+
<div className="flex items-center space-x-16">
56+
<nav className="flex items-center space-x-16 h-full">
57+
{navItems.map((item) => (
58+
<div
59+
key={item.title}
60+
onMouseEnter={() => setActiveMenu(item.title)}
61+
className="flex items-center h-[56px] cursor-pointer w-20 justify-center"
62+
>
63+
<span className="text-sm font-pretendardBold">{item.title}</span>
64+
</div>
65+
))}
66+
</nav>
67+
<Link to="/auth/login" className="text-sm font-pretendardBold whitespace-nowrap">로그인 / 회원가입</Link>
68+
</div>
69+
</div>
70+
</div>
71+
</div>
72+
73+
{/* 메뉴바 */}
74+
<div className={`absolute top-[56px] left-0 w-full bg-mainBlack transition-all duration-300 ease-in-out overflow-hidden hidden md:block ${activeMenu ? 'max-h-40' : 'max-h-0'}`}>
75+
<div className="w-full max-w-screen-xl mx-auto flex justify-end px-4">
76+
<div className="flex items-center space-x-16">
77+
<nav className="flex items-start space-x-16 h-full py-4">
78+
{navItems.map((item) => (
79+
<div key={item.title} className="flex h-full w-20 justify-center">
80+
<div className="flex flex-col items-center space-y-2">
81+
{item.links.map((link) => (
82+
<Link
83+
key={link.name}
84+
to={link.path}
85+
className={`text-sm font-pretendardRegular hover:text-mainColor whitespace-nowrap transition-opacity ${activeMenu === item.title ? 'opacity-100' : 'opacity-0'}`}>
86+
{link.name}
87+
</Link>
88+
))}
89+
</div>
90+
</div>
91+
))}
92+
</nav>
93+
<div className="invisible">
94+
<Link to="/auth/login" className="text-sm font-pretendardBold whitespace-nowrap">로그인 / 회원가입</Link>
95+
</div>
96+
</div>
97+
</div>
98+
</div>
99+
100+
{/* 모바일 메뉴바 */}
101+
{isMobileMenuOpen && <MobileNav navItems={navItems} onClose={toggleMobileMenu} />}
102+
</header>
103+
)
104+
}
105+
106+
export default Header
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react'
2+
import { Link } from 'react-router-dom'
3+
import { X } from 'lucide-react'
4+
5+
interface NavItem {
6+
title: string
7+
links: { name: string; path: string }[]
8+
}
9+
10+
interface MobileNavProps {
11+
navItems: NavItem[]
12+
onClose: () => void
13+
}
14+
15+
const MobileNav = ({ navItems, onClose }: MobileNavProps) => {
16+
return (
17+
<div className="fixed inset-0 bg-mainBlack z-50 flex flex-col items-center justify-center text-white">
18+
<button onClick={onClose} className="absolute top-5 right-5 text-4xl hover:text-mainColor transition-colors duration-300">
19+
<X />
20+
</button>
21+
<nav className="flex flex-col items-center space-y-8">
22+
{navItems.map((item) => (
23+
<div key={item.title} className="text-center">
24+
<h3 className="text-xl font-pretendardBold mb-4 hover:text-mainColor transition-colors duration-300">{item.title}</h3>
25+
<div className="flex flex-col space-y-3">
26+
{item.links.map((link) => (
27+
<Link
28+
key={link.name}
29+
to={link.path}
30+
onClick={onClose}
31+
className="text-lg font-pretendardRegular hover:text-mainColor transition-colors duration-300"
32+
>
33+
{link.name}
34+
</Link>
35+
))}
36+
</div>
37+
</div>
38+
))}
39+
<Link to="/auth/login" onClick={onClose} className="text-xl font-pretendardBold mt-8 hover:text-mainColor transition-colors duration-300">
40+
로그인 / 회원가입
41+
</Link>
42+
</nav>
43+
</div>
44+
)
45+
}
46+
47+
export default MobileNav

src/pages/UserMain.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import React from 'react'
22
import MobileLayout from '../components/layout/MobileLayout'
3-
import { Header } from '../components/UI/Header'
43

54
const UserMain: React.FC = () => {
65
return (
76
<MobileLayout>
8-
<Header />
7+
<div>User Main Page</div>
98
</MobileLayout>
109
)
1110
}

0 commit comments

Comments
 (0)