Skip to content

Commit b39839f

Browse files
authored
Merge pull request #22 from DguFarmSystem/Feature/#20
Feature/#20 메인페이지 반응형 작업(트랙 소개 제외)
2 parents c6e337e + 16c9a61 commit b39839f

25 files changed

+579
-286
lines changed

package-lock.json

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/assets/Icons/Hamburger.svg

Lines changed: 3 additions & 0 deletions
Loading

src/components/Header/Header.styled.tsx

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,24 @@ export const Nav = styled.nav`
2323
align-items: flex-end;
2424
justify-content: flex-start;
2525
gap: 30px;
26+
27+
@media (max-width: 768px) {
28+
display: none;
29+
}
2630
`;
2731

2832
export const NavItem = styled.a`
29-
position: relative;
30-
display: flex;
31-
flex-direction: column;
32-
align-items: center;
3333
text-decoration: none;
3434
font-size: 16px;
3535
font-weight: 500;
3636
color: #49aa59;
3737
cursor: pointer;
38-
margin-left: 30px;
38+
margin: 10px 0;
3939
&:hover {
4040
color: #28723f;
4141
}
4242
`;
4343

44-
export const NavLineActive = styled.img`
45-
position: absolute;
46-
top: 30px;
47-
width: 120px;
48-
`;
49-
50-
export const NavLineInactive = styled.img`
51-
position: absolute;
52-
top: 30px;
53-
width: 120px;
54-
`;
55-
5644
export const FarmingLogButton = styled.button`
5745
width: 120px;
5846
height: 40px;
@@ -69,3 +57,39 @@ export const FarmingLogButton = styled.button`
6957
background-color: #1f5a2f;
7058
}
7159
`;
60+
61+
export const HamburgerIcon = styled.img`
62+
width: 30px;
63+
height: 30px;
64+
cursor: pointer;
65+
66+
@media (min-width: 769px) {
67+
display: none;
68+
}
69+
`;
70+
71+
export const MobileNavWrapper = styled.div<{ $isMenuOpen: boolean }>`
72+
position: absolute;
73+
top: 70px;
74+
left: 0;
75+
width: 100%;
76+
background-color: #fcfcfc;
77+
display: flex;
78+
flex-direction: column;
79+
align-items: center;
80+
padding: 10px 0;
81+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
82+
z-index: 1000;
83+
overflow: hidden;
84+
height: ${({ $isMenuOpen }) => ($isMenuOpen ? "auto" : "0")};
85+
opacity: ${({ $isMenuOpen }) => ($isMenuOpen ? "1" : "0")};
86+
transform: ${({ $isMenuOpen }) => ($isMenuOpen ? "translateY(0)" : "translateY(-10px)")};
87+
transition: height 0.3s ease, opacity 0.3s ease, transform 0.3s ease;
88+
`;
89+
90+
export const MobileNav = styled.nav`
91+
display: flex;
92+
flex-direction: column;
93+
align-items: center;
94+
width: 100%;
95+
`;

src/components/Header/Header.tsx

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,58 @@
1-
import { useCallback } from 'react';
1+
import { useCallback, useState } from 'react';
22
import { useNavigate } from 'react-router';
33
import * as S from './Header.styled';
4+
import Popup from '../Popup/Popup';
5+
import Hamburger from '../../assets/Icons/Hamburger.svg';
6+
import useMediaQueries from '@/hooks/useMediaQueries';
47

58
export default function Header() {
9+
const [isPopupOpen, setPopupOpen] = useState(false);
10+
const [isMenuOpen, setMenuOpen] = useState(false);
611
const navigate = useNavigate();
7-
const onContainerClick = useCallback(() => {
8-
}, []);
12+
const { isMobile } = useMediaQueries();
13+
14+
const onContainerClick = useCallback(() => {}, []);
915

1016
return (
1117
<S.HeaderContainer>
1218
<S.Logo onClick={() => navigate('/')}>Farm System</S.Logo>
19+
20+
{isMobile ? (
21+
<S.HamburgerIcon src={Hamburger} alt="Menu" onClick={() => setMenuOpen(!isMenuOpen)} />
22+
) : (
23+
<>
24+
<S.Nav>
25+
<S.NavItem onClick={() => navigate('/')}></S.NavItem>
26+
<S.NavItem onClick={() => setPopupOpen(true)}>블로그 / 프로젝트</S.NavItem>
27+
<S.NavItem onClick={() => setPopupOpen(true)}>소식</S.NavItem>
28+
<S.NavItem onClick={() => setPopupOpen(true)}>FAQ</S.NavItem>
29+
<S.NavItem onClick={() => navigate('/apply')}>지원하기</S.NavItem>
30+
</S.Nav>
1331

14-
<S.Nav>
15-
<S.NavItem onClick={() => navigate('/')}>
16-
17-
</S.NavItem>
18-
<S.NavItem onClick={() => navigate('/blog-project')}>
19-
블로그 / 프로젝트
20-
</S.NavItem>
21-
<S.NavItem onClick={() => navigate('/news')}>
22-
소식
23-
</S.NavItem>
24-
<S.NavItem onClick={() => navigate('/faq')}>
25-
FAQ
26-
</S.NavItem>
27-
<S.NavItem onClick={() => navigate('/apply')}>
28-
지원하기
29-
</S.NavItem>
30-
</S.Nav>
31-
32-
{/* 파밍로그 버튼 */}
33-
<S.FarmingLogButton onClick={onContainerClick}>파밍로그</S.FarmingLogButton>
32+
{/* 파밍로그 버튼 */}
33+
<S.FarmingLogButton onClick={onContainerClick}>파밍로그</S.FarmingLogButton>
34+
</>
35+
)}
36+
37+
<S.MobileNavWrapper $isMenuOpen={isMenuOpen}>
38+
{isMobile && (
39+
<S.MobileNav>
40+
<S.NavItem onClick={() => navigate('/')}></S.NavItem>
41+
<S.NavItem onClick={() => setPopupOpen(true)}>블로그 / 프로젝트</S.NavItem>
42+
<S.NavItem onClick={() => setPopupOpen(true)}>소식</S.NavItem>
43+
<S.NavItem onClick={() => setPopupOpen(true)}>FAQ</S.NavItem>
44+
<S.NavItem onClick={() => navigate('/apply')}>지원하기</S.NavItem>
45+
<S.NavItem onClick={() => setPopupOpen(true)}>파밍로그</S.NavItem>
46+
</S.MobileNav>
47+
)}
48+
</S.MobileNavWrapper>
49+
50+
<Popup
51+
isOpen={isPopupOpen}
52+
onClose={() => setPopupOpen(false)}
53+
title={"아직 오픈되지 않았습니다."}
54+
content={"오픈 예정: 2025년 4월"}
55+
/>
3456
</S.HeaderContainer>
3557
);
36-
}
58+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import styled from 'styled-components';
2+
3+
export const PopupOverlay = styled.div`
4+
position: fixed;
5+
inset: 0;
6+
background: rgba(113, 113, 113, 0.3);
7+
display: flex;
8+
align-items: center;
9+
justify-content: center;
10+
z-index: 9999;
11+
`;
12+
13+
export const PopupBox = styled.div`
14+
width: 500px;
15+
background-color: #fcfcfc;
16+
border: 3px solid #28723f;
17+
border-radius: 15px;
18+
text-align: center;
19+
padding: 40px;
20+
z-index: 10000;
21+
`;
22+
23+
export const PopupTitle = styled.p`
24+
font-size: 22px;
25+
font-weight: 700;
26+
color: black;
27+
margin-bottom: 20px;
28+
`;
29+
30+
export const PopupText = styled.p`
31+
font-size: 18px;
32+
color: black;
33+
margin-bottom: 20px;
34+
`;
35+
36+
export const PopupCloseButton = styled.button`
37+
background-color: #28723f;
38+
color: #fcfcfc;
39+
font-size: 16px;
40+
padding: 10px 20px;
41+
border: none;
42+
border-radius: 10px;
43+
cursor: pointer;
44+
box-shadow: 0px 2px 10px rgba(25, 25, 25, 0.2);
45+
width: 100px;
46+
margin-top: 20px;
47+
&:hover {
48+
background-color: #1f5b30;
49+
}
50+
`;

src/components/Popup/Popup.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
import * as S from './Popup.styled';
3+
4+
interface PopupProps {
5+
isOpen: boolean;
6+
onClose: () => void;
7+
title: string;
8+
content: string;
9+
}
10+
11+
const Popup: React.FC<PopupProps> = ({ isOpen, onClose, title, content }) => {
12+
if (!isOpen) return null;
13+
14+
return (
15+
<S.PopupOverlay onClick={onClose}>
16+
<S.PopupBox onClick={(e) => e.stopPropagation()}>
17+
<S.PopupTitle>{title}</S.PopupTitle>
18+
<S.PopupText>{content}</S.PopupText>
19+
<S.PopupCloseButton onClick={onClose}>확인</S.PopupCloseButton>
20+
</S.PopupBox>
21+
</S.PopupOverlay>
22+
);
23+
};
24+
25+
export default Popup;

src/pages/Main/Achievements/AchievementItem.styles.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
11
import styled from 'styled-components';
22

3-
export const ItemContainer = styled.div`
4-
width: 400px;
5-
height: 400px;
6-
background-color:#175321;
3+
export const ItemContainer = styled.div<{ $isMobile: boolean; $isTablet: boolean }>`
4+
width: ${({ $isMobile, $isTablet }) => ($isMobile ? "280px" : $isTablet ? "330px" : "390px")};
5+
height: ${({ $isMobile, $isTablet }) => ($isMobile ? "280px" : $isTablet ? "330px" : "390px")};
6+
margin-left: 30px;
7+
margin-right: 30px;
8+
background-color: #175321;
79
border-radius: 10px;
810
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
911
overflow: hidden;
1012
text-align: center;
1113
`;
1214

13-
export const Image = styled.img`
15+
export const Image = styled.img<{ $isMobile: boolean }>`
1416
width: 100%;
15-
height: 180px;
17+
height: ${({ $isMobile }) => ($isMobile ? "140px" : "180px")};
1618
object-fit: cover;
1719
`;
1820

19-
export const Content = styled.div`
20-
padding: 20px;
21+
export const Content = styled.div<{ $isMobile: boolean }>`
22+
padding: ${({ $isMobile }) => ($isMobile ? "10px" : "20px")};
2123
`;
2224

23-
export const Title = styled.h3`
24-
font-size: 14px;
25+
export const Title = styled.h3<{ $isMobile: boolean }>`
26+
font-size: ${({ $isMobile }) => ($isMobile ? "12px" : "14px")};
2527
color: #fcfcfc;
2628
`;
2729

28-
export const Description = styled.p`
29-
font-size: 20px;
30+
export const Description = styled.p<{ $isMobile: boolean }>`
31+
font-size: ${({ $isMobile }) => ($isMobile ? "16px" : "20px")};
3032
font-weight: bold;
3133
color: #fcfcfc;
3234
line-height: 1.5;

src/pages/Main/Achievements/AchievementItem.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as S from './AchievementItem.styles';
2+
import useMediaQueries from '@/hooks/useMediaQueries';
23

34
interface AchievementItemProps {
45
title: string;
@@ -7,12 +8,14 @@ interface AchievementItemProps {
78
}
89

910
const AchievementItem: React.FC<AchievementItemProps> = ({ title, description, imageUrl }) => {
11+
const { isMobile, isTablet } = useMediaQueries();
12+
1013
return (
11-
<S.ItemContainer>
12-
<S.Image src={imageUrl} alt={title} />
13-
<S.Content>
14-
<S.Title>{title}</S.Title>
15-
<S.Description>{description}</S.Description>
14+
<S.ItemContainer $isMobile={isMobile} $isTablet={isTablet}>
15+
<S.Image src={imageUrl} alt={title} $isMobile={isMobile} />
16+
<S.Content $isMobile={isMobile}>
17+
<S.Title $isMobile={isMobile}>{title}</S.Title>
18+
<S.Description $isMobile={isMobile}>{description}</S.Description>
1619
</S.Content>
1720
</S.ItemContainer>
1821
);

0 commit comments

Comments
 (0)