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 + 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,