From cc23371b4f6e91ac0e361ad7e6245b54b352ee39 Mon Sep 17 00:00:00 2001 From: jungmir Date: Sun, 2 Jun 2024 19:51:05 +0900 Subject: [PATCH] Feat: apply responsive style for mobile. --- package.json | 1 + src/components/Footer/index.tsx | 103 +------ src/components/Nav/index.tsx | 99 ++---- src/components/common/Page/style.scss | 419 +++++++++++++++++++++++--- src/locale/English/translation.ts | 3 +- src/pages/Home/index.tsx | 36 +-- src/utils/hooks/useIsMobile.ts | 13 + yarn.lock | 36 +-- 8 files changed, 451 insertions(+), 259 deletions(-) create mode 100644 src/utils/hooks/useIsMobile.ts diff --git a/package.json b/package.json index 2a65ee2..c16da98 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@testing-library/user-event": "^13.5.0", "axios": "^1.6.8", "dotenv": "^16.4.5", + "hamburger-react": "^2.5.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-helmet": "^6.1.0", diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx index 3af781b..765d3d6 100644 --- a/src/components/Footer/index.tsx +++ b/src/components/Footer/index.tsx @@ -78,7 +78,7 @@ const Footer = () => { )) )} */} - +
@@ -126,9 +126,9 @@ const Footer = () => { {t("개인 정보 처리 방침")} -
- - + {/*
*/} + +
{t("파이콘 한국 행동 강령")} (CoC)
@@ -159,7 +159,7 @@ const Footer = () => {
- +
); }; @@ -175,96 +175,3 @@ const Sponsors = styled.div` background-color: deeppink; ////////////////////////// `; - -const About = styled.div` - height: 9rem; - margin-bottom: 2.5rem; - color: #FEBD99; - height: max-content; - - border-top: 1px solid black; - - display: flex; - justify-content: space-between; - align-items: center; - - font-size: 0.8rem; - - & > section.left { - width: 29%; - padding-left: 1%; - - & > table { - border: 1px; - td { - background-color: #090909 !important; - } - tr > td:nth-of-type(2) { - padding-left: 1.5rem; - } - } - } - - & > section.center { - width: 70%; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - font-size: 0.75rem; - - & > div.slogan { - font-size: 1rem; - } - & > div + div { - margin-top: 1vh; - } - & > div a { - text-decoration: none; - color: #B0A8FE; - } - } - - & > section.right { - width: 29%; - padding-right: 1%; - } -`; - -const Fixed = styled.div` - position: fixed; - bottom: 0; - - width: 100%; - height: 2.5rem; - - display: flex; - justify-content: space-between; - align-items: center; - - padding: 0 2vw 0 1vw; - - & > section.left { - font-weight: bold; - } - - & > section.right { - padding-top: 4px; - - svg { - width: 1.4rem; - fill: #FEBD99; - } - - a + a { - margin-left: 1.1rem; - } - } - - ////////////////////////// - background-color: #141414; - color: #FEBD99; - ////////////////////////// -`; diff --git a/src/components/Nav/index.tsx b/src/components/Nav/index.tsx index 4bfcacd..ee2bed1 100644 --- a/src/components/Nav/index.tsx +++ b/src/components/Nav/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import { useSelector } from "react-redux"; import { useDispatch } from "react-redux"; import { useNavigate } from "react-router"; @@ -8,13 +8,17 @@ import styled from "styled-components"; import useTranslation from "utils/hooks/useTranslation"; import MenuRoutes from "./menus"; import { Slogan as SloganSvg } from "assets/icons"; +import Hamburger from "hamburger-react"; +import useIsMobile from "utils/hooks/useIsMobile"; const Nav = () => { const navigate = useNavigate(); const dispatch = useDispatch(); + const isMobile = useIsMobile(); const language = useSelector( (state) => state.core.language ); + const [openMenu, setOpenMenu] = useState(false); const t = useTranslation(); // 로그인 여부 확인 @@ -24,23 +28,22 @@ const Nav = () => { const isLogin = localStorage.getItem("id"); return ( - - { - navigate("/"); - }} - > + +
navigate("/")}> - - +
+ {isMobile && } +
{Object.entries(MenuRoutes).map(([path, menu]) => ( - - {t(menu.name)} - + + {t(menu.name)} + {menu.sub.map((subMenu) => ( { + setOpenMenu(false); navigate(`/${path}/${subMenu.path}`); }} > @@ -50,12 +53,12 @@ const Nav = () => { ))} - - - + {isLogin ? ( { + setOpenMenu(false); localStorage.removeItem("id"); navigate("/"); }} @@ -64,7 +67,9 @@ const Nav = () => { ) : ( { + setOpenMenu(false); navigate("/login"); }} > @@ -72,18 +77,22 @@ const Nav = () => { )} - - {t("언어")} - + + {t("언어")} + { + setOpenMenu(false); dispatch(setLanguage("KOR")); }} > 한국어 { + setOpenMenu(false); dispatch(setLanguage("ENG")); }} > @@ -91,7 +100,7 @@ const Nav = () => { - +
); }; @@ -99,8 +108,6 @@ const Nav = () => { export default Nav; const Container = styled.div` - height: 8vh; - padding: 0 2rem; display: flex; justify-content: space-between; align-items: center; @@ -108,28 +115,12 @@ const Container = styled.div` background-color: #141414; `; -const Logo = styled.div` - display: flex; - justify-content: center; - align-items: center; - - width: 10%; - height: 100%; - - cursor: pointer; -`; - const SubMenus = styled.div` display: none; position: absolute; - top: 85%; - left: -10%; - - padding: 0.2rem 0.5rem; + top: 70%; background-color: #141414; - border: 1px solid; - border-color: #FEBD99; font-size: initial; font-weight: initial; @@ -138,54 +129,30 @@ const SubMenus = styled.div` const SubMenu = styled.div` cursor: pointer; - white-space: nowrap; - padding: 0.1rem 0.2rem; - color: #FEBD99; + color: #febd99; & + & { margin-top: 0.2rem; } &:hover { - color: #B0A8FE; + color: #b0a8fe; } `; -const Menus = styled.div` - display: flex; - align-items: center; - - height: 100%; -`; - const Menu = styled.div` position: relative; cursor: pointer; user-select: none; - padding: 2vh 1vw; + padding: 1vh 1vw; &:hover { - color: #B0A8FE; + color: #b0a8fe; & > ${SubMenus} { display: initial; } } - - & + & { - margin-left: 3vw; - } -`; - -const LeftMenus = styled(Menus)` - font-weight: bold; - font-size: 1.25rem; -`; - -const RightMenus = styled(Menus)` - ${Menu} + ${Menu} { - margin-left: 1vw; - } `; diff --git a/src/components/common/Page/style.scss b/src/components/common/Page/style.scss index 1d972ac..5d25090 100644 --- a/src/components/common/Page/style.scss +++ b/src/components/common/Page/style.scss @@ -1,74 +1,411 @@ -$peach-puzz: #FEBD99; -$purple: #B0A8FE; -$yellow: #DEF080; +$peach-puzz: #febd99; +$purple: #b0a8fe; +$yellow: #def080; $black: #141414; @font-face { - font-family: 'Pretendard-Regular'; - src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') format('woff'); - font-weight: 400; - font-style: normal; + font-family: "Pretendard-Regular"; + src: url("https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff") + format("woff"); + font-weight: 400; + font-style: normal; } html { - font-family: "Pretendard-Regular", sans-serif; + font-family: "Pretendard-Regular", sans-serif; + background-color: #090909; } -body { - background-color: #090909; - font-size: 20px; - font-weight: 400; +.purple { + color: $purple; } -h2 { - font-size: 24px; - font-weight: 600; +.peach-puzz { + color: $peach-puzz; } -div.cm-page { - margin: 3vh 5vw; - padding: 0 1vw; - width: 90vw; - min-height: 90vh; +.black { + color: $black; +} + +.yellow { + color: $yellow; } span { - color: #C2C7D0; + color: #c2c7d0; } -ul, ol { - margin-left: 2rem; +.hidden { + display: none; } -li > a, span > a { - color: $purple; +.visible { + display: block; + width: 0px; } -.purple { - color: $purple; +.vertical { + display: flex; + flex-direction: column; } -.peach-puzz { - color: $peach-puzz; +.vertical-item { + padding-bottom: 1rem; } -.black { - color: $black; +.vertical-item:last-child { + padding-bottom: 0; } -.yellow { - color: $yellow; +body { + background-color: #090909; + font-weight: 400; } -.vertical { - display: flex; - flex-direction: column; +.border-bottom { + border-bottom: 1px $peach-puzz solid; } -.vertical-item { - padding-bottom: 1rem; +// mobile +@media only screen and (min-width: 375px) { + body { + font-size: 12px; + } + h2 { + font-size: 16px; + font-weight: 600; + } + + .nav-bar { + border-bottom: 1px $peach-puzz solid; + height: 8vh; + } + + .nav-logo { + display: flex; + width: 100px; + cursor: pointer; + padding-left: 1rem; + } + + div.hamburger-react { + cursor: pointer; + height: 48px; + position: relative; + transition: all 0.4s cubic-bezier(0, 0, 0, 1) 0s; + user-select: none; + width: 48px; + outline: none; + transform: none; + background-color: $black; + color: $peach-puzz; + border: none; + } + + .menus { + width: 100%; + position: absolute; + top: 8vh; + height: 100%; + background-color: $black; + padding: 0 1rem; + color: $peach-puzz; + text-align: center; + + & > .menu-item { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + font-size: 20px; + + & > span { + color: $peach-puzz; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + font-size: 20px; + height: 6vh; + border-bottom: 1px $peach-puzz solid; + + &:hover { + color: $purple; + } + } + & > .sub-menu { + position: relative; + width: 100%; + background-color: $black; + border: 1px $peach-puzz solid; + + & > .sub-menu-item { + color: $peach-puzz; + font-size: 14px; + padding-top: 1rem; + + &:last-child { + padding-bottom: 1rem; + } + + &:hover { + color: $purple; + } + } + } + } + } + + .mobile-logo { + width: 84px; + } + .mobile-slogan { + width: 300px; + } + .welcome-text { + font-size: large; + white-space: nowrap; + } + + .small-text { + font-size: 12px; + font-weight: 600; + font-style: italic; + } + + .big-text { + font-size: 30px; + font-weight: 800; + } + + .welcome-section { + border-radius: 16px; + background-color: $black; + padding: 2rem 4rem; + align-items: center; + width: 100%; + } + + .footer-about-section { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + font-size: 12px; + color: $peach-puzz; + margin-bottom: 2rem; + + & > section { + width: 100%; + margin-bottom: 2rem; + } + + & > section.left { + width: 50%; + order: 2; + + & > table { + border: 1px; + td { + background-color: #090909 !important; + } + tr > td:nth-of-type(2) { + padding-left: 1.5rem; + } + } + } + + & > section.center { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + white-space: nowrap; + order: 1; + + & > .slogan { + font-weight: 600; + } + + & > div + div { + margin-top: 1vh; + } + + & > div a { + text-decoration: none; + color: $purple; + } + } + } + + .footer-fixed-section { + position: fixed; + bottom: 0; + width: 100%; + height: fit-content; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 0.5rem; + color: $peach-puzz; + background-color: $black; + + & > .left { + font-weight: 800; + } + + & > .right { + & > a { + margin-left: 0.5rem; + + svg { + width: 1rem; + fill: $peach-puzz; + } + } + & > a:first-child { + margin-left: 0; + } + } + } } -.vertical-item:last-child { - padding-bottom: 0; -} \ No newline at end of file +// Desktop +@media only screen and (min-width: 810px) { + body { + font-size: 20px; + } + + h2 { + font-size: 24px; + font-weight: 600; + } + + div.cm-page { + margin: 3vh 5vw; + padding: 0 1vw; + width: 90vw; + min-height: 90vh; + } + + ul, + ol { + margin-left: 2rem; + } + + li > a, + span > a { + color: $purple; + } + + .nav-logo { + width: 150px; + } + + .nav-bar { + display: flex; + padding: 0 1rem; + justify-content: space-between; + height: 6vh; + } + + .menus { + display: flex; + justify-content: flex-end; + align-items: center; + font-weight: 800; + position: initial; + color: $peach-puzz; + + & > .menu-item { + border: none; + + & > span { + border-bottom: none; + } + + &:hover { + & > .sub-menu { + position: absolute; + width: max-content; + } + } + + & > .sub-menu { + background-color: $black; + border: 1px $peach-puzz solid; + color: $peach-puzz; + + & > .sub-menu-item { + cursor: pointer; + color: $peach-puzz; + + &:hover { + color: $purple; + } + } + } + } + } + + .slide-open { + visibility: hidden; + } + + .mobile-logo { + width: 181px; + } + + .mobile-slogan { + width: 510px; + } + + .welcome-text { + font-size: x-large; + white-space: nowrap; + } + + .small-text { + font-size: 16px; + font-weight: 600; + font-style: italic; + } + + .big-text { + font-size: 40px; + font-weight: 800; + } + + .welcome-section { + border-radius: 16px; + background-color: $black; + padding: 2rem 10rem; + align-items: center; + } + + // .footer-about-section { + // display: flex; + // flex-direction: row; + // justify-content: space-between; + // align-items: center; + // justify-content: center; + // align-items: center; + // padding: 0 1rem; + // font-size: 16px; + + // & > section.left, + // & > section.right { + // flex-shrink: 0; + // width: 50%; + // } + + // & > section.center { + // flex-grow: 2; + // margin-bottom: 2rem; + // } + // } +} + +@media only screen and (min-width: 1200px) { +} diff --git a/src/locale/English/translation.ts b/src/locale/English/translation.ts index dffacab..6863b28 100644 --- a/src/locale/English/translation.ts +++ b/src/locale/English/translation.ts @@ -56,7 +56,8 @@ const EnglishTranslation = { "수원 컨벤션 센터": "Suwon Convention Center", "2024.10.25": "October 25, 2024", "2024.10.27": "October 27, 2024", - "10번째 파이콘 한국에 여러분을 초대합니다.": "Join us for the 10th PyCon in Korea.", + "10번째 파이콘 한국에": "Join us", + "여러분을 초대합니다.": "for the 10th PyCon in Korea.", // Tutorial Page translations "PyCon Korea 2024 튜토리얼 진행자 모집": "Recruitment of Tutorial Instructors for PyCon Korea 2024", "PyCon Korea 2024 참가자 분들께 새로운 기술, 라이브러리를 전수해주실 진행자 분들을 모집합니다.": "We are looking for instructors to teach new technologies and libraries to participants at PyCon Korea 2024.", diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index 91c4bf5..3a4c31d 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -8,19 +8,20 @@ const Home = () => { return ( - introduceSlogan.png + introduceSlogan.png - - - {t("10번째 파이콘 한국에 여러분을 초대합니다.")} - - logo.png - +
+ + {t("10번째 파이콘 한국에")}
+ {t("여러분을 초대합니다.")} +
+ logo.png +
- {t("2024.10.25")} - {t("2024.10.27")} - {t("수원 컨벤션 센터")} + October 25-27 + in Suwon Convention Center
); @@ -33,19 +34,4 @@ const Container = styled.div` justify-content: center; align-items: center; padding: 10rem 0; -`; - -const Block = styled.div` - border-radius: 16px; - background-color: #141414; - padding: 2rem 10rem; - align-items: center; -`; - -const BigText = styled.span` - font-size: xx-large; -` - -const MediumText = styled.span` - font-size: larger; -` \ No newline at end of file +`; \ No newline at end of file diff --git a/src/utils/hooks/useIsMobile.ts b/src/utils/hooks/useIsMobile.ts new file mode 100644 index 0000000..b737810 --- /dev/null +++ b/src/utils/hooks/useIsMobile.ts @@ -0,0 +1,13 @@ +import React, {useEffect, useState} from "react"; + +const useIsMobile = () => { + const [isMobile, setIsMobile] = useState(false); + useEffect(() => { + if (!window.matchMedia) return; + setIsMobile(window.matchMedia("(pointer:coarse)").matches); + }, []); + + return isMobile; + } + + export default useIsMobile; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 0cefe44..d03116e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5223,6 +5223,11 @@ gzip-size@^6.0.0: dependencies: duplexer "^0.1.2" +hamburger-react@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/hamburger-react/-/hamburger-react-2.5.1.tgz#a15973cacabbc414f490ab0aa13340e260fc6ec1" + integrity sha512-XlTIinYeYzLu76q4Vd9olwOJP0hFgAeZfJFX6tTT/ufTLhmOjI77CGFYIwGc6gcDeeT86660ZoKx3/L67vdZEw== + handle-thing@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" @@ -8982,16 +8987,7 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -9078,14 +9074,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -10163,16 +10152,7 @@ workbox-window@6.6.1: "@types/trusted-types" "^2.0.2" workbox-core "6.6.1" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==