Skip to content

Commit 9162a57

Browse files
authored
Merge pull request #325 from DguFarmSystem/feat/#322
[Feat] S3를 활용한 대량 게임 랜딩 페이지 퍼블리싱 수정
2 parents 1084d4d + 119de22 commit 9162a57

File tree

3 files changed

+113
-13
lines changed

3 files changed

+113
-13
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { useEffect, useState } from "react";
2+
3+
/**
4+
* 문서 전체 높이(가 임계값을 넘는지 감지하는 훅입니다
5+
* 기본 임계값 3000px이며, 리사이즈/레이아웃 변경에 반응
6+
*/
7+
export default function useTallPage(threshold: number = 3000): boolean {
8+
const [isTall, setIsTall] = useState<boolean>(false);
9+
10+
useEffect(() => {
11+
const getPageHeight = () => document.documentElement.scrollHeight;
12+
13+
// 동일 프레임 내 여러번 호출 방지
14+
let rafId: number | null = null;
15+
const evaluate = () => {
16+
if (rafId != null) return;
17+
rafId = window.requestAnimationFrame(() => {
18+
rafId = null;
19+
setIsTall(getPageHeight() > threshold);
20+
});
21+
};
22+
23+
// 최초 1회 평가
24+
evaluate();
25+
26+
let ro: ResizeObserver | null = null;
27+
let bodyRo: ResizeObserver | null = null;
28+
let mo: MutationObserver | null = null;
29+
30+
// 레이아웃 변화에 반응함
31+
if (typeof ResizeObserver !== "undefined") {
32+
ro = new ResizeObserver(() => {
33+
evaluate();
34+
});
35+
ro.observe(document.documentElement);
36+
37+
// body 높이 변화도 감지함
38+
if (document.body) {
39+
bodyRo = new ResizeObserver(() => {
40+
evaluate();
41+
});
42+
bodyRo.observe(document.body);
43+
}
44+
} else {
45+
// fallback 윈도우 리사이즈 시 반응함
46+
window.addEventListener("resize", evaluate);
47+
}
48+
49+
// DOM 변동에 반응함
50+
if (typeof MutationObserver !== "undefined" && document.body) {
51+
mo = new MutationObserver(() => {
52+
evaluate();
53+
});
54+
mo.observe(document.body, {
55+
subtree: true,
56+
childList: true,
57+
attributes: false,
58+
});
59+
}
60+
61+
// 추가 이벤트: 방향 전환 등
62+
window.addEventListener("orientationchange", evaluate);
63+
64+
return () => {
65+
if (ro) ro.disconnect();
66+
if (bodyRo) bodyRo.disconnect();
67+
if (mo) mo.disconnect();
68+
else window.removeEventListener("resize", evaluate);
69+
window.removeEventListener("orientationchange", evaluate);
70+
if (rafId != null) cancelAnimationFrame(rafId);
71+
};
72+
}, [threshold]);
73+
74+
return isTall;
75+
}
76+
77+

apps/farminglog/src/pages/game/index.styled.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,27 +128,28 @@ export const LandingHero = styled.div<{
128128
$bgDesktop: string;
129129
$bgMobile?: string;
130130
}>`
131-
width: 100%;
132-
height: 59760px;
131+
width: 1200px;
132+
margin: 0 auto;
133+
height: 35000px;
133134
134135
135-
background: ${({ $bgDesktop }) => `url(${$bgDesktop}) center / cover no-repeat`};
136+
background: ${({ $bgDesktop }) => `url(${$bgDesktop}) center / contain no-repeat`};
136137
137138
138139
// 모바일에선 잘모르겠음 일단 때리쳐!
139140
@media (max-width: 768px) {
140141
aspect-ratio: 750 / 2237;
141142
background-image: ${({ $bgDesktop, $bgMobile }) =>
142143
`url(${($bgMobile && $bgMobile.length > 0) ? $bgMobile : $bgDesktop})`};
143-
background-size: cover;
144+
background-size: contain;
144145
background-position: center;
145146
}
146147
`;
147148

148149
export const UpButton = styled.div`
149150
position: fixed;
150-
bottom: 100px;
151-
right: 100px;
151+
bottom: 70px;
152+
right: 70px;
152153
width: 150px;
153154
height: 150px;
154155
border-radius: 50%;

apps/farminglog/src/pages/game/index.tsx

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,50 @@
1-
import React, { useState } from 'react'; // useState를 import 합니다.
1+
import { useEffect, useRef, useState } from 'react'; // useState를 import 합니다.
22
import { UnityWebGL } from '../../components/UnityWebGL';
33
import useMediaQueries from "@/hooks/useMediaQueries";
4+
import useTallPage from "@/hooks/useTallPage";
45
import { GameContainer, StartButton, StartContainer, LandingHero, UpButton, UpButtonImage } from './index.styled.ts';
56

67

78
const Game: React.FC = () => {
89
const [isGameStarted, setIsGameStarted] = useState(false);
9-
const [isLanding, setIsLanding] = useState(true);
1010
const { isMobile } = useMediaQueries();
1111
const landingImage = 'https://farmsystem-bucket.s3.ap-northeast-2.amazonaws.com/game/DetailGameLanding.png';
1212
const upButtonImage = 'https://farmsystem-bucket.s3.ap-northeast-2.amazonaws.com/game/UpGameButton.png';
13+
const isTallPage = useTallPage(3000);
14+
const gameContainerRef = useRef<HTMLDivElement | null>(null);
15+
const [isGameContainerInView, setIsGameContainerInView] = useState(false);
1316
const handleStartGame = () => {
1417
setIsGameStarted(true);
1518
};
1619
const handleScrollTop = () => {
1720
window.scrollTo({ top: 0, behavior: 'smooth' });
1821
};
1922

23+
useEffect(() => {
24+
if (isMobile) return;
25+
if (!gameContainerRef.current) return;
26+
27+
const observer = new IntersectionObserver(
28+
(entries) => {
29+
const entry = entries[0];
30+
setIsGameContainerInView(entry.isIntersecting);
31+
},
32+
{
33+
root: null,
34+
rootMargin: '0px',
35+
threshold: 0.1,
36+
}
37+
);
38+
39+
observer.observe(gameContainerRef.current);
40+
return () => observer.disconnect();
41+
}, [isMobile]);
42+
2043
return (
2144
<div
2245
style={{ backgroundColor: '#46D77C' }}
2346
>
24-
<GameContainer>
47+
<GameContainer ref={gameContainerRef}>
2548

2649

2750
{/** isGameStarted 값에 따라 조건부로 렌더링. */}
@@ -39,16 +62,15 @@ const Game: React.FC = () => {
3962
)}
4063
</GameContainer>
4164

42-
{!isMobile && (
65+
{(!isMobile) && (
4366
<LandingHero
4467
$bgDesktop={landingImage}
4568
$bgMobile={landingImage}
46-
onClick={() => setIsLanding(false)}
4769
>
4870
</LandingHero>
4971
)}
50-
{( !isMobile && isLanding &&
51-
<UpButton onClick={handleScrollTop} title="맨 위로">
72+
{(!isMobile && isTallPage && !isGameContainerInView) && (
73+
<UpButton onClick={handleScrollTop} title="맨 위로">
5274
<UpButtonImage src={upButtonImage} alt="Up Button" />
5375
</UpButton>)}
5476

0 commit comments

Comments
 (0)