diff --git a/src/App.css b/src/App.css deleted file mode 100644 index b9d355df..00000000 --- a/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/src/App.tsx b/src/App.tsx index 66309e2d..ae2ef041 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,7 +2,6 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useState } from 'react'; import { RouterProvider } from 'react-router-dom'; import { RecoilRoot } from 'recoil'; -import './App.css'; import router from './router/Router'; import GlobalStyle from './style/GlobalStyle'; diff --git a/src/components/common/title/SubTitle.tsx b/src/components/common/title/SubTitle.tsx new file mode 100644 index 00000000..a500a69c --- /dev/null +++ b/src/components/common/title/SubTitle.tsx @@ -0,0 +1,11 @@ +import * as S from './Title.style'; + +interface SubTitleProps { + subTitle: string; +} + +const SubTitle = ({ subTitle }: SubTitleProps) => { + return {subTitle}; +}; + +export default SubTitle; diff --git a/src/components/common/title/Title.style.ts b/src/components/common/title/Title.style.ts new file mode 100644 index 00000000..e4fe4d09 --- /dev/null +++ b/src/components/common/title/Title.style.ts @@ -0,0 +1,11 @@ +import styled from 'styled-components'; +import theme from '../../../style/theme'; + +export const Title = styled.p` + color: ${theme.colors.B_01}; + ${theme.fonts.heading_01}; +`; +export const SubTitle = styled.p` + color: ${theme.colors.G_10}; + ${theme.fonts.caption_02}; +`; diff --git a/src/components/common/title/Title.tsx b/src/components/common/title/Title.tsx new file mode 100644 index 00000000..e6771279 --- /dev/null +++ b/src/components/common/title/Title.tsx @@ -0,0 +1,11 @@ +import * as S from './Title.style'; + +interface TitleProps { + title: string; +} + +const Title = ({ title }: TitleProps) => { + return {title}; +}; + +export default Title; diff --git a/src/components/onboarding/step01/Step01.style.ts b/src/components/onboarding/step01/Step01.style.ts new file mode 100644 index 00000000..96ae15b4 --- /dev/null +++ b/src/components/onboarding/step01/Step01.style.ts @@ -0,0 +1,46 @@ +import styled, { css } from 'styled-components'; +import theme from '../../../style/theme'; + +export const Input = styled.input<{ hasContent: boolean; maxLengthReached: boolean }>` + display: flex; + justify-content: center; + align-items: flex-start; + width: 100%; + margin-top: 7.2rem; + border: none; + border-bottom: 0.1rem solid ${theme.colors.G_02}; + outline: none; + gap: 0.8rem; + + ${(props) => + props.hasContent && + css` + border-bottom: 0.1rem solid ${theme.colors.P_06}; + `} + + ${(props) => + props.maxLengthReached && + css` + border-bottom: 0.1rem solid ${theme.colors.G_02}; + `} + + input::placeholder { + color: ${theme.colors.G_07}; + ${theme.fonts.body_06} + } + + &::-webkit-input-placeholder { + color: ${theme.colors.G_07}; + ${theme.fonts.body_06} + } + + &:-ms-input-placeholder { + color: ${theme.colors.G_07}; + ${theme.fonts.body_06} + } +`; + +export const LetterLength = styled.p` + color: ${theme.colors.G_07}; + ${theme.fonts.body_10} +`; diff --git a/src/components/onboarding/step01/Step01.tsx b/src/components/onboarding/step01/Step01.tsx new file mode 100644 index 00000000..33f949d0 --- /dev/null +++ b/src/components/onboarding/step01/Step01.tsx @@ -0,0 +1,32 @@ +import { useState } from 'react'; +import Title from '../../common/title/Title'; +import * as S from './Step01.style'; + +const NameInput = () => { + const [text, setText] = useState(''); + + const onChange = (e: React.ChangeEvent) => { + const inputValue = e.target.value; + const unicodeChars = [...inputValue].filter((char) => /[\ud800-\udfff]/.test(char)).length; + + inputValue.length + unicodeChars <= 10 ? setText(inputValue) : e.preventDefault(); + }; + + return ( + <> + + <Title title='이름, 혹은 닉네임을 알려주세요' /> + <S.Input + type='text' + onChange={onChange} + maxLength={10} + placeholder='이름을 입력해주세요' + hasContent={text.length > 0} + maxLengthReached={text.length === 10} + /> + <S.LetterLength>({text.length}/10)</S.LetterLength> + </> + ); +}; + +export default NameInput; diff --git a/src/components/onboarding/step02/Step02.tsx b/src/components/onboarding/step02/Step02.tsx new file mode 100644 index 00000000..0424e97c --- /dev/null +++ b/src/components/onboarding/step02/Step02.tsx @@ -0,0 +1,7 @@ +import Title from '../../common/title/Title'; + +const ThumbnailInput = () => { + return <Title title='썸네일을 등록해주세요' />; +}; + +export default ThumbnailInput; diff --git a/src/components/onboarding/step03/Step03.tsx b/src/components/onboarding/step03/Step03.tsx new file mode 100644 index 00000000..3f21a54e --- /dev/null +++ b/src/components/onboarding/step03/Step03.tsx @@ -0,0 +1,13 @@ +import Title from '../../common/title/Title'; + +const GiftDelivery = () => { + return ( + <> + <Title title='님께' /> + <Title title='언제 선물을' /> + <Title title='전달하실 예정인가요?' /> + </> + ); +}; + +export default GiftDelivery; diff --git a/src/components/onboarding/step04/Step04.tsx b/src/components/onboarding/step04/Step04.tsx new file mode 100644 index 00000000..4e5b1bd6 --- /dev/null +++ b/src/components/onboarding/step04/Step04.tsx @@ -0,0 +1,14 @@ +import SubTitle from '../../common/title/SubTitle'; +import Title from '../../common/title/Title'; + +const SetTournamentSchedule = () => { + return ( + <> + <Title title='선물 토너먼트' /> + <Title title='시작 일정을 설정해주세요' /> + <SubTitle subTitle='토너먼트 시작 전까지 선물을 등록할 수 있어요.' /> + </> + ); +}; + +export default SetTournamentSchedule; diff --git a/src/components/onboarding/step05/Step05.tsx b/src/components/onboarding/step05/Step05.tsx new file mode 100644 index 00000000..560d3d72 --- /dev/null +++ b/src/components/onboarding/step05/Step05.tsx @@ -0,0 +1,14 @@ +import SubTitle from '../../common/title/SubTitle'; +import Title from '../../common/title/Title'; + +const SetTournamentDuration = () => { + return ( + <> + <Title title='선물 토너먼트' /> + <Title title='진행 시간을 설정해주세요' /> + <SubTitle subTitle='토너먼트가 아래 시간 동안 진행돼요.' /> + </> + ); +}; + +export default SetTournamentDuration; diff --git a/src/core/onboarding.ts b/src/core/onboarding.ts new file mode 100644 index 00000000..30a6a41f --- /dev/null +++ b/src/core/onboarding.ts @@ -0,0 +1,7 @@ +export const ONBOARDING_FORM_STEP = [ + 'NAME', + 'THUMBNAIL', + 'PRESENT', + 'TOURNAMENT_SCHEDULE_REGISTRATION', + 'TOURNAMENT_PROCEEDING', +] as const; diff --git a/src/index.css b/src/index.css deleted file mode 100644 index 6119ad9a..00000000 --- a/src/index.css +++ /dev/null @@ -1,68 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/src/main.tsx b/src/main.tsx index b7439da4..089abf09 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,7 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App.tsx'; -import './index.css'; import Styles from './style/index.tsx'; ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/src/pages/OnBoardingPage.tsx b/src/pages/OnBoardingPage.tsx new file mode 100644 index 00000000..96836df3 --- /dev/null +++ b/src/pages/OnBoardingPage.tsx @@ -0,0 +1,18 @@ +//온보딩 모든 컴포넌트를 funnel로 관리하는 최상위 페이지 + +import styled from 'styled-components'; +import NameInput from '../components/onboarding/step01/Step01'; + +const OnBoardingPage = () => { + return ( + <OnBoardingPageWrapper> + <NameInput /> + </OnBoardingPageWrapper> + ); +}; + +export default OnBoardingPage; + +const OnBoardingPageWrapper = styled.div` + margin: 2rem; +`; diff --git a/src/router/Router.tsx b/src/router/Router.tsx index fefce05c..13bbf868 100644 --- a/src/router/Router.tsx +++ b/src/router/Router.tsx @@ -2,6 +2,7 @@ import { createBrowserRouter } from 'react-router-dom'; import Main from '../pages/Main'; import Mypage from '../pages/Mypage'; import Layout from '../layouts/Layout'; +import OnBoardingPage from '../pages/OnBoardingPage'; const router = createBrowserRouter([ { @@ -16,6 +17,10 @@ const router = createBrowserRouter([ path: '/mypage', element: <Mypage />, }, + { + path: '/onboarding', + element: <OnBoardingPage />, + }, ], }, ]);