diff --git a/component/Button/Button.styled.ts b/component/Button/Button.styled.ts index 7185683..0c43e43 100644 --- a/component/Button/Button.styled.ts +++ b/component/Button/Button.styled.ts @@ -4,6 +4,8 @@ import { ButtonProps } from './Button.types'; const getSize = ({ size }: Pick) => { switch (size) { + case 'None': + return ''; case 'XS': return css` width: 72px; @@ -19,6 +21,11 @@ const getSize = ({ size }: Pick) => { width: 320px; height: 54px; `; + case 'XL': + return css` + width: 100%; + height: 100%; + `; } }; diff --git a/component/Button/Button.tsx b/component/Button/Button.tsx index e5dddbd..53a93e7 100644 --- a/component/Button/Button.tsx +++ b/component/Button/Button.tsx @@ -1,39 +1,46 @@ -import React from 'react'; +import React, { forwardRef } from 'react'; import classNames from 'classnames'; import { ButtonProps } from './Button.types'; import { ButtonWrapper } from './Button.styled'; import { SerializedStyles, css } from '@emotion/react'; -export const Button = ({ - type = 'button', - className, - size, - disabled = false, - radius = true, - backgroundColor, - onClick, - style, - children, -}: ButtonProps) => { - return ( - <> - { - if (onClick) { - onClick(e); - } - }} - backgroundColor={backgroundColor} - css={style as SerializedStyles} - > - {children} - - - ); -}; +// eslint-disable-next-line react/display-name +export const Button = forwardRef( + ( + { + type = 'button', + className, + size, + disabled = false, + radius = true, + backgroundColor, + onClick, + style, + children, + }: ButtonProps, + ref, + ) => { + return ( + <> + { + if (onClick) { + onClick(e); + } + }} + backgroundColor={backgroundColor} + css={style as SerializedStyles} + ref={ref} + > + {children} + + + ); + }, +); diff --git a/component/Button/Button.types.ts b/component/Button/Button.types.ts index c62b4e0..32385c6 100644 --- a/component/Button/Button.types.ts +++ b/component/Button/Button.types.ts @@ -4,7 +4,7 @@ import { Property } from 'csstype'; export interface ButtonProps { type?: 'submit' | 'reset' | 'button' | undefined; className?: string; - size: 'XS' | 'S' | 'L'; + size: 'None' | 'XS' | 'S' | 'L' | 'XL'; disabled?: boolean; radius?: boolean; backgroundColor: Property.BackgroundColor; diff --git a/component/Icon/asset/share.svg b/component/Icon/asset/share.svg new file mode 100644 index 0000000..0bd7ff0 --- /dev/null +++ b/component/Icon/asset/share.svg @@ -0,0 +1,3 @@ + + + diff --git a/component/Icon/asset/yello-question.svg b/component/Icon/asset/yello-question.svg new file mode 100644 index 0000000..090c250 --- /dev/null +++ b/component/Icon/asset/yello-question.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pages/404.tsx b/pages/404.tsx new file mode 100644 index 0000000..86e21ba --- /dev/null +++ b/pages/404.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import Image from 'next/image'; + +import { BodyMedium, Spacing } from '@/component'; +import { Button } from '@/component/Button'; + +import yello_question_svg from '@/component/Icon/asset/yello-question.svg'; +import { pallete } from '@/styles/Color'; +import Link from 'next/link'; + +export default function Custom404() { + return ( +
+
{'404 ERROR'}
+ + yello_question + + + {'다시 접속하거나,\n인터넷 연결을 다시 확인해주세요'} + + + + + +
+ ); +} diff --git a/pages/school-attack/[groupId].tsx b/pages/school-attack/[groupId].tsx index 22e8e02..b5c34d3 100644 --- a/pages/school-attack/[groupId].tsx +++ b/pages/school-attack/[groupId].tsx @@ -1,8 +1,8 @@ -import React, { Fragment, useState } from 'react'; +import React, { Fragment, useCallback, useRef, useState } from 'react'; import Image from 'next/image'; import { css } from '@emotion/react'; import { useRouter } from 'next/router'; -import { TextInput } from '@primer/react'; +import { Dialog, TextInput } from '@primer/react'; import { BodyMedium, @@ -30,6 +30,7 @@ import ranking_2_svg from '@/component/Icon/asset/ranking-2.svg'; import ranking_3_svg from '@/component/Icon/asset/ranking-3.svg'; import ranking_up_svg from '@/component/Icon/asset/ranking-up.svg'; import ranking_down_svg from '@/component/Icon/asset/ranking-down.svg'; +import share_svg from '@/component/Icon/asset/share.svg'; import { useInfiniteQuery, useQuery } from '@tanstack/react-query'; import { QUERY_KEY } from '@/util/string'; @@ -38,6 +39,8 @@ import { getSchoolAttackStatisticsDetail, getSchoolAttackStatisticsLikeGroupName, } from '@/repository/statistics'; +import Script from 'next/script'; +import Link from 'next/link'; const maxWidth = 425; @@ -77,10 +80,58 @@ export default function SchoolAttack() { const firstRankingGroup = statisticsQuery.data?.pages[0].data.data.statisticsList[0]; + const observer = useRef(); + const lastItemRef = useCallback( + (node: HTMLDivElement) => { + if (observer.current) observer.current.disconnect(); + observer.current = new IntersectionObserver((entries) => { + if (entries[0].isIntersecting) { + searchQuery.hasNextPage && searchQuery.fetchNextPage(); + } + }); + if (node) observer.current.observe(node); + }, + [searchQuery], + ); + return ( <> + +
+ + +
{searchKey && ( -
+
{searchQuery.data?.pages.map((page, index) => ( {page.data.data.statisticsList.map((statistics, index) => { return ( - + <> + + + ); })} ))} +
)}
-
+
{'전국 중/고등학교 TOP 10'} @@ -372,7 +427,7 @@ const ListItem = ({ {rank} - {diffRank && ( + {diffRank && diffRank > 0 && (
0 ? ranking_up_svg : ranking_down_svg} diff --git a/public/favicon.ico b/public/favicon.ico index 718d6fe..437ce1c 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..df74c41 Binary files /dev/null and b/public/favicon.png differ diff --git a/styles/SchoolAttack.styled.ts b/styles/SchoolAttack.styled.ts index f9767cf..98ebe34 100644 --- a/styles/SchoolAttack.styled.ts +++ b/styles/SchoolAttack.styled.ts @@ -3,11 +3,13 @@ import emotionStyled from '@emotion/styled'; export const SystemLayout = emotionStyled.div` width: 100vw; height: content-fit; - + display: flex; flex-direction: row; align-items: center; justify-content: center; + + position: relative; `; export const MainLayout = emotionStyled.main<{ maxWidth: number }>` @@ -16,4 +18,5 @@ export const MainLayout = emotionStyled.main<{ maxWidth: number }>` max-width: ${(props) => props.maxWidth}px; width: 100vw; + min-height: 100vh; `; diff --git a/styles/globals.css b/styles/globals.css index 5a70290..2b5ba76 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -1,4 +1,5 @@ @import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css'); +@import url('https://fonts.googleapis.com/css2?family=Unbounded:wght@200..900&display=swap'); @tailwind base; @tailwind components; @@ -12,3 +13,64 @@ div { body { background-color: black; } + +a { + width: fit-content; + height: fit-content; +} + +.unbounded-200 { + font-family: 'Unbounded', sans-serif; + font-optical-sizing: auto; + font-weight: 200; + font-style: normal; +} + +.unbounded-300 { + font-family: 'Unbounded', sans-serif; + font-optical-sizing: auto; + font-weight: 300; + font-style: normal; +} + +.unbounded-400 { + font-family: 'Unbounded', sans-serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; +} + +.unbounded-500 { + font-family: 'Unbounded', sans-serif; + font-optical-sizing: auto; + font-weight: 500; + font-style: normal; +} + +.unbounded-600 { + font-family: 'Unbounded', sans-serif; + font-optical-sizing: auto; + font-weight: 600; + font-style: normal; +} + +.unbounded-700 { + font-family: 'Unbounded', sans-serif; + font-optical-sizing: auto; + font-weight: 700; + font-style: normal; +} + +.unbounded-800 { + font-family: 'Unbounded', sans-serif; + font-optical-sizing: auto; + font-weight: 800; + font-style: normal; +} + +.unbounded-900 { + font-family: 'Unbounded', sans-serif; + font-optical-sizing: auto; + font-weight: 900; + font-style: normal; +}