From 68021b3e4b7a45b0059ef35c2461f059b5dd6d97 Mon Sep 17 00:00:00 2001 From: Hyesu Date: Tue, 1 Oct 2024 10:56:43 +0900 Subject: [PATCH] =?UTF-8?q?update:=EC=9E=85=EA=B5=AD=20=ED=97=88=EA=B0=80?= =?UTF-8?q?=EC=9A=94=EA=B1=B4,=20=EA=B5=AD=EA=B0=80=EB=B3=84=20=EB=8C=80?= =?UTF-8?q?=EC=82=AC=EA=B4=80=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20=EC=B5=9C?= =?UTF-8?q?=EC=A0=81=ED=99=94=20=EB=B0=8F=20=EC=9D=BC=EB=B6=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++- src/App.css | 2 +- src/App.tsx | 62 +++++++++++++++++++-- src/components/common/Header.tsx | 2 +- src/components/common/PageHeader.tsx | 6 +- src/components/common/ScrollableTable.tsx | 22 +++++++- src/components/layout/EmbrassyComponent.tsx | 2 +- src/components/layout/LevelColors.tsx | 4 +- src/components/layout/globeComponent.tsx | 60 +++++++++++++++++--- src/pages/CountryInfoPage.tsx | 4 +- src/pages/EmbassyPage.tsx | 8 ++- src/pages/PermissionEnter.tsx | 5 ++ tsconfig.json | 10 ++-- 13 files changed, 166 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 83c4e8b..cab09af 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Travel Guard +# ✈️ Travel Guard ### ☑️ 진행상황 @@ -7,6 +7,7 @@ --- - [x] [Main] globe.gl 연동 & 대륙 입히기 +- [x] [Main] 배경 Color + 별 추가 - [x] [Main] 위험 경보 API - 3D 지구본 연동 - [x] [Main] Mobile & Web UI 최적화 @@ -22,5 +23,9 @@ - [x] [국가별 대사관 정보] API 연동 - [x] [국가별 대사관 정보] 국가 별 정보 (전체 / 디테일)페이지 제작 - [x] [국가별 대사관 정보] 검색 및 단계 별 정렬 구현 -- [ ] [국가별 대사관 정보] Mobile & Web UI 최적화(WEB 완료) +- [x] [국가별 대사관 정보] Mobile & Web UI 최적화 - [ ] Encountered two children with the same key ``에러 해결 . . . + +--- + +- [x] [입국 허가요건 & 국가별 대사관 정보] 모바일 표 사이즈 최적화 diff --git a/src/App.css b/src/App.css index 5fa84bf..ea8f3b4 100644 --- a/src/App.css +++ b/src/App.css @@ -3,7 +3,7 @@ body { margin: 0; padding: 0; height: 100%; - /* overflow: hidden; */ + overflow: hidden; color: #f0f0f0; background: "linear-gradient(to bottom, #03003d 0%, #070024 43%, #000014 100%)"; } diff --git a/src/App.tsx b/src/App.tsx index bce3ef1..53d364c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,3 +1,4 @@ +import { useMemo } from "react"; import "./App.css"; import GlobeComponent from "./components/layout/globeComponent"; import Header from "./components/common/Header"; @@ -7,24 +8,73 @@ import CountryDetail from "./pages/CountryDetail"; import PermissionEnter from "./pages/PermissionEnter"; import EmbassyPage from "./pages/EmbassyPage"; import styled from "@emotion/styled"; +import { keyframes } from "@emotion/react"; + +const twinkle = keyframes` + 0% { opacity: 0.5; } + 100% { opacity: 1; } +`; + +const AppContainer = styled.div` + position: relative; + min-height: 100vh; + background: linear-gradient(to bottom, #0a0818 45%, #1b3d50); + overflow: hidden; +`; + +const Star = styled.div<{ + size: number; + top: string; + left: string; + delay: string; +}>` + position: absolute; + background-color: white; + border-radius: 50%; + width: ${(props) => props.size}px; + height: ${(props) => props.size}px; + top: ${(props) => props.top}; + left: ${(props) => props.left}; + animation: ${twinkle} 2s infinite alternate; + animation-delay: ${(props) => props.delay}; +`; const SubContainer = styled.div` padding: 0 15%; height: 100%; - /* background: linear-gradient(to bottom, #0a033a 0%, #040019 43%, #040019 100%); */ - /* background: #040019; */ - background: linear-gradient(to bottom, #0a0818, #1b3d50); - overflow: auto; + position: relative; + z-index: 1; @media (max-width: 768px) { padding: 0 12% 0 5%; } `; +const generateStars = (count: number) => { + return Array.from({ length: count }, (_, i) => ({ + id: i, + size: Math.random() * 2 + 1, + top: `${Math.random() * 100}%`, + left: `${Math.random() * 100}%`, + delay: `${Math.random() * 2}s`, + })); +}; + function App() { + const stars = useMemo(() => generateStars(100), []); + return ( -
+ + {stars.map((star) => ( + + ))}
} /> @@ -61,7 +111,7 @@ function App() { } /> -
+
); } diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx index 1f8de5e..a3f482b 100644 --- a/src/components/common/Header.tsx +++ b/src/components/common/Header.tsx @@ -52,7 +52,7 @@ const Menu = styled.ul` const MenuItem = styled.li<{ isActive: boolean }>` font-family: "Pretendard", sans-serif; - font-size: 20px; + font-size: 23px; font-weight: 400; color: #f0f0f0; text-align: center; diff --git a/src/components/common/PageHeader.tsx b/src/components/common/PageHeader.tsx index 543f21c..71e163e 100644 --- a/src/components/common/PageHeader.tsx +++ b/src/components/common/PageHeader.tsx @@ -7,6 +7,9 @@ import { faSearch } from "@fortawesome/free-solid-svg-icons"; const HeaderContainer = styled.div` margin: 50px auto; color: #f0f0f0; + @media (max-width: 768px) { + padding: 0 10px; + } `; const Title = styled.h1` @@ -59,6 +62,7 @@ const SearchInput = styled.input` } @media (max-width: 768px) { font-size: 14px; + width: 77%; } `; @@ -94,7 +98,7 @@ const PageHeader: React.FC = ({ diff --git a/src/components/common/ScrollableTable.tsx b/src/components/common/ScrollableTable.tsx index 3d4f625..ec55aec 100644 --- a/src/components/common/ScrollableTable.tsx +++ b/src/components/common/ScrollableTable.tsx @@ -3,8 +3,9 @@ import styled from "@emotion/styled"; const ScrollWrapper = styled.div` max-height: 560px; + width: 100%; overflow-x: auto; - padding: 0 20px; + padding: 0 10px; &::-webkit-scrollbar { height: 8px; @@ -18,12 +19,20 @@ const ScrollWrapper = styled.div` background: #5e5e5e; border-radius: 10px; } + + @media (max-width: 768px) { + padding: 0 5px; + } `; const TableContainer = styled.div` background: rgba(41, 46, 52, 0.7); border-radius: 10px; padding: 20px; + + @media (max-width: 768px) { + padding: 5px; + } `; const Table = styled.table` @@ -37,6 +46,7 @@ const Table = styled.table` text-align: left; border-bottom: 1px solid #5e5e5e; line-height: 150%; + word-break: break-word; } th { @@ -45,6 +55,12 @@ const Table = styled.table` font-size: 24px; line-height: 100%; font-weight: 500; + + @media (max-width: 768px) { + font-size: 16px; + padding: 8px; + position: sticky; + } } th:nth-child(1) { @@ -61,6 +77,10 @@ const Table = styled.table` color: #f0f0f0; font-size: 20px; padding-right: 5px; + + @media (max-width: 768px) { + font-size: 14px; + } } tr:hover td { diff --git a/src/components/layout/EmbrassyComponent.tsx b/src/components/layout/EmbrassyComponent.tsx index e2057bc..f9f5126 100644 --- a/src/components/layout/EmbrassyComponent.tsx +++ b/src/components/layout/EmbrassyComponent.tsx @@ -25,7 +25,7 @@ const EmbassyInfoContainer = styled.div` margin-top: 20px; @media (max-width: 768px) { - width: 50%; + width: 100%; padding: 0; // 모바일 여백 조정 font-size: 10px; } diff --git a/src/components/layout/LevelColors.tsx b/src/components/layout/LevelColors.tsx index 93b37fd..a2c410b 100644 --- a/src/components/layout/LevelColors.tsx +++ b/src/components/layout/LevelColors.tsx @@ -62,8 +62,8 @@ const containerStyle = css` z-index: 100; @media (max-width: 768px) { - bottom: 32%; - left: 43%; + bottom: 25%; + left: 50%; transform: translate(-50%, 50%); width: 300px; padding: 15px; diff --git a/src/components/layout/globeComponent.tsx b/src/components/layout/globeComponent.tsx index f28e297..f2353c1 100644 --- a/src/components/layout/globeComponent.tsx +++ b/src/components/layout/globeComponent.tsx @@ -60,13 +60,7 @@ const GlobeComponent: React.FC = () => { const globeContainerStyle = css` width: 100%; height: calc(100vh - 140px); - - background: linear-gradient( - to bottom, - #0a033a 0%, - #040019 43%, - #040019 100% - ); + background: linear-gradient(to bottom, #0a0818 45%, #1b3d50); display: flex; justify-content: center; align-items: center; @@ -76,6 +70,41 @@ const GlobeComponent: React.FC = () => { height: 100vh; } `; + const starFieldStyle = css` + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + pointer-events: none; + `; + + const starStyle = css` + position: absolute; + background-color: white; + border-radius: 50%; + animation: twinkle 2s infinite alternate; + + @keyframes twinkle { + 0% { + opacity: 0.5; + } + 100% { + opacity: 1; + } + } + `; + const generateStars = (count: number) => { + return Array.from({ length: count }, (_, i) => ({ + id: i, + size: Math.random() * 2 + 1, + left: `${Math.random() * 100}%`, + top: `${Math.random() * 100}%`, + animationDelay: `${Math.random() * 2}s`, + })); + }; + + const stars = generateStars(50); const selectedCountryStyle = css` position: absolute; @@ -138,7 +167,7 @@ const GlobeComponent: React.FC = () => { color: #b0b0b0; @media (max-width: 768px) { - font-size: 10px; + font-size: 12px; } } `; @@ -160,6 +189,21 @@ const GlobeComponent: React.FC = () => { return (
+
+ {stars.map((star) => ( +
+ ))} +
` } @media (max-width: 768px) { - padding: 8px 10px; + padding: 10px 25px; font-size: 14px; } `; @@ -85,6 +85,8 @@ const DataContainer = styled.div` @media (max-width: 768px) { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + max-height: 410px; + padding: 10px 5px; } `; diff --git a/src/pages/EmbassyPage.tsx b/src/pages/EmbassyPage.tsx index ca9b100..2e9a0fb 100644 --- a/src/pages/EmbassyPage.tsx +++ b/src/pages/EmbassyPage.tsx @@ -16,6 +16,12 @@ const Container = styled.div` background: transparent; min-height: 100vh; padding: 20px; + width: 100%; + + @media (max-width: 768px) { + padding: 0; + width: 110%; + } `; const EmbassyPage: React.FC = () => { @@ -52,7 +58,7 @@ const EmbassyPage: React.FC = () => { {filteredData && filteredData.length > 0 ? ( diff --git a/src/pages/PermissionEnter.tsx b/src/pages/PermissionEnter.tsx index 836d6b7..f882590 100644 --- a/src/pages/PermissionEnter.tsx +++ b/src/pages/PermissionEnter.tsx @@ -7,7 +7,12 @@ import styled from "@emotion/styled"; const Container = styled.div` background: transparent; min-height: 100vh; + width: 100%; padding: 20px; + @media (max-width: 768px) { + padding: 0; + width: 110%; + } `; const PermissionEnter: React.FC = () => { diff --git a/tsconfig.json b/tsconfig.json index f2486c4..32c6882 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "target": "ES6", "lib": ["DOM", "DOM.Iterable", "ESNext"], "jsx": "react-jsx", + "jsxImportSource": "@emotion/react", "module": "ESNext", "rootDir": "./", "moduleResolution": "node", @@ -10,17 +11,16 @@ "allowJs": true, "checkJs": false, "outDir": "./dist", - "removeComments": true /*컴파일 시 주석이 제거된다.*/, - "noEmit": true /* true로 설정하면, 컴파일 해도 .js 파일이 생성되지 않는다. -.js 파일을 생성하지 않고 .ts 파일에 에러가 없는지 확인 하고 싶을 때 사용한다.*/, - "noEmitOnError": true /* ts파일에 에러가 있으면 .js파일을 생성하지 않는다. */, + "removeComments": true, + "noEmit": true, + "noEmitOnError": true, "isolatedModules": true, "allowSyntheticDefaultImports": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "noFallthroughCasesInSwitch": true, - "skipLibCheck": true /* 이 옵션은 외부 라이브러리(타입 정의 파일)에 대한 타입 체크를 건너뛸지 여부를 설정한다. true로 설정하면 TypeScript 컴파일러는 외부 라이브러리의 타입을 체크하지 않는다*/ + "skipLibCheck": true }, "include": ["src", "react-app-env.d.ts", "declarations.d.ts"], "exclude": ["node_modules"]