Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web-domains): skeleton 및 confetti 적용 #211

Merged
merged 11 commits into from
Sep 13, 2024
1 change: 1 addition & 0 deletions packages/web-domains/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@tanstack/react-query": "^5.50.1",
"@toss/use-overlay": "^1.4.0",
"axios": "^1.7.2",
"react-canvas-confetti": "^2.0.7",
"react-copy-to-clipboard": "^5.1.0",
"react-countdown": "^2.3.5",
"react-hook-form": "^7.52.1"
Expand Down
52 changes: 52 additions & 0 deletions packages/web-domains/src/common/animates/Confetti.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { colors } from '@sds/theme';
import { CSSProperties } from 'react';
import Fireworks from 'react-canvas-confetti/dist/presets/fireworks';

interface ConfettiProps {
position: {
top: number;
left: number;
};
width?: number;
height?: number;
}

export const Confetti = (props: ConfettiProps) => {
const {
position: { top, left },
width,
height,
} = props;

const canvasStyles: CSSProperties = {
width: width ?? '100%',
height: height ?? '100%',
zIndex: '3',
position: 'absolute',
top,
left,
};

const decorateOptions = (originalOptions: any) => {
return {
...originalOptions,
particleCount: 100, // 조각 개수 설정
spread: 100, // 퍼짐 정도 설정
startVelocity: 50, // 초기 속도 설정
ticks: 200, // 애니메이션 지속 시간 설정
origin: { x: 0.5, y: 0.7 }, // 발사 위치 설정
shapes: ['square', 'circle', 'square'], // 이미지 배열을 shapes로 설정
gravity: 0.8, // 중력 설정
scalar: 1.5, // 색종이 크기
colors: [colors.primary500, colors.quaternary500, colors.secondary500, colors.tertiary500],
};
};

return (
<Fireworks
autorun={{ speed: 0.1, duration: 1 }}
style={canvasStyles}
decorateOptions={decorateOptions} // 함수 실행을 위해 괄호를 추가
/>
);
};
1 change: 1 addition & 0 deletions packages/web-domains/src/common/animates/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Confetti } from './Confetti';
1 change: 1 addition & 0 deletions packages/web-domains/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { RootLayout } from './layout/RootLayout';
export { GlobalStyle } from './styles/GlobalStyles';
export { getWebDomain } from './utils/getWebDomain';
export * from './components/Error';
export * from './animates';
Original file line number Diff line number Diff line change
@@ -1,63 +1,58 @@
import { Txt } from '@sambad/sds/components';
import { If } from '@sambad/react-utils';
import { Skeleton, Txt } from '@sambad/sds/components';
import { colors, size } from '@sambad/sds/theme';
import Image from 'next/image';

import ClosingBackground from '../../../common/assets/images/closing-background.png';
import { Confetti } from '@/common';

import { useGetMeetingNameService } from '../services/useGetMeetingNameService';

interface ClosingMessageProps {
name?: string;
inviteCode: string;
}

const ClosingMessage = (props: ClosingMessageProps) => {
const { name } = props;
export const ClosingMessage = (props: ClosingMessageProps) => {
const { inviteCode } = props;

if (!name) {
null;
}
const { data, isLoading, isSuccess } = useGetMeetingNameService({ inviteCode });

return (
<div
css={{
position: 'absolute',
top: '108px',
width: '100%',
zIndex: '1',
textAlign: 'center',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
'@media (max-width: 365px)': {
top: '64px',
},
}}
>
<div css={{ transform: 'translate(0, 20%)' }}>
{name && (
<Txt as="h1" color={colors.primary500} typography="heading1">
{name}
</Txt>
)}
<Txt as="h2" color={colors.black} typography="heading1">
모임을 만들었어요!
</Txt>
<Txt as="p" color={colors.grey600} typography="body3" css={{ marginTop: size['6xs'] }}>
이제 모임원을 초대해보세요!
</Txt>
</div>

<>
<Confetti position={{ top: 0, left: 0 }} height={350} />
<div
css={{
position: 'absolute',
width: '90%',
aspectRatio: '3/2',
maxWidth: '500px',
top: '108px',
width: '100%',
zIndex: '1',
textAlign: 'center',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
'@media (max-width: 365px)': {
top: '64px',
},
}}
>
<Image alt="background-image" src={ClosingBackground} quality={100} fill style={{ objectFit: 'contain' }} />
<div css={{ transform: 'translate(0, 20%)' }}>
<If condition={isLoading}>
<Skeleton width={200} height={36} />
</If>
<If condition={isSuccess}>
{data?.name && (
<Txt as="h1" color={colors.primary500} typography="heading1">
{data.name}
</Txt>
)}
</If>
<Txt as="h2" color={colors.black} typography="heading1">
모임을 만들었어요!
</Txt>
<Txt as="p" color={colors.grey600} typography="body3" css={{ marginTop: size['6xs'] }}>
이제 모임원을 초대해보세요!
</Txt>
</div>
</div>
</div>
</>
);
};

export default ClosingMessage;
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import Image from 'next/image';

import Character from '../../../common/assets/images/meeting-character.png';
import { InviteCodeShareButton } from '../components/Button/InviteCodeShareButton';
import ClosingMessage from '../components/ClosingMessage';
import { useGetMeetingNameService } from '../services/useGetMeetingNameService';
import { ClosingMessage } from '../components/ClosingMessage';

interface NewMeetingClosingContainerProps {
inviteCode: string;
Expand All @@ -16,8 +15,6 @@ interface NewMeetingClosingContainerProps {
const NewMeetingClosingContainer = (props: NewMeetingClosingContainerProps) => {
const { inviteCode } = props;

const { data } = useGetMeetingNameService({ inviteCode });

return (
<div
css={{
Expand All @@ -31,7 +28,7 @@ const NewMeetingClosingContainer = (props: NewMeetingClosingContainerProps) => {
justifyContent: 'center',
}}
>
<ClosingMessage name={data?.name} />
<ClosingMessage inviteCode={inviteCode} />
<div
css={{
position: 'relative',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
'use client';

import { Txt } from '@sambad/sds/components';
import { If } from '@sambad/react-utils';
import { Skeleton, Txt } from '@sambad/sds/components';
import { colors } from '@sambad/sds/theme';
import Image from 'next/image';

import { Confetti } from '@/common';
import { useGetMeetingName } from '@/common/apis/queries/useGetMeetingName';

import ClosingBackground from '../../../common/assets/images/member-closing-background.png';
import MemberCharacter from '../../../common/assets/images/member-closing-character.png';

interface MemberClosingContainerProps {
Expand All @@ -16,59 +17,58 @@ interface MemberClosingContainerProps {
export const MemberClosingContainer = (props: MemberClosingContainerProps) => {
const { inviteCode } = props;

const { data } = useGetMeetingName({ inviteCode });
const { data, isLoading, isSuccess } = useGetMeetingName({ inviteCode });

return (
<section
css={{
width: '100%',
height: '100dvh',
overflow: 'hidden',
backgroundColor: colors.primary50,
}}
>
<div
<>
<Confetti position={{ top: 0, left: 0 }} height={350} />
<section
css={{
position: 'relative',
marginTop: '28px',
display: 'flex',
flexDirection: 'column',
alignContent: 'center',
justifyContent: 'center',
height: '280px',
zIndex: '10',
width: '100%',
height: '100dvh',
overflow: 'hidden',
backgroundColor: colors.primary50,
}}
>
{data?.name && (
<Txt as="p" color={colors.primary500} typography="heading1" css={{ textAlign: 'center' }}>
{data?.name}
<div
css={{
position: 'relative',
marginTop: '28px',
display: 'flex',
flexDirection: 'column',
alignContent: 'center',
justifyContent: 'center',
height: '280px',
zIndex: '10',
}}
>
<If condition={isLoading}>
<Skeleton width={200} height={36} />
</If>
<If condition={isSuccess}>
{data?.name && (
<Txt as="p" color={colors.primary500} typography="heading1" css={{ textAlign: 'center' }}>
{data?.name}
</Txt>
)}
</If>
<Txt as="p" color={colors.black} typography="heading1" css={{ textAlign: 'center' }}>
가입이 완료되었어요!
</Txt>
)}
<Txt as="p" color={colors.black} typography="heading1" css={{ textAlign: 'center' }}>
가입이 완료되었어요!
</Txt>
</div>
<Image
alt="background"
src={ClosingBackground}
quality={100}
fill
src={MemberCharacter}
width={240}
height={240}
alt="character"
style={{
objectFit: 'contain',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
}}
/>
</div>
<Image
src={MemberCharacter}
width={240}
height={240}
alt="character"
style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
}}
/>
</section>
</section>
</>
);
};
21 changes: 21 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.