diff --git a/.env b/.env new file mode 100644 index 0000000..588bf8c --- /dev/null +++ b/.env @@ -0,0 +1 @@ +REACT_APP_API_ENDPOINT = https://api.tadak.dev \ No newline at end of file diff --git a/src/components/LanguageCard/styles.js b/src/components/LanguageCard/styles.js index 3366eaa..8ccd805 100644 --- a/src/components/LanguageCard/styles.js +++ b/src/components/LanguageCard/styles.js @@ -1,5 +1,4 @@ import styled from "@emotion/styled"; -import { theme } from "styles/theme"; import { BadgeIconContainer } from "components/common/Badge/styles"; export const CardContainer = styled.div` @@ -19,7 +18,7 @@ export const IconContainer = styled(BadgeIconContainer)` justify-content: center; align-items:center; - background-color:${theme.color.white}; + background-color:${({ theme }) => theme.color.white}; border-radius:10px; width:64px; height:64px; @@ -53,5 +52,5 @@ export const Summary = styled.div` font-weight: 400; font-size: 12px; - color: ${theme.color.white}; + color: ${({ theme }) => theme.color.white}; `; \ No newline at end of file diff --git a/src/components/LeaderBoard/index.js b/src/components/LeaderBoard/index.js index 49b6822..bfdd600 100644 --- a/src/components/LeaderBoard/index.js +++ b/src/components/LeaderBoard/index.js @@ -37,11 +37,11 @@ function LeaderBoard({ ranks }) { {ranks && ranks.map((rank, index) => ( props.color || theme.color.white}; -` - -export const ModalTitle = styled(ModalText)` - font-size: 40px; - font-weight: 700; -` - -export const ModalHeader = styled(ModalText)` - font-size: 36px; - font-weight: 700; -` - -export const ModalBody = styled(ModalText)` - font-size: 16px; -` - -export const ModalButton = styled.div` - padding: 10px; - width: 100%; - background-color: #bfcdf0; - border-radius: 10px; - cursor: pointer; - font-size: 16px; - color: #26262d; - text-align: center; - font-weight: bold; - &.active { - background-color: ${theme.color.primary500}; - } - - &:hover { - background-color: ${theme.color.primary200}; - } - transition: 0.3s; -` - -export const DimmedArea = styled.div` - position: fixed; - top: 0; - left: 0; - - display: flex; - justify-content: center; - align-items: center; - - width: 100%; - height: 100%; - - background-color: ${({ theme }) => hexToRgba(theme.color.white, 0.2)}; - - z-index: 1000; -`; diff --git a/src/components/PortalModal/styles.js b/src/components/PortalModal/styles.js new file mode 100644 index 0000000..b44ec31 --- /dev/null +++ b/src/components/PortalModal/styles.js @@ -0,0 +1,39 @@ +import styled from "@emotion/styled/macro"; +import { hexToRgba } from "utils/color"; +import { motion } from "framer-motion"; + +export const StyledModal = styled(motion.div)` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + font-size: 14px; + gap: 16px; + border-radius: 10px; + padding: 40px 20px; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 100; + width: 400px; + background: ${({ theme }) => theme.color.modalBG}; + box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); +`; + +export const DimmedArea = styled.div` + position: fixed; + top: 0; + left: 0; + + display: flex; + justify-content: center; + align-items: center; + + width: 100%; + height: 100%; + + background-color: ${({ theme }) => hexToRgba(theme.color.white, 0.2)}; + + z-index: 1000; +`; diff --git a/src/components/Timer/index.js b/src/components/Timer/index.js index 8a86e49..ea42248 100644 --- a/src/components/Timer/index.js +++ b/src/components/Timer/index.js @@ -1,6 +1,6 @@ import React from "react"; import { useState, useEffect } from "react"; -import { DigitText, SymbolText, TimerDiv } from "./style"; +import { DigitText, SymbolText, TimerDiv } from "components/Timer/styles"; // EXAMPLE // const [stopState, setStopState] = useState(false); diff --git a/src/components/Timer/style.js b/src/components/Timer/styles.js similarity index 81% rename from src/components/Timer/style.js rename to src/components/Timer/styles.js index d04ade6..ffc3b8a 100644 --- a/src/components/Timer/style.js +++ b/src/components/Timer/styles.js @@ -1,5 +1,4 @@ import styled from "@emotion/styled/macro"; -import { theme } from "styles/theme"; export const TimerDiv = styled.div` display: flex; flex-direction: row; @@ -11,11 +10,11 @@ border-radius: 20px; background: #161B21 ` -const baseText=styled.div` +const baseText = styled.div` font-style: normal; font-weight: 400; font-size: 48px; -color: ${theme.color.white}; +color: ${({ theme }) => theme.color.white}; ` export const DigitText = styled(baseText)` diff --git a/src/components/TypeInput/index.js b/src/components/TypeInput/index.js index 36e7a5c..391086a 100644 --- a/src/components/TypeInput/index.js +++ b/src/components/TypeInput/index.js @@ -6,8 +6,7 @@ import { useLocation } from "react-router-dom"; import { serverAxios } from "utils/commonAxios"; import PortalModal from "components/PortalModal"; import Button from "components/common/Button"; -import { ModalBody, ModalButton, ModalHeader, ModalIcon, ModalTitle } from "components/PortalModal/style"; -import { theme } from "styles/theme"; +import { ModalBody, ModalButton, ModalHeader, ModalIcon, ModalTitle } from "components/common/styles"; import TimerIcon from "assets/svgs/Tumer_light.svg"; function generateLetterStatus(currentInputString, letter, currentLetterIndex) { @@ -266,7 +265,7 @@ function TypeInput({ timePassed, setCurrentKPM, currentKPM, setIsPlaying, paragr open={showCountdownModal} onClose={() => { }} > - 준비하세요! + theme.color.blue.light}>준비하세요! {countDownSeconds} { setIsReady(false) }}>바로시작! diff --git a/src/components/common/styles.js b/src/components/common/styles.js new file mode 100644 index 0000000..715499c --- /dev/null +++ b/src/components/common/styles.js @@ -0,0 +1,45 @@ +import styled from "@emotion/styled/macro"; + +// TODO: 일단 Modal에서만 사용하는 스타일임, Modal 이외의 style에서도 활용가능하도록 일반화 +export const ModalIcon = styled.img` + width:40px; + height:40px; +` + +export const ModalText = styled.div` + color: ${({ theme, color }) => color ?? theme.color.white}; +` + +export const ModalTitle = styled(ModalText)` + font-size: 40px; + font-weight: 700; +` + +export const ModalHeader = styled(ModalText)` + font-size: 36px; + font-weight: 700; +` + +export const ModalBody = styled(ModalText)` + font-size: 16px; +` + +export const ModalButton = styled.div` + padding: 10px; + width: 100%; + background-color: #bfcdf0; + border-radius: 10px; + cursor: pointer; + font-size: 16px; + color: #26262d; + text-align: center; + font-weight: bold; + &.active { + background-color: ${({ theme }) => theme.color.primary500}; + } + + &:hover { + background-color: ${({ theme }) => theme.color.primary200}; + } + transition: 0.3s; +` diff --git a/src/constants/pagination.js b/src/constants/pagination.js new file mode 100644 index 0000000..dedc20d --- /dev/null +++ b/src/constants/pagination.js @@ -0,0 +1 @@ +export const LEADERBOARD_PAGE_SIZE = 10; \ No newline at end of file diff --git a/src/constants/paragraphs.js b/src/constants/paragraphs.js index f51c4d1..f264ddc 100644 --- a/src/constants/paragraphs.js +++ b/src/constants/paragraphs.js @@ -5,27 +5,27 @@ export const MOCKUP_STRING = [ `'languages = ['python', 'perl', 'c', 'java']\n\nfor lang in languages:\n if lang in ['pytohn', 'perl']:\n print("%6s need interpreter" % lang)\n elif lang in ['c', 'java']:\n print("%6s need compiler" % lang)\n else:\n print("should not reach here")'`, 'def fibonacci(n):\n if n <= 1:\n return n\n else:\n return(fibonacci(n-1) + fibonacci(n-2))\nnterms = int(input("How many Fibonacci do you want?: "))\nif nterms <= 0:\n print("Error : Please enter a positive number")\nelse:\n print("Fibonacci: ", end="")\n for i in range(nterms):\n print(fibonacci(i), end="")', `import random\nf1 = open('score.txt', 'w')\nfor i in range(5):\n for j in range(5):\n f1.write(str(random.randint(1, 100)) + ' ')\n f1.write('\n')\nf1 = open('score.txt', 'r')\nf2 = open('report.txt', 'w')\nwhile True:\n score = f1.readline()\n if score == '':\n break\n scorelist = score.split()\n sum = 0\n for i in range(5):\n sum += int(scorelist[i])\nf1.close()\nf2.close()`, - "class Caculator:\n def __init__(self, first, second): self.first = first\n self.second = second\n def add(self):\n result = self.first + self.second\n return result\n def sub(self):\n result = self.first - self.second\n return result\n def div(self):\n result = self.first / self.second\n return result\n def mult(self):\n result = self.first * self.second\n return result", + "class Caculator:\n def __init__(self, first, second):\n self.first = first\n self.second = second\n def add(self):\n result = self.first + self.second\n return result\n def sub(self):\n result = self.first - self.second\n return result\n def div(self):\n result = self.first / self.second\n return result\n def mult(self):\n result = self.first * self.second\n return result", + // html - '\n\n\n My First Webpage\n \n \n

Hello World!

\n

This is a test page.

\n world picture\n \n', + '\n\n \n My First Webpage\n \n \n

Hello World!

\n

This is a test page.

\n world picture\n \n', '\n\n \n \n \n \n Document\n \n \n \n', - '\n\n \n Countries Class\n \n \n
\n

Japan

\n

Tokyo is the capital of Japan.

\n
\n

India

\n

New Delhi is the capital of India.

\n
\n \n', - `\n\n \n Video Sample\n \n \n
\n \n
\n Tagline over the backgroud video.\n
\n
\n \n`, + '\n\n \n Countries Class\n \n \n
\n

Japan

\n

Tokyo is the capital of Japan.

\n
\n
\n

India

\n

New Delhi is the capital of India.

\n
\n \n', + `\n\n \n Video Sample\n \n \n
\n \n
\n Tagline over the backgroud video.\n
\n
\n \n`, '\n\n \n HTML from Tag\n \n \n
\n First name:\n \n
\n Last name:\n \n \n
\n \n', '\n\n \n Table Sample\n \n \n \n \n \n \n \n \n \n \n \n \n \n
first cellsecond cell
third cellfourth cell
\n \n', // c - "#include \n\n int main(){\n\n printf(“Hello world” );\n return 0;\n}", + "#include \n\nint main() {\n printf(“Hello world”);\n return 0;\n}", '#include \n\nint main() {\n int myAge = 43;\n printf("%p", &myAge);\n return 0;\n}', '#include \n\nint main() {\n int i = 0;\n for (i = 0; i <= 10; i = i + 2) {\n printf("%d", i);\n }\n}', - '#include \n\nint main() {\n int integer = 15;\n\n if(integer > 0) {\n printf("positive");\n }\n else if(integer < 0) {\n printf("negative");\n }\n else {\n printf("0");\n }\n}', + '#include \n\nint main() {\n int integer = 15;\n\n if(integer > 0) {\n printf("positive");\n }\n else if(integer < 0) {\n printf("negative");\n }\n else {\n printf("zero");\n }\n}', '#include \n\nint sum(int k) {\n if (k > 0) {\n return k + sum(k - 1);\n } else {\n return 0;\n }\n}\n\nint main() {\n int result = sum(10);\n printf("%d", result);\n return 0;\n}', - '#include \n\nint main() {\n int day = 4;\n switch (day) {\n case 1:\n printf("Monday");\n break;\n case 2:\n printf("Tuesday");\n break;\n case 3:\n printf("Wednesday");\n break;\n case 4:\n printf("Thursday");\n break;\n case 5:\n printf("Friday");\n break;\n case 6:\n printf("Saturday");\n break;\n case 7:\n printf("Sunday");\n break;\n }\n}', - - // 'include \n#include \ntypedef struct NODE{\n int data;\n struct NODE* next;\n}node;\n\nint main(void) {\n node* head = (node*)malloc(sizeof(node));\n head->next=NULL;\n node* node1 = (node*)malloc(sizeof(node));\n node1->next = head->next;\n node1->data = 10;\n head->next = node1;\n\n node* node2 = (node*)malloc(sizeof(node));\n node2->next = node1->next;\n node2->data = 20;\n node1->next = node2;\n\n node* curr = head->next;\n while(curr != NULL){\n printf("%d", curr->data);\n curr = curr->next; }\n\n free(head);\n free(node1);\n free(node2);\n return 0;\n}' + '#include \nint main() {\n int day = 4;\n switch (day) {\n case 1:\n printf("Monday");\n break;\n case 2:\n printf("Tuesday");\n break;\n case 3:\n printf("Wednesday");\n break;\n case 4:\n printf("Thursday");\n break;\n case 5:\n printf("Friday");\n break;\n case 6:\n printf("Saturday");\n break;\n case 7:\n printf("Sunday");\n break;\n }\n}', "Authors often misinterpret the lettuce as a folklore rabbi, when in actuality it feels more like an uncursed bacon. Pursued d", "Authors often\nmisinterpret", + // eslint-disable-next-line no-template-curly-in-string "${resetCSS}\n* {\n-webkit-tap-highlight-color: transparent;\nbox-sizing: border-box;\ntransition: background-color 0.2s;\nwill-change: background-color\n}", '\n\n\n \n \n \n Document\n\n\n \n\n', diff --git a/src/hooks/useRanks.js b/src/hooks/useRanks.js index 29aeabd..ab99fdf 100644 --- a/src/hooks/useRanks.js +++ b/src/hooks/useRanks.js @@ -15,6 +15,7 @@ function useRanks(pageNumber, pageSize, languageNo = 1, grammarNo = 1) { return { ranks: data?.ranks, + ranks_meta: data?.ranks_meta, error, mutate, // 데이터 변경 시 이 API 를 이용하는 모든 컴포넌트에 UI 업데이트 방송. }; diff --git a/src/pages/Leaderboard/index.js b/src/pages/Leaderboard/index.js index 371765a..330fe7e 100644 --- a/src/pages/Leaderboard/index.js +++ b/src/pages/Leaderboard/index.js @@ -17,17 +17,29 @@ import Spinner from "components/common/Spinner"; import DropdownComponent from "components/Dropdown"; import { mutate } from "swr"; import Pagination from "@mui/material/Pagination"; +import { LEADERBOARD_PAGE_SIZE } from "constants/pagination"; function Leaderboard() { + + const [pageNumber, setPageNumber] = useState(1); const [languageNo, setLanguageNo] = useState(1); const [languageText, setLanguageText] = useState(null); const [grammarNo, setgrammarNo] = useState(1); const [grammarText, setGrammarText] = useState(null); - const { ranks, error } = useRanks(1, 10, languageNo, grammarNo); + const { ranks, ranks_meta, error } = useRanks(pageNumber, LEADERBOARD_PAGE_SIZE, languageNo, grammarNo); const LanguageList = ["PYTHON", "HTML", "C"]; const [language, setSelected] = useState(undefined); - const [page, setPage] = useState(1); + //const [offSet, setOffSet] = useState(2); + + + const topRanks = useRanks(1, 2, languageNo, grammarNo).ranks; + + + const handlePageChange = (event, value) => { + setPageNumber(value); + + } useEffect(() => { if (languageText === "PYTHON") { @@ -50,7 +62,7 @@ function Leaderboard() { console.log(ranks); return ( <> - {ranks[0] && ( + {topRanks[0] && ( - {ranks[1] && ( + {topRanks[1] && ( )} @@ -101,11 +113,15 @@ function Leaderboard() { }} setItem={setLanguageText} /> - {ranks.slice(2).length !== 0 && ( - <> - + {ranks.length !== 0 && ( + <> + - + + )} diff --git a/src/pages/Login/index.js b/src/pages/Login/index.js index 89347bc..da4eac1 100644 --- a/src/pages/Login/index.js +++ b/src/pages/Login/index.js @@ -9,11 +9,20 @@ import Button from "components/common/Button"; import { useNavigate } from "react-router-dom"; import { Link } from "react-router-dom"; import PortalModal from "components/PortalModal"; -import { ModalHeader, ModalBody, ModalButton } from "components/PortalModal/style"; +import { ModalHeader, ModalBody, ModalButton } from "components/common/styles"; +import useUser from "hooks/useUser"; function Login() { const [showOnFailModal, setShowOnFailModal] = useState(false); const navigate = useNavigate(); + + const {loggedOut} = useUser(); + + // 로그인 된 상태에서 로그인 페이지 접속 시 메인 화면으로 redirect + if(!loggedOut) { + navigate("/"); + } + const handleSubmit = useCallback((e) => { e.preventDefault(); async function login() { @@ -60,8 +69,16 @@ function Login() { 로그인하기 - - + + + + + + 회원가입 + + 하러 가기 + + diff --git a/src/pages/Main/styles.js b/src/pages/Main/styles.js index 5f3f582..e979993 100644 --- a/src/pages/Main/styles.js +++ b/src/pages/Main/styles.js @@ -1,6 +1,5 @@ import styled from "@emotion/styled/macro"; import { motion } from "framer-motion"; -import { theme } from "styles/theme"; export const MainPageContainer = styled.main` display: flex; diff --git a/src/pages/Register/index.js b/src/pages/Register/index.js index a95342d..005a2fe 100644 --- a/src/pages/Register/index.js +++ b/src/pages/Register/index.js @@ -3,7 +3,7 @@ import InputEmail from "components/common/Inputs/InputEmail"; import InputPasswordAndCheck from "components/common/Inputs/InputPasswordAndCheck"; import InputUserName from "components/common/Inputs/InputUserName"; import PortalModal from "components/PortalModal"; -import { ModalHeader, ModalBody, ModalButton } from "components/PortalModal/style"; +import { ModalHeader, ModalBody, ModalButton } from "components/common/styles"; import React, { useState } from "react"; import { useCallback } from "react"; import { Link } from "react-router-dom"; @@ -54,7 +54,16 @@ function Register() { + + + 계정이 이미 있으세요?{" "} + + 로그인 + + 하러 가기 + +