Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 99fa5a93d0 | |||
| a1b896b37f | |||
| 72bfdeb5a3 | |||
| d1b6eb7c82 | |||
| 4afbf6bf66 | |||
| 54d48c8ce3 | |||
| 226397afac | |||
| 1497d6ede3 | |||
| 6a415ec165 |
@@ -2,4 +2,6 @@
|
|||||||
# VITE_API_URL=http://192.168.1.144:4002
|
# VITE_API_URL=http://192.168.1.144:4002
|
||||||
# VITE_API_URL=http://194.26.138.94:4002
|
# VITE_API_URL=http://194.26.138.94:4002
|
||||||
# VITE_API_URL=https://irthtest.online/api
|
# VITE_API_URL=https://irthtest.online/api
|
||||||
VITE_API_URL=https://irth.graff.estate/api
|
VITE_API_URL=https://irth.graff.estate/api
|
||||||
|
VITE_GOOGLE_MAP_API_KEY=AIzaSyD1aCnh8qEIh9ACrZWeHddYJLyHMX4KsoE
|
||||||
|
VITE_GOOGLE_MAP_ID=30ff24bdc133c941ee0d0608
|
||||||
@@ -25,3 +25,5 @@ public/virtual-tours
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
.env
|
||||||
@@ -4,11 +4,13 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "irth-new",
|
"name": "irth-new",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@googlemaps/markerclusterer": "^2.6.2",
|
||||||
"@tailwindcss/vite": "^4.1.3",
|
"@tailwindcss/vite": "^4.1.3",
|
||||||
"@tanstack/react-query": "^5.74.4",
|
"@tanstack/react-query": "^5.74.4",
|
||||||
"@tanstack/react-query-devtools": "^5.74.7",
|
"@tanstack/react-query-devtools": "^5.74.7",
|
||||||
"@tweenjs/tween.js": "^25.0.0",
|
"@tweenjs/tween.js": "^25.0.0",
|
||||||
"@uidotdev/usehooks": "^2.4.1",
|
"@uidotdev/usehooks": "^2.4.1",
|
||||||
|
"@vis.gl/react-google-maps": "^1.5.4",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
@@ -111,6 +113,8 @@
|
|||||||
|
|
||||||
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.8", "", { "dependencies": { "@eslint/core": "^0.13.0", "levn": "^0.4.1" } }, "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA=="],
|
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.8", "", { "dependencies": { "@eslint/core": "^0.13.0", "levn": "^0.4.1" } }, "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA=="],
|
||||||
|
|
||||||
|
"@googlemaps/markerclusterer": ["@googlemaps/markerclusterer@2.6.2", "", { "dependencies": { "@types/supercluster": "^7.1.3", "fast-equals": "^5.2.2", "supercluster": "^8.0.1" } }, "sha512-U6uVhq8iWhiIckA89sgRu8OK35mjd6/3CuoZKWakKEf0QmRRWpatlsPb3kqXkoWSmbcZkopRiI4dnW6DQSd7bQ=="],
|
||||||
|
|
||||||
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
||||||
|
|
||||||
"@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="],
|
"@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="],
|
||||||
@@ -237,6 +241,10 @@
|
|||||||
|
|
||||||
"@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
|
"@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
|
||||||
|
|
||||||
|
"@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="],
|
||||||
|
|
||||||
|
"@types/google.maps": ["@types/google.maps@3.58.1", "", {}, "sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ=="],
|
||||||
|
|
||||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@22.14.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA=="],
|
"@types/node": ["@types/node@22.14.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA=="],
|
||||||
@@ -245,6 +253,8 @@
|
|||||||
|
|
||||||
"@types/react-dom": ["@types/react-dom@19.1.1", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-jFf/woGTVTjUJsl2O7hcopJ1r0upqoq/vIOoCj0yLh3RIXxWcljlpuZ+vEBRXsymD1jhfeJrlyTy/S1UW+4y1w=="],
|
"@types/react-dom": ["@types/react-dom@19.1.1", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-jFf/woGTVTjUJsl2O7hcopJ1r0upqoq/vIOoCj0yLh3RIXxWcljlpuZ+vEBRXsymD1jhfeJrlyTy/S1UW+4y1w=="],
|
||||||
|
|
||||||
|
"@types/supercluster": ["@types/supercluster@7.1.3", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA=="],
|
||||||
|
|
||||||
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.29.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.29.0", "@typescript-eslint/type-utils": "8.29.0", "@typescript-eslint/utils": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ=="],
|
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.29.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.29.0", "@typescript-eslint/type-utils": "8.29.0", "@typescript-eslint/utils": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ=="],
|
||||||
@@ -265,6 +275,8 @@
|
|||||||
|
|
||||||
"@uidotdev/usehooks": ["@uidotdev/usehooks@2.4.1", "", { "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg=="],
|
"@uidotdev/usehooks": ["@uidotdev/usehooks@2.4.1", "", { "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg=="],
|
||||||
|
|
||||||
|
"@vis.gl/react-google-maps": ["@vis.gl/react-google-maps@1.5.4", "", { "dependencies": { "@types/google.maps": "^3.54.10", "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "react": ">=16.8.0 || ^19.0 || ^19.0.0-rc", "react-dom": ">=16.8.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-pD3e2wDtOfd439mamkacRgrM6I2B/lue61QCR0pGQT8MVaG9pz9/LajHbsjZW2lms8Ao8mf2PQJeiGC2FxI0Fw=="],
|
||||||
|
|
||||||
"@vitejs/plugin-react-swc": ["@vitejs/plugin-react-swc@3.8.1", "", { "dependencies": { "@swc/core": "^1.11.11" }, "peerDependencies": { "vite": "^4 || ^5 || ^6" } }, "sha512-aEUPCckHDcFyxpwFm0AIkbtv6PpUp3xTb9wYGFjtABynXjCYKkWoxX0AOK9NT9XCrdk6mBBUOeHQS+RKdcNO1A=="],
|
"@vitejs/plugin-react-swc": ["@vitejs/plugin-react-swc@3.8.1", "", { "dependencies": { "@swc/core": "^1.11.11" }, "peerDependencies": { "vite": "^4 || ^5 || ^6" } }, "sha512-aEUPCckHDcFyxpwFm0AIkbtv6PpUp3xTb9wYGFjtABynXjCYKkWoxX0AOK9NT9XCrdk6mBBUOeHQS+RKdcNO1A=="],
|
||||||
|
|
||||||
"acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="],
|
"acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="],
|
||||||
@@ -343,6 +355,8 @@
|
|||||||
|
|
||||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||||
|
|
||||||
|
"fast-equals": ["fast-equals@5.2.2", "", {}, "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw=="],
|
||||||
|
|
||||||
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||||
|
|
||||||
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
||||||
@@ -403,6 +417,8 @@
|
|||||||
|
|
||||||
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
|
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
|
||||||
|
|
||||||
|
"kdbush": ["kdbush@4.0.2", "", {}, "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA=="],
|
||||||
|
|
||||||
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
||||||
|
|
||||||
"ky": ["ky@1.8.1", "", {}, "sha512-7Bp3TpsE+L+TARSnnDpk3xg8Idi8RwSLdj6CMbNWoOARIrGrbuLGusV0dYwbZOm4bB3jHNxSw8Wk/ByDqJEnDw=="],
|
"ky": ["ky@1.8.1", "", {}, "sha512-7Bp3TpsE+L+TARSnnDpk3xg8Idi8RwSLdj6CMbNWoOARIrGrbuLGusV0dYwbZOm4bB3jHNxSw8Wk/ByDqJEnDw=="],
|
||||||
@@ -513,6 +529,8 @@
|
|||||||
|
|
||||||
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
||||||
|
|
||||||
|
"supercluster": ["supercluster@8.0.1", "", { "dependencies": { "kdbush": "^4.0.2" } }, "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ=="],
|
||||||
|
|
||||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||||
|
|
||||||
"tailwindcss": ["tailwindcss@4.1.3", "", {}, "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g=="],
|
"tailwindcss": ["tailwindcss@4.1.3", "", {}, "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g=="],
|
||||||
|
|||||||
@@ -10,11 +10,13 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@googlemaps/markerclusterer": "^2.6.2",
|
||||||
"@tailwindcss/vite": "^4.1.3",
|
"@tailwindcss/vite": "^4.1.3",
|
||||||
"@tanstack/react-query": "^5.74.4",
|
"@tanstack/react-query": "^5.74.4",
|
||||||
"@tanstack/react-query-devtools": "^5.74.7",
|
"@tanstack/react-query-devtools": "^5.74.7",
|
||||||
"@tweenjs/tween.js": "^25.0.0",
|
"@tweenjs/tween.js": "^25.0.0",
|
||||||
"@uidotdev/usehooks": "^2.4.1",
|
"@uidotdev/usehooks": "^2.4.1",
|
||||||
|
"@vis.gl/react-google-maps": "^1.5.4",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="32" height="32" rx="16" fill="#0D1922"/>
|
||||||
|
<path d="M13 11.6869H11C10.4477 11.6869 10 12.1346 10 12.6869V22C10 22.5523 10.4477 23 11 23H20.9993C21.5516 23 21.9993 22.5523 21.9993 22.0001L21.9999 12.687C22 12.1346 21.5522 11.6869 20.9999 11.6869H19M13 11.6869V11C13 9.34315 14.3431 8 16 8V8C17.6569 8 19 9.34315 19 11V11.6869M13 11.6869H19" stroke="white" stroke-width="1.5" stroke-linecap="square"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 514 B |
@@ -20,6 +20,9 @@ import clsx from "clsx";
|
|||||||
import Slider from "./Slider";
|
import Slider from "./Slider";
|
||||||
import PlusIcon from "./icons/map/PlusIcon";
|
import PlusIcon from "./icons/map/PlusIcon";
|
||||||
import EqualIcon from "./icons/EqualIcon";
|
import EqualIcon from "./icons/EqualIcon";
|
||||||
|
import GoogleMap from "./google-map/GoogleMap";
|
||||||
|
import { GoogleMapData } from "../data/googleMapData";
|
||||||
|
import GoogleMapMobile from "./google-map/GoogleMapMobile";
|
||||||
// import FullScreenButton from "./FullScreenButton";
|
// import FullScreenButton from "./FullScreenButton";
|
||||||
|
|
||||||
function AboutDubaiMarina() {
|
function AboutDubaiMarina() {
|
||||||
@@ -336,7 +339,7 @@ function AboutDubaiMarina() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-center gap-[2.222vw] bg-white px-[2.222vw] pb-[8.333vw] max-md:gap-[6.667vw] max-md:px-[4.444vw] max-2xl:gap-[4.167vw]">
|
<div className="flex flex-col items-center gap-[2.222vw] bg-white px-[2.222vw] pb-[8.333vw] max-md:gap-[6.667vw] max-md:px-[4.444vw] max-2xl:gap-[4.167vw]">
|
||||||
{/* <h1
|
<h1
|
||||||
className="font-mixcase-unmixed text-[3.889vw] text-[#0D1922] w-[44.861vw] leading-[100%] tracking-[-0.05em] pt-[7.222vw] text-center
|
className="font-mixcase-unmixed text-[3.889vw] text-[#0D1922] w-[44.861vw] leading-[100%] tracking-[-0.05em] pt-[7.222vw] text-center
|
||||||
max-md:text-[6.667vw] max-md:w-full max-2xl:text-[7.292vw] max-2xl:w-[84.115vw]"
|
max-md:text-[6.667vw] max-md:w-full max-2xl:text-[7.292vw] max-2xl:w-[84.115vw]"
|
||||||
>
|
>
|
||||||
@@ -347,31 +350,18 @@ function AboutDubaiMarina() {
|
|||||||
living meets modern convenience. Enjoy an energetic lifestyle surrounded by
|
living meets modern convenience. Enjoy an energetic lifestyle surrounded by
|
||||||
trendy cafés, shops, and entertainment options – all within reach.`}
|
trendy cafés, shops, and entertainment options – all within reach.`}
|
||||||
</p>
|
</p>
|
||||||
<motion.img
|
<div className="w-full 2xl:aspect-[1376/688] max-2xl:aspect-[720/688] max-md:hidden rounded-[1.667vw] overflow-hidden">
|
||||||
ref={mapRef}
|
<GoogleMap
|
||||||
src="/images/about-complex/dubai-marina/central_map.png"
|
markers={GoogleMapData.markers}
|
||||||
alt="central map"
|
mapCenter={GoogleMapData.dubaiMarinaDefaultCenter}
|
||||||
className="rounded-3xl object-cover object-center aspect-[1376/609] max-md:hidden max-2xl:w-[93.75vw] max-2xl:h-[89.583vw] max-2xl:aspect-[720/688] max-2xl:mt-[1.563vw]"
|
|
||||||
initial={{ width: "47.083vw" }}
|
|
||||||
animate={
|
|
||||||
isMapInView ? { width: "95.556vw" } : { width: "47.083vw" }
|
|
||||||
}
|
|
||||||
transition={{ duration: 0.6, ease: "easeInOut" }}
|
|
||||||
/>
|
|
||||||
<div className="min-md:hidden relative w-[89.167vw] aspect-square overflow-hidden rounded-2xl">
|
|
||||||
<img
|
|
||||||
src="/images/about-complex/dubai-marina/central_map.png"
|
|
||||||
alt="central map"
|
|
||||||
className="w-full h-full object-cover object-center scale-120"
|
|
||||||
/>
|
/>
|
||||||
<div className="absolute bottom-[1.111vw] right-[1.111vw] w-[11.111vw] h-[11.111vw]">
|
</div>
|
||||||
<FullScreenButton
|
<div className="w-full">
|
||||||
isFullScreen={false}
|
<GoogleMapMobile
|
||||||
onClick={() => {}}
|
markers={GoogleMapData.markers}
|
||||||
onFullScreenChange={() => {}}
|
mapCenter={GoogleMapData.dubaiMarinaDefaultCenter}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.section>
|
</motion.section>
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import {
|
import {
|
||||||
marasiDriveFeatures,
|
marasiDriveFeatures,
|
||||||
marasiDriveDescriptionBadges,
|
marasiDriveDescriptionBadges,
|
||||||
marasiDriveMapCards,
|
// marasiDriveMapCards,
|
||||||
} from "../data/aboutMarasiDrive";
|
} from "../data/aboutMarasiDrive";
|
||||||
import MarariDriveNeighboursSliderDesktop from "./MarasiDriveNeighboursSliderDesktop";
|
import MarariDriveNeighboursSliderDesktop from "./MarasiDriveNeighboursSliderDesktop";
|
||||||
import MarasiDriveInteriorsSlider from "./MarasiDriveInteriorsSlider";
|
import MarasiDriveInteriorsSlider from "./MarasiDriveInteriorsSlider";
|
||||||
import MarasiDriveInteriorsSliderMobile from "./MarasiDriveInteriorsSliderMobile";
|
import MarasiDriveInteriorsSliderMobile from "./MarasiDriveInteriorsSliderMobile";
|
||||||
import MarasiDriveNeighboursSliderMobile from "./MarasiDriveNeighboursSliderMobile";
|
import MarasiDriveNeighboursSliderMobile from "./MarasiDriveNeighboursSliderMobile";
|
||||||
import MarasiDriveMapMobile from "./MarasiDriveMapMobile";
|
import GoogleMapMobile from "./google-map/GoogleMapMobile";
|
||||||
import TextBox from "./ui/TextBox";
|
import TextBox from "./ui/TextBox";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { useScroll } from "motion/react";
|
import { useScroll } from "motion/react";
|
||||||
import MarasiDriveMapCard from "./MarasiDriveMapCard";
|
// import MarasiDriveMapCard from "./MarasiDriveMapCard";
|
||||||
|
import GoogleMap from "./google-map/GoogleMap";
|
||||||
import MarasiDriveNeighboursSliderTablet from "./MarasiDriveNeighboursSliderTablet";
|
import MarasiDriveNeighboursSliderTablet from "./MarasiDriveNeighboursSliderTablet";
|
||||||
import CustomScrollBar from "./ui/ScrollBar";
|
import CustomScrollBar from "./ui/ScrollBar";
|
||||||
import BrochureButton from "./ui/BrochureButton";
|
import BrochureButton from "./ui/BrochureButton";
|
||||||
|
import { GoogleMapData } from "../data/googleMapData";
|
||||||
|
|
||||||
function AboutMarasiDrive() {
|
function AboutMarasiDrive() {
|
||||||
const target = useRef<HTMLDivElement>(null);
|
const target = useRef<HTMLDivElement>(null);
|
||||||
@@ -98,19 +99,32 @@ function AboutMarasiDrive() {
|
|||||||
destination for artful inspiration and cleverly activated spaces.`}
|
destination for artful inspiration and cleverly activated spaces.`}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div ref={homeSliderRef} className="flex max-2xl:flex-wrap max-2xl:justify-center 2xl:gap-[0.556vw] gap-2 md:max-2xl:w-[93.75vw] max-md:flex-row max-md:flex-nowrap max-md:overflow-x-scroll max-md:overflow-y-hidden max-md:justify-start max-md:snap-x max-md:snap-mandatory [&::-webkit-scrollbar]:h-[1.111vw] [&::-webkit-scrollbar]:w-[none] [&::-webkit-scrollbar-thumb]:bg-transparent [&::-webkit-scrollbar-thumb]:w-4 [&::-webkit-scrollbar-thumb]:rounded-full max-md:-mx-4 max-md:px-4">
|
<div
|
||||||
|
ref={homeSliderRef}
|
||||||
|
className="flex max-2xl:flex-wrap max-2xl:justify-center 2xl:gap-[0.556vw] gap-2 md:max-2xl:w-[93.75vw] max-md:flex-row max-md:flex-nowrap max-md:overflow-x-scroll max-md:overflow-y-hidden max-md:justify-start max-md:snap-x max-md:snap-mandatory [&::-webkit-scrollbar]:h-[1.111vw] [&::-webkit-scrollbar]:w-[none] [&::-webkit-scrollbar-thumb]:bg-transparent [&::-webkit-scrollbar-thumb]:w-4 [&::-webkit-scrollbar-thumb]:rounded-full max-md:-mx-4 max-md:px-4"
|
||||||
|
>
|
||||||
{marasiDriveFeatures.map(({ image, name }) => (
|
{marasiDriveFeatures.map(({ image, name }) => (
|
||||||
<div key={name} className="relative md:max-2xl:w-[30.208vw] max-md:w-full max-md:max-w-[530px] max-md:flex-shrink-0 max-md:snap-center">
|
<div
|
||||||
|
key={name}
|
||||||
|
className="relative md:max-2xl:w-[30.208vw] max-md:w-full max-md:max-w-[530px] max-md:flex-shrink-0 max-md:snap-center"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
src={image}
|
src={image}
|
||||||
alt={name}
|
alt={name}
|
||||||
className="object-cover object-center 2xl:rounded-[1.667vw] max-md:!aspect-[328/287] max-md:rounded-2xl md:max-2xl:rounded-[3.125vw]"
|
className="object-cover object-center 2xl:rounded-[1.667vw] max-md:!aspect-[328/287] max-md:rounded-2xl md:max-2xl:rounded-[3.125vw]"
|
||||||
/>
|
/>
|
||||||
<span className="md:hidden absolute bottom-[16px] text-white text-h5 left-1/2 -translate-x-1/2 text-center text-nowrap">{name}</span>
|
<span className="md:hidden absolute bottom-[16px] text-white text-h5 left-1/2 -translate-x-1/2 text-center text-nowrap">
|
||||||
|
{name}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<CustomScrollBar containerRef={homeSliderRef} inlinePadding={16} trackStyle="min-md:hidden" thumbStyle="min-md:hidden" />
|
<CustomScrollBar
|
||||||
|
containerRef={homeSliderRef}
|
||||||
|
inlinePadding={16}
|
||||||
|
trackStyle="min-md:hidden"
|
||||||
|
thumbStyle="min-md:hidden"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
<section className="bg-white w-full overflow-clip flex flex-col 2xl:gap-[4.444vw] gap-12 2xl:pt-[9.444vw] 2xl:px-[2.222vw] 2xl:pb-[2.222vw] md:max-2xl:pt-[104px] md:max-2xl:px-6 md:max-2xl:pb-8 pt-16 px-4 pb-8">
|
<section className="bg-white w-full overflow-clip flex flex-col 2xl:gap-[4.444vw] gap-12 2xl:pt-[9.444vw] 2xl:px-[2.222vw] 2xl:pb-[2.222vw] md:max-2xl:pt-[104px] md:max-2xl:px-6 md:max-2xl:pb-8 pt-16 px-4 pb-8">
|
||||||
<div className="flex flex-col 2xl:gap-[2.222vw] md:max-2xl:gap-8 gap-6 items-center">
|
<div className="flex flex-col 2xl:gap-[2.222vw] md:max-2xl:gap-8 gap-6 items-center">
|
||||||
@@ -165,7 +179,7 @@ function AboutMarasiDrive() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<MarasiDriveInteriorsSlider />
|
<MarasiDriveInteriorsSlider />
|
||||||
<MarasiDriveInteriorsSliderMobile/>
|
<MarasiDriveInteriorsSliderMobile />
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div className="2xl:sticky relative">
|
<div className="2xl:sticky relative">
|
||||||
@@ -220,22 +234,30 @@ function AboutMarasiDrive() {
|
|||||||
trendy cafés, shops, and entertainment options - all within reach.`}
|
trendy cafés, shops, and entertainment options - all within reach.`}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-6 grid-rows-5 gap-x-[1.111vw] gap-y-[0.556vw] max-2xl:hidden">
|
{/* <div className="grid grid-cols-6 grid-rows-5 gap-x-[1.111vw] gap-y-[0.556vw] max-2xl:hidden">
|
||||||
{marasiDriveMapCards.map((card) => (
|
{marasiDriveMapCards.map((card) => (
|
||||||
<MarasiDriveMapCard {...card} key={card.title} />
|
<MarasiDriveMapCard {...card} key={card.title} />
|
||||||
))}
|
))}
|
||||||
<div className="col-start-3 col-span-full row-start-1 row-span-full">
|
<div className="col-start-3 col-span-full row-start-1 row-span-full rounded-[1.667vw] overflow-hidden">
|
||||||
<img
|
<GoogleMap
|
||||||
src="/images/about-complex/marasi-drive/map/map.png"
|
mapCenter={GoogleMapData.marasiDriveDefaultCenter}
|
||||||
alt=""
|
markers={GoogleMapData.markers}
|
||||||
className="object-cover size-full 2xl:rounded-[1.667vw]"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div> */}
|
||||||
|
<div className="w-full 2xl:aspect-[1376/676] max-2xl:aspect-[720/688] max-md:hidden rounded-[1.667vw] overflow-hidden">
|
||||||
|
<GoogleMap
|
||||||
|
mapCenter={GoogleMapData.marasiDriveDefaultCenter}
|
||||||
|
markers={GoogleMapData.markers}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<MarasiDriveMapMobile/>
|
<GoogleMapMobile
|
||||||
|
mapCenter={GoogleMapData.marasiDriveDefaultCenter}
|
||||||
|
markers={GoogleMapData.markers}
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
<section className="bg-white w-full overflow-clip flex items-stretch justify-center gap-[1.111vw] 2xl:px-[10.278vw] 2xl:pt-[9.444vw] 2xl:pb-[15vw] md:max-2xl:py-[104px] md:mx-2xl:px-6 max-md:pt-20 max-md:pb-12 px-4 max-2xl:flex-col-reverse md:max-2xl:gap-[6.25vw] md:max-2xl:px-6">
|
<section className="bg-white w-full overflow-clip flex items-stretch justify-center gap-[1.111vw] 2xl:px-[10.278vw] 2xl:pt-[9.444vw] 2xl:pb-[15vw] md:max-2xl:py-[104px] md:mx-2xl:px-6 max-md:pt-20 max-md:pb-12 px-4 max-2xl:flex-col-reverse md:max-2xl:gap-[6.25vw] md:max-2xl:px-6">
|
||||||
<div >
|
<div>
|
||||||
<img
|
<img
|
||||||
src="/images/about-complex/marasi-drive/podium.png"
|
src="/images/about-complex/marasi-drive/podium.png"
|
||||||
className="object-cover size-full rounded-[1.667vw] max-md:mt-[48px] max-md:aspect-[328/400] max-md:rounded-[6.667vw] md:max-2xl:rounded-[3.125vw] md:max-2xl:aspect-[720/400]"
|
className="object-cover size-full rounded-[1.667vw] max-md:mt-[48px] max-md:aspect-[328/400] max-md:rounded-[6.667vw] md:max-2xl:rounded-[3.125vw] md:max-2xl:aspect-[720/400]"
|
||||||
@@ -254,7 +276,9 @@ function AboutMarasiDrive() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-[1.111vw]">
|
<div className="space-y-[1.111vw]">
|
||||||
<h5 className="text-h5 font-medium max-md:mb-[16px] md:max-2xl:mb-[2.083vw]">Download our brochures</h5>
|
<h5 className="text-h5 font-medium max-md:mb-[16px] md:max-2xl:mb-[2.083vw]">
|
||||||
|
Download our brochures
|
||||||
|
</h5>
|
||||||
<div className="space-y-[0.833vw] max-md:space-y-[3.333vw] md:max-2xl:space-y-[1.563vw]">
|
<div className="space-y-[0.833vw] max-md:space-y-[3.333vw] md:max-2xl:space-y-[1.563vw]">
|
||||||
<BrochureButton
|
<BrochureButton
|
||||||
title={"Main Brochure"}
|
title={"Main Brochure"}
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
import { useRef } from "react";
|
|
||||||
import { marasiDriveMapCards } from "../data/aboutMarasiDrive";
|
|
||||||
import CustomScrollBar from "./ui/ScrollBar";
|
|
||||||
|
|
||||||
function MarasiDriveMapMobile() {
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="min-2xl:hidden relative flex flex-col">
|
|
||||||
<div className="max-md:aspect-[328/544] md:max-2xl:aspect[1/1] max-2xl:mb-4">
|
|
||||||
<img
|
|
||||||
src="/images/about-complex/marasi-drive/map/map.png"
|
|
||||||
alt=""
|
|
||||||
className="object-cover size-full rounded-[6.667vw] md:max-2xl:rounded-[3.125vw]"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
ref={containerRef}
|
|
||||||
className="flex flex-nowrap overflow-x-scroll scroll-pl-4 gap-x-[16px] overflow-y-hidden justify-start snap-x snap-mandatory [&::-webkit-scrollbar]:h-[1.111vw] [&::-webkit-scrollbar]:w-[none] [&::-webkit-scrollbar-thumb]:bg-[#FFFFFF] [&::-webkit-scrollbar-thumb]:w-4 [&::-webkit-scrollbar-thumb]:rounded-full -mx-4 px-4 "
|
|
||||||
>
|
|
||||||
{marasiDriveMapCards.map((card, index) => (
|
|
||||||
<div key={index} className="snap-start">
|
|
||||||
<div
|
|
||||||
className={`rounded-[6.667vw] px-[4.444vw] py-[3.333vw] w-[51.111vw] aspect-[184/122] bg-[#F3F3F2] flex-shrink-0 flex flex-col justify-between relative md:max-2xl:w-[25vw] md:max-2xl:rounded-[3.125vw] md:max-2xl:px-[2.083vw] md:max-2xl:py-[1.563vw]`}
|
|
||||||
>
|
|
||||||
<div className="space-y-[0.278vw]">
|
|
||||||
<p className="text-m">{card.title}</p>
|
|
||||||
<p className="text-s text-[#73787C]">{`${card.mins} mins`}</p>
|
|
||||||
</div>
|
|
||||||
<img
|
|
||||||
src={card.image}
|
|
||||||
className="rounded-[0.278vw] size-[13.333vw] object-cover absolute bottom-[4.444vw] right-[3.333vw] md:max-2xl:size-[6.25vw] md:max-2xl:bottom-[1.563vw] md:max-2xl:right-[2.083vw]"
|
|
||||||
alt={card.title}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<CustomScrollBar containerRef={containerRef} inlinePadding={16} trackStyle="min-2xl:hidden max-2xl:translate-y-5" thumbStyle="min-2xl:hidden"/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MarasiDriveMapMobile;
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import IGMapPoi from "../../types/IGMapPoi";
|
||||||
|
import GoogleMapMarkers from "./GoogleMapMarkers";
|
||||||
|
import { Map, useMap } from "@vis.gl/react-google-maps";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
// import GoogleMapFilterButtons from "./GoogleMapFilterButtons";
|
||||||
|
|
||||||
|
interface IGMapProps {
|
||||||
|
mapCenter: google.maps.LatLngLiteral;
|
||||||
|
defaultZoom?: number;
|
||||||
|
markers?: IGMapPoi[];
|
||||||
|
minZoom?: number;
|
||||||
|
mobile?: boolean;
|
||||||
|
mobileActive?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MapFilter = "All" | "Hotels" | "Malls" | "Entertainment" | "Other";
|
||||||
|
export default function GoogleMap({
|
||||||
|
mapCenter,
|
||||||
|
markers,
|
||||||
|
defaultZoom = 14,
|
||||||
|
minZoom = 10,
|
||||||
|
mobile = false,
|
||||||
|
mobileActive = false,
|
||||||
|
}: IGMapProps) {
|
||||||
|
const [mapMarkersFilter, setMapMarkersFilter] = useState<MapFilter>("All");
|
||||||
|
const [isInteractale, setIsInteractale] = useState(!mobile);
|
||||||
|
const map = useMap();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!map) return;
|
||||||
|
|
||||||
|
setIsInteractale(!mobile || (mobile && mobileActive));
|
||||||
|
if (!mobileActive && mobile) {
|
||||||
|
map.panTo(mapCenter);
|
||||||
|
map.setZoom(defaultZoom);
|
||||||
|
}
|
||||||
|
}, [mobile, mobileActive, defaultZoom, mapCenter, map]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!mobileActive) setMapMarkersFilter("All");
|
||||||
|
}, [mobileActive]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`size-[100%] ${
|
||||||
|
isInteractale ? "pointer-events-auto" : "pointer-events-none"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Map
|
||||||
|
mapId={import.meta.env.VITE_GOOGLE_MAP_ID}
|
||||||
|
defaultCenter={mapCenter}
|
||||||
|
defaultZoom={defaultZoom}
|
||||||
|
disableDefaultUI={true}
|
||||||
|
minZoom={minZoom}
|
||||||
|
gestureHandling={
|
||||||
|
mobile ? (mobileActive ? "greedy" : "none") : "cooperative"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{markers && (
|
||||||
|
<GoogleMapMarkers data={markers} filter={mapMarkersFilter} />
|
||||||
|
)}
|
||||||
|
{/* <GoogleMapFilterButtons
|
||||||
|
mobile={mobile}
|
||||||
|
mobileActive={mobileActive}
|
||||||
|
currentFilter={mapMarkersFilter}
|
||||||
|
onChange={setMapMarkersFilter}
|
||||||
|
/> */}
|
||||||
|
</Map>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import AllIcon from "../icons/map/AllIcon";
|
||||||
|
import EntertainmentIcon from "../icons/map/EntertainmentIcon";
|
||||||
|
import HotelIcon from "../icons/map/HotelIcon";
|
||||||
|
import MallsIcon from "../icons/map/MallsIcon";
|
||||||
|
import OtherIcon from "../icons/map/OtherIcon";
|
||||||
|
import Button from "../ui/Button";
|
||||||
|
import { AnimatePresence, motion } from "motion/react";
|
||||||
|
import { MapFilter } from "./GoogleMap";
|
||||||
|
|
||||||
|
export default function GoogleMapFilterButtons({
|
||||||
|
mobile,
|
||||||
|
mobileActive,
|
||||||
|
currentFilter,
|
||||||
|
onChange,
|
||||||
|
}: {
|
||||||
|
mobile: boolean;
|
||||||
|
mobileActive: boolean;
|
||||||
|
currentFilter: MapFilter;
|
||||||
|
onChange: (newFilter: MapFilter) => void;
|
||||||
|
}) {
|
||||||
|
const filters: MapFilter[] = [
|
||||||
|
"All",
|
||||||
|
"Hotels",
|
||||||
|
"Malls",
|
||||||
|
"Entertainment",
|
||||||
|
"Other",
|
||||||
|
];
|
||||||
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
const buttonsVisisble = (expanded && mobile && mobileActive) || !mobile;
|
||||||
|
|
||||||
|
const IconsByFilter = {
|
||||||
|
All: <AllIcon />,
|
||||||
|
Hotels: <HotelIcon />,
|
||||||
|
Malls: <MallsIcon />,
|
||||||
|
Entertainment: <EntertainmentIcon />,
|
||||||
|
Other: <OtherIcon />,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`flex gap-[0.556vw] absolute items-center bottom-[1.111vw] left-1/2 -translate-x-1/2 ${
|
||||||
|
mobile &&
|
||||||
|
`flex-col gap-[1.111vw] w-full pt-5 translate-y-2 ${
|
||||||
|
expanded && "backdrop-blur-[1px]"
|
||||||
|
}`
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<AnimatePresence>
|
||||||
|
{buttonsVisisble &&
|
||||||
|
filters.map((key) => (
|
||||||
|
<motion.div
|
||||||
|
initial={{ translateY: 150, opacity: 0 }}
|
||||||
|
animate={{ translateY: 0, opacity: 1 }}
|
||||||
|
exit={{ translateY: 150, opacity: 0 }}
|
||||||
|
// transition={{ duration: 0.1, delay: index * 0.1 }}
|
||||||
|
key={key}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
onClick={() => onChange(key)}
|
||||||
|
variant={key === currentFilter ? "cta" : "secondary"}
|
||||||
|
>
|
||||||
|
<div className="size-5">{IconsByFilter[key]}</div>
|
||||||
|
{key}
|
||||||
|
</Button>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
|
{mobile && mobileActive && (
|
||||||
|
<Button
|
||||||
|
onClick={() => setExpanded(!expanded)}
|
||||||
|
variant={expanded ? "cta" : "secondary"}
|
||||||
|
className="my-4 px-[3.889vw] py-[2.778vw] z-10 h-10 transition-all"
|
||||||
|
>
|
||||||
|
{!expanded && <div>{IconsByFilter[currentFilter]}</div>}
|
||||||
|
|
||||||
|
{expanded ? (
|
||||||
|
<span>Apply</span>
|
||||||
|
) : currentFilter === "All" ? (
|
||||||
|
<span>Select Category</span>
|
||||||
|
) : (
|
||||||
|
<span>{currentFilter}</span>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import { useMap } from "@vis.gl/react-google-maps";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import IGMapPoi from "../../types/IGMapPoi";
|
||||||
|
import MapMarker from "./MapMarker";
|
||||||
|
import {
|
||||||
|
MarkerClusterer,
|
||||||
|
DefaultRenderer,
|
||||||
|
Cluster,
|
||||||
|
Marker,
|
||||||
|
} from "@googlemaps/markerclusterer";
|
||||||
|
|
||||||
|
class CustomMarkerRenderer extends DefaultRenderer {
|
||||||
|
render({
|
||||||
|
count,
|
||||||
|
position,
|
||||||
|
}: Cluster): google.maps.marker.AdvancedMarkerElement {
|
||||||
|
const svgElement = document.createElement("div");
|
||||||
|
svgElement.innerHTML = `
|
||||||
|
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240" width="50" height="50">
|
||||||
|
<circle cx="120" cy="120" opacity="1" r="70" />
|
||||||
|
</svg>
|
||||||
|
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: black; font-size: 12px; font-weight: bold;">
|
||||||
|
${count}
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
const marker = new google.maps.marker.AdvancedMarkerElement({
|
||||||
|
position,
|
||||||
|
content: svgElement,
|
||||||
|
zIndex: Math.max(1000, count),
|
||||||
|
});
|
||||||
|
|
||||||
|
return marker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function GoogleMapMarkers({
|
||||||
|
data,
|
||||||
|
filter,
|
||||||
|
}: {
|
||||||
|
data: IGMapPoi[];
|
||||||
|
filter: string;
|
||||||
|
}) {
|
||||||
|
const map = useMap();
|
||||||
|
const [markers, setMarkers] = useState<{ [key: string]: Marker }>({});
|
||||||
|
const [selectedMarker, setSelectedMarker] = useState<number | null>(null);
|
||||||
|
const clusterer = useRef<MarkerClusterer | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!map) return;
|
||||||
|
if (!clusterer.current) {
|
||||||
|
clusterer.current = new MarkerClusterer({
|
||||||
|
map: map,
|
||||||
|
renderer: new CustomMarkerRenderer(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [map]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
clusterer.current?.clearMarkers();
|
||||||
|
clusterer.current?.addMarkers(Object.values(markers));
|
||||||
|
}, [markers]);
|
||||||
|
|
||||||
|
const setMarkerRef = (marker: Marker | null, key: string) => {
|
||||||
|
if (marker && markers[key]) return;
|
||||||
|
if (!marker && !markers[key]) return;
|
||||||
|
|
||||||
|
setMarkers((prev) => {
|
||||||
|
if (prev[key] === marker) return prev;
|
||||||
|
|
||||||
|
if (marker) {
|
||||||
|
return { ...prev, [key]: marker };
|
||||||
|
} else {
|
||||||
|
const newMarkers = { ...prev };
|
||||||
|
delete newMarkers[key];
|
||||||
|
return newMarkers;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{data.map(
|
||||||
|
(poi: IGMapPoi, index: number) =>
|
||||||
|
(filter === poi.type || filter === "All") && (
|
||||||
|
<MapMarker
|
||||||
|
key={index}
|
||||||
|
markerKey={index}
|
||||||
|
poi={poi}
|
||||||
|
setMarkerRef={setMarkerRef}
|
||||||
|
isSelected={selectedMarker === index}
|
||||||
|
setSelectedMarker={setSelectedMarker}
|
||||||
|
>
|
||||||
|
{poi.customMarker}
|
||||||
|
</MapMarker>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
// import { marasiDriveMapCards } from "../data/aboutMarasiDrive";
|
||||||
|
// import CustomScrollBar from "./ui/ScrollBar";
|
||||||
|
// import { GoogleMapData } from "../data/googleMapData";
|
||||||
|
import GoogleMap from "./GoogleMap";
|
||||||
|
import Button from "../ui/Button";
|
||||||
|
import FullScreenIcon from "../icons/FullScreenIcon";
|
||||||
|
import useModalStore from "../../stores/useModalStore";
|
||||||
|
import IGMapPoi from "../../types/IGMapPoi";
|
||||||
|
|
||||||
|
function GoogleMapMobile({
|
||||||
|
markers,
|
||||||
|
mapCenter,
|
||||||
|
}: {
|
||||||
|
markers?: IGMapPoi[];
|
||||||
|
mapCenter: google.maps.LatLngLiteral;
|
||||||
|
}) {
|
||||||
|
// const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [mapActive, setMapActive] = useState(false);
|
||||||
|
const { modal, setModal } = useModalStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (mapActive) setModal(<MapModal />);
|
||||||
|
else setModal(null);
|
||||||
|
}, [mapActive]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMapActive(!!modal);
|
||||||
|
}, [modal]);
|
||||||
|
|
||||||
|
const MapModal = () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`relative max-md:aspect-[360/640] md:max-2xl:aspect[1/1] max-2xl:mb-4 overflow-clip rounded-[4.444vw] h-[calc(100dvh-100px)]`}
|
||||||
|
>
|
||||||
|
<GoogleMap
|
||||||
|
mapCenter={mapCenter}
|
||||||
|
markers={markers}
|
||||||
|
mobileActive={true}
|
||||||
|
mobile={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="md:hidden relative flex flex-col">
|
||||||
|
{
|
||||||
|
<div
|
||||||
|
className={` relative max-md:aspect-[328/328] scroll-mt-10 md:max-2xl:aspect[1/1] transition-all max-2xl:mb-4 overflow-clip rounded-[4.444vw]`}
|
||||||
|
>
|
||||||
|
<GoogleMap
|
||||||
|
mapCenter={mapCenter}
|
||||||
|
markers={markers}
|
||||||
|
mobileActive={false}
|
||||||
|
mobile={true}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className={`absolute size-[11.111vw] right-[1.111vw] bottom-[1.111vw] `}
|
||||||
|
onClick={() => setMapActive(true)}
|
||||||
|
>
|
||||||
|
<div className="size-[5.556vw] text-[#0D1922]">
|
||||||
|
<FullScreenIcon />
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{/*
|
||||||
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className="flex flex-nowrap overflow-x-scroll scroll-pl-4 gap-x-[16px] overflow-y-hidden justify-start snap-x snap-mandatory [&::-webkit-scrollbar]:h-[1.111vw] [&::-webkit-scrollbar]:w-[none] [&::-webkit-scrollbar-thumb]:bg-[#FFFFFF] [&::-webkit-scrollbar-thumb]:w-4 [&::-webkit-scrollbar-thumb]:rounded-full -mx-4 px-4 "
|
||||||
|
>
|
||||||
|
{marasiDriveMapCards.map((card, index) => (
|
||||||
|
<div key={index} className="snap-start">
|
||||||
|
<div
|
||||||
|
className={`rounded-[6.667vw] px-[4.444vw] py-[3.333vw] w-[51.111vw] aspect-[184/122] bg-[#F3F3F2] flex-shrink-0 flex flex-col justify-between relative md:max-2xl:w-[25vw] md:max-2xl:rounded-[3.125vw] md:max-2xl:px-[2.083vw] md:max-2xl:py-[1.563vw]`}
|
||||||
|
>
|
||||||
|
<div className="space-y-[0.278vw]">
|
||||||
|
<p className="text-m">{card.title}</p>
|
||||||
|
<p className="text-s text-[#73787C]">{`${card.mins} mins`}</p>
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
src={card.image}
|
||||||
|
className="rounded-[0.278vw] size-[13.333vw] object-cover absolute bottom-[4.444vw] right-[3.333vw] md:max-2xl:size-[6.25vw] md:max-2xl:bottom-[1.563vw] md:max-2xl:right-[2.083vw]"
|
||||||
|
alt={card.title}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<CustomScrollBar
|
||||||
|
containerRef={containerRef}
|
||||||
|
inlinePadding={16}
|
||||||
|
trackStyle="min-2xl:hidden max-2xl:translate-y-5"
|
||||||
|
thumbStyle="min-2xl:hidden"
|
||||||
|
/> */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GoogleMapMobile;
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { AdvancedMarker, useMap } from "@vis.gl/react-google-maps";
|
||||||
|
import type { Marker } from "@googlemaps/markerclusterer";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import IGMapPoi from "../../types/IGMapPoi";
|
||||||
|
|
||||||
|
interface IGMapMarker {
|
||||||
|
markerKey: number;
|
||||||
|
poi: IGMapPoi;
|
||||||
|
setMarkerRef: (marker: Marker | null, key: string) => void | undefined;
|
||||||
|
children: React.ReactNode;
|
||||||
|
isSelected: boolean;
|
||||||
|
setSelectedMarker: React.Dispatch<React.SetStateAction<number | null>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MapMarker({
|
||||||
|
poi,
|
||||||
|
children,
|
||||||
|
markerKey,
|
||||||
|
setMarkerRef,
|
||||||
|
isSelected,
|
||||||
|
setSelectedMarker,
|
||||||
|
}: IGMapMarker) {
|
||||||
|
const map = useMap();
|
||||||
|
const { location, ignoreClusterization, label } = poi;
|
||||||
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
const markerRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ignoreClusterization) {
|
||||||
|
setMarkerRef(markerRef.current, markerKey.toString());
|
||||||
|
}
|
||||||
|
}, [ignoreClusterization, markerKey, setMarkerRef]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdvancedMarker
|
||||||
|
key={markerKey}
|
||||||
|
position={location}
|
||||||
|
ref={markerRef}
|
||||||
|
onMouseEnter={() => setIsHovered(true)}
|
||||||
|
onMouseLeave={() => setIsHovered(false)}
|
||||||
|
onClick={() => {
|
||||||
|
map?.panTo({ lat: location.lat, lng: location.lng + 0.001 }); // 0.001 is a small align to fit long labels (generally for mobile devices)
|
||||||
|
map?.setZoom(17);
|
||||||
|
setSelectedMarker(markerKey);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`relative flex items-center gap-x-2 ${
|
||||||
|
isHovered || isSelected ? "[&>.gmap-img-container]:z-150" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{label && (
|
||||||
|
<div
|
||||||
|
className={`label-container text-black absolute text-s left-0 opacity-0 w-max pointer-events-none transition-[left,opacity] bg-white pl-11 pr-3 py-2.5 rounded-2xl ${
|
||||||
|
isHovered || isSelected
|
||||||
|
? "opacity-100 left-[calc(100%-38px)] pointer-events-auto z-140"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</AdvancedMarker>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { SVGProps } from "react";
|
||||||
|
|
||||||
|
const AllIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
width={21}
|
||||||
|
height={20}
|
||||||
|
viewBox="0 0 21 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.517 13.97h.028v.024zm0-7.952h.029v.023zm7.971 7.976h.029v.024zm-.029-7.976h.029v.023z"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={3}
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
export default AllIcon;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { SVGProps } from "react";
|
||||||
|
|
||||||
|
const EntertainmentIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
width={21}
|
||||||
|
height={20}
|
||||||
|
viewBox="0 0 21 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M7.49 6.07a.1.1 0 0 1 .186 0l1.188 3.01a.1.1 0 0 0 .056.057l3.01 1.187a.1.1 0 0 1 0 .186l-3.01 1.188a.1.1 0 0 0-.056.056l-1.188 3.01a.1.1 0 0 1-.186 0l-1.187-3.01a.1.1 0 0 0-.056-.056L3.236 10.51a.1.1 0 0 1 0-.186l3.01-1.187a.1.1 0 0 0 .057-.056zm7.13 4.882a.05.05 0 0 1 .093 0l.77 1.954a.05.05 0 0 0 .029.028l1.953.77a.05.05 0 0 1 0 .093l-1.953.77a.05.05 0 0 0-.028.029l-.77 1.953a.05.05 0 0 1-.094 0l-.77-1.953a.05.05 0 0 0-.028-.028l-1.954-.77a.05.05 0 0 1 0-.094l1.954-.77a.05.05 0 0 0 .028-.028zm-1.25-8.334a.05.05 0 0 1 .093 0l.77 1.954a.05.05 0 0 0 .029.028l1.953.77a.05.05 0 0 1 0 .093l-1.953.77a.05.05 0 0 0-.028.029l-.77 1.953a.05.05 0 0 1-.094 0l-.77-1.953a.05.05 0 0 0-.028-.028l-1.954-.77a.05.05 0 0 1 0-.094l1.954-.77a.05.05 0 0 0 .028-.028z"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
export default EntertainmentIcon;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { SVGProps } from "react";
|
||||||
|
|
||||||
|
const HotelIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
width={21}
|
||||||
|
height={20}
|
||||||
|
viewBox="0 0 21 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M15.834 10.247h.333a1 1 0 0 1 1 1v2.19a1 1 0 0 1-1 1H4.834a1 1 0 0 1-1-1v-2.19a1 1 0 0 1 1-1h.333m10.667 0V6.882c0-.579-.448-1.048-1-1.048H10.5m5.334 4.413H10.5m-5.333 0V6.882c0-.579.448-1.048 1-1.048H10.5m-5.333 4.413H10.5m-5.833 4.19v1.397m11.667-1.397v1.397M10.5 10.247V5.834"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
export default HotelIcon;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { SVGProps } from "react";
|
||||||
|
|
||||||
|
const MallsIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
width={21}
|
||||||
|
height={20}
|
||||||
|
viewBox="0 0 21 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8 6.406H6.5a1 1 0 0 0-1 1v7.428a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V7.406a1 1 0 0 0-1-1H13m-5 0v-.572a2.5 2.5 0 0 1 2.5-2.5v0a2.5 2.5 0 0 1 2.5 2.5v.572m-5 0h5"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
strokeLinecap="square"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
export default MallsIcon;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { SVGProps } from "react";
|
||||||
|
|
||||||
|
const OtherIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
width={21}
|
||||||
|
height={20}
|
||||||
|
viewBox="0 0 21 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M10.5 4.166v11.667M5.45 7.086l10.104 5.834m-10.1 0 10.103-5.833"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
export default OtherIcon;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export default function PinIcon() {
|
||||||
|
return (
|
||||||
|
<svg fill="none" width={16} height={16}>
|
||||||
|
<path
|
||||||
|
d="M6.134 10.5a1 1 0 0 0 1.732 0l5.196-9a1 1 0 0 0-.866-1.5H1.804a1 1 0 0 0-.866 1.5z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
/* eslint-disable no-loss-of-precision */
|
||||||
|
import IGMapPoi from "../types/IGMapPoi";
|
||||||
|
import MarasiMarker from "../../public/images/search/rove_home_marasi_drive.png";
|
||||||
|
import MarinaMarker from "../../public/images/search/rove_home_dubai_marina.png";
|
||||||
|
import { marasiDriveMapCards } from "./aboutMarasiDrive";
|
||||||
|
import PinIcon from "../components/icons/map/PinIcon";
|
||||||
|
|
||||||
|
function GetMarkerHTML(name: string, primary: boolean = false) {
|
||||||
|
const src = !primary
|
||||||
|
? marasiDriveMapCards.find((item) => item.title === name)?.image
|
||||||
|
: name;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={`gmap-img-container z-20 overflow-hidden rounded-full flex justify-center items-center border-2 border-white ${
|
||||||
|
!primary ? "size-8" : "size-14"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<img src={src} className="" alt="" />
|
||||||
|
</div>
|
||||||
|
{/* ADD POINTER FOR PRIMARY POINTS */}
|
||||||
|
{primary && (
|
||||||
|
<div className=" size-4 mx-auto text-white absolute -bottom-[20px] left-1/2 -translate-x-1/2">
|
||||||
|
<PinIcon />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GoogleMapData: {
|
||||||
|
marasiDriveDefaultCenter: { lat: number; lng: number };
|
||||||
|
dubaiMarinaDefaultCenter: { lat: number; lng: number };
|
||||||
|
markers: IGMapPoi[];
|
||||||
|
} = {
|
||||||
|
marasiDriveDefaultCenter: {
|
||||||
|
lat: 25.183476007744233,
|
||||||
|
lng: 55.274782084720286,
|
||||||
|
},
|
||||||
|
dubaiMarinaDefaultCenter: {
|
||||||
|
lat: 25.069466431595334,
|
||||||
|
lng: 55.128736429300375,
|
||||||
|
},
|
||||||
|
markers: [
|
||||||
|
{
|
||||||
|
//Rove Dubai Marina Hotel
|
||||||
|
location: { lat: 25.069466431595334, lng: 55.128736429300375 },
|
||||||
|
type: "Hotels",
|
||||||
|
ignoreClusterization: true,
|
||||||
|
customMarker: GetMarkerHTML(MarinaMarker, true),
|
||||||
|
clickableAreaScale: 3,
|
||||||
|
label: "Rove Dubai Marina Hotel",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.181371868546396, lng: 55.27515332907251 },
|
||||||
|
type: "Hotels",
|
||||||
|
ignoreClusterization: true,
|
||||||
|
customMarker: GetMarkerHTML(MarasiMarker, true),
|
||||||
|
clickableAreaScale: 3,
|
||||||
|
label: "Rove Marasi Drive Hotel",
|
||||||
|
},
|
||||||
|
// HOTELS
|
||||||
|
{
|
||||||
|
location: { lat: 25.197249056658244, lng: 55.27438894800352 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("Burj Khalifa"),
|
||||||
|
label: "Burj Khalifa",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.195237825881613, lng: 55.27528478028406 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("Dubai Fountain"),
|
||||||
|
label: "The Dubai Fountain",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.197748564692787, lng: 55.2802703666763 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("Dubai Mall"),
|
||||||
|
label: "Dubai Mall",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.195811139364157, lng: 55.27207211658565 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("Dubai Opera"),
|
||||||
|
label: "Dubai Opera",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.18774242603455, lng: 55.27024382999044 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("Marasi Promenade"),
|
||||||
|
label: "Marasi Promenade",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.203319687345175, lng: 55.279495993292876 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("Rove Downtown Hotel"),
|
||||||
|
label: "Rove Downtown Hotel",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.20535369013859, lng: 55.26803667795135 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("Rove City Walk Hotel"),
|
||||||
|
label: "Rove City Walk Hotel",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.20768362042376, lng: 55.26248238220776 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("City Walk"),
|
||||||
|
label: "City Walk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.204504325496778, lng: 55.265693333774536 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("Coca-Cola Arena"),
|
||||||
|
label: "Coca-Cola Arena",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
location: { lat: 25.26087724994889, lng: 55.372561586751665 },
|
||||||
|
type: "Hotels",
|
||||||
|
customMarker: GetMarkerHTML("Dubai International Airport"),
|
||||||
|
label: "Dubai International Airport",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
+9
-6
@@ -1,6 +1,6 @@
|
|||||||
// Initialize Eruda for mobile debugging in development
|
// Initialize Eruda for mobile debugging in development
|
||||||
if (import.meta.env.DEV) {
|
if (import.meta.env.DEV) {
|
||||||
import('eruda').then(eruda => eruda.default.init());
|
import("eruda").then((eruda) => eruda.default.init());
|
||||||
}
|
}
|
||||||
|
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
@@ -24,6 +24,7 @@ import TestPage from "./pages/TestPage.tsx";
|
|||||||
import UnitPage from "./pages/UnitPage.tsx";
|
import UnitPage from "./pages/UnitPage.tsx";
|
||||||
import PopupContainer from "./components/PopupContainer.tsx";
|
import PopupContainer from "./components/PopupContainer.tsx";
|
||||||
import VirtualTourPage from "./pages/VirtualTourPage.tsx";
|
import VirtualTourPage from "./pages/VirtualTourPage.tsx";
|
||||||
|
import { APIProvider } from "@vis.gl/react-google-maps";
|
||||||
|
|
||||||
const route = createBrowserRouter([
|
const route = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@@ -88,10 +89,12 @@ const route = createBrowserRouter([
|
|||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
<>
|
<>
|
||||||
<QueryClientProvider client={queryClient}>
|
<APIProvider apiKey={import.meta.env.VITE_GOOGLE_MAP_API_KEY}>
|
||||||
<RouterProvider router={route} />
|
<QueryClientProvider client={queryClient}>
|
||||||
<PopupContainer />
|
<RouterProvider router={route} />
|
||||||
<ModalContainer />
|
<PopupContainer />
|
||||||
</QueryClientProvider>
|
<ModalContainer />
|
||||||
|
</QueryClientProvider>
|
||||||
|
</APIProvider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export default interface IGMapPoi {
|
||||||
|
location: google.maps.LatLngLiteral;
|
||||||
|
ignoreClusterization?:boolean;
|
||||||
|
type:"All" | "Hotels" | "Malls" | "Entertainment"| "Other";
|
||||||
|
|
||||||
|
// Scale multiplyer for Pin (MapMarker.tsx) component. (To match visible marker size).
|
||||||
|
clickableAreaScale?:number;
|
||||||
|
label?:string;
|
||||||
|
customMarker?: React.ReactNode;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user