Skip to content

Commit 6fd1a0a

Browse files
committed
feat: Add URL-based location sharing for map and buildings
1 parent 61fe952 commit 6fd1a0a

3 files changed

Lines changed: 108 additions & 1 deletion

File tree

src/buildings.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Building center positions for URL sharing
2+
export const buildingCenters: Record<string, [number, number]> = {
3+
building1: [1064, 1904],
4+
building2: [921, 1095],
5+
building5: [1558, 1488],
6+
building7: [1401, 1645],
7+
building8: [1393, 2073],
8+
building9: [1569, 1971],
9+
building10: [1400, 1824],
10+
building11: [1104, 1567],
11+
building12: [1017, 1267],
12+
building13: [1169, 1314],
13+
building14: [1120, 1072],
14+
building15: [1409, 816],
15+
building16: [1575, 881],
16+
building17: [1537, 1222],
17+
building18: [1641, 1770],
18+
building19: [2039, 2628],
19+
building101: [1149, 2300],
20+
building900: [808, 1465],
21+
komcee_west: [1643, 2226],
22+
komcee_east: [1533, 2343],
23+
info_edu: [431, 1603],
24+
administration: [644, 2244],
25+
comipla_north: [1350, 2786],
26+
library: [938, 2800],
27+
second_gymnasium: [1628, 2686],
28+
first_gymnasium: [1716, 2988],
29+
campus_plaza_a: [1504, 2823],
30+
campus_plaza_b: [1505, 2941],
31+
komaba_museum: [818, 2336],
32+
advanced_research_lab: [1859, 1609],
33+
komaba_international_edu: [1401, 1249],
34+
komaba_health_center: [550, 1539],
35+
coop_cafeteria: [1123, 2571],
36+
science_center_a: [836, 2068],
37+
science_center_b: [850, 2288],
38+
science_center_c: [843, 2187],
39+
science_center_d: [834, 2399],
40+
science_center_e: [835, 2640],
41+
science_center_f: [921, 2638],
42+
science_center_g: [1081, 2288],
43+
science_center_h: [1081, 2220],
44+
science_center_i: [1081, 2172],
45+
};
46+
47+
export function getBuildingCenter(buildingId: string): [number, number] | null {
48+
return buildingCenters[buildingId] || null;
49+
}

src/markers.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,16 @@ export function setupBuildingPolygons(map: L.Map) {
9090
詳細
9191
</a>`
9292
: "";
93+
const shareUrl = `${window.location.origin}/?building=${buildingId}`;
94+
const shareButtonHtml = `
95+
<button onclick="navigator.clipboard.writeText('${shareUrl}').then(()=>alert('URLをコピーしました!')).catch(()=>{})" style="${buttonStyle}">
96+
共有
97+
</button>
98+
`;
9399
return `
94100
<div style="text-align: center; padding: 8px;">
95-
<p style="margin: 0 0 ${showButton ? "8px" : "0"} 0; font-weight: bold; font-size: 16px;">${name}</p>
101+
<p style="margin: 0 0 4px 0; font-weight: bold; font-size: 16px;">${name}</p>
102+
${shareButtonHtml}
96103
${buttonHtml}
97104
</div>
98105
`;

src/pages/MapPage.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useEffect, useRef, useState } from "react";
22
import L from "leaflet";
3+
import { useSearchParams } from "react-router-dom";
34
import { Komabamap } from "../assets";
45
import UtcFavicon from "../assets/utc-favicon.svg";
56
import { setupGeolocation } from "../geolocation";
@@ -10,6 +11,7 @@ import {
1011
toggleMarkers,
1112
} from "../markers";
1213
import { searchItems, type SearchableItem } from "../search";
14+
import { getBuildingCenter } from "../buildings";
1315

1416
const imgWidth = 4000;
1517
const imgHeight = 2800;
@@ -25,6 +27,8 @@ export function MapPage() {
2527
const [searchQuery, setSearchQuery] = useState("");
2628
const [searchResults, setSearchResults] = useState<SearchableItem[]>([]);
2729
const [selectedItem, setSelectedItem] = useState<SearchableItem | null>(null);
30+
const [searchParams] = useSearchParams();
31+
const initialParamsProcessed = useRef(false);
2832

2933
useEffect(() => {
3034
if (!containerRef.current) return;
@@ -50,6 +54,48 @@ export function MapPage() {
5054
const vmMarkers = setupVendingMachineMarkers(map);
5155
vmMarkersRef.current = vmMarkers.markers;
5256
setupBuildingPolygons(map);
57+
58+
// Process URL parameters for sharing location
59+
const buildingId = searchParams.get("building");
60+
const lat = searchParams.get("lat");
61+
const lng = searchParams.get("lng");
62+
const zoom = searchParams.get("zoom");
63+
64+
if (buildingId) {
65+
const center = getBuildingCenter(buildingId);
66+
if (center) {
67+
map.flyTo([center[0], center[1]], 0, { duration: 1.5 });
68+
69+
// Show popup with pin
70+
const buildingItem = searchItems(buildingId).find(
71+
(item) => item.buildingId === buildingId,
72+
);
73+
if (buildingItem && buildingItem.buildingId) {
74+
const popupContent = `
75+
<div style="text-align: center;">
76+
<p style="margin: 0 0 8px 0; font-weight: bold;">${buildingItem.name}</p>
77+
<a href="/building/${buildingItem.buildingId}" style="display: inline-block; padding: 8px 16px; background-color: #3b82f6; color: white; border-radius: 6px; text-decoration: none;">詳細</a>
78+
</div>
79+
`;
80+
L.popup()
81+
.setLatLng([center[0], center[1]])
82+
.setContent(popupContent)
83+
.openOn(map);
84+
}
85+
}
86+
} else if (lat && lng) {
87+
const position: [number, number] = [Number(lat), Number(lng)];
88+
const zoomLevel = zoom ? Number(zoom) : 0;
89+
map.flyTo(position, zoomLevel, { duration: 1.5 });
90+
91+
L.popup()
92+
.setLatLng(position)
93+
.setContent(`<b>共有された位置</b>`)
94+
.openOn(map);
95+
}
96+
97+
initialParamsProcessed.current = true;
98+
5399
return () => {
54100
geo.cleanup();
55101
map.remove();
@@ -94,12 +140,17 @@ export function MapPage() {
94140

95141
// If it's a building with a detail page, show a popup with link
96142
if (item.type === "building" && item.buildingId) {
143+
const shareUrl = `${window.location.origin}/?building=${item.buildingId}`;
97144
L.popup()
98145
.setLatLng([item.lat, item.lng])
99146
.setContent(
100147
`
101148
<div style="text-align: center;">
102149
<p style="margin: 0 0 8px 0; font-weight: bold;">${item.name}</p>
150+
<button onclick="navigator.clipboard.writeText('${shareUrl}').then(()=>alert('URLをコピーしました!')).catch(()=>{})" style="display: inline-block; padding: 8px 16px; background-color: #3b82f6; color: white; border-radius: 6px; text-decoration: none; border: none; cursor: pointer; margin-bottom: 8px;">
151+
共有
152+
</button>
153+
<br/>
103154
<a href="/building/${item.buildingId}" style="display: inline-block; padding: 8px 16px; background-color: #3b82f6; color: white; border-radius: 6px; text-decoration: none;">詳細</a>
104155
</div>
105156
`,

0 commit comments

Comments
 (0)