diff --git a/frontend/calpoly-map/src/app/App.tsx b/frontend/calpoly-map/src/app/App.tsx index 51bdc49..7f39f0c 100644 --- a/frontend/calpoly-map/src/app/App.tsx +++ b/frontend/calpoly-map/src/app/App.tsx @@ -123,6 +123,7 @@ function MapScreen({ routingActive, routeRequested, routeAccessibleOnly, + routeStartIsCurrentLocation, setActivePath, setRouteError, ]); diff --git a/frontend/calpoly-map/src/components/features/map/MapFilters.tsx b/frontend/calpoly-map/src/components/features/map/MapFilters.tsx index 3e3ef59..fcf39b1 100644 --- a/frontend/calpoly-map/src/components/features/map/MapFilters.tsx +++ b/frontend/calpoly-map/src/components/features/map/MapFilters.tsx @@ -45,7 +45,7 @@ export function MapFilters({ Map Style - Appearance + Appearance - - Navigation Mode + + Navigation Mode {navSteps.length > 0 && ( - + Step {activeStepIndex + 1}/{navSteps.length}:{" "} {navSteps[activeStepIndex]?.instruction} )} - + {place.coordinate[1].toFixed(5)}, {place.coordinate[0].toFixed(5)} - {place.name} {place.ref && ( - Building {place.ref} + + Building {place.ref} + )} @@ -524,7 +525,7 @@ export function SearchPanel({ cameraMove, cameraFitRoute, bottomSheetPosition, o onPress={() => removeFromHistory(place.id)} style={styles.iconButton} > - + )} @@ -588,39 +589,26 @@ export function SearchPanel({ cameraMove, cameraFitRoute, bottomSheetPosition, o {routingActive ? "Directions" : "Search"} - {routingActive ? ( - - openRoutingSearchSheet("start")} - onChangeText={(text) => { - setStartValue(text); - setActiveField("start"); - setRouteStart(null); - setRouteRequested(false); - setRouteStartIsCurrentLocation(false); - () => { - // When a building is selected and we're not routing, show building info - if (selectedBuilding && !routingActive) { - return ( + {!routingActive && } + + {selectedBuilding && !routingActive ? ( - {selectedBuildingName} - {selectedBuildingSubtitle} + + {selectedBuildingName} + + + {selectedBuildingSubtitle} + - + @@ -639,171 +627,115 @@ export function SearchPanel({ cameraMove, cameraFitRoute, bottomSheetPosition, o Directions - ); - } - - - - {routingActive ? "Directions" : "Search"} - - - {!routingActive && } - - {routingActive ? ( - - - - openRoutingSearchSheet("start")} - onChangeText={(text) => { - setStartValue(text); - setActiveField("start"); - setRouteStart(null); - setRouteRequested(false); - setRouteStartIsCurrentLocation(false); - }} - /> - - openRoutingSearchSheet("end")} - onChangeText={(text) => { - setEndValue(text); - setActiveField("end"); - setRouteEnd(null); - setRouteRequested(false); - }} - /> - - - { - const prevStart = startValue; - const prevEnd = endValue; - const prevRouteStart = routeStart; - const prevRouteEnd = routeEnd; - - setStartValue(prevEnd); - setEndValue(prevStart); - setRouteStart(prevRouteEnd); - setRouteEnd(prevRouteStart); + ) : routingActive ? ( + + + + openRoutingSearchSheet("start")} + onChangeText={(text) => { + setStartValue(text); + setActiveField("start"); + setRouteStart(null); + setRouteRequested(false); setRouteStartIsCurrentLocation(false); - setRouteRequested(Boolean(prevRouteEnd && prevRouteStart)); - }} - style={styles.swapButton} - > - {"↑\n↓"} - - - - - { - const next = !routeAccessibleOnly; - setRouteAccessibleOnly(next); - setRouteRequested(Boolean(routeStart && routeEnd)); }} - style={({ pressed }) => [ - styles.accessibleToggle, - routeAccessibleOnly && styles.accessibleToggleActive, - pressed && styles.accessibleTogglePressed, - ]} - > - - {routeAccessibleOnly && ( - - )} - - - Accessible Routes Only - - - - - { - clearRoute(); - setStartValue(""); - setEndValue(""); - setSearchQuery(""); + /> + + openRoutingSearchSheet("end")} + onChangeText={(text) => { + setEndValue(text); setActiveField("end"); - closeRoutingSearchSheet(); + setRouteEnd(null); + setRouteRequested(false); }} - style={styles.clearChip} - > - Clear - + /> - - ) : ( - { - openSheet(); - setFocused(true); - setSearchQuery(mainSearchInput); - }} - onSubmitEditing={() => commitSearch(mainSearchInput)} - onBlur={() => commitSearch(mainSearchInput)} - returnKeyType="search" - /> - )} - {routeError && ( - - {routeError} + { + const prevStart = startValue; + const prevEnd = endValue; + const prevRouteStart = routeStart; + const prevRouteEnd = routeEnd; + + setStartValue(prevEnd); + setEndValue(prevStart); + setRouteStart(prevRouteEnd); + setRouteEnd(prevRouteStart); + setRouteStartIsCurrentLocation(false); + setRouteRequested(Boolean(prevRouteEnd && prevRouteStart)); + }} + style={styles.swapButton} + > + {"↑\n↓"} + - )} - {summaryVisible && ( - - - {formatTime()} - - {formatDistance()} • {formatETA()} + + { + const next = !routeAccessibleOnly; + setRouteAccessibleOnly(next); + setRouteRequested(Boolean(routeStart && routeEnd)); + }} + style={({ pressed }) => [ + styles.accessibleToggle, + isDark && styles.accessibleToggleDark, + routeAccessibleOnly && styles.accessibleToggleActive, + routeAccessibleOnly && isDark && styles.accessibleToggleActiveDark, + pressed && styles.accessibleTogglePressed, + ]} + > + + {routeAccessibleOnly && ( + + )} + + + Accessible Routes Only - + + { - startNavigation(); + clearRoute(); + setStartValue(""); + setEndValue(""); + setSearchQuery(""); + setActiveField("end"); + closeRoutingSearchSheet(); }} + style={[styles.clearChip, isDark && styles.clearChipDark]} > - GO + Clear @@ -866,10 +798,6 @@ export function SearchPanel({ cameraMove, cameraFitRoute, bottomSheetPosition, o )} ), - )} - - ); - }, [ activePath, clearRoute, @@ -921,9 +849,8 @@ export function SearchPanel({ cameraMove, cameraFitRoute, bottomSheetPosition, o style={[styles.routingSearchCloseButton, isDark && styles.routingSearchCloseButtonDark]} > - X + ✕ - @@ -1111,7 +1038,6 @@ export function SearchPanel({ cameraMove, cameraFitRoute, bottomSheetPosition, o bounces={false} style={styles.resultsList} // BottomSheet background is themed; list itself stays transparent. - contentContainerStyle={styles.resultsListContent} contentContainerStyle={[styles.resultsListContent, searchRows.length === 0 && { paddingBottom: 0 }]} ListHeaderComponent={ @@ -1320,10 +1246,18 @@ const styles = StyleSheet.create({ paddingHorizontal: 10, gap: 8, }, + accessibleToggleDark: { + borderColor: "#3A4048", + backgroundColor: "#2A2F38", + }, accessibleToggleActive: { borderColor: "#15803D", backgroundColor: "#ECFDF3", }, + accessibleToggleActiveDark: { + borderColor: "#16A34A", + backgroundColor: "#14532D", + }, accessibleTogglePressed: { opacity: 0.85, }, @@ -1337,6 +1271,10 @@ const styles = StyleSheet.create({ justifyContent: "center", backgroundColor: "#FFFFFF", }, + accessibleCheckboxDark: { + borderColor: "#6B7280", + backgroundColor: "#1C1F26", + }, accessibleCheckboxActive: { borderColor: "#15803D", backgroundColor: "#16A34A", @@ -1352,11 +1290,17 @@ const styles = StyleSheet.create({ fontSize: 12, fontWeight: "600", }, + accessibleToggleTextDark: { + color: "#E6E8EB", + }, accessibleToggleIcon: { color: "#374151", fontSize: 13, fontWeight: "700", }, + accessibleToggleIconDark: { + color: "#CBD5E1", + }, clearChip: { borderRadius: 999, borderWidth: 1, @@ -1365,11 +1309,18 @@ const styles = StyleSheet.create({ paddingHorizontal: 12, backgroundColor: "#FEE2E2", }, + clearChipDark: { + borderColor: "#7F1D1D", + backgroundColor: "#3F1D1D", + }, clearChipText: { color: "#B91C1C", fontSize: 12, fontWeight: "600", }, + clearChipTextDark: { + color: "#FCA5A5", + }, statusRow: { marginTop: 6, flexDirection: "row", @@ -1415,11 +1366,15 @@ const styles = StyleSheet.create({ }, buildingNameDark: { color: "#F1F3F5", + }, buildingNumber: { fontSize: 13, color: "#6B7280", marginTop: 2, }, + buildingNumberDark: { + color: "#CBD5E1", + }, subscript: { fontSize: 14, marginLeft: 10, @@ -1451,6 +1406,9 @@ const styles = StyleSheet.create({ fontWeight: "700", color: "#9CA3AF", }, + removeIconDark: { + color: "#CBD5E1", + }, sectionHeader: { marginTop: 12, marginLeft: 10, @@ -1510,12 +1468,18 @@ const styles = StyleSheet.create({ fontWeight: "800", color: "#111827", }, + buildingInfoNameDark: { + color: "#F1F3F5", + }, buildingInfoSubtitle: { fontSize: 13, color: "#6B7280", textTransform: "capitalize", marginTop: 2, }, + buildingInfoSubtitleDark: { + color: "#CBD5E1", + }, buildingInfoClose: { width: 32, height: 32, @@ -1526,11 +1490,18 @@ const styles = StyleSheet.create({ borderWidth: 1, borderColor: "#D1D5DB", }, + buildingInfoCloseDark: { + backgroundColor: "#2A2F38", + borderColor: "#3A4048", + }, buildingInfoCloseText: { fontSize: 16, fontWeight: "700", color: "#6B7280", }, + buildingInfoCloseTextDark: { + color: "#E6E8EB", + }, directionHeaderDark: { color: "#F1F3F5", }, diff --git a/frontend/calpoly-map/src/components/map/AmenityPopup.tsx b/frontend/calpoly-map/src/components/map/AmenityPopup.tsx index 80f6a59..d3839bc 100644 --- a/frontend/calpoly-map/src/components/map/AmenityPopup.tsx +++ b/frontend/calpoly-map/src/components/map/AmenityPopup.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Modal, Pressable, StyleSheet, Text, View, ScrollView } from "react-native"; import type { Feature, Geometry, GeoJsonProperties } from "geojson"; +import { useMapContext } from "../../context/MapContext"; interface AmenityPopupProps { visible: boolean; @@ -11,6 +12,9 @@ interface AmenityPopupProps { } export function AmenityPopup({ visible, amenity, levels, onClose }: AmenityPopupProps) { + const { mapStyle } = useMapContext(); + const isDark = mapStyle === "dark"; + if (!amenity || !visible) return null; const props = amenity.properties || {}; @@ -26,37 +30,37 @@ export function AmenityPopup({ visible, amenity, levels, onClose }: AmenityPopup onRequestClose={onClose} > - e.stopPropagation()}> - - {name} - - + e.stopPropagation()}> + + {name} + + {category && ( - Category: - {formatCategory(category)} + Category: + {formatCategory(category)} )} {building && ( - Building: - {building} + Building: + {building} )} {levels.length > 0 && ( - + {levels.length === 1 ? "Level:" : "Available on Levels:"} {levels.map((level) => ( - + {level} ))} @@ -98,6 +102,9 @@ const styles = StyleSheet.create({ shadowOffset: { width: 0, height: 4 }, elevation: 5, }, + popupDark: { + backgroundColor: "#1C1F26", + }, header: { flexDirection: "row", justifyContent: "space-between", @@ -106,6 +113,9 @@ const styles = StyleSheet.create({ borderBottomWidth: 1, borderBottomColor: "#E5E7EB", }, + headerDark: { + borderBottomColor: "#3A4048", + }, title: { fontSize: 18, fontWeight: "600", @@ -113,6 +123,9 @@ const styles = StyleSheet.create({ flex: 1, marginRight: 8, }, + titleDark: { + color: "#F1F3F5", + }, closeButton: { width: 32, height: 32, @@ -121,11 +134,17 @@ const styles = StyleSheet.create({ justifyContent: "center", alignItems: "center", }, + closeButtonDark: { + backgroundColor: "#2A2F38", + }, closeButtonText: { fontSize: 18, color: "#6B7280", fontWeight: "600", }, + closeButtonTextDark: { + color: "#E6E8EB", + }, content: { padding: 16, }, @@ -139,10 +158,16 @@ const styles = StyleSheet.create({ textTransform: "uppercase", marginBottom: 4, }, + labelDark: { + color: "#CBD5E1", + }, value: { fontSize: 16, color: "#111827", }, + valueDark: { + color: "#F1F3F5", + }, levelsContainer: { flexDirection: "row", flexWrap: "wrap", @@ -157,6 +182,10 @@ const styles = StyleSheet.create({ borderWidth: 1, borderColor: "#BFDBFE", }, + levelBadgeDark: { + backgroundColor: "#1E3A8A", + borderColor: "#1D4ED8", + }, levelBadgeText: { fontSize: 14, fontWeight: "600", diff --git a/frontend/calpoly-map/src/components/map/BuildingPopup.tsx b/frontend/calpoly-map/src/components/map/BuildingPopup.tsx index 6dcf404..578f4cc 100644 --- a/frontend/calpoly-map/src/components/map/BuildingPopup.tsx +++ b/frontend/calpoly-map/src/components/map/BuildingPopup.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Modal, Pressable, StyleSheet, Text, View, ScrollView } from "react-native"; import type { Feature, Geometry, GeoJsonProperties } from "geojson"; +import { useMapContext } from "../../context/MapContext"; interface BuildingPopupProps { visible: boolean; @@ -10,6 +11,9 @@ interface BuildingPopupProps { } export function BuildingPopup({ visible, building, onClose, onNavigate }: BuildingPopupProps) { + const { mapStyle } = useMapContext(); + const isDark = mapStyle === "dark"; + if (!building || !visible) return null; const props = building.properties || {}; @@ -27,54 +31,54 @@ export function BuildingPopup({ visible, building, onClose, onNavigate }: Buildi onRequestClose={onClose} > - e.stopPropagation()}> - - {name} - - + e.stopPropagation()}> + + {name} + + {amenity && ( - Type: - {formatAmenityType(amenity)} + Type: + {formatAmenityType(amenity)} )} {buildingType && buildingType !== "yes" && ( - Building: - {formatBuildingType(buildingType)} + Building: + {formatBuildingType(buildingType)} )} {universityFunction && ( - Function: - {formatUniversityFunction(universityFunction)} + Function: + {formatUniversityFunction(universityFunction)} )} {address && ( - Address: - {address} + Address: + {address} )} {props["building:levels"] && ( - Levels: - {props["building:levels"]} + Levels: + {props["building:levels"]} )} {props.wheelchair && ( - Wheelchair Accessible: - {props.wheelchair === "yes" ? "Yes" : "No"} + Wheelchair Accessible: + {props.wheelchair === "yes" ? "Yes" : "No"} )} @@ -134,6 +138,9 @@ const styles = StyleSheet.create({ shadowOffset: { width: 0, height: 4 }, elevation: 5, }, + popupDark: { + backgroundColor: "#1C1F26", + }, header: { flexDirection: "row", justifyContent: "space-between", @@ -142,6 +149,9 @@ const styles = StyleSheet.create({ borderBottomWidth: 1, borderBottomColor: "#E5E7EB", }, + headerDark: { + borderBottomColor: "#3A4048", + }, title: { fontSize: 18, fontWeight: "600", @@ -149,6 +159,9 @@ const styles = StyleSheet.create({ flex: 1, marginRight: 8, }, + titleDark: { + color: "#F1F3F5", + }, closeButton: { width: 32, height: 32, @@ -157,11 +170,17 @@ const styles = StyleSheet.create({ justifyContent: "center", alignItems: "center", }, + closeButtonDark: { + backgroundColor: "#2A2F38", + }, closeButtonText: { fontSize: 18, color: "#6B7280", fontWeight: "600", }, + closeButtonTextDark: { + color: "#E6E8EB", + }, content: { padding: 16, }, @@ -179,10 +198,16 @@ const styles = StyleSheet.create({ textTransform: "uppercase", marginBottom: 4, }, + labelDark: { + color: "#CBD5E1", + }, value: { fontSize: 16, color: "#111827", }, + valueDark: { + color: "#F1F3F5", + }, primaryButton: { backgroundColor: "#3B82F6", borderRadius: 10, diff --git a/frontend/calpoly-map/src/components/map/MapContainer.tsx b/frontend/calpoly-map/src/components/map/MapContainer.tsx index e1077c6..9ae16ac 100644 --- a/frontend/calpoly-map/src/components/map/MapContainer.tsx +++ b/frontend/calpoly-map/src/components/map/MapContainer.tsx @@ -94,6 +94,7 @@ export function MapContainer({ mapStyle === "dark" ? "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json" : "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json"; + const isDark = mapStyle === "dark"; const { latitude, longitude } = useUserLocation(); const userLocation = @@ -191,11 +192,21 @@ export function MapContainer({ accessibilityRole="button" accessibilityLabel="Center User Location" onPress={toggleFollowUser} - style={[styles.locationButton, followUser && styles.locationButtonActive]} + style={[ + styles.locationButton, + isDark && styles.locationButtonDark, + followUser && styles.locationButtonActive, + ]} > - - + + ); @@ -510,11 +521,11 @@ export function MapContainer({ /> {(hasLoading || errorMessage) && ( - + {errorMessage ? ( - - Map data failed to load - {errorMessage} + + Map data failed to load + {errorMessage} ) : ( - - - Loading map data... + + + Loading map data... )} @@ -580,6 +591,9 @@ const styles = StyleSheet.create({ paddingHorizontal: 24, backgroundColor: "rgba(255, 255, 255, 0.6)", }, + statusOverlayDark: { + backgroundColor: "rgba(11, 17, 32, 0.55)", + }, statusCard: { width: "100%", maxWidth: 360, @@ -592,17 +606,26 @@ const styles = StyleSheet.create({ shadowOffset: { width: 0, height: 4 }, elevation: 4, }, + statusCardDark: { + backgroundColor: "#1C1F26", + }, statusTitle: { fontSize: 16, fontWeight: "700", color: "#111827", marginBottom: 6, }, + statusTitleDark: { + color: "#F1F3F5", + }, statusMessage: { fontSize: 13, color: "#6B7280", marginBottom: 12, }, + statusMessageDark: { + color: "#CBD5E1", + }, retryButton: { alignSelf: "flex-start", paddingHorizontal: 14, @@ -631,11 +654,17 @@ const styles = StyleSheet.create({ shadowOffset: { width: 0, height: 4 }, elevation: 4, }, + loadingCardDark: { + backgroundColor: "#1C1F26", + }, loadingText: { fontSize: 13, color: "#374151", fontWeight: "600", }, + loadingTextDark: { + color: "#E6E8EB", + }, locationButtonContainer: { position: "absolute", right: 16, @@ -657,6 +686,10 @@ const styles = StyleSheet.create({ shadowOffset: { width: 0, height: 2 }, elevation: 3, }, + locationButtonDark: { + backgroundColor: "#1C1F26", + borderColor: "#3A4048", + }, locationIcon: { width: 20, height: 20, @@ -670,6 +703,9 @@ const styles = StyleSheet.create({ borderWidth: 2.5, borderColor: "#6B7280", }, + locationIconRingDark: { + borderColor: "#CBD5E1", + }, locationIconDot: { position: "absolute", width: 6, @@ -677,6 +713,9 @@ const styles = StyleSheet.create({ borderRadius: 3, backgroundColor: "#6B7280", }, + locationIconDotDark: { + backgroundColor: "#CBD5E1", + }, locationIconDotActive: { backgroundColor: "#2563EB", }, diff --git a/frontend/calpoly-map/src/components/map/layers/BuildingLayer.tsx b/frontend/calpoly-map/src/components/map/layers/BuildingLayer.tsx index cb6be93..cacc536 100644 --- a/frontend/calpoly-map/src/components/map/layers/BuildingLayer.tsx +++ b/frontend/calpoly-map/src/components/map/layers/BuildingLayer.tsx @@ -247,7 +247,6 @@ export function BuildingLayer({ onPress={(event) => { if (event.features && event.features.length > 0) { const feature = event.features[0]; - console.log('Building tapped:', feature.properties?.name); onBuildingPress?.(feature); } return true; diff --git a/frontend/calpoly-map/src/components/map/markers/UserLocationMarker.tsx b/frontend/calpoly-map/src/components/map/markers/UserLocationMarker.tsx index 854c5ee..bf0193d 100644 --- a/frontend/calpoly-map/src/components/map/markers/UserLocationMarker.tsx +++ b/frontend/calpoly-map/src/components/map/markers/UserLocationMarker.tsx @@ -3,13 +3,12 @@ import type { Feature, Point } from "geojson"; import { CircleLayer, ShapeSource } from "@maplibre/maplibre-react-native"; import { useUserLocation } from "../../../context/UserLocationContext"; -export default function UserLocationMarker() { - const { latitude, longitude, errorMsg } = useUserLocation(); - - if (latitude == null || longitude == null) { - console.log("UserLocationMarker:", errorMsg); - return null; - } +export default function UserLocationMarker() { + const { latitude, longitude } = useUserLocation(); + + if (latitude == null || longitude == null) { + return null; + } const shape: Feature = { type: "Feature", @@ -34,4 +33,4 @@ export default function UserLocationMarker() { /> ); -} \ No newline at end of file +} diff --git a/frontend/calpoly-map/src/hooks/useSearch.ts b/frontend/calpoly-map/src/hooks/useSearch.ts index a6b3646..4dddfc3 100644 --- a/frontend/calpoly-map/src/hooks/useSearch.ts +++ b/frontend/calpoly-map/src/hooks/useSearch.ts @@ -1,14 +1,14 @@ -import React from "react"; import { useCallback, useState } from "react"; -export const [search, setSearch] = useState(""); +export function useSearch(initialValue = "") { + const [search, setSearch] = useState(initialValue); -export const useSearch = useCallback((text?: string) => { - if (text !== undefined) { - setSearch(text); - } - }, [setSearch]); + const updateSearch = useCallback((text: string) => { + setSearch(text); + }, []); -export const getSearch = React.useCallback((text: string) => { - return search; -}, [search]); \ No newline at end of file + return { + search, + setSearch: updateSearch, + }; +}