diff --git a/src/App.tsx b/src/App.tsx index 2d2abb8..a62e381 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,6 @@ import AddTime from './pages/addTime'; import Current from './pages/current'; import RoomCalendar from './pages/roomCalendar'; import RoomStart from './pages/roomStart'; -import Start from './pages/start'; import Timer from './pages/roomTimer'; import Login from './pages/login'; import Result from './pages/result'; @@ -14,13 +13,15 @@ import Error from './pages/404'; import useScrollToTop from './hooks/useScrollToTop'; import useGoogleAnalytics from './hooks/useGoogleAnalytics'; +import Landing from './pages/landing'; + function App() { useGoogleAnalytics(); useScrollToTop(); return ( - } /> + } /> } /> } /> } /> diff --git a/src/assets/icons/scrollArrow.webp b/src/assets/icons/scrollArrow.webp new file mode 100644 index 0000000..0910edd Binary files /dev/null and b/src/assets/icons/scrollArrow.webp differ diff --git a/src/assets/images/landing1.webp b/src/assets/images/landing1.webp new file mode 100644 index 0000000..0b4da48 Binary files /dev/null and b/src/assets/images/landing1.webp differ diff --git a/src/assets/images/landing2.webp b/src/assets/images/landing2.webp new file mode 100644 index 0000000..adc9ea6 Binary files /dev/null and b/src/assets/images/landing2.webp differ diff --git a/src/assets/images/landing3.webp b/src/assets/images/landing3.webp new file mode 100644 index 0000000..d71ae7d Binary files /dev/null and b/src/assets/images/landing3.webp differ diff --git a/src/assets/images/landing4.webp b/src/assets/images/landing4.webp new file mode 100644 index 0000000..b1362d4 Binary files /dev/null and b/src/assets/images/landing4.webp differ diff --git a/src/assets/images/landing5.webp b/src/assets/images/landing5.webp new file mode 100644 index 0000000..03aed6f Binary files /dev/null and b/src/assets/images/landing5.webp differ diff --git a/src/assets/images/landing6.webp b/src/assets/images/landing6.webp new file mode 100644 index 0000000..f3b1548 Binary files /dev/null and b/src/assets/images/landing6.webp differ diff --git a/src/assets/images/landingBack.webp b/src/assets/images/landingBack.webp new file mode 100644 index 0000000..f17d981 Binary files /dev/null and b/src/assets/images/landingBack.webp differ diff --git a/src/assets/images/logo.webp b/src/assets/images/logo.webp new file mode 100644 index 0000000..acf9ce5 Binary files /dev/null and b/src/assets/images/logo.webp differ diff --git a/src/assets/images/rabbit.webp b/src/assets/images/rabbit.webp new file mode 100644 index 0000000..03ec558 Binary files /dev/null and b/src/assets/images/rabbit.webp differ diff --git a/src/components/createRoom/calendar/index.tsx b/src/components/createRoom/calendar/index.tsx index f94f452..2887811 100644 --- a/src/components/createRoom/calendar/index.tsx +++ b/src/components/createRoom/calendar/index.tsx @@ -14,7 +14,7 @@ interface Calendar { } const Calendar = ({ dates, setDates, setMonth }: Calendar) => { - const [isRange, setIsRange] = useState(true); + const [isRange, setIsRange] = useState(false); const [value, setValue] = useState(); const ko = { diff --git a/src/components/createRoom/toggle/index.tsx b/src/components/createRoom/toggle/index.tsx index d8e0a77..4b3f6e9 100644 --- a/src/components/createRoom/toggle/index.tsx +++ b/src/components/createRoom/toggle/index.tsx @@ -18,9 +18,9 @@ const Toggle = ({ text, toggle, setData }: ToggleProps) => { return ( - {text[0]} {text[1]} - {isToggle ? text[0] : text[1]} + {text[0]} + {isToggle ? text[0] : text[1]} ); }; diff --git a/src/hooks/useComponentOnScreen.ts b/src/hooks/useComponentOnScreen.ts new file mode 100644 index 0000000..7740025 --- /dev/null +++ b/src/hooks/useComponentOnScreen.ts @@ -0,0 +1,26 @@ +import { useEffect, RefObject } from 'react'; + +export const useComponentOnScreen = (refs: RefObject[]) => { + const handleScroll = (entries: any[]) => { + entries.forEach((item) => { + if (item.isIntersecting) { + item.target.style.opacity = 1; + item.target.style.transform = 'translateZ(0)'; + } + }); + }; + + const observer = new IntersectionObserver(handleScroll, { + threshold: 0.2, + }); + + useEffect(() => { + refs.forEach((ref) => { + if (ref.current) { + observer.observe(ref.current); + } + }); + + return () => observer && observer.disconnect(); + }, []); +}; diff --git a/src/pages/landing/index.styles.ts b/src/pages/landing/index.styles.ts new file mode 100644 index 0000000..fa6d498 --- /dev/null +++ b/src/pages/landing/index.styles.ts @@ -0,0 +1,188 @@ +import styled from '@emotion/styled'; +import theme from '../../styles/theme'; +import landingBack from '@/assets/images/landingBack.webp'; +import { flotingAnimation } from '@/utils/flotingAnimation'; + +export const MainContainer = styled.div` + display: flex; + flex-direction: column; + width: 100%; + max-width: 412px; + height: 6000px; + margin: 0 auto; + background-image: url(${landingBack}); + background-size: cover; + background-position: center; + background-color: ${theme.colors.purple05}; + &::-webkit-scrollbar { + display: none; + } + overflow-x: hidden; +`; + +export const StartWrapper = styled.div` + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + padding-top: 150px; + + @media screen and (max-width: 375px) { + padding-top: 80px; + } + + height: 900px; + + .logo-header { + ${theme.typography.semibold02} + background: linear-gradient(180deg, #e3e7ff 0%, #f8f8ff 100%); + color: transparent; + -webkit-background-clip: text; + padding-bottom: 12px; + } + + .logo { + width: 250px; + height: 42px; + margin-bottom: 58px; + } + + .rabbit { + width: 250px; + } +`; + +export const ScrollWrapper = styled.div` + display: flex; + flex-direction: row; + padding-top: 55px; + gap: 6px; + position: absolute; + bottom: 100px; + + color: ${theme.colors.gray01}; + ${theme.typography.semibold04} + + .arrow { + width: 17px; + height: 19px; + } + + animation: ${flotingAnimation} 2s 5; +`; + +export const IntroWrapper = styled.div` + display: flex; + flex-direction: column; + width: 100%; + height: 550px; + font-size: 22px; + color: ${theme.colors.gray01}; + opacity: 0; + transition: all 2s; + transform: translateY(150px); + + align-items: center; + ${theme.typography.semibold04} + + gap: 40px; + + white-space: pre-line; + + .title { + text-align: center; + color: ${theme.colors.gray01}; + ${theme.typography.semibold04}; + font-size: 22px; + } + + .chat { + width: calc(100% - 42px); + } + + .logo { + width: 199px; + margin-inline: 10px; + } + + .section { + margin-top: 50px; + display: flex; + flex-direction: column; + align-items: center; + + .section-text { + font-size: 28px; + } + } +`; + +export const ContentsWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 70px; + padding-top: 340px; + + @media screen and (max-width: 375px) { + gap: 170px; + } + + white-space: pre-line; +`; + +export const ContentWrapper = styled.div<{ index: number }>` + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + font-size: 22px; + opacity: 0; + transition: all 2s; + transform: translateY(150px); + + img { + width: ${(props) => + props.index == 1 + ? 'calc(100% - 142px)' + : props.index == 2 + ? 'calc(100% - 41px)' + : props.index == 3 + ? 'calc(100% - 140px)' + : 'calc(100% - 144px)'}; + } +`; + +export const LastWrapper = styled.div` + margin-top: 180px; + white-space: pre-line; + text-align: center; + opacity: 0; + transition: all 2s; + transform: translateY(50px); + + .title { + color: ${theme.colors.gray01}; + ${theme.typography.semibold02} + } +`; + +export const TitleWrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 8px; + text-align: center; + white-space: pre-line; + padding-bottom: 45px; + + .title-header { + color: ${theme.colors.purple06}; + ${theme.typography.semibold06}; + } + + .title { + color: ${theme.colors.gray07}; + ${theme.typography.semibold01}; + } +`; diff --git a/src/pages/landing/index.tsx b/src/pages/landing/index.tsx new file mode 100644 index 0000000..049833d --- /dev/null +++ b/src/pages/landing/index.tsx @@ -0,0 +1,123 @@ +import { useRef } from 'react'; +import { Link } from 'react-router-dom'; + +import * as S from './index.styles'; + +import BottomButton from '@/components/commons/bottomButton'; +import { useComponentOnScreen } from '@/hooks/useComponentOnScreen'; + +import Rabbit from '@/assets/images/rabbit.webp'; +import Logo from '@/assets/images/logo.webp'; +import ScrollArrow from '@/assets/icons/scrollArrow.webp'; +import landing1 from '@/assets/images/landing1.webp'; +import landing2 from '@/assets/images/landing2.webp'; +import landing3 from '@/assets/images/landing3.webp'; +import landing4 from '@/assets/images/landing4.webp'; +import landing5 from '@/assets/images/landing5.webp'; +import landing6 from '@/assets/images/landing6.webp'; + +const Landing = () => { + const introRef = useRef(null); + const firstRef = useRef(null); + const secondRef = useRef(null); + const thirdRef = useRef(null); + const fourthRef = useRef(null); + const lastRef = useRef(null); + + useComponentOnScreen([ + introRef, + firstRef, + secondRef, + thirdRef, + fourthRef, + lastRef, + ]); + + const CONTENTS = [ + { + id: 1, + titleHeader: '약속 시간 만들기', + title: '간단하게 약속 모임을\n만들어보세요', + images: [landing2, landing3], + ref: firstRef, + }, + { + id: 2, + titleHeader: '시간 입력하기', + title: '되는 시간/안되는 시간 토글로\n일정을 등록해보세요', + images: [landing4], + ref: secondRef, + }, + { + id: 3, + titleHeader: '실시간 확인하기', + title: '일정등록 타이머와 함께\n실시간 참여율을 확인할 수 있어요', + images: [landing5], + ref: thirdRef, + }, + { + id: 4, + titleHeader: '우선순위 확인하기', + title: '조율 결과를\n한눈에 확인해볼까요?', + images: [landing6], + ref: fourthRef, + }, + ]; + + return ( + + +
쉽고 빠른 약속 정하기
+ + + + + 스크롤해보세요 + +
+ +
+ {`3인 이상 약속을 잡을 때, + 일정 조율하기 어렵지 않으셨나요?`} +
+ +
+
+ 이 +
+
도와드릴게요!
+
+
+ + {CONTENTS.map((item) => { + return ( + + +
{item.titleHeader}
+
{item.title}
+
+ {item.images.map((image) => { + return ; + })} +
+ ); + })} +
+ +
+ {`간편하고 빠르게 약속시간을 정하고 싶다면 + 모두의 시간과 함께 해보세요!`} +
+
+ + + +
+ ); +}; + +export default Landing; diff --git a/src/pages/roomStart/index.styles.ts b/src/pages/roomStart/index.styles.ts index 585bfde..9fc938b 100644 --- a/src/pages/roomStart/index.styles.ts +++ b/src/pages/roomStart/index.styles.ts @@ -183,7 +183,7 @@ export const ChceckContainer = styled.div` padding-right: 20px; `; -export const CheckListText = styled.text` +export const CheckListText = styled.div` font-family: Pretendard; `; diff --git a/src/pages/start/index.styles.ts b/src/pages/start/index.styles.ts deleted file mode 100644 index 4168877..0000000 --- a/src/pages/start/index.styles.ts +++ /dev/null @@ -1,36 +0,0 @@ -import styled from '@emotion/styled'; -import theme from '@/styles/theme'; -import background from '@/assets/images/startBack.webp'; - -export const MainContainer = styled.div` - width: 100%; - max-width: 412px; - height: 100vh; - position: relative; - left: 0; - right: 0; - margin: 0 auto; - background-size: cover; - background-position: center; - background-image: url(${background}); - overflow-y: hidden; -`; - -export const BottomButton = styled.button` - width: calc(100% - 40px); - max-width: 375px; - height: 52px; - margin: 0 auto; - position: absolute; - border-radius: 6px; - ${theme.typography.semibold03}; - color: ${theme.colors.purple06}; - background: ${theme.colors.gray01}; - display: flex; - align-items: center; - justify-content: center; - position: fixed; - left: 0; - right: 0; - bottom: 28px; -`; diff --git a/src/pages/start/index.tsx b/src/pages/start/index.tsx deleted file mode 100644 index 6a8445a..0000000 --- a/src/pages/start/index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Link } from 'react-router-dom'; -import { BottomButton, MainContainer } from './index.styles'; -import { ROUTES } from '@/constants/ROUTES'; - -const StartPage = () => { - return ( - - - 시작하기 - - - ); -}; - -export default StartPage; diff --git a/src/utils/flotingAnimation.ts b/src/utils/flotingAnimation.ts new file mode 100644 index 0000000..e0b049f --- /dev/null +++ b/src/utils/flotingAnimation.ts @@ -0,0 +1,13 @@ +import { keyframes } from '@emotion/react'; + +export const flotingAnimation = keyframes` +0% { + transform: translatey(0px); + } + 50% { + transform: translatey(-20px); + } + 100% { + transform: translatey(0px); + } +`;