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(toks-components, quiz): Image Preview 기능 구현 #403

Merged
merged 10 commits into from
Feb 18, 2024
5 changes: 3 additions & 2 deletions src/app/my-page/components/LogoutBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ export const LogoutBar = () => {
로그아웃
</Text>
<Image
className="h-auto w-24px"
src={ICON_URL.CHEVRON_RIGHT}
alt="로그아웃 버튼"
width={24}
height={24}
width="0"
height="0"
Comment on lines +26 to +30
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거 무슨 차이인가요??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next Image를 사용할 때 콘솔에 src has either width or height modified, but not the other. If you use CSS to change the size of your image, also include the styles 'width: "auto"' or 'height: "auto"' to maintain the aspect ratio. warning이 여러번 떴었는데요, 해당 warning을 해결하기 위해서는 width나 height 둘 중 하나를 auto로 설정해서 ratio를 맞춰야하는데 next Image를 사용할 때에는 width와 height 두 속성 모두 지정을 해줘야만했기 때문에 위와 같은 방식으로 작성하게 되었습니다!
next/image

/>
</button>
<LogoutBottomSheet onClose={() => setIsShow(false)} isShow={isShow} />
Expand Down
5 changes: 3 additions & 2 deletions src/app/my-page/components/LogoutBottonSheet/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ export const LogoutBottomSheet = ({ onClose, isShow }: BottomSheetProps) => {
로그아웃 하시겠어요?
</Text>
<Image
className="h-auto w-14px"
onClick={() => onClose()}
src={ICON_URL.SMALL_X}
alt="바텀시트 닫기버튼"
width={14}
height={14}
width="0"
height="0"
/>
</div>
<div className="h-40px" />
Expand Down
2 changes: 1 addition & 1 deletion src/app/my-page/components/UserInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const UserInfo = () => {
{user?.nickname}
</Text>
<Image
className="ml-4px"
className="ml-4px h-auto w-24px"
src={ICON_URL.CHEVRON_RIGHT}
alt="닉네임 수정 버튼"
width={24}
Expand Down
6 changes: 3 additions & 3 deletions src/app/my-page/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ const MyPage = () => {
똑스에서 풀고 싶은 퀴즈가 있다면?
</Text>
<Image
className="mx-auto my-20px"
className="mx-auto my-20px h-auto w-160px"
src={ICON_URL.EMOJI_ROCKET}
width={160}
height={160}
width="0"
height="0"
alt="로켓 이미지"
/>
<Button
Expand Down
5 changes: 3 additions & 2 deletions src/app/nickname/components/NicknameBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ export const NicknameBox = ({
)}
>
<Image
className="h-auto w-52px"
src={ICON_URL.EMOJI_DROOLING}
alt="똑스 아이콘"
width={52.5}
height={52.5}
width="0"
height="0"
/>
<div className="mt-16px flex w-full flex-col items-center">
<Text typo="headingM" color="white">
Expand Down
28 changes: 23 additions & 5 deletions src/app/quiz/[quizId]/@detail/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import clsx from 'clsx';
import { useState } from 'react';

import {
QuizButton,
Expand All @@ -13,6 +14,7 @@ import {
} from '@/app/quiz/hooks/';
import { OX, QuizButtonType } from '@/app/quiz/models/quiz';
import { Text, bgColor } from '@/common';
import { Modal } from '@/common/components/Modal';

import { Comments } from '../../components/Comment/Comments';

Expand All @@ -25,6 +27,7 @@ type Props = {
function DetailPage({ params: { quizId } }: Props) {
const { submitQuiz } = useSubmitQuizMutation(quizId);
const { data: quizDetail, isLoading } = useGetQuizDetailQuery(quizId);
const [isShow, setIsShow] = useState(false);

if (quizDetail === undefined || isLoading) {
return <SkeletonQuizDetail />;
Expand Down Expand Up @@ -75,11 +78,26 @@ function DetailPage({ params: { quizId } }: Props) {
</Text>
<div className="mt-48px">
{isVisibleOXImage && (
<Thumbnail
className="mb-24px w-full"
imageUrl={oxImageUrl}
name="OX퀴즈 설명"
/>
<>
<Thumbnail
className="mb-24px w-full"
imageUrl={oxImageUrl}
name="OX퀴즈 설명"
onClick={() => setIsShow(true)}
/>
<Modal isShow={isShow} onClose={() => setIsShow(false)}>
<img
className="rounded-16px"
src={oxImageUrl}
alt="OX퀴즈 설명"
style={{
width: '100%',
objectFit: 'cover',
objectPosition: 'center',
}}
/>
</Modal>
</>
)}
<div className="flex gap-16px">
{checkSameQuizType('A_B_') ? (
Expand Down
8 changes: 7 additions & 1 deletion src/app/quiz/components/QuizButton/Thumbnail.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
'use client';

import Image from 'next/image';
import { HTMLAttributes } from 'react';

import { ICON_URL, bgColor, cn } from '@/common';

import { QuizButtonProps } from './type';

interface ThumbnailProps
extends Pick<QuizButtonProps, 'OXType' | 'imageUrl' | 'className'> {
extends Pick<QuizButtonProps, 'OXType' | 'imageUrl' | 'className'>,
HTMLAttributes<HTMLDivElement> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 onClick이 필요해서 HTMLAttributes<HTMLDivElement>이 타입을 붙인거라면 QuizButtonProps에 onClick이 있기 때문에 Pick<QuizButtonProps, 'OXType' | 'imageUrl' | 'className' | 'onClick'>해주었어도 좋았을 것 같습니다...!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'onClick' 속성의 형식이 호환되지 않습니다. 'MouseEventHandler<HTMLButtonElement> | undefined' 형식은 'MouseEventHandler<HTMLDivElement> | undefined' 형식에 할당할 수 없습니다. onClick이 호환이 안되는 문제 때문에 따로 extends 해주었습니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

근데 썸네일 컴포넌트 내부로 모달 컴포넌트를 종속시키면 해당 attribute extends는 더이상 필요 없을 것 같네요!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아아 그러네요 그나저나 저렇게 하면 안되는군요 흠흠

name?: string;
}

Expand All @@ -14,9 +18,11 @@ export function Thumbnail({
imageUrl,
name = '퀴즈',
className,
...rest
}: ThumbnailProps) {
return (
<div
{...rest}
className={cn(
'relative flex aspect-square w-140px items-center justify-center overflow-hidden rounded-8px',
OXType &&
Expand Down
50 changes: 36 additions & 14 deletions src/app/quiz/components/QuizButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use client';

import clsx from 'clsx';
import { useState } from 'react';

import { Text, bgColor } from '@/common';
import { Modal } from '@/common/components/Modal';

import { ProgressBar } from './ProgressBar';
import { Thumbnail } from './Thumbnail';
Expand All @@ -20,19 +22,35 @@ export function QuizButton({
name,
...rest
}: QuizButtonProps) {
const [isShow, setIsShow] = useState(false);
return (
<button
className={clsx(className, 'flex flex-1 flex-col items-center')}
disabled={isSubmitted}
{...rest}
>
<div className={clsx(className, 'flex flex-1 flex-col items-center')}>
{(OXType || imageUrl) && (
<Thumbnail
className="mb-24px w-full"
OXType={OXType}
imageUrl={imageUrl}
name={name}
/>
<>
<Thumbnail
className="mb-24px w-full"
OXType={OXType}
imageUrl={imageUrl}
name={name}
onClick={() => {
setIsShow(true);
}}
/>
{!OXType && (
<Modal isShow={isShow} onClose={() => setIsShow(false)}>
<img
className="rounded-8px"
src={imageUrl}
alt={`${name}사진`}
style={{
width: '100%',
objectFit: 'cover',
objectPosition: 'center',
}}
/>
</Modal>
)}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

썸네일 클릭 => 모달 등장이 서비스 내 고정적인 스펙이라면 해당 썸네일 확대용 모달을 썸네일 컴포넌트 안에 종속시키면 어떨까요?
모달이 썸네일 안으로 들어가고 isShow state를 썸네일 안에 두면 어떨지 의견 남겨봅니다!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 같은 의견으로 Preview + Modal은 세트로 가져가도 좋을 것 같습니다

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵넵 썸네일과 모달 컴포넌트 하나로 합쳐볼게요~!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

40a8a69 썸네일 컴포넌트에 모달 컴포넌트 종속시키는 방식으로 수정했습니다!

</>
)}
<div
className={clsx(
Expand All @@ -43,11 +61,15 @@ export function QuizButton({
{isSubmitted && (
<ProgressBar percentage={percentage} isSelected={isSelected} />
)}
<div className="absolute z-10 flex h-full w-full items-center justify-center">
<button
className="absolute z-10 flex h-full w-full items-center justify-center"
disabled={isSubmitted}
{...rest}
>
<Text typo="bodyBold" color="gray10">
{name}
</Text>
</div>
</button>
</div>
{isSubmitted && participationLabel && (
<Text
Expand All @@ -58,6 +80,6 @@ export function QuizButton({
{participationLabel}
</Text>
)}
</button>
</div>
);
}
5 changes: 3 additions & 2 deletions src/app/quiz/components/ScrollToTopButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ export function ScrollToTopButton() {
}}
>
<Image
className="h-auto w-16px"
src={ICON_URL.CHEVRON_UP}
width={16}
height={9}
width="0"
height="0"
alt="맨 위로가기 아이콘"
/>
</button>
Expand Down
6 changes: 3 additions & 3 deletions src/common/components/Appbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ export const Appbar = () => {
}}
>
<Image
layout="fixed"
width={60}
height={20}
width="0"
height="0"
src={ICON_URL.TOKS_LOGO}
alt="toks 로고"
className="h-auto w-60px"
/>
{/* TODO: POPOVER 구현 */}
<Tooltip
Expand Down
5 changes: 3 additions & 2 deletions src/common/components/BackHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ export const BackHeader = () => {
<div className="flex h-full w-full items-center justify-between">
<button type="button" onClick={() => router.back()}>
<Image
className="h-auto w-24px"
src={ICON_URL.CHEVRON_LEFT_BIG}
alt="뒤로가기 버튼"
width={24}
height={24}
width="0"
height="0"
/>
</button>
</div>
Expand Down
58 changes: 58 additions & 0 deletions src/common/components/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use client';

import Image from 'next/image';
import { PropsWithChildren, ReactNode } from 'react';

import { ICON_URL } from '@/common';
import { cn } from '@/common/utils';

import { GlobalPortal } from '../GlobalPortal';

type ModalProp = {
isShow: boolean;
onClose: VoidFunction;
};

export const Modal = ({
isShow,
onClose,
children,
}: PropsWithChildren<ModalProp>) => {
return (
<GlobalPortal.Consumer>
<Dimmer isShow={isShow} onClose={onClose} children={children} />
</GlobalPortal.Consumer>
);
};

const Dimmer = ({
isShow,
onClose,
children,
}: {
isShow: boolean;
onClose: VoidFunction;
children: ReactNode;
}) => {
return (
<div
onClick={() => {
onClose();
}}
className={cn(
'fixed left-0 top-0 z-50 flex h-full w-full items-center justify-center bg-gray-120/80 p-20px',
{
hidden: !isShow,
'animate-fade-in-back-drop': isShow,
}
)}
>
<div className="flex flex-col">
<button className="flex justify-end pb-16px" onClick={() => onClose()}>
<Image src={ICON_URL.CLOSE} alt="close" width={24} height={24} />
</button>
{children}
</div>
</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 framer-motion 라이브러리 있는데 요거로 바꾸면 좋을 것 같습니다.

AnimationPresence 등 유용한 유틸을 추후에 추가하기 편할 것 같아서 제시해봅니당

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dfa9684 framer 적용했습니다 ~!

);
};
Loading