Skip to content

Commit 144b8ea

Browse files
committed
feat: 모바일 모임 페이지 로딩 ui 수정
1 parent 4fd801d commit 144b8ea

File tree

7 files changed

+83
-7
lines changed

7 files changed

+83
-7
lines changed

apps/tuk-web/public/logo.png

267 KB
Loading
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use client';
2+
3+
import Image from 'next/image';
4+
5+
export default function Loading() {
6+
return (
7+
<div className="flex h-screen w-full items-center justify-center bg-white-default">
8+
<Image src="/logo.png" alt="App Logo" width={200} height={200} priority />
9+
</div>
10+
);
11+
}
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import InviteGathering from '@/app/invite/gathering/[gatheringId]/src/components/InviteGathering';
2+
import SplashGate from '@/app/invite/gathering/[gatheringId]/src/components/SplashGate';
23

3-
export default function InviteGatheringPage() {
4-
return <InviteGathering />;
4+
export default async function InviteGatheringPage() {
5+
return (
6+
<SplashGate minMs={1000} fadeMs={250} logoSrc="/logo.png" logoSize={200}>
7+
<InviteGathering />
8+
</SplashGate>
9+
);
510
}

apps/tuk-web/src/app/invite/gathering/[gatheringId]/src/components/InviteGathering.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const InviteGathering = () => {
2323
{({ reset }) => (
2424
<ErrorBoundary onReset={reset} FallbackComponent={InviteGatheringErrorFallback}>
2525
<SkeletonGuard minMs={250} skeleton={<InviteGatheringSkeleton />}>
26-
<Suspense fallback={<InviteGatheringSkeleton />}>
26+
<Suspense fallback={null}>
2727
<InviteGatheringContent />
2828
</Suspense>
2929
</SkeletonGuard>

apps/tuk-web/src/app/invite/gathering/[gatheringId]/src/components/InviteGatheringContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const InviteGatheringContent = () => {
4747
<h2
4848
className={cn(
4949
'serif-title-22-M font-bold text-gray-900',
50-
showBanner ? 'mt-[4.125rem]' : 'mt-[1.875rem]'
50+
showBanner ? 'mt-[6.875rem]' : 'mt-[1.875rem]'
5151
)}
5252
>
5353
모임에

apps/tuk-web/src/app/invite/gathering/[gatheringId]/src/components/InviteGatheringSkeleton.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const InviteGatheringSkeleton = () => {
22
return (
3-
<div className="mt-12 flex flex-col items-center justify-center">
3+
<div className="mt-[200px] flex flex-col items-center justify-center">
44
<div
55
className="relative h-[321px] w-[288px] animate-pulse overflow-hidden rounded-[0.625rem] bg-[#f0f1f3] px-4 py-3"
66
aria-busy="true"
@@ -27,8 +27,6 @@ const InviteGatheringSkeleton = () => {
2727
<div className="h-3 w-10 rounded bg-gray-200" />
2828
<div className="h-3 w-16 rounded bg-gray-200" />
2929
</div>
30-
31-
<div className="pointer-events-none absolute inset-0 -skew-x-12 bg-gradient-to-r from-transparent via-[rgba(255,255,255,0.3)] to-transparent" />
3230
</div>
3331
</div>
3432
);
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use client';
2+
3+
import Image from 'next/image';
4+
import { useEffect, useState } from 'react';
5+
6+
type SplashGateProps = {
7+
/** 최소 표시 시간 (ms) */
8+
minMs?: number;
9+
/** 로고 경로 (public/ 기준) */
10+
logoSrc?: string;
11+
/** 로고 크기(px) */
12+
logoSize?: number;
13+
/** 페이드아웃 시간(ms) */
14+
fadeMs?: number;
15+
children: React.ReactNode;
16+
};
17+
18+
export default function SplashGate({
19+
minMs = 1000,
20+
fadeMs = 250,
21+
logoSrc = '/logo.png',
22+
logoSize = 200,
23+
children,
24+
}: SplashGateProps) {
25+
const [show, setShow] = useState(true);
26+
const [fadeOut, setFadeOut] = useState(false);
27+
28+
useEffect(() => {
29+
// 최소 표시 시간 보장
30+
const t = setTimeout(() => {
31+
// 모션 감소 환경이면 바로 제거
32+
const media = window.matchMedia('(prefers-reduced-motion: reduce)');
33+
if (media.matches || fadeMs === 0) {
34+
setShow(false);
35+
} else {
36+
setFadeOut(true);
37+
const t2 = setTimeout(() => setShow(false), fadeMs);
38+
return () => clearTimeout(t2);
39+
}
40+
}, minMs);
41+
42+
return () => clearTimeout(t);
43+
}, [minMs, fadeMs]);
44+
45+
return (
46+
<>
47+
{children}
48+
49+
{show && (
50+
<div
51+
aria-busy="true"
52+
aria-live="polite"
53+
className={`fixed inset-0 z-[9999] flex items-center justify-center bg-white-default ${fadeOut ? 'opacity-0 transition-opacity' : 'opacity-100'} `}
54+
// Tailwind transition-duration 커스텀
55+
style={{ transitionDuration: `${fadeMs}ms` }}
56+
>
57+
<Image src={logoSrc} alt="App Logo" width={logoSize} height={logoSize} priority />
58+
</div>
59+
)}
60+
</>
61+
);
62+
}

0 commit comments

Comments
 (0)