Skip to content

Commit

Permalink
[JR-679] 투표 홈 퍼블리싱 (#134)
Browse files Browse the repository at this point in the history
* feat: 플립 애니메이션 훅 구현

* fix: 버튼 폰트 수정

* feat: 투표 홈 페이지 구현

* feat react import 제거
  • Loading branch information
leejiho9898 authored Sep 6, 2023
1 parent 7e7c285 commit 4a08000
Show file tree
Hide file tree
Showing 3 changed files with 292 additions and 0 deletions.
75 changes: 75 additions & 0 deletions apps/jurumarble/src/app/vote/hooks/useFlipAnimation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useRef, useState } from "react";

export type Drag = "up" | "down" | null;
function useFlipAnimation(onChangeNowShowing: (index: number) => void) {
const [drag, setDrag] = useState<Drag>(null);
const [startTouchPosition, setStartTouchPosition] = useState({
y: 0,
});
const lastTouchEventTimeRef = useRef(0);

const onActFlip = (e: React.WheelEvent<HTMLDivElement>) => {
const now = Date.now();
const timeDiff = now - lastTouchEventTimeRef.current;
if (timeDiff < 1500) {
// 이전 이벤트가 1.5초 내에 발생한 경우 무시
return;
}
lastTouchEventTimeRef.current = now;
// 휠을 올리면 up, 내리면 down
if (e.deltaY < 0) {
setDrag("up");
setTimeout(() => {
onChangeNowShowing(-1);
}, 750);
}
if (e.deltaY > 0) {
setDrag("down");
setTimeout(() => {
onChangeNowShowing(1);
}, 750);
}

setTimeout(() => {
setDrag(null);
}, 850);
};

const onTouchStartPosition = (e: React.TouchEvent<HTMLDivElement>) => {
setStartTouchPosition({
y: e.changedTouches[0].clientY,
});
};

const onTouchMoveActFlip = (e: React.TouchEvent<HTMLDivElement>) => {
const now = Date.now();
const timeDiff = now - lastTouchEventTimeRef.current;
if (timeDiff < 1500) {
// 이전 이벤트가 1.5초 내에 발생한 경우 무시
return;
}
lastTouchEventTimeRef.current = now;

//터치의 시작이 끝보다 위면 up, 아래면 down
if (e.changedTouches[0].clientY - startTouchPosition.y > 0) {
setDrag("up");
setTimeout(() => {
onChangeNowShowing(-1);
}, 750);
}
if (e.changedTouches[0].clientY - startTouchPosition.y < 0) {
setDrag("down");
setTimeout(() => {
onChangeNowShowing(1);
}, 750);
}

setTimeout(() => {
setDrag(null);
}, 850);
};

return { onActFlip, drag, onTouchStartPosition, onTouchMoveActFlip };
}

export default useFlipAnimation;
216 changes: 216 additions & 0 deletions apps/jurumarble/src/app/vote/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
"use client";

import BottomBar from "components/BottomBar";
import { Button } from "components/button";
import Header from "components/Header";
import { media } from "lib/styles";
import { ExImg1 } from "public/images";
import React, { useState } from "react";
import SvgIcDetail from "src/assets/icons/components/IcDetail";
import styled, { css } from "styled-components";
import useFlipAnimation from "./hooks/useFlipAnimation";
import ChipContainer from "./[id]/components/ChipContainer";
import VoteDescription from "./[id]/components/VoteDescription";

export type Drag = "up" | "down" | null;

function VoteHomePage() {
// const { data, isError, isLoading, mainVoteList, nowShowing, onChangeNowShowing } =
// useInfiniteMainListService({ size: 5, sortBy: "ByTime" });
const [selected, setSelected] = useState<"A" | "B" | null>(null);
const onMutateVoting = (select: "A" | "B") => {
setSelected(select);
};

const onChangeNowShowing = () => {
console.log("z");
};

const { onActFlip, drag, onTouchStartPosition, onTouchMoveActFlip } =
useFlipAnimation(onChangeNowShowing);
return (
<>
<Background>
<Header />
<AskVoteBox>
<AskVoteText>
당신의 투표를
<br /> 기다리고 있어요
</AskVoteText>
<div>
<Button variant="primary" width="104px" height="40px">
작성하기 <BigFont></BigFont>
</Button>
</div>
</AskVoteBox>
<Container>
<PageInner
className="animate"
onWheel={onActFlip}
onTouchStart={onTouchStartPosition}
onTouchEnd={onTouchMoveActFlip}
drag={drag}
>
<ChipContainer />
<VoteDescription
imageA={ExImg1}
imageB={ExImg1}
percentageA={50}
percentageB={50}
titleA={"A가 더 좋아요"}
titleB={"B가 더 좋아요"}
totalCountA={100}
totalCountB={100}
select={selected}
onMutateVoting={onMutateVoting}
/>
<MoreButton>
더보기 <SvgIcDetail width={16} height={16} />
</MoreButton>
</PageInner>
<FirstPageBase className="animate2" drag={drag} />
<SecondPageBase className="animate3" drag={drag} />
</Container>
</Background>
<BottomBar />
</>
);
}

const Background = styled.div`
background-color: ${({ theme }) => theme.colors.bg_01};
height: calc(100svh - 100px);
`;

const Container = styled.div`
position: relative;
width: 100%;
display: flex;
justify-content: center;
scrollbar-width: none;
`;

const PageInner = styled.div<{ drag: Drag }>`
position: relative;
margin: 0 auto;
border-radius: 10px;
min-height: 453px;
background-color: ${({ theme }) => theme.colors.white};
max-width: 640px;
padding: 30px;
z-index: 1000;
width: 100%;
${media.small} {
height: 600px;
padding: 40px;
}
${({ drag }) =>
drag === "up" &&
css`
transition: all 0.5s ease-in-out;
transform-origin: 50% 0;
perspective: 600px;
transform: rotateX(-90deg) scale(0.9, 1.032);
opacity: 0;
`}
${({ drag }) =>
drag === "down" &&
css`
transition: all 0.5s ease-in-out;
transform: rotateX(90deg) scale(0.9, 1.032);
transform-origin: 50% 100%;
perspective: 600px;
opacity: 0.5;
`}
`;

const AskVoteBox = styled.div`
width: 100%;
display: flex;
margin: 0 auto;
justify-content: space-between;
padding: 24px 20px;
max-width: 640px;
background-color: ${({ theme }) => theme.colors.bg_01};
`;

const FirstPageBase = styled.div<{ drag: Drag }>`
position: absolute;
background-color: ${({ theme }) => theme.colors.white};
border-radius: 4px;
width: 90%;
max-width: 576px;
min-height: 473px;
opacity: 0.6;
z-index: 500;
transition: all 0.5s ease-in-out;
${media.small} {
height: 620px;
}
${({ drag }) =>
drag === "up" &&
css`
perspective: 600px;
transform-origin: 50% 0;
transform: scale(1.11, 0.97);
opacity: 1;
`}
${({ drag }) =>
drag === "down" &&
css`
opacity: 1;
transform: scale(1.11, 0.97);
`}
`;

const SecondPageBase = styled(FirstPageBase)`
width: 78%;
max-width: 496px;
min-height: 493px;
opacity: 0;
z-index: 500;
transition: all 0.5s ease-in-out;
${media.small} {
height: 640px;
}
${({ drag }) =>
drag === "up" &&
css`
opacity: 0.6;
`}
${({ drag }) =>
drag === "down" &&
css`
opacity: 0.6;
`}
`;

const BigFont = styled.span`
font-size: 17px;
`;

const AskVoteText = styled.div`
${({ theme }) => theme.typography.headline02}
`;

const MoreButton = styled.button`
position: absolute;
left: 50%;
right: 50%;
transform: translate(-50%, -50%);
bottom: -40px;
height: 40px;
width: 94px;
border-radius: 8px;
${({ theme }) => css`
color: ${theme.colors.white};
background-color: ${theme.colors.black_02};
${theme.typography.button01}
`};
display: flex;
justify-content: center;
align-items: center;
gap: 6px;
`;
export default VoteHomePage;
1 change: 1 addition & 0 deletions apps/jurumarble/src/components/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const ButtonStyled = styled.button<ButtonStyledProps>`
border: none;
cursor: pointer;
${variant && variantStyles[variant]};
${theme.typography.button01}
`}
`;

Expand Down

0 comments on commit 4a08000

Please sign in to comment.