From a1c28bae9e2032f20e5fd03032aed5c1af90da1b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B5=9C=ED=98=B8?=
<67588757+choihooo@users.noreply.github.com>
Date: Thu, 24 Oct 2024 16:39:51 +0900
Subject: [PATCH 1/2] Feature/22 map page (#23)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* [feat] #22 맵 페이지 ui 틀 구현
* [feat] #22 맵 페이지 드로우 구현 & 파일 분리
* [feat] #22 네이버 로고 위쪽으로 변경 및 바텀 드로우 가로 스크롤 구현
* [feat] #22 선택하면 보더 생기는 이벤트 구현
* [feat] #22 공유 버튼 및 로케이션 버튼 기능 구현
* [feat] #22 eslint 해결
---
fe/package-lock.json | 137 +++++++++++++++++-
fe/package.json | 6 +-
fe/public/svg/Grabber.svg | 3 +
fe/public/svg/add.svg | 5 +
fe/public/svg/arrow-back.svg | 4 +
fe/public/svg/edit.svg | 5 +
fe/public/svg/my-location.svg | 9 ++
fe/public/svg/refresh.svg | 5 +
fe/public/svg/share.svg | 4 +
fe/src/app/layout.tsx | 13 +-
.../app/map-page/components/BottomDrawer.tsx | 126 ++++++++++++++++
.../app/map-page/components/MapComponent.tsx | 45 ++++++
fe/src/app/map-page/components/User.tsx | 24 +++
fe/src/app/map-page/hooks/useDrawer.ts | 33 +++++
fe/src/app/map-page/page.tsx | 44 ++++++
.../app/map-page/stores/useLocationStore.ts | 14 ++
fe/src/app/map-page/types/types.ts | 26 ++++
.../naver-map-test/components/NaverMap.tsx | 135 -----------------
fe/src/app/naver-map-test/page.tsx | 9 --
fe/src/app/page.tsx | 5 -
fe/src/styles/globals.css | 1 -
fe/tailwind.config.ts | 64 ++++----
22 files changed, 520 insertions(+), 197 deletions(-)
create mode 100644 fe/public/svg/Grabber.svg
create mode 100644 fe/public/svg/add.svg
create mode 100644 fe/public/svg/arrow-back.svg
create mode 100644 fe/public/svg/edit.svg
create mode 100644 fe/public/svg/my-location.svg
create mode 100644 fe/public/svg/refresh.svg
create mode 100644 fe/public/svg/share.svg
create mode 100644 fe/src/app/map-page/components/BottomDrawer.tsx
create mode 100644 fe/src/app/map-page/components/MapComponent.tsx
create mode 100644 fe/src/app/map-page/components/User.tsx
create mode 100644 fe/src/app/map-page/hooks/useDrawer.ts
create mode 100644 fe/src/app/map-page/page.tsx
create mode 100644 fe/src/app/map-page/stores/useLocationStore.ts
create mode 100644 fe/src/app/map-page/types/types.ts
delete mode 100644 fe/src/app/naver-map-test/components/NaverMap.tsx
delete mode 100644 fe/src/app/naver-map-test/page.tsx
diff --git a/fe/package-lock.json b/fe/package-lock.json
index f21d16e..e3354d3 100644
--- a/fe/package-lock.json
+++ b/fe/package-lock.json
@@ -8,6 +8,8 @@
"name": "my-next-app",
"version": "0.1.0",
"dependencies": {
+ "@react-spring/web": "^9.7.5",
+ "@use-gesture/react": "^10.3.1",
"axios": "^1.7.7",
"dotenv": "^16.4.5",
"express": "^4.21.0",
@@ -15,7 +17,9 @@
"next-auth": "^4.24.8",
"react": "^18",
"react-dom": "^18",
- "winston": "^3.14.2"
+ "tailwind-scrollbar-hide": "^1.1.7",
+ "winston": "^3.14.2",
+ "zustand": "^5.0.0"
},
"devDependencies": {
"@types/navermaps": "^3.7.8",
@@ -490,6 +494,78 @@
"url": "https://opencollective.com/unts"
}
},
+ "node_modules/@react-spring/animated": {
+ "version": "9.7.5",
+ "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz",
+ "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-spring/shared": "~9.7.5",
+ "@react-spring/types": "~9.7.5"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/@react-spring/core": {
+ "version": "9.7.5",
+ "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz",
+ "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-spring/animated": "~9.7.5",
+ "@react-spring/shared": "~9.7.5",
+ "@react-spring/types": "~9.7.5"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-spring/donate"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/@react-spring/rafz": {
+ "version": "9.7.5",
+ "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz",
+ "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==",
+ "license": "MIT"
+ },
+ "node_modules/@react-spring/shared": {
+ "version": "9.7.5",
+ "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz",
+ "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-spring/rafz": "~9.7.5",
+ "@react-spring/types": "~9.7.5"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/@react-spring/types": {
+ "version": "9.7.5",
+ "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz",
+ "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==",
+ "license": "MIT"
+ },
+ "node_modules/@react-spring/web": {
+ "version": "9.7.5",
+ "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz",
+ "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-spring/animated": "~9.7.5",
+ "@react-spring/core": "~9.7.5",
+ "@react-spring/shared": "~9.7.5",
+ "@react-spring/types": "~9.7.5"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -550,13 +626,13 @@
"version": "15.7.13",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/react": {
"version": "18.3.10",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.10.tgz",
"integrity": "sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -791,6 +867,24 @@
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
"dev": true
},
+ "node_modules/@use-gesture/core": {
+ "version": "10.3.1",
+ "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz",
+ "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==",
+ "license": "MIT"
+ },
+ "node_modules/@use-gesture/react": {
+ "version": "10.3.1",
+ "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz",
+ "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==",
+ "license": "MIT",
+ "dependencies": {
+ "@use-gesture/core": "10.3.1"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0"
+ }
+ },
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@@ -1709,7 +1803,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true
+ "devOptional": true
},
"node_modules/damerau-levenshtein": {
"version": "1.0.8",
@@ -6459,6 +6553,12 @@
"url": "https://opencollective.com/unts"
}
},
+ "node_modules/tailwind-scrollbar-hide": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/tailwind-scrollbar-hide/-/tailwind-scrollbar-hide-1.1.7.tgz",
+ "integrity": "sha512-X324n9OtpTmOMqEgDUEA/RgLrNfBF/jwJdctaPZDzB3mppxJk7TLIDmOreEDm1Bq4R9LSPu4Epf8VSdovNU+iA==",
+ "license": "MIT"
+ },
"node_modules/tailwindcss": {
"version": "3.4.13",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz",
@@ -7110,6 +7210,35 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zustand": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.0.tgz",
+ "integrity": "sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=18.0.0",
+ "immer": ">=9.0.6",
+ "react": ">=18.0.0",
+ "use-sync-external-store": ">=1.2.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "use-sync-external-store": {
+ "optional": true
+ }
+ }
}
}
}
diff --git a/fe/package.json b/fe/package.json
index 233b179..d153b37 100644
--- a/fe/package.json
+++ b/fe/package.json
@@ -11,6 +11,8 @@
"prepare": "husky install"
},
"dependencies": {
+ "@react-spring/web": "^9.7.5",
+ "@use-gesture/react": "^10.3.1",
"axios": "^1.7.7",
"dotenv": "^16.4.5",
"express": "^4.21.0",
@@ -18,7 +20,9 @@
"next-auth": "^4.24.8",
"react": "^18",
"react-dom": "^18",
- "winston": "^3.14.2"
+ "tailwind-scrollbar-hide": "^1.1.7",
+ "winston": "^3.14.2",
+ "zustand": "^5.0.0"
},
"devDependencies": {
"@types/navermaps": "^3.7.8",
diff --git a/fe/public/svg/Grabber.svg b/fe/public/svg/Grabber.svg
new file mode 100644
index 0000000..d2ba29b
--- /dev/null
+++ b/fe/public/svg/Grabber.svg
@@ -0,0 +1,3 @@
+
diff --git a/fe/public/svg/add.svg b/fe/public/svg/add.svg
new file mode 100644
index 0000000..5ccc597
--- /dev/null
+++ b/fe/public/svg/add.svg
@@ -0,0 +1,5 @@
+
diff --git a/fe/public/svg/arrow-back.svg b/fe/public/svg/arrow-back.svg
new file mode 100644
index 0000000..e3605e5
--- /dev/null
+++ b/fe/public/svg/arrow-back.svg
@@ -0,0 +1,4 @@
+
diff --git a/fe/public/svg/edit.svg b/fe/public/svg/edit.svg
new file mode 100644
index 0000000..8e1f26b
--- /dev/null
+++ b/fe/public/svg/edit.svg
@@ -0,0 +1,5 @@
+
diff --git a/fe/public/svg/my-location.svg b/fe/public/svg/my-location.svg
new file mode 100644
index 0000000..acbbe81
--- /dev/null
+++ b/fe/public/svg/my-location.svg
@@ -0,0 +1,9 @@
+
diff --git a/fe/public/svg/refresh.svg b/fe/public/svg/refresh.svg
new file mode 100644
index 0000000..30a2667
--- /dev/null
+++ b/fe/public/svg/refresh.svg
@@ -0,0 +1,5 @@
+
diff --git a/fe/public/svg/share.svg b/fe/public/svg/share.svg
new file mode 100644
index 0000000..6e03fb7
--- /dev/null
+++ b/fe/public/svg/share.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/fe/src/app/layout.tsx b/fe/src/app/layout.tsx
index 6dea505..206b9b7 100644
--- a/fe/src/app/layout.tsx
+++ b/fe/src/app/layout.tsx
@@ -1,7 +1,6 @@
"use client";
import "../styles/globals.css";
-import Script from "next/script";
export default function RootLayout({
children,
@@ -11,20 +10,14 @@ export default function RootLayout({
return (
- */}
{children}
-
-
- {/* 네이버 지도 API 스크립트 로드 */}
-
+ {/* */}
);
diff --git a/fe/src/app/map-page/components/BottomDrawer.tsx b/fe/src/app/map-page/components/BottomDrawer.tsx
new file mode 100644
index 0000000..d7b3be3
--- /dev/null
+++ b/fe/src/app/map-page/components/BottomDrawer.tsx
@@ -0,0 +1,126 @@
+import React, { useState } from "react";
+import Image from "next/image"; // Import Next.js Image component
+import { useLocationStore } from "../stores/useLocationStore";
+
+export default function BottomDrawer() {
+ const [selectedButton, setSelectedButton] = useState(0);
+ const moveToLocation = useLocationStore((state) => state.moveToLocation); // 상태에서 함수 가져오기
+
+ const handleLocationClick = () => {
+ if (navigator.geolocation) {
+ navigator.geolocation.getCurrentPosition(
+ (position) => {
+ const { latitude, longitude } = position.coords;
+ moveToLocation(latitude, longitude); // 현재 위치로 이동
+ },
+ () => alert("현재 위치 정보를 가져올 수 없습니다.")
+ );
+ }
+ };
+
+ const handleButtonClick = (id: number) => {
+ setSelectedButton(id);
+ };
+
+ const handleShare = () => {
+ if (navigator.share) {
+ navigator
+ .share({
+ title: "공유할 제목",
+ text: "공유할 내용",
+ url: window.location.href, // 현재 페이지의 URL을 공유
+ })
+ .then()
+ .catch();
+ } else {
+ alert("이 브라우저에서는 공유 기능을 지원하지 않습니다.");
+ }
+ };
+
+ const buttons = [
+ { label: "메롱메롱", id: 1 },
+ { label: "메롱메롱", id: 2 },
+ { label: "메롱메롱", id: 3 },
+ { label: "메롱윤소민", id: 4 },
+ { label: "메롱윤소민", id: 5 },
+ { label: "메롱윤소민", id: 6 },
+ ];
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ 텍스트텍스트텍스트텍스트텍스트
+
+
+
+
+
+
+
+
+
+ {buttons.map((button) => (
+
+
+
{button.label}
+
+ ))}
+
+
+ );
+}
diff --git a/fe/src/app/map-page/components/MapComponent.tsx b/fe/src/app/map-page/components/MapComponent.tsx
new file mode 100644
index 0000000..8e541c9
--- /dev/null
+++ b/fe/src/app/map-page/components/MapComponent.tsx
@@ -0,0 +1,45 @@
+import React, { useEffect, useRef } from "react";
+import { useLocationStore } from "../stores/useLocationStore";
+
+export default function MapComponent() {
+ const mapRef = useRef(null);
+ const mapInstanceRef = useRef(null); // Allow null
+
+ const { center } = useLocationStore();
+
+ useEffect(() => {
+ if (!mapRef.current) return;
+
+ const initializeMap = () => {
+ if (window.naver && mapRef.current) {
+ // Assign the map instance safely
+ mapInstanceRef.current = new window.naver.maps.Map(mapRef.current, {
+ center: new window.naver.maps.LatLng(
+ center.latitude,
+ center.longitude
+ ),
+ zoom: 15,
+ scaleControl: false,
+ logoControl: true,
+ logoControlOptions: {
+ position: window.naver.maps.Position.TOP_RIGHT,
+ },
+ mapDataControl: false,
+ mapTypeControl: false,
+ });
+ }
+ };
+
+ if (window.naver) {
+ initializeMap();
+ } else {
+ const script = document.createElement("script");
+ script.src = `https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${process.env.NEXT_PUBLIC_NAVER_MAP_CLIENT_ID}`;
+ script.async = true;
+ script.onload = initializeMap;
+ document.head.appendChild(script);
+ }
+ }, [center]);
+
+ return ;
+}
diff --git a/fe/src/app/map-page/components/User.tsx b/fe/src/app/map-page/components/User.tsx
new file mode 100644
index 0000000..ab8a23d
--- /dev/null
+++ b/fe/src/app/map-page/components/User.tsx
@@ -0,0 +1,24 @@
+import Image from "next/image";
+import { UserProps } from "../types/types";
+
+export default function User({
+ id,
+ label,
+ selectedButton,
+ handleButtonClick,
+}: UserProps) {
+ return (
+
+
+
{label}
+
+ );
+}
diff --git a/fe/src/app/map-page/hooks/useDrawer.ts b/fe/src/app/map-page/hooks/useDrawer.ts
new file mode 100644
index 0000000..d05822a
--- /dev/null
+++ b/fe/src/app/map-page/hooks/useDrawer.ts
@@ -0,0 +1,33 @@
+import { useState } from "react";
+import { useSpring } from "@react-spring/web";
+
+const useDrawer = () => {
+ const [isOpen, setIsOpen] = useState(false);
+ const [{ y }, api] = useSpring(() => ({ y: 0 })); // 드로어 기본값 설정 (130은 닫힌 상태)
+
+ const openDrawer = () => {
+ setIsOpen(true);
+ api.start({ y: 0 }); // 드로어 열기
+ };
+
+ const closeDrawer = () => {
+ setIsOpen(false);
+ api.start({ y: 130 }); // 드로어 닫기
+ };
+
+ const setPosition = (newY: number) => {
+ const limitedY = Math.min(Math.max(newY, 0), 130); // y 값이 0보다 작거나 130보다 크지 않도록 제한
+ api.start({ y: limitedY });
+ };
+
+ return {
+ y,
+ isOpen,
+ openDrawer,
+ closeDrawer,
+ setPosition,
+ api, // 필요한 경우 외부에서 제어할 수 있도록 spring API를 반환
+ };
+};
+
+export default useDrawer;
diff --git a/fe/src/app/map-page/page.tsx b/fe/src/app/map-page/page.tsx
new file mode 100644
index 0000000..c7cdea2
--- /dev/null
+++ b/fe/src/app/map-page/page.tsx
@@ -0,0 +1,44 @@
+"use client";
+
+import React from "react";
+import Image from "next/image";
+import { a } from "@react-spring/web"; // External imports first
+import { useDrag } from "@use-gesture/react"; // External imports
+import BottomDrawer from "./components/BottomDrawer"; // Local imports after external ones
+import MapComponent from "./components/MapComponent";
+import useDrawer from "./hooks/useDrawer"; // Local hook import
+
+export default function Page() {
+ // Ensure the function component uses function declaration
+ const { y, openDrawer, closeDrawer, setPosition } = useDrawer();
+
+ const bind = useDrag(({ last, movement: [, my] }) => {
+ if (last) {
+ if (my > 100) {
+ closeDrawer(); // Close if dragged more than 100px
+ } else {
+ openDrawer(); // Open if dragged less than 100px
+ }
+ } else {
+ setPosition(my); // Update the position during the drag
+ }
+ });
+
+ return (
+
+ );
+}
diff --git a/fe/src/app/map-page/stores/useLocationStore.ts b/fe/src/app/map-page/stores/useLocationStore.ts
new file mode 100644
index 0000000..c9c2674
--- /dev/null
+++ b/fe/src/app/map-page/stores/useLocationStore.ts
@@ -0,0 +1,14 @@
+import { create } from "zustand";
+import { LocationState } from "../types/types"; // types 파일에서 타입을 import
+
+// 위치 상태를 zustand로 관리
+export const useLocationStore = create((set) => ({
+ center: {
+ latitude: 37.5665, // 초기값: 서울
+ longitude: 126.978,
+ },
+ moveToLocation: (latitude, longitude) =>
+ set(() => ({
+ center: { latitude, longitude },
+ })),
+}));
diff --git a/fe/src/app/map-page/types/types.ts b/fe/src/app/map-page/types/types.ts
new file mode 100644
index 0000000..d0a4070
--- /dev/null
+++ b/fe/src/app/map-page/types/types.ts
@@ -0,0 +1,26 @@
+// 위치 정보를 담는 타입 정의
+export interface Location {
+ latitude: number;
+ longitude: number;
+}
+
+// 상태 관리용 LocationState 타입 정의
+export interface LocationState {
+ center: {
+ latitude: number;
+ longitude: number;
+ };
+ moveToLocation: (latitude: number, longitude: number) => void;
+}
+
+// MapComponent의 props 타입 정의
+export interface MapComponentProps {
+ mapInstance: React.MutableRefObject;
+}
+
+export interface UserProps {
+ id: number;
+ label: string;
+ selectedButton: number;
+ handleButtonClick: (id: number) => void;
+}
diff --git a/fe/src/app/naver-map-test/components/NaverMap.tsx b/fe/src/app/naver-map-test/components/NaverMap.tsx
deleted file mode 100644
index cdc7ab2..0000000
--- a/fe/src/app/naver-map-test/components/NaverMap.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-"use client";
-
-import React, { useEffect, useRef, useState } from "react";
-
-// 현재 위치 타입 정의
-interface Location {
- latitude: number;
- longitude: number;
-}
-
-// 네이버 지도 타입 선언
-declare global {
- interface Window {
- naver: typeof naver;
- }
-}
-
-function NaverMap() {
- const mapRef = useRef(null);
- const mapInstance = useRef(null);
- const [myLocation, setMyLocation] = useState({
- latitude: 37.4979517,
- longitude: 127.0276188,
- });
- const [address, setAddress] = useState("");
-
- useEffect(() => {
- const initializeMap = () => {
- if (mapInstance.current || !window.naver) return;
-
- const { naver } = window;
- const center = new naver.maps.LatLng(
- myLocation.latitude,
- myLocation.longitude
- );
-
- mapInstance.current = new naver.maps.Map(mapRef.current as HTMLElement, {
- center,
- zoom: 15,
- });
-
- const markerPosition = new naver.maps.LatLng(37.4979517, 127.0276188);
-
- const marker = new naver.maps.Marker({
- position: markerPosition,
- map: mapInstance.current,
- icon: {
- url: "/favicon.ico",
- size: new naver.maps.Size(50, 50),
- origin: new naver.maps.Point(0, 0),
- anchor: new naver.maps.Point(25, 50),
- },
- title: "서울 시청",
- });
-
- naver.maps.Event.addListener(marker, "click", () => {
- window.location.href =
- "https://map.naver.com/p/search/셀렉티드닉스/place/1776798877";
- });
- };
-
- if (window.naver?.maps) {
- initializeMap();
- } else {
- const script = document.createElement("script");
- script.src = `https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${process.env.NEXT_PUBLIC_NAVER_MAP_CLIENT_ID}`;
- script.onload = initializeMap;
- document.head.appendChild(script);
-
- return () => {
- if (mapInstance.current) {
- mapInstance.current.destroy();
- mapInstance.current = null;
- }
- document.head.removeChild(script);
- };
- }
- return undefined;
- }, [myLocation.latitude, myLocation.longitude]);
-
- const handleMoveToCurrentLocation = () => {
- if (navigator.geolocation) {
- navigator.geolocation.getCurrentPosition(
- (position) => {
- const { latitude, longitude } = position.coords;
- setMyLocation({ latitude, longitude });
-
- const { naver } = window;
- const newCenter = new naver.maps.LatLng(latitude, longitude);
- mapInstance.current?.setCenter(newCenter);
-
- // 현재 위치의 주소를 가져와 표시
- naver.maps.Service.reverseGeocode(
- {
- coords: new naver.maps.LatLng(latitude, longitude),
- },
- (
- status: naver.maps.Service.Status,
- response: naver.maps.Service.ReverseGeocodeResponse
- ) => {
- if (
- status === naver.maps.Service.Status.OK &&
- response.v2.address.jibunAddress
- ) {
- const userAddress =
- response.v2.address.jibunAddress ||
- "주소 정보를 가져올 수 없습니다.";
- setAddress(userAddress);
- } else {
- setAddress("주소 정보를 가져오는 데 실패했습니다.");
- }
- }
- );
- },
- () => alert("위치 정보를 가져올 수 없습니다.")
- );
- }
- };
-
- return (
-
-
-
- {address &&
현재 주소: {address}
}
-
- );
-}
-
-export default NaverMap;
diff --git a/fe/src/app/naver-map-test/page.tsx b/fe/src/app/naver-map-test/page.tsx
deleted file mode 100644
index 95ab98b..0000000
--- a/fe/src/app/naver-map-test/page.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from "react";
-
-import NaverMap from "./components/NaverMap";
-
-const page = () => {
- return ;
-};
-
-export default page;
diff --git a/fe/src/app/page.tsx b/fe/src/app/page.tsx
index 262321a..561b26c 100644
--- a/fe/src/app/page.tsx
+++ b/fe/src/app/page.tsx
@@ -1,5 +1,4 @@
import NaverLoginButton from "@/app/components/NaverLoginButton";
-import Script from "next/script";
export default function Home() {
return (
@@ -7,10 +6,6 @@ export default function Home() {
Welcome to My App
Please login using Naver:
-
);
}
diff --git a/fe/src/styles/globals.css b/fe/src/styles/globals.css
index 25a43f6..4371e19 100644
--- a/fe/src/styles/globals.css
+++ b/fe/src/styles/globals.css
@@ -19,5 +19,4 @@ body {
padding: 0;
width: 360px;
height: 100vh;
- margin: 0 auto;
}
diff --git a/fe/tailwind.config.ts b/fe/tailwind.config.ts
index 6b1411a..2ce7a9e 100644
--- a/fe/tailwind.config.ts
+++ b/fe/tailwind.config.ts
@@ -1,58 +1,58 @@
-import type { Config } from 'tailwindcss';
+import type { Config } from "tailwindcss";
const config: Config = {
- darkMode: 'class', // 다크 모드 설정 (필요 시 활성화 가능)
+ darkMode: "class", // 다크 모드 설정 (필요 시 활성화 가능)
content: [
- './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
- './src/components/**/*.{js,ts,jsx,tsx,mdx}',
- './src/app/**/*.{js,ts,jsx,tsx,mdx}',
+ "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
+ "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
+ "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
// Gray 팔레트 (웹 접근성 대비율 준수)
gray: {
- 50: '#F8F8F8',
- 100: '#F5F5F5',
- 200: '#E8E8E8',
- 300: '#D1D1D1',
- 400: '#BFBFBF',
- 500: '#A6A6A6',
- 600: '#777777',
- 700: '#444444',
- 800: '#333333',
- 900: '#222527',
+ 50: "#F8F8F8",
+ 100: "#F5F5F5",
+ 200: "#E8E8E8",
+ 300: "#D1D1D1",
+ 400: "#BFBFBF",
+ 500: "#A6A6A6",
+ 600: "#777777",
+ 700: "#444444",
+ 800: "#333333",
+ 900: "#222527",
},
// Semantic Colors (텍스트, 아이콘, 경계선 등)
text: {
- default: '#222527', // 기본 텍스트
- subdued: '#444444', // 보조 텍스트
- info: '#777777', // 정보 텍스트
- disabled: '#A6A6A6', // 비활성화 텍스트
- heading: '#222527', // 타이틀 텍스트
+ default: "#222527", // 기본 텍스트
+ subdued: "#444444", // 보조 텍스트
+ info: "#777777", // 정보 텍스트
+ disabled: "#A6A6A6", // 비활성화 텍스트
+ heading: "#222527", // 타이틀 텍스트
},
icon: {
- default: '#444444', // 기본 아이콘 색상
- sub: '#777777', // 보조 아이콘 색상
- disabled: '#BFBFBF', // 비활성화 아이콘 색상
+ default: "#444444", // 기본 아이콘 색상
+ sub: "#777777", // 보조 아이콘 색상
+ disabled: "#BFBFBF", // 비활성화 아이콘 색상
},
border: {
- default: '#BFBFBF', // 기본 경계선 색상
- strong: '#A6A6A6', // 강조된 경계선 색상
- disabled: '#E8E8E8', // 비활성화된 경계선 색상
+ default: "#BFBFBF", // 기본 경계선 색상
+ strong: "#A6A6A6", // 강조된 경계선 색상
+ disabled: "#E8E8E8", // 비활성화된 경계선 색상
},
divider: {
- default: '#E8E8E8', // 기본 구분선 색상
- strong: '#A6A6A6', // 강조된 구분선 색상
+ default: "#E8E8E8", // 기본 구분선 색상
+ strong: "#A6A6A6", // 강조된 구분선 색상
},
background: {
- light: '#F8F8F8', // 밝은 배경색
- deep: '#F5F5F5', // 진한 배경색
+ light: "#F8F8F8", // 밝은 배경색
+ deep: "#F5F5F5", // 진한 배경색
},
// 기존 Primary, Secondary, Grayscale 등 컬러 팔레트
@@ -152,7 +152,7 @@ const config: Config = {
},
},
},
- plugins: [],
+ plugins: [require("tailwind-scrollbar-hide")],
};
-export default config;
\ No newline at end of file
+export default config;
From 46584d02398692cadf78037515d2f91bce2d7488 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B5=9C=ED=98=B8?=
<67588757+choihooo@users.noreply.github.com>
Date: Thu, 24 Oct 2024 16:55:50 +0900
Subject: [PATCH 2/2] Bugfix/map page user select (#24)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* [feat] #22 맵 페이지 ui 틀 구현
* [feat] #22 맵 페이지 드로우 구현 & 파일 분리
* [feat] #22 네이버 로고 위쪽으로 변경 및 바텀 드로우 가로 스크롤 구현
* [feat] #22 선택하면 보더 생기는 이벤트 구현
* [feat] #22 공유 버튼 및 로케이션 버튼 기능 구현
* [feat] #22 eslint 해결
* [feat] #22 누르면 보더 해제
* 유저 셀렉트 취소 추가
---
fe/src/app/map-page/components/BottomDrawer.tsx | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/fe/src/app/map-page/components/BottomDrawer.tsx b/fe/src/app/map-page/components/BottomDrawer.tsx
index d7b3be3..68c99a9 100644
--- a/fe/src/app/map-page/components/BottomDrawer.tsx
+++ b/fe/src/app/map-page/components/BottomDrawer.tsx
@@ -3,7 +3,7 @@ import Image from "next/image"; // Import Next.js Image component
import { useLocationStore } from "../stores/useLocationStore";
export default function BottomDrawer() {
- const [selectedButton, setSelectedButton] = useState(0);
+ const [selectedButton, setSelectedButton] = useState(null); // Allows deselection
const moveToLocation = useLocationStore((state) => state.moveToLocation); // 상태에서 함수 가져오기
const handleLocationClick = () => {
@@ -19,7 +19,7 @@ export default function BottomDrawer() {
};
const handleButtonClick = (id: number) => {
- setSelectedButton(id);
+ setSelectedButton((prevId) => (prevId === id ? null : id)); // Toggle selection and deselection
};
const handleShare = () => {
@@ -41,7 +41,7 @@ export default function BottomDrawer() {
{ label: "메롱메롱", id: 1 },
{ label: "메롱메롱", id: 2 },
{ label: "메롱메롱", id: 3 },
- { label: "메롱윤소민", id: 4 },
+ { label: "메윤소민", id: 4 },
{ label: "메롱윤소민", id: 5 },
{ label: "메롱윤소민", id: 6 },
];
@@ -54,8 +54,7 @@ export default function BottomDrawer() {
className="w-[48px] h-[48px] mb-[12px]"
onClick={handleShare}
>
- {" "}
- {/* Optimized image */}
+
{" "}
- {/* Optimized image */}
+ />