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

✨ Feature: 이미지 저장 기능 구현 #361

Merged
merged 1 commit into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/components/GradientBackground/GradientBackground.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ const GradientBackgroundContainer = styled.div`
background: linear-gradient(135deg, #e0f7fa, #a2c9cf);
transition: opacity 1s ease;
opacity: ${(props) => (props.$showContent ? 1 : 0)};
z-index: 0;
z-index: -1;
`;

const GradientsContainer = styled.div`
filter: blur(40px);
width: 100%;
height: 100%;
position: relative;
position: absolute;
top: 0;
left: 0;
`;

const Circle = styled.div`
Expand Down
5 changes: 4 additions & 1 deletion src/pages/AgreePage/AgreePage.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React from "react";
import React, { useEffect } from "react";
import { AGREE_TEXT } from "@/constants/Text/title";
import * as S from "./style";
import { useNavigate, useParams } from "react-router-dom";
export const AgreePage = () => {
const navigate = useNavigate();
const params = useParams();
console.log(params);
useEffect(() => {
window.scrollTo(0, 0);
}, []);
return (
<S.Wrapper>
<>
Expand Down
52 changes: 47 additions & 5 deletions src/pages/Share/Share.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,65 @@
import React, { useRef } from "react";
import html2canvas from "html2canvas";
import { captureScreenshot } from "@/utils/share";
import * as S from "./styled";
import { useMoveonStarP } from "@/hooks/useStar";
import shareIcon from "@/assets/shareIcon.svg";
import ClearStarPIcon1 from "@/assets/starclearPicon1.svg";
import ClearStarPIcon2 from "@/assets/starclearPicon2.svg";

const SharePage = () => {
const SharePage = ({ onBack }) => {
const captureRef = useRef();
const { starP } = useMoveonStarP();
const handleCapture = async () => {
const canvas = await html2canvas(captureRef.current);
await captureScreenshot(canvas);
};

const starData = starP && starP.data ? starP.data : null;
if (!starData) {
return <p>데이터를 불러오는 중입니다...</p>; // theme이 null인 경우 처리
}

return (
<div>
<div ref={captureRef}>
{/* 캡처할 내용 */}
<h1>Hello, World!</h1>
<p>This is a page that will be captured.</p>
<S.Wrapper>
<S.Header>
<S.BannerImage src={starData.photo} alt={starData.name} />
<S.BannerTitle>
<div>{starData.name}</div>
<div className="profession">{starData.profession}</div>
</S.BannerTitle>
</S.Header>
<S.ClearCantainr>
<S.ClearMain>
<div className="text">축하합니다!</div>
<div className="imgContainr">
<img src={ClearStarPIcon1} />
<img className="icon2" src={ClearStarPIcon2} />
<div className="textOverlay">
{starData.routines_added_count}회
</div>
</div>
<div className="text">루틴 완료 달성!</div>
</S.ClearMain>
</S.ClearCantainr>
</S.Wrapper>
<div id="share-button">
{/* 공유 버튼 제외할 태그 */}
<button onClick={handleCapture}>Share this page</button>
<button onClick={handleCapture}>
<S.shareContainr>
<S.shareBtn>
<div className="ImgSave">
이미지 저장하고 공유하기
<img src={shareIcon} />
</div>
</S.shareBtn>
<button className="backBtn" onClick={onBack}>
뒤로가기
</button>
</S.shareContainr>
</button>
</div>
</div>
</div>
Expand Down
161 changes: 161 additions & 0 deletions src/pages/Share/styled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { styled } from "styled-components";
import Back from "../../assets/background.svg";

export const Wrapper = styled.div`
display: flex;
width: 100%;
min-height: 100vh;
background-size: cover;
flex-direction: column;
background-image: url(${Back});
`;
export const Header = styled.div`
position: relative;
width: 100%;
`;
export const BannerImage = styled.img`
display: block;
width: 100%;
height: 282px;
object-fit: cover;
mask-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 1) 60%,
rgba(0, 0, 0, 0) 100%
);
position: relative;
`;
export const BannerTitle = styled.div`
position: absolute;
display: flex;
flex-direction: column;

bottom: 70px;
left: 10px;
z-index: 2;
font-size: 1.8rem;
color: white;
font-weight: 600;
.profession {
color: var(--naver-text, #fff);
font-family: "AppleSDGothicNeoL";
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: normal;
}
`;
export const RoutineBoxContainer = styled.div`
margin-top: 2rem;
display: flex;
flex-direction: column;
gap: 3rem;
margin-bottom: 10rem;
`;

export const ClearCantainr = styled.div`
margin-top: 2rem;
display: flex;
flex-direction: column;
margin-bottom: 10rem;

justify-content: center;
align-items: center;
gap: 2rem;
`;

export const ClearMain = styled.div`
display: flex;
flex-direction: column;
position: relative;
width: 100%;
flex: 1;
justify-content: center;
align-items: center;
gap: 20px;
color: white;

.imgContainr {
position: relative;
display: flex;
width: 100%;
margin: 0;
padding: 0;
justify-content: center;
align-items: center;
}

.icon2 {
position: absolute;
top: 50%;
left: 50%;
z-index: 2;
transform: translate(-50%, -50%);
}
.textOverlay {
position: absolute;
top: 54%;
left: 49%;
z-index: 5;
font-weight: bold;
text-align: center;
color: white;
transform: translate(-50%, -50%);
}

.text {
color: var(--naver-text, #fff);
text-align: center;
font-family: "AppleSDGothicNeoL";
font-size: 24px;
font-style: normal;
font-weight: 400;
line-height: normal;
}
`;
export const shareBtn = styled.button`
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 12px;
width: 196.505px;
height: 39.301px;
color: black;
border-radius: 19px;
border: 1.228px solid #c4d9e2;
background: rgba(196, 217, 226, 0.5);

.ImgSave {
display: flex;

padding: 6px;
justify-content: center;
align-items: center;
gap: 10px;
flex-shrink: 0;
text-align: center;
}
`;
export const shareContainr = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 1rem;
.backBtn {
display: flex;
width: 160px;
height: 32px;
padding: 6px;
justify-content: center;
align-items: center;
gap: 10px;
color: black;
flex-shrink: 0;
text-align: center;
border-radius: 15px;
border: 1px solid #c4d9e2;
background: rgba(196, 217, 226, 0.5);
}
`;
3 changes: 2 additions & 1 deletion src/pages/StarPage/StarPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Modal from "../../components/Modal/Modal";
import { CheckUp } from "../../components/CheckUp/CheckUp";
import { StarHeader } from "../../components/StarHeader/StarHeader";
import ClearStarP from "./ClearStarP";
import SharePage from "@/pages/Share/Share";
import { useRecoilValue, useRecoilState, useSetRecoilState } from "recoil";
import {
routineStart,
Expand Down Expand Up @@ -62,7 +63,7 @@ const StarPage = () => {
return (
<>
{isClearStarPVisible ? (
<ClearStarP onBack={() => setIsClearStarPVisible(false)} />
<SharePage onBack={() => setIsClearStarPVisible(false)} />
) : (
<>
<S.Header>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/StarPage/styled.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ export const ClearMain = styled.div`
}
.textOverlay {
position: absolute;
top: 50%;
left: 50%;
top: 54%;
left: 49%;
z-index: 5;
font-weight: bold;
text-align: center;
Expand Down