diff --git a/.env.template b/.env.template new file mode 100644 index 00000000..96230dd1 --- /dev/null +++ b/.env.template @@ -0,0 +1 @@ +VITE_TMAP_APP_KEY= \ No newline at end of file diff --git a/.gitignore b/.gitignore index a547bf36..d7de12f3 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ dist dist-ssr *.local +.env + # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/index.html b/index.html index 5525a8ae..882dcc82 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,14 @@ - - - - - 여행 지도 계획 플래너, 어디 (Audy) - - -
- - + + + + + 여행 지도 계획 플래너, 어디 (Audy) + + + +
+ + diff --git a/package.json b/package.json index 3f4a64fb..9bd4c341 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "devDependencies": { "@tanstack/react-query-devtools": "^5.17.10", "@trivago/prettier-plugin-sort-imports": "^4.3.0", + "@types/node": "^20.11.5", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@typescript-eslint/eslint-plugin": "^6.14.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 06ef406d..e6659e47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,9 @@ devDependencies: '@trivago/prettier-plugin-sort-imports': specifier: ^4.3.0 version: 4.3.0(prettier@3.2.1) + '@types/node': + specifier: ^20.11.5 + version: 20.11.5 '@types/react': specifier: ^18.2.43 version: 18.2.47 @@ -51,7 +54,7 @@ devDependencies: version: 0.5.1(@vanilla-extract/css@1.14.0) '@vanilla-extract/vite-plugin': specifier: ^3.9.3 - version: 3.9.3(vite@5.0.11) + version: 3.9.3(@types/node@20.11.5)(vite@5.0.11) '@vitejs/plugin-react-swc': specifier: ^3.5.0 version: 3.5.0(vite@5.0.11) @@ -75,7 +78,7 @@ devDependencies: version: 5.3.3 vite: specifier: ^5.0.8 - version: 5.0.11 + version: 5.0.11(@types/node@20.11.5) vite-plugin-svgr: specifier: ^4.2.0 version: 4.2.0(typescript@5.3.3)(vite@5.0.11) @@ -1482,8 +1485,8 @@ packages: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true - /@types/node@20.11.0: - resolution: {integrity: sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==} + /@types/node@20.11.5: + resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==} dependencies: undici-types: 5.26.5 dev: true @@ -1673,7 +1676,7 @@ packages: modern-ahocorasick: 1.0.1 outdent: 0.8.0 - /@vanilla-extract/integration@6.2.4: + /@vanilla-extract/integration@6.2.4(@types/node@20.11.5): resolution: {integrity: sha512-+AfymNMVq9sEUe0OJpdCokmPZg4Zi6CqKaW/PnUOfDwEn53ighHOMOBl5hAgxYR8Kiz9NG43Bn00mkjWlFi+ng==} dependencies: '@babel/core': 7.23.7 @@ -1687,8 +1690,8 @@ packages: lodash: 4.17.21 mlly: 1.5.0 outdent: 0.8.0 - vite: 4.5.1 - vite-node: 0.28.5 + vite: 4.5.1(@types/node@20.11.5) + vite-node: 0.28.5(@types/node@20.11.5) transitivePeerDependencies: - '@types/node' - less @@ -1711,16 +1714,16 @@ packages: '@vanilla-extract/css': 1.14.0 dev: true - /@vanilla-extract/vite-plugin@3.9.3(vite@5.0.11): + /@vanilla-extract/vite-plugin@3.9.3(@types/node@20.11.5)(vite@5.0.11): resolution: {integrity: sha512-bGyHG98OYTRs5roLRv7LDeyRnD72+vBLonk8cC9VG/xd6hsiHPPj5GyBwoKElT7DyDRfapxWLwLlhgYynrW2Fw==} peerDependencies: vite: ^2.2.3 || ^3.0.0 || ^4.0.3 || ^5.0.0 dependencies: - '@vanilla-extract/integration': 6.2.4 + '@vanilla-extract/integration': 6.2.4(@types/node@20.11.5) outdent: 0.8.0 postcss: 8.4.33 postcss-load-config: 4.0.2(postcss@8.4.33) - vite: 5.0.11 + vite: 5.0.11(@types/node@20.11.5) transitivePeerDependencies: - '@types/node' - less @@ -1739,7 +1742,7 @@ packages: vite: ^4 || ^5 dependencies: '@swc/core': 1.3.102 - vite: 5.0.11 + vite: 5.0.11(@types/node@20.11.5) transitivePeerDependencies: - '@swc/helpers' dev: true @@ -2250,7 +2253,7 @@ packages: resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==} engines: {node: '>= 0.8'} dependencies: - '@types/node': 20.11.0 + '@types/node': 20.11.5 require-like: 0.1.2 dev: true @@ -3086,7 +3089,7 @@ packages: punycode: 2.3.1 dev: true - /vite-node@0.28.5: + /vite-node@0.28.5(@types/node@20.11.5): resolution: {integrity: sha512-LmXb9saMGlrMZbXTvOveJKwMTBTNUH66c8rJnQ0ZPNX+myPEol64+szRzXtV5ORb0Hb/91yq+/D3oERoyAt6LA==} engines: {node: '>=v14.16.0'} hasBin: true @@ -3098,7 +3101,7 @@ packages: picocolors: 1.0.0 source-map: 0.6.1 source-map-support: 0.5.21 - vite: 4.5.1 + vite: 4.5.1(@types/node@20.11.5) transitivePeerDependencies: - '@types/node' - less @@ -3118,14 +3121,14 @@ packages: '@rollup/pluginutils': 5.1.0 '@svgr/core': 8.1.0(typescript@5.3.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0) - vite: 5.0.11 + vite: 5.0.11(@types/node@20.11.5) transitivePeerDependencies: - rollup - supports-color - typescript dev: true - /vite@4.5.1: + /vite@4.5.1(@types/node@20.11.5): resolution: {integrity: sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -3153,6 +3156,7 @@ packages: terser: optional: true dependencies: + '@types/node': 20.11.5 esbuild: 0.18.20 postcss: 8.4.33 rollup: 3.29.4 @@ -3160,7 +3164,7 @@ packages: fsevents: 2.3.3 dev: true - /vite@5.0.11: + /vite@5.0.11(@types/node@20.11.5): resolution: {integrity: sha512-XBMnDjZcNAw/G1gEiskiM1v6yzM4GE5aMGvhWTlHAYYhxb7S3/V1s3m2LDHa8Vh6yIWYYB0iJwsEaS523c4oYA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -3188,6 +3192,7 @@ packages: terser: optional: true dependencies: + '@types/node': 20.11.5 esbuild: 0.19.11 postcss: 8.4.33 rollup: 4.9.5 diff --git a/src/App.tsx b/src/App.tsx index 46496098..d95a4040 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,15 +1,57 @@ -import { Route, Routes } from 'react-router-dom'; +import { useState } from 'react'; -import LoginPage from './pages/LoginPage'; -import RedirectionPage from './pages/RedirectionPage'; +import reactLogo from '@/assets/react.svg'; +import { useTmap } from '@/hooks/useTmap'; + +import viteLogo from '/vite.svg'; + +import './App.css'; function App() { - - } /> - } /> - ; + const [count, setCount] = useState(0); + + const { tmapModuleRef, mapContainerRef } = useTmap({ + mapId: 'tmap', + latitude: 37.5652045, + longitude: 126.98702028, + }); + + const handleTestAddMarker = () => { + if (!tmapModuleRef.current) return; + console.log(tmapModuleRef.current); + tmapModuleRef.current.setMarker({latitude: 37.56520450, longitude: 126.98602028}); + + } - return ; + return ( + <> +
+
+ + Vite logo + + + React logo + +
+

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ); } export default App; diff --git a/src/hooks/useTmap.ts b/src/hooks/useTmap.ts new file mode 100644 index 00000000..bd40c0b4 --- /dev/null +++ b/src/hooks/useTmap.ts @@ -0,0 +1,31 @@ +import { useEffect, useRef } from 'react'; + +import { TMapModule, type TmapConstructorType } from '@/utils/tmap'; + +export const useTmap = ({ + mapId = 'tmap', + width = 640, + height = 480, + zoom = 10, + latitude, + longitude, +}: TmapConstructorType) => { + const mapContainerRef = useRef(null); + const tmapModuleRef = useRef(null); + + useEffect(() => { + if (!mapContainerRef.current) return; + + mapContainerRef.current.id = mapId; + tmapModuleRef.current = new TMapModule({ + mapId, + width, + height, + zoom, + latitude, + longitude, + }); + }, [height, latitude, longitude, mapId, width, zoom]); + + return { mapContainerRef, tmapModuleRef }; +}; diff --git a/src/main.tsx b/src/main.tsx index 6a5b9984..62f7b50d 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,12 +1,6 @@ -import { StrictMode } from 'react'; - import { createRoot } from 'react-dom/client'; import App from './App.tsx'; import './index.css'; -createRoot(document.getElementById('root')!).render( - - - , -); +createRoot(document.getElementById('root')!).render(); diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 27045cd0..48f5a650 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -1,9 +1,3 @@ -// SVGR Plugin NameSpace -declare module '*.svg' { - const svg: React.FunctionComponent>; - export default svg; -} - // T-MAP API NameSpace declare global { interface Window { @@ -12,3 +6,11 @@ declare global { Tmapv3: any; } } + +// SVGR Plugin NameSpace +declare module '*.svg' { + const svg: React.FunctionComponent>; + export default svg; +} + +export {}; \ No newline at end of file diff --git a/src/utils/tmap.ts b/src/utils/tmap.ts new file mode 100644 index 00000000..67e13ad0 --- /dev/null +++ b/src/utils/tmap.ts @@ -0,0 +1,46 @@ +export interface TmapConstructorType { + /** 지도를 렌더링할 HTMLDivElement 에 적용할 id */ + mapId?: string; + /** 지도 Element 의 width (px) */ + width?: number; + /** 지도 Element 의 height (px) */ + height?: number; + /** 지도 Element 의 확대 정도 (1 ~ 15) */ + zoom?: number; + /** 지도 의 중심점 위도 */ + latitude: number; + /** 지도 의 중심점 경도 */ + longitude: number; +} + +export class TMapModule { + #mapInstance: typeof window.Tmapv3; + + constructor({ + mapId = 'tmap', + width = 640, + height = 480, + zoom = 10, + latitude, + longitude, + }: TmapConstructorType) { + if (typeof window === 'undefined') { + throw new Error('T Map 은 Server Side 에서 사용할 수 없습니다.'); + } + + const mapElement = document.getElementById(mapId); + + if (!mapElement) { + throw new Error( + 'T Map 을 렌더링하기 위해 필요한 HTMLDivElement 가 없습니다.', + ); + } + + this.#mapInstance = new window.Tmapv3.Map(mapId, { + center: new window.Tmapv3.LatLng(latitude, longitude), + width: `${width}px`, + height: `${height}px`, + zoom, + }); + } +} diff --git a/tsconfig.json b/tsconfig.json index 4e8a6b05..1f479c5b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ES2020", "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true,