Skip to content

Commit 320c195

Browse files
authored
Merge pull request #235 from CSE-Shaco/develop
feat(event/homecoming): 레이아웃 구성 완료, TODO: 타이포 및 문구 작성
2 parents 12c1d10 + 3392cef commit 320c195

File tree

9 files changed

+228
-91
lines changed

9 files changed

+228
-91
lines changed

public/images/logo.png

8.7 KB
Loading

src/app/event/homecoming/component/mobile/HomecomingMobile.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ export default function HomecomingMobile() {
4040
{/* 상단 고정 영역 */}
4141
<div className="px-4 pt-4 fixed z-10">
4242
<header className="flex items-center gap-2 mb-6">
43-
<img src="/logo.png" alt="GDGoC logo" className="h-6 w-auto"/>
43+
<img src="/images/logo.png" alt="GDGoC logo" className="h-6 w-auto"/>
4444
</header>
4545

4646
<div className="w-full max-w-[390px] left-1/2 -translate-x-1/2 fixed">
4747
<img
48-
src="/homecoming_main_img.png"
48+
src="/images/homecoming/main_img.png"
4949
alt="Homecoming illustration"
5050
className="h-auto block"
5151
/>

src/app/event/homecoming/component/pc/Frame.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export default function Frame() {
1313
h-10 w-[732px]
1414
rounded-full bg-cred
1515
-translate-y-1/2
16-
-rotate-15
16+
-rotate-[15deg]
1717
"
1818
/>
1919

@@ -24,7 +24,7 @@ export default function Frame() {
2424
h-10 w-[732px]
2525
rounded-full bg-cblue
2626
-translate-y-1/2
27-
rotate-15
27+
rotate-[15deg]
2828
"
2929
/>
3030
</div>

src/app/event/homecoming/component/pc/FrameLayout.jsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import Frame from './Frame';
55
import FrameViewport from './FrameViewport';
66
import ScrollDots from './ScrollDots';
77

8-
export default function FrameLayout({visible}) {
8+
export default function FrameLayout() {
99
const viewportRef = useRef(null);
1010
const [activeIndex, setActiveIndex] = useState(0);
1111
const TOTAL = 4;
12+
const SCROLL_DAMPING = 0.2;
13+
const MAX_DELTA = 60;
1214

1315
const onScroll = () => {
1416
const el = viewportRef.current;
@@ -24,17 +26,18 @@ export default function FrameLayout({visible}) {
2426
};
2527

2628
const onWheel = (e) => {
27-
if (!visible) return;
2829
const el = viewportRef.current;
2930
if (!el) return;
3031

31-
// 내부가 스크롤 가능할 때만 page 스크롤을 막고 내부로 보냄
32-
const delta = e.deltaY;
32+
const raw = e.deltaY;
33+
const clamped = Math.max(-MAX_DELTA, Math.min(MAX_DELTA, raw));
34+
const delta = clamped * SCROLL_DAMPING;
35+
3336
const atTop = el.scrollTop <= 0;
3437
const atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 1;
3538
const canScrollInside = (delta > 0 && !atBottom) || (delta < 0 && !atTop);
3639

37-
if (!canScrollInside) return; // 내부 못 움직이면 바깥 스크롤/스냅에 맡김
40+
if (!canScrollInside) return;
3841

3942
e.preventDefault();
4043
el.scrollTop += delta;
@@ -43,7 +46,6 @@ export default function FrameLayout({visible}) {
4346
return (<div
4447
className={`
4548
absolute inset-0 w-[1400px] h-[1000px] m-auto pt-60 pb-10
46-
${visible ? '' : 'hidden'}
4749
`}
4850
onWheel={onWheel}
4951
>

src/app/event/homecoming/component/pc/FrameSection.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
export default function FrameSection({ children }) {
44
return (
5-
<section className="h-full w-full snap-start flex items-center justify-center">
5+
<section className="h-full w-full snap-start justify-center text-white">
66
{children}
77
</section>
88
);

src/app/event/homecoming/component/pc/FrameViewport.jsx

Lines changed: 110 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,121 @@
22

33
import React, {forwardRef} from 'react';
44
import FrameSection from './FrameSection';
5+
import {GoogleMap, Marker, useJsApiLoader} from "@react-google-maps/api";
56

67
const FrameViewport = forwardRef(function FrameViewport({onScroll}, ref) {
78
return (<div
8-
ref={ref}
9-
onScroll={onScroll}
10-
className="
9+
ref={ref}
10+
onScroll={onScroll}
11+
className="
1112
relative
1213
h-full w-full
13-
overflow-y-auto no-scrollbar
14-
snap-y snap-mandatory
14+
overflow-y-auto no-scrollbar snap-y snap-mandatory font-pretendard text-cwhite
1515
"
16-
>
17-
<FrameSection><p>1st</p></FrameSection>
18-
<FrameSection><p>2nd</p></FrameSection>
19-
<FrameSection><p>3rd</p></FrameSection>
20-
<FrameSection><p>4th</p></FrameSection>
21-
</div>);
16+
>
17+
<FrameSection><FirstSection/></FrameSection>
18+
<FrameSection><SecondSection/></FrameSection>
19+
<FrameSection><ThirdSection/></FrameSection>
20+
<FrameSection><FourthSection/></FrameSection>
21+
</div>);
2222
});
2323

24-
export default FrameViewport;
24+
export default FrameViewport;
25+
26+
function FirstSection() {
27+
return (<div className="flex flex-col justify-center pt-16">
28+
{/* 로고 */}
29+
<div className="flex items-center font-ocra tracking-tight text-6xl self-center font-bold">
30+
<span className="text-cred">G</span>
31+
<span className="text-cgreen">D</span>
32+
<span className="text-cyellow">G</span>
33+
<span className="text-cblue">o</span>
34+
<span className="text-cred mr-2">C</span>
35+
<span className="text-cwhite ml-1">INHA</span>
36+
</div>
37+
<div className="mt-8 flex text-8xl self-center font-bold">제 1회 홈커밍 데이</div>
38+
<p className="mt-20 pl-80"><strong>GDGoC HomeComing : Networking with INCHEON</strong>
39+
<br/>
40+
오후 1시 입장을 시작으로, <strong>1부 프로젝트 성과 발표회</strong><strong>시상</strong>,
41+
<br/>
42+
이후 <strong>특강 세션과 Cross-Chapter 오프닝</strong>을 거쳐
43+
<br/>
44+
<strong>팀별 경쟁 게임·퀴즈·네트워킹 프로그램</strong>으로 이어지는 구성입니다.
45+
<br/>
46+
행사는 <strong>13:00–19:00</strong>까지 진행되며,
47+
<br/>
48+
마지막에는 <strong>전체 교류를 마무리하는 네트워킹 및 뒤풀이 이동</strong>으로 마무리됩니다.</p>
49+
</div>);
50+
}
51+
52+
function SecondSection() {
53+
return (<div className="flex flex-col text-center">
54+
<div className="flex items-center text-6xl self-center font-bold">
55+
2025년 12월 20일 (토)
56+
</div>
57+
<div className="mt-8 flex items-center text-5xl self-center font-bold left-1/3">
58+
1부
59+
</div>
60+
61+
</div>)
62+
}
63+
64+
function ThirdSection() {
65+
return (<div className="flex flex-col text-center">
66+
<div className="flex items-center text-6xl self-center font-bold">
67+
2025년 12월 20일 (토)
68+
</div>
69+
<div className="mt-8 flex items-center text-5xl self-center font-bold left-1/3">
70+
2부
71+
</div>
72+
73+
</div>)
74+
}
75+
76+
function FourthSection() {
77+
return (<div className="flex flex-col text-center">
78+
<div className="flex items-center text-6xl self-center font-bold">
79+
신한 스퀘어 브릿지 인천
80+
</div>
81+
<div className="mt-8 flex items-center text-2xl self-center font-medium">
82+
(인천광역시 연수구 컨벤시아대로 204 인스타2)
83+
</div>
84+
85+
<HomecomingMap/>
86+
</div>)
87+
88+
}
89+
90+
91+
function HomecomingMap() {
92+
const {isLoaded, loadError} = useJsApiLoader({
93+
googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY, id: 'homecoming-map-script',
94+
});
95+
96+
const center = {lat: 37.388493, lng: 126.639989};
97+
98+
if (loadError) {
99+
return (<div
100+
className="rounded-2xl border border-red-300 bg-red-50 text-red-700 text-xs md:text-sm flex items-center justify-center h-[220px] md:h-[320px] lg:h-[420px]">
101+
지도를 불러오는 중 오류가 발생했습니다.
102+
</div>);
103+
}
104+
105+
if (!isLoaded) {
106+
return (<div
107+
className="rounded-2xl border border-neutral-200 bg-neutral-100 text-neutral-500 text-xs md:text-sm flex items-center justify-center h-[220px] md:h-[320px] lg:h-[420px]">
108+
지도를 불러오는 중입니다...
109+
</div>);
110+
}
111+
112+
return (<div className="mt-16 rounded-2xl w-[1000px] h-[400px] overflow-hidden self-center">
113+
<GoogleMap
114+
mapContainerClassName="w-full h-full"
115+
center={center}
116+
zoom={17}
117+
options={{disableDefaultUI: true, clickableIcons: false}}
118+
>
119+
<Marker position={center}/>
120+
</GoogleMap>
121+
</div>);
122+
}
Lines changed: 56 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,68 @@
11
'use client';
22

3-
import {useEffect} from "react";
4-
5-
export default function HeroIntro({userName, phase, onEnter}) {
6-
useEffect(() => {
7-
const onWheel = (e) => {
8-
if (e.deltaY > 0) {
9-
onEnter();
10-
}
11-
};
12-
window.addEventListener('wheel', onWheel, {passive: true});
13-
return () => window.removeEventListener('wheel', onWheel);
14-
}, [onEnter]);
15-
16-
return (<div className="absolute inset-0 z-20 overflow-hidden">
17-
<img
18-
src="/homecoming_main_img.png"
19-
alt=""
3+
export default function HeroIntro({userName, phase, onEnter, leaving}) {
4+
return (<div
205
className={`
21-
absolute inset-0 m-auto w-[72vw] max-w-[1400px]
6+
absolute inset-0 overflow-hidden
7+
transition-[opacity,transform,filter]
8+
duration-700 ease-out will-change-transform
9+
${leaving ? 'opacity-0 scale-90 translate-y-8 blur-sm' : 'opacity-100 scale-100 translate-y-0 blur-0'}
10+
`}
11+
>
12+
{/* 배경 */}
13+
<img
14+
src="/images/homecoming/main_img.png"
15+
alt=""
16+
className={`
17+
absolute inset-0 m-auto
18+
w-full h-auto max-w-[1400px]
2219
transition-opacity duration-1000 ease-out
23-
${phase ? 'opacity-30' : 'opacity-100'}
20+
${phase ? 'opacity-20' : 'opacity-100'}
2421
`}
25-
/>
22+
/>
2623

27-
{/* 글자: phase=1 되면 떠오르며 등장 */}
28-
<div className="absolute inset-0 grid place-items-center">
29-
<div
30-
className={`
31-
flex flex-col items-center -translate-y-4
24+
{/* 콘텐츠 */}
25+
<div className="absolute inset-0 grid place-items-center">
26+
<div
27+
className={`
28+
flex flex-col items-center
3229
transition-all duration-1000 ease-out
33-
${phase ? 'opacity-100 translate-y-0 scale-100' : 'opacity-0 translate-y-12 scale-95'}
30+
${phase ? 'opacity-100 -translate-y-4 scale-100' : 'opacity-0 translate-y-12 scale-95'}
3431
`}
35-
>
36-
<div className="flex items-center font-ocra tracking-tight text-[2.8vw] max-[1200px]:text-[44px]">
37-
<span className="text-cred">G</span>
38-
<span className="text-cgreen">D</span>
39-
<span className="text-cyellow">G</span>
40-
<span className="text-cblue">o</span>
41-
<span className="text-cred mr-2">C</span>
42-
<span className="text-white ml-1">INHA</span>
43-
</div>
32+
>
33+
{/* 로고 */}
34+
<div className="flex items-center font-ocra tracking-tight text-6xl">
35+
<span className="text-cred">G</span>
36+
<span className="text-cgreen">D</span>
37+
<span className="text-cyellow">G</span>
38+
<span className="text-cblue">o</span>
39+
<span className="text-cred mr-2">C</span>
40+
<span className="text-cwhite ml-1">INHA</span>
41+
</div>
4442

45-
<p className="text-center text-white leading-snug text-[2.4vw] max-[1200px]:text-[34px]">
46-
<span className="font-extrabold">제 1회 홈커밍 데이</span>{' '}
47-
{userName ? (<>
48-
<span className="font-extrabold">{userName}</span>님을 초대합니다!
49-
</>) : (<>여러분을 초대합니다!</>)}
50-
</p>
51-
</div>
43+
{/* 문구 */}
44+
<p className="text-center text-cwhite text-4xl leading-snug">
45+
<span className="font-extrabold">제 1회 홈커밍 데이</span>{' '}
46+
{userName ? (<>
47+
<span className="font-extrabold">{userName}</span>님을 초대합니다!
48+
</>) : (<>여러분을 초대합니다!</>)}
49+
</p>
5250

53-
{/* 아래 화살표(인트로 전용) */}
54-
<div className="absolute bottom-10 left-1/2 -translate-x-1/2 h-[52px] w-[326px] animate-floatY">
55-
<div
56-
className="absolute left-0 h-2 w-[169.5px] translate-y-[26px] rotate-15 rounded-full bg-cwhite"/>
57-
<div
58-
className="absolute right-0 h-2 w-[169.5px] translate-y-[26px] -rotate-15 rounded-full bg-cwhite"/>
51+
{/* CTA 버튼 */}
52+
<button
53+
onClick={onEnter}
54+
className="
55+
mt-12 px-8 py-4
56+
rounded-full
57+
bg-cwhite text-cblack font-semibold
58+
transition-all duration-300
59+
hover:scale-105 hover:bg-cwhite
60+
active:scale-95
61+
"
62+
>
63+
초대장 펼쳐보기
64+
</button>
65+
</div>
5966
</div>
60-
</div>
61-
</div>);
67+
</div>);
6268
}

0 commit comments

Comments
 (0)