Skip to content

Commit 8729ca3

Browse files
authored
Merge pull request #489 from TEAM-HOUME/feat/home-view/#472
[feat] Home 탐색 뷰 리뉴얼 및 공컴 구현
2 parents 994f61a + 1b4a2f9 commit 8729ca3

37 files changed

+987
-568
lines changed

src/pages/home/HomePage.css.ts

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,12 @@
11
import { style } from '@vanilla-extract/css';
22

33
import { colorVars } from '@styles/tokens/color.css';
4-
import { zIndex } from '@styles/tokens/zIndex';
54

65
export const page = style({
76
position: 'relative',
87
display: 'flex',
98
flexDirection: 'column',
109
alignItems: 'center',
11-
background: colorVars.color.bg_grad,
12-
width: '100%',
13-
});
14-
15-
export const gradFrame = style({
16-
display: 'flex',
17-
flexDirection: 'column',
18-
alignItems: 'center',
19-
background:
20-
'linear-gradient(180deg, #A696FF -15.93%, #DDD6FF 13.05%, #FFF 47.05%, #FFF 100%)',
21-
width: '100%',
22-
height: '55.65rem',
23-
});
24-
25-
export const introSection = style({
26-
display: 'flex',
27-
flexDirection: 'column',
28-
alignItems: 'center',
29-
padding: '1.6rem 2rem 0 2rem',
3010
width: '100%',
3111
});
3212

@@ -38,15 +18,10 @@ export const contents = style({
3818
width: '100%',
3919
});
4020

41-
export const buttonContainer = style({
42-
position: 'fixed',
43-
zIndex: zIndex.button,
44-
bottom: '0',
21+
export const tabContentView = style({
4522
display: 'flex',
23+
flexDirection: 'column',
4624
alignItems: 'center',
47-
justifyContent: 'center',
48-
marginTop: '4rem',
49-
padding: '0rem 2rem 2rem 2rem',
5025
width: '100%',
51-
maxWidth: '44rem',
26+
minHeight: '20rem',
5227
});

src/pages/home/HomePage.tsx

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef } from 'react';
1+
import { useEffect, useRef, useState } from 'react';
22

33
import { useNavigate } from 'react-router-dom';
44

@@ -8,24 +8,25 @@ import { ROUTES } from '@routes/paths';
88

99
import { useUserStore } from '@store/useUserStore';
1010

11-
import CtaButton from '@components/button/ctaButton/CtaButton';
12-
import LogoNavBar from '@components/navBar/LogoNavBar';
11+
import MenuTab from '@components/v2/menuTab/MenuTab';
12+
import LogoNavBar from '@components/v2/navBar/LogoNavBar';
1313

14-
import AnimatedSection from './components/AnimatedSection';
15-
import IntroSection from './components/introSection/IntroSection';
16-
import ReviewSection from './components/reviewSection/ReviewSection';
17-
import StepGuideSection from './components/stepGuideSection/StepGuideSection';
14+
import ExploreTab from './components/explore/ExploreTab';
15+
import ProductTab from './components/product/ProductTab';
1816
import * as styles from './HomePage.css';
1917
import {
2018
logLandingClickBtnCTA,
2119
logLandingClickBtnMypage,
2220
logLandingScrollDepthTreshold,
2321
} from './utils/analytics';
2422

23+
export type HomeMenuTab = 'explore' | 'product';
24+
2525
const HomePage = () => {
2626
const navigate = useNavigate();
2727
const accessToken = useUserStore((state) => state.accessToken);
2828
const isLoggedIn = !!accessToken;
29+
const [activeMenuTab, setActiveMenuTab] = useState<HomeMenuTab>('explore');
2930

3031
const scrollDepth50Sent = useRef(false);
3132
const scrollDepth100Sent = useRef(false);
@@ -70,24 +71,12 @@ const HomePage = () => {
7071
};
7172
}, []);
7273

73-
/**
74-
* 플로팅 버튼 텍스트 결정
75-
* - 로그인 안됨: "우리집에 딱 맞는 스타일 만들기"
76-
* - 로그인됨 + 로딩중: "로딩중..."
77-
* - 로그인됨: "우리집에 딱 맞는 스타일 만들기"
78-
*/
79-
const getButtonText = () => {
80-
if (!isLoggedIn) return '우리집에 딱 맞는 스타일 만들기';
81-
if (isUserDataLoading) return '로딩중...';
82-
return '우리집에 딱 맞는 스타일 만들기';
83-
};
84-
8574
/**
8675
* 플로팅 버튼 클릭 핸들러
8776
* - 로그인 안됨: 로그인 페이지로 이동
8877
* - 로그인됨: imageSetup 이미지 생성 플로우로 이동 (크레딧 체크는 ActivityInfo에서 수행)
8978
*/
90-
const handleCtaButtonClick = () => {
79+
const handleGenerate = () => {
9180
logLandingClickBtnCTA();
9281

9382
if (!isLoggedIn) {
@@ -102,36 +91,37 @@ const HomePage = () => {
10291
};
10392

10493
// 프로필 버튼 클릭 핸들러 (마이페이지 버튼 클릭 이벤트 전송)
105-
const handleProfileClick = () => {
94+
const handleProfile = () => {
10695
if (isLoggedIn) {
10796
logLandingClickBtnMypage();
10897
}
10998
navigate(ROUTES.MYPAGE);
11099
};
111100

101+
const handleLogin = () => {
102+
navigate(ROUTES.LOGIN);
103+
};
104+
112105
return (
113106
<main className={styles.page}>
114-
<div className={styles.gradFrame}>
115-
<LogoNavBar
116-
buttonType={isLoggedIn ? 'profile' : 'login'}
117-
onProfileClick={isLoggedIn ? handleProfileClick : undefined}
118-
/>
119-
<div className={styles.introSection}>
120-
<IntroSection />
121-
</div>
122-
</div>
123-
<div className={styles.contents}>
124-
<StepGuideSection />
125-
<AnimatedSection animationType="fadeInUp" delay={200} duration={1000}>
126-
<ReviewSection />
127-
</AnimatedSection>
128-
</div>
129-
<div className={styles.buttonContainer}>
130-
{/* 로그인 상태에 따라 하단 플로팅 버튼 동적 변경 */}
131-
<CtaButton onClick={handleCtaButtonClick} isActive={!isUserDataLoading}>
132-
{getButtonText()}
133-
</CtaButton>
134-
</div>
107+
<LogoNavBar
108+
page="home"
109+
showGenerateButton
110+
authSlot={isLoggedIn ? 'profile' : 'login'}
111+
onGenerateClick={handleGenerate}
112+
onProfileClick={handleProfile}
113+
onLoginClick={handleLogin}
114+
/>
115+
<MenuTab
116+
tabs={[
117+
{ value: 'explore', label: '탐색' },
118+
{ value: 'product', label: '상품' },
119+
]}
120+
activeTab={activeMenuTab}
121+
onTabChange={setActiveMenuTab}
122+
/>
123+
{activeMenuTab === 'explore' && <ExploreTab />}
124+
{activeMenuTab === 'product' && <ProductTab />}
135125
</main>
136126
);
137127
};

src/pages/home/components/AnimatedSection.tsx

Lines changed: 0 additions & 74 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { style } from '@vanilla-extract/css';
2+
3+
import { unitVars } from '@styles/tokensV2/unit.css';
4+
5+
export const container = style({
6+
boxSizing: 'border-box',
7+
display: 'flex',
8+
flexDirection: 'column',
9+
alignItems: 'stretch',
10+
alignSelf: 'stretch',
11+
width: '100%',
12+
minWidth: 0,
13+
maxWidth: unitVars.unit.dimension.wMax,
14+
});
15+
16+
export const content = style({
17+
display: 'flex',
18+
flexDirection: 'column',
19+
alignItems: 'center',
20+
gap: unitVars.unit.gapPadding['800'],
21+
padding: unitVars.unit.gapPadding['500'],
22+
width: '100%',
23+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import Banner, {
2+
type BannerSlide,
3+
} from '@pages/home/components/explore/banner/Banner';
4+
5+
import imgBanner01 from '@assets/v2/images/ImgBanner_01.png';
6+
import imgBanner02 from '@assets/v2/images/ImgBanner_02.png';
7+
import imgBanner03 from '@assets/v2/images/ImgBanner_03.png';
8+
import imgBanner04 from '@assets/v2/images/ImgBanner_04.png';
9+
10+
import * as styles from './ExploreTab.css';
11+
import RoomTypeSection from './RoomTypeSection/RoomTypeSection';
12+
import StyleSection from './StyleSection/StyleSection';
13+
14+
const BANNER_SLIDES_MOCK: BannerSlide[] = [
15+
{ id: 1, title: '잦은 재택근무에 딱 맞는', imageUrl: imgBanner01 },
16+
{ id: 2, title: '창가에서 브런치 즐기는', imageUrl: imgBanner02 },
17+
{ id: 3, title: '친구 초대하기 좋은', imageUrl: imgBanner03 },
18+
{ id: 4, title: 'OTT 감상하기 좋은', imageUrl: imgBanner04 },
19+
];
20+
21+
const ExploreTab = () => {
22+
const handleBannerSlideClick = (_slide: BannerSlide) => {
23+
// TODO: 슬라이드별 디테일 페이지 이동 등 연동
24+
};
25+
26+
return (
27+
<div className={styles.container}>
28+
<Banner
29+
slides={BANNER_SLIDES_MOCK}
30+
onSlideClick={handleBannerSlideClick}
31+
/>
32+
<div className={styles.content}>
33+
<RoomTypeSection />
34+
<StyleSection />
35+
</div>
36+
</div>
37+
);
38+
};
39+
40+
export default ExploreTab;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { style } from '@vanilla-extract/css';
2+
3+
import { colorVars } from '@styles/tokensV2/color.css';
4+
import { fontVars } from '@styles/tokensV2/font.css';
5+
import { unitVars } from '@styles/tokensV2/unit.css';
6+
7+
export const section = style({
8+
display: 'flex',
9+
flexDirection: 'column',
10+
gap: unitVars.unit.gapPadding['400'],
11+
width: '100%',
12+
});
13+
14+
export const headerRow = style({
15+
display: 'flex',
16+
alignItems: 'center',
17+
justifyContent: 'space-between',
18+
width: '100%',
19+
});
20+
21+
export const sectionTitle = style({
22+
...fontVars.font.title_sb_16,
23+
padding: `0 ${unitVars.unit.gapPadding['100']}`,
24+
color: colorVars.color.text.primary,
25+
});
26+
27+
export const cardScroll = style({
28+
margin: `0 calc(${unitVars.unit.gapPadding['500']} * -1)`,
29+
width: `calc(100% + ${unitVars.unit.gapPadding['500']} * 2)`,
30+
overflowX: 'auto',
31+
overflowY: 'hidden',
32+
selectors: {
33+
'&::-webkit-scrollbar': {
34+
display: 'none',
35+
},
36+
},
37+
});
38+
39+
export const cardList = style({
40+
display: 'flex',
41+
flexWrap: 'nowrap',
42+
gap: unitVars.unit.gapPadding['200'],
43+
padding: `0 ${unitVars.unit.gapPadding['500']}`,
44+
width: 'max-content',
45+
});

0 commit comments

Comments
 (0)