Skip to content

Commit

Permalink
feat: CardSection 컴포넌트 구현 (#25)
Browse files Browse the repository at this point in the history
- html2canvas 라이브러리 추가
- change.svg, download.svg 파일 추가
  • Loading branch information
AAminha committed May 15, 2024
1 parent 391dce9 commit 8849886
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"axios": "^1.6.8",
"html2canvas": "^1.4.1",
"react": "^18.2.0",
"react-cookie": "^7.1.4",
"react-dom": "^18.2.0",
Expand Down
6 changes: 6 additions & 0 deletions src/assets/icons/change.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/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.
182 changes: 182 additions & 0 deletions src/components/DefineResultPage/CardSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { useRef, useState } from 'react';

import html2canvas from 'html2canvas';
import styled from 'styled-components';

import { ReactComponent as ChangeIcon } from '@/assets/icons/change.svg';
import { ReactComponent as DownloadIcon } from '@/assets/icons/download.svg';
import { ReactComponent as KakaoIcon } from '@/assets/icons/kakaoIcon.svg';

interface CardSectionProps {
piece: string;
}

export const CardSection = ({ piece }: CardSectionProps) => {
const [isFront, setIsFront] = useState(true);
const captureRef = useRef<HTMLImageElement>(null);

const handleSaveImage = () => {
if (!captureRef.current) return;

const capture = captureRef.current;

html2canvas(capture, { scrollY: -window.scrollY }).then((canvas) => {
const image = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
const link = document.createElement('a');
link.href = image;
link.download = `define-result-${isFront ? 'front' : 'back'}.jpg`;
link.click();
});
};

return (
<StyledCardSection>
<StyledImageContainer>
<img
src={`/src/assets/cards/${isFront ? 'front' : 'back'}/${piece}.png`}
alt="card"
ref={captureRef}
/>
<div className="hover-view">
<StyledChangeButton type="button" onClick={() => setIsFront((prev) => !prev)}>
<ChangeIcon />
</StyledChangeButton>
<StyleButtonContainer>
<button type="button" className="download-button" onClick={handleSaveImage}>
<DownloadIcon />
<span>이미지로 저장</span>
<div />
</button>
<button
type="button"
className="share-button"
onClick={() => {
// TODO: 공유 기능 구현
}}
>
<KakaoIcon />
<span>카카오로 공유</span>
<div />
</button>
</StyleButtonContainer>
</div>
</StyledImageContainer>
<div className="notice">카드에 마우스를 가져가 보세요!</div>
</StyledCardSection>
);
};

const StyledCardSection = styled.section`
display: flex;
flex-direction: column;
justify-content: space-between;
.notice {
text-align: center;
${({ theme }) => theme.font.desktop.label1m};
color: ${({ theme }) => theme.color.primary700};
}
`;

// TODO: Change 버튼 클릭시 카드 앞뒤 돌아가는 애니메이션 추가

const StyledImageContainer = styled.div`
width: 264px;
height: 426px;
position: relative;
img {
width: 100%;
height: 100%;
border-radius: 13px;
}
.hover-view {
visibility: hidden;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding: 20px;
border-radius: 13px;
background: ${({ theme }) => theme.color.bgModal};
filter: drop-shadow(0px 0px 10px rgba(0, 0, 0, 0.25));
backdrop-filter: blur(4px);
button {
color: white;
}
}
&:hover .hover-view {
visibility: visible;
}
`;

const StyledChangeButton = styled.button`
display: flex;
width: 48px;
height: 48px;
justify-content: center;
align-items: center;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.2);
&:hover {
background: rgba(255, 255, 255, 0.1);
}
`;

const StyleButtonContainer = styled.div`
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
button {
display: flex;
justify-content: space-between;
align-items: center;
height: 48px;
padding: 8px 16px;
border-radius: 8px;
span {
${({ theme }) => theme.font.desktop.label1m};
}
}
.download-button {
background: ${({ theme }) => theme.color.primary50};
span {
color: ${({ theme }) => theme.color.primary700};
}
}
.share-button {
background: #fee500;
span {
color: #191600;
}
}
div {
width: 24px;
}
`;
34 changes: 34 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1920,6 +1920,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==

base64-arraybuffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==

boolbase@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
Expand Down Expand Up @@ -2092,6 +2097,13 @@ css-color-keywords@^1.0.0:
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==

css-line-break@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0"
integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
dependencies:
utrie "^1.0.2"

css-select@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6"
Expand Down Expand Up @@ -2962,6 +2974,14 @@ hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
dependencies:
react-is "^16.7.0"

html2canvas@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543"
integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
dependencies:
css-line-break "^2.1.0"
text-segmentation "^1.0.3"

ignore@^5.2.0, ignore@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
Expand Down Expand Up @@ -4116,6 +4136,13 @@ tapable@^2.2.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==

text-segmentation@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943"
integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
dependencies:
utrie "^1.0.2"

text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
Expand Down Expand Up @@ -4285,6 +4312,13 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"

utrie@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645"
integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
dependencies:
base64-arraybuffer "^1.0.2"

vite-plugin-svgr@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/vite-plugin-svgr/-/vite-plugin-svgr-4.2.0.tgz#9f3bf5206b0ec510287e56d16f1915e729bb4e6b"
Expand Down

0 comments on commit 8849886

Please sign in to comment.