Skip to content

Commit

Permalink
Merge pull request #25 from causyj/dev/selectframe
Browse files Browse the repository at this point in the history
[DEV] 프로필 프레임 - 프레임 변경 & 사진 다운로드 구현
  • Loading branch information
yugenius0213 authored Sep 17, 2024
2 parents 0fa1bca + 21eee2a commit 215aff4
Show file tree
Hide file tree
Showing 38 changed files with 1,264 additions and 1,850 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @falconlee236 @1lsang @ldh019 @yymin1022 @causyj
2,771 changes: 947 additions & 1,824 deletions package-lock.json

Large diffs are not rendered by default.

Binary file added public/basicframe1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/basicframe2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/basicframe3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/basicframe4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/basicframecircle1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/basicframecircle2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/basicframecircle3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/basicframecircle4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/basicframecircle5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframe1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframe2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframe3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframe4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframe5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframe6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframecircle1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframecircle2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframecircle3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframecircle4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframecircle5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/premiumframecircle6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/resultsample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions src/app/frame/_components/SelectFrame.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Image from 'next/image';
import { FrameProps } from '@/interfaces';

export default function SelectFrame({
circle,
description,
onClick,
}: FrameProps) {
return (
<button type="button" onClick={onClick} className="cursor-pointer">
<Image
src={circle}
alt={description}
width={40}
height={40}
priority
className="relative"
/>
</button>
);
}
98 changes: 94 additions & 4 deletions src/app/frame/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,100 @@
import MyButton from '@/components/MyButton';
'use client';

import Image from 'next/image';
import Link from 'next/link';
import { useState } from 'react';
import PreviousPage from '@/components/PreviousPage';
import { BASIC_FRAME_DATA, PREMIUM_FRAME_DATA } from '@/constants';
import SVGDownload from '@/styles/icons/download.svg';
import SVGGoToList from '@/styles/icons/gotolist.svg';
import DownloadImage from '@/utils/DownloadImage';
import SelectFrame from './_components/SelectFrame';

export default function FrameSelectView() {
const [colorOfCircle, setColorOfCircle] = useState<string>('');
const [isPremiumSelected, setIsPremiumSelected] = useState<boolean>(false);

const frametype = isPremiumSelected ? PREMIUM_FRAME_DATA : BASIC_FRAME_DATA;
const frameWidth = colorOfCircle === '/premiumframe2.png' ? 283 : 239;
const frameHeight = colorOfCircle === '/premiumframe2.png' ? 332 : 290;
const imageSrc = '/resultsample.png'; // 생성된 이미지(임시)

const onCaptureClick = () => {
DownloadImage({ colorOfCircle, imageSrc, frameWidth, frameHeight });
};

return (
<div>
<h1>This is 프레임 선택 Page</h1>
<MyButton name="다운로드" target="/" />
<div className="flex w-full flex-col items-center justify-center">
<div className="flex w-full flex-row justify-between px-4">
<PreviousPage target="/" />
<Link href="/list" className="pr-4">
<SVGGoToList />
</Link>
</div>
<h1 className="text-xl">AI 프로필이 완성!</h1>
<h2 className="py-1 font-sfpro text-2xs font-bold text-white">
사진과 어울리는 프레임을 선택해주세요 😀
</h2>
<div className="text-2sx mb-6 mt-4 flex h-[35px] w-[183px] flex-row items-center justify-evenly rounded-full bg-white font-sfpro font-bold">
<button
type="button"
onClick={() => setIsPremiumSelected(false)}
className={`flex h-[27px] w-[86px] items-center justify-center rounded-full ${isPremiumSelected ? 'bg-white text-primary-middlegray' : 'bg-primary-darkblue text-white'}`}
>
기본
</button>
<button
type="button"
onClick={() => setIsPremiumSelected(true)}
className={`flex h-[27px] w-[86px] items-center justify-center rounded-full ${isPremiumSelected ? 'bg-primary-darkblue text-white' : 'bg-white text-primary-middlegray'}`}
>
프리미엄
</button>
</div>

<div
className={`relative flex ${colorOfCircle === '/premiumframe2.png' ? 'h-[332px] w-[283px]' : 'h-[290px] w-[239px]'} justify-center`}
>
<Image
src={imageSrc}
alt="Sample Image"
width={206}
height={206}
priority
className="absolute mt-4"
/>
{colorOfCircle && colorOfCircle !== '' && (
<Image
src={colorOfCircle}
alt="Selected Frame"
width={frameWidth}
height={frameHeight}
priority
className={`relative ${colorOfCircle === '/premiumframe2.png' ? '-mt-5 mb-6' : ''}`}
/>
)}
</div>

<div
className={`flex flex-row gap-x-2.5 ${colorOfCircle === '/premiumframe2.png' ? '-mt-5 pb-6' : 'py-6'}`}
>
{Object.entries(frametype).map(([key, frame]) => (
<SelectFrame
key={key}
{...frame}
onClick={() => setColorOfCircle(frame.frame)}
/>
))}
</div>

<button
type="button"
onClick={onCaptureClick}
className="flex h-12 w-full items-center justify-center gap-x-3 rounded-full bg-primary-darkblue text-xl text-white"
>
<SVGDownload />
다운로드
</button>
</div>
);
}
10 changes: 1 addition & 9 deletions src/app/guide/_components/GuideDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Image from 'next/image';
import { ImageWithDescriptionProps } from '@/interfaces';
import { GuideDetailProps, ImageWithDescriptionProps } from '@/interfaces';
import SVGTriangle from '@/styles/icons/triangle.svg';

function ImageWithDescription({ src, description }: ImageWithDescriptionProps) {
Expand All @@ -24,14 +24,6 @@ function ImageWithDescription({ src, description }: ImageWithDescriptionProps) {
);
}

interface GuideDetailProps {
puang: string;
title: string;
children: React.ReactNode;
examples: { id: string; src: string; description: string }[];
explanation: React.ReactNode;
}

export default function GuideDetail({
puang,
title,
Expand Down
37 changes: 25 additions & 12 deletions src/app/waiting/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
'use client';

import Image from 'next/image';
import { useEffect, useRef, useState } from 'react';
import CopyToClipboard from 'react-copy-to-clipboard';
import SVGLink from '@/styles/icons/link.svg';
import { useRef } from 'react';

export default function WaitingView() {
const [url, setUrl] = useState<string>('');
const copyRef = useRef<HTMLButtonElement>(null);
const copyToClipboardFunc = (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>,
) => {

useEffect(() => {
if (typeof window !== 'undefined') {
setUrl(window.location.href);
}
}, []);

const copyToClipboardFunc = () => {
if (copyRef.current) {
copyRef.current.click();
}
Expand Down Expand Up @@ -47,14 +53,21 @@ export default function WaitingView() {
링크복사
<SVGLink />
</button>
<CopyToClipboard
text={window.location.href}
onCopy={() => {
alert('클립보드에 복사되었습니다.');
}}
>
<button ref={copyRef} style={{ display: 'none' }} />
</CopyToClipboard>
{url && (
<CopyToClipboard
text={url}
onCopy={() => {
alert('클립보드에 복사되었습니다.');
}}
>
<button
type="button"
ref={copyRef}
style={{ display: 'none' }}
aria-label="링크 복사 버튼"
/>
</CopyToClipboard>
)}
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default function Modal({
</div>

<div className="flex w-full flex-col">
<MyButton target={target} name={button1} />
<MyButton target={target} name={button1} enabled />
<button
type="button"
onClick={onClose}
Expand Down
72 changes: 72 additions & 0 deletions src/constants/frameData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
type FrameData = {
circle: string;
description: string;
frame: string;
};

export const BASIC_FRAME_DATA: Record<
'frame1' | 'frame2' | 'frame3' | 'frame4' | 'frame5',
FrameData
> = {
frame1: {
circle: '/basicframecircle1.png',
description: '기본 프레임 1-없음',
frame: '',
},
frame2: {
circle: '/basicframecircle2.png',
description: '기본 프레임 2-흰색',
frame: '/basicframe1.png',
},
frame3: {
circle: '/basicframecircle3.png',
description: '기본 프레임 3-검은색',
frame: '/basicframe2.png',
},
frame4: {
circle: '/basicframecircle4.png',
description: '기본 프레임 4-파란색',
frame: '/basicframe3.png',
},
frame5: {
circle: '/basicframecircle5.png',
description: '기본 프레임 4-핑크색',
frame: '/basicframe4.png',
},
};

export const PREMIUM_FRAME_DATA: Record<
'frame1' | 'frame2' | 'frame3' | 'frame4' | 'frame5' | 'frame6',
FrameData
> = {
frame1: {
circle: '/premiumframecircle1.png',
description: '기본 프레임 1-푸앙이',
frame: '/premiumframe1.png',
},
frame2: {
circle: '/premiumframecircle2.png',
description: '기본 프레임 2-체크',
frame: '/premiumframe2.png',
},
frame3: {
circle: '/premiumframecircle3.png',
description: '기본 프레임 3-darkblue',
frame: '/premiumframe3.png',
},
frame4: {
circle: '/premiumframecircle4.png',
description: '기본 프레임 4-smile',
frame: '/premiumframe4.png',
},
frame5: {
circle: '/premiumframecircle5.png',
description: '기본 프레임 4-insta',
frame: '/premiumframe5.png',
},
frame6: {
circle: '/premiumframecircle6.png',
description: '기본 프레임 4-회색',
frame: '/premiumframe6.png',
},
};
1 change: 1 addition & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './frameData';
12 changes: 12 additions & 0 deletions src/interfaces/frame.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface FrameProps {
circle: string;
description: string;
onClick: () => void;
}

export interface DownloadImageProps {
colorOfCircle: string;
imageSrc: string;
frameWidth: number;
frameHeight: number;
}
7 changes: 7 additions & 0 deletions src/interfaces/image-with-description.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@ export interface ImageWithDescriptionProps {
src: string;
description: string;
}
export interface GuideDetailProps {
puang: string;
title: string;
children: React.ReactNode;
examples: { id: string; src: string; description: string }[];
explanation: React.ReactNode;
}
1 change: 1 addition & 0 deletions src/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './image-with-description.interface';
export * from './button.interface';
export * from './modals.interface';
export * from './frame.interface';
3 changes: 3 additions & 0 deletions src/styles/icons/download.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/styles/icons/gotolist.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 215aff4

Please sign in to comment.