Skip to content

Commit f3ff8dc

Browse files
authored
details button on map with 3rd state to hide path (#445)
* show path details button * now button gets 3 states * keep dots gray
1 parent e6b7790 commit f3ff8dc

File tree

6 files changed

+94
-70
lines changed

6 files changed

+94
-70
lines changed

src/App.module.css

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,29 @@
7272
box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.1);
7373
}
7474

75+
.inclineButton {
76+
position: absolute;
77+
right: 10px;
78+
top: 114px;
79+
width: 34px;
80+
height: 34px;
81+
padding: 4px;
82+
display: flex;
83+
align-items: center;
84+
justify-content: center;
85+
cursor: pointer;
86+
}
87+
88+
.inclineButton svg {
89+
width: 100%;
90+
height: 100%;
91+
}
92+
93+
.inclineButtonActive {
94+
background-color: #e0f0e4 !important;
95+
border: 1px solid #2E7D32 !important;
96+
}
97+
7598
.pathDetails {
7699
grid-column: 1 / span 1;
77100
grid-row: 1 / span 1;

src/App.tsx

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -122,35 +122,17 @@ export default function App() {
122122
useAreasLayer(map, settings.drawAreasEnabled, query.customModelStr, query.customModelEnabled)
123123
useRoutingGraphLayer(map, mapOptions.routingGraphEnabled)
124124
useUrbanDensityLayer(map, mapOptions.urbanDensityEnabled)
125-
const [showPaths, setShowPaths] = useState(true)
125+
type PathDisplayMode = 'normal' | 'incline' | 'hidden'
126+
const [pathDisplayMode, setPathDisplayMode] = useState<PathDisplayMode>('normal')
127+
const showPaths = pathDisplayMode !== 'hidden'
128+
const inclineOnMap = pathDisplayMode === 'incline'
126129
usePathsLayer(map, route.routingResult.paths, route.selectedPath, query.queryPoints, showPaths)
127130
useQueryPointsLayer(map, query.queryPoints)
128131
const [activeDetail, setActiveDetail] = useState<ChartPathDetail | null>(null)
129132
usePathDetailsLayer(map, pathDetails, activeDetail, showPaths)
130133
usePOIsLayer(map, pois)
131134
useCurrentLocationLayer(map, currentLocation)
132135

133-
useEffect(() => {
134-
const handleKeyDown = (e: KeyboardEvent) => {
135-
if (e.key === 'h') setShowPaths(false)
136-
}
137-
const handleKeyUp = (e: KeyboardEvent) => {
138-
if (e.key === 'h') setShowPaths(true)
139-
}
140-
141-
const viewport = map.getViewport()
142-
if (!viewport) return
143-
144-
viewport.tabIndex = -1 // Make element focusable but not in tab order
145-
146-
window.addEventListener('keydown', handleKeyDown)
147-
window.addEventListener('keyup', handleKeyUp)
148-
return () => {
149-
window.removeEventListener('keydown', handleKeyDown)
150-
window.removeEventListener('keyup', handleKeyUp)
151-
}
152-
}, [])
153-
154136
const isSmallScreen = useMediaQuery({ query: '(max-width: 44rem)' })
155137
return (
156138
<SettingsContext.Provider value={settings}>
@@ -174,6 +156,8 @@ export default function App() {
174156
drawAreas={settings.drawAreasEnabled}
175157
currentLocation={currentLocation}
176158
onActiveDetailChanged={setActiveDetail}
159+
pathDisplayMode={pathDisplayMode}
160+
onCyclePathDisplay={() => setPathDisplayMode(m => m === 'normal' ? 'incline' : m === 'incline' ? 'hidden' : 'normal')}
177161
/>
178162
) : (
179163
<LargeScreenLayout
@@ -186,13 +170,39 @@ export default function App() {
186170
drawAreas={settings.drawAreasEnabled}
187171
currentLocation={currentLocation}
188172
onActiveDetailChanged={setActiveDetail}
173+
pathDisplayMode={pathDisplayMode}
174+
onCyclePathDisplay={() => setPathDisplayMode(m => m === 'normal' ? 'incline' : m === 'incline' ? 'hidden' : 'normal')}
189175
/>
190176
)}
191177
</div>
192178
</SettingsContext.Provider>
193179
)
194180
}
195181

182+
function InclineIcon({ mode }: { mode: 'normal' | 'incline' | 'hidden' }) {
183+
if (mode === 'incline') return (
184+
<svg viewBox="0 0 14 14" fill="none">
185+
<polyline points="3,11 5.5,5 8,9 11,3" stroke="#2E7D32" strokeWidth="1.2" fill="none" />
186+
<circle cx="3" cy="11" r="1.5" fill="#2E7D32" />
187+
<circle cx="11" cy="3" r="1.5" fill="#F44336" />
188+
</svg>
189+
)
190+
if (mode === 'hidden') return (
191+
<svg viewBox="0 0 14 14" fill="none">
192+
<polyline points="3,11 5.5,5 8,9 11,3" stroke="gray" strokeWidth="1.2" fill="none" opacity="0.3" />
193+
<circle cx="3" cy="11" r="1.5" fill="gray" />
194+
<circle cx="11" cy="3" r="1.5" fill="gray" />
195+
</svg>
196+
)
197+
return (
198+
<svg viewBox="0 0 14 14" fill="none">
199+
<polyline points="3,11 5.5,5 8,9 11,3" stroke="gray" strokeWidth="1.2" fill="none" />
200+
<circle cx="3" cy="11" r="1.5" fill="gray" />
201+
<circle cx="11" cy="3" r="1.5" fill="gray" />
202+
</svg>
203+
)
204+
}
205+
196206
interface LayoutProps {
197207
query: QueryStoreState
198208
route: RouteStoreState
@@ -203,6 +213,8 @@ interface LayoutProps {
203213
encodedValues: object[]
204214
drawAreas: boolean
205215
onActiveDetailChanged: (detail: ChartPathDetail | null) => void
216+
pathDisplayMode: 'normal' | 'incline' | 'hidden'
217+
onCyclePathDisplay: () => void
206218
}
207219

208220
function LargeScreenLayout({
@@ -215,7 +227,10 @@ function LargeScreenLayout({
215227
drawAreas,
216228
currentLocation,
217229
onActiveDetailChanged,
230+
pathDisplayMode,
231+
onCyclePathDisplay,
218232
}: LayoutProps) {
233+
const inclineOnMap = pathDisplayMode === 'incline'
219234
const [showSidebar, setShowSidebar] = useState(true)
220235
const [showCustomModelBox, setShowCustomModelBox] = useState(false)
221236
const [elevationState, setElevationState] = useState<'compact' | 'expanded' | 'closed'>('closed')
@@ -285,6 +300,15 @@ function LargeScreenLayout({
285300
<div className={styles.onMapRightSide}>
286301
<MapOptions {...mapOptions} />
287302
<LocationButton currentLocation={currentLocation} />
303+
{hasRoute && (
304+
<div
305+
className={styles.inclineButton + (pathDisplayMode === 'incline' ? ' ' + styles.inclineButtonActive : '')}
306+
onClick={onCyclePathDisplay}
307+
title={pathDisplayMode === 'normal' ? 'Show incline on map' : pathDisplayMode === 'incline' ? 'Hide path' : 'Show path'}
308+
>
309+
<InclineIcon mode={pathDisplayMode} />
310+
</div>
311+
)}
288312
</div>
289313
<div className={styles.map}>
290314
<MapComponent map={map} />
@@ -313,6 +337,7 @@ function LargeScreenLayout({
313337
onToggleExpanded={() => setElevationState(s => s === 'expanded' ? 'compact' : 'expanded')}
314338
onClose={() => setElevationState('closed')}
315339
onActiveDetailChanged={onActiveDetailChanged}
340+
inclineOnMap={inclineOnMap}
316341
/>
317342
</div>
318343
</>
@@ -329,7 +354,10 @@ function SmallScreenLayout({
329354
drawAreas,
330355
currentLocation,
331356
onActiveDetailChanged,
357+
pathDisplayMode,
358+
onCyclePathDisplay,
332359
}: LayoutProps) {
360+
const inclineOnMap = pathDisplayMode === 'incline'
333361
const hasPath = route.selectedPath.points.coordinates.length > 0
334362
const elevationWidget = hasPath ? (
335363
<ElevationInfoBar
@@ -339,6 +367,7 @@ function SmallScreenLayout({
339367
isExpanded={false}
340368
onToggleExpanded={() => {}}
341369
onActiveDetailChanged={onActiveDetailChanged}
370+
inclineOnMap={inclineOnMap}
342371
/>
343372
) : undefined
344373
return (
@@ -360,6 +389,15 @@ function SmallScreenLayout({
360389
<div className={styles.onMapRightSide}>
361390
<MapOptions {...mapOptions} />
362391
<LocationButton currentLocation={currentLocation} />
392+
{hasPath && (
393+
<div
394+
className={styles.inclineButton + (pathDisplayMode === 'incline' ? ' ' + styles.inclineButtonActive : '')}
395+
onClick={onCyclePathDisplay}
396+
title={pathDisplayMode === 'normal' ? 'Show incline on map' : pathDisplayMode === 'incline' ? 'Hide path' : 'Show path'}
397+
>
398+
<InclineIcon mode={pathDisplayMode} />
399+
</div>
400+
)}
363401
</div>
364402
</div>
365403

src/map/Map.module.css

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
.customZoom {
1111
right: 17px;
12-
top: 115px;
12+
top: 165px;
1313
}
1414

1515
@media (max-width: 44rem) {
@@ -42,3 +42,11 @@
4242
.customAttribution button {
4343
display: none;
4444
}
45+
46+
@media (max-width: 44rem) {
47+
.customAttribution {
48+
right: auto;
49+
left: 0;
50+
border-radius: 0 4px 0 0;
51+
}
52+
}

src/pathDetails/ElevationInfoBar.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface ElevationInfoBarProps {
1616
onToggleExpanded: () => void
1717
onClose?: () => void
1818
onActiveDetailChanged: (detail: ChartPathDetail | null) => void
19+
inclineOnMap: boolean
1920
}
2021

2122
export default function ElevationInfoBar({
@@ -26,9 +27,9 @@ export default function ElevationInfoBar({
2627
onToggleExpanded,
2728
onClose,
2829
onActiveDetailChanged,
30+
inclineOnMap,
2931
}: ElevationInfoBarProps) {
3032
const settings = useContext(SettingsContext)
31-
const [inclineOnMap, setInclineOnMap] = useState(false)
3233
const [selectedDropdownDetail, setSelectedDropdownDetail] = useState<ChartPathDetail | null>(null)
3334

3435
const chartData = useMemo(
@@ -79,10 +80,6 @@ export default function ElevationInfoBar({
7980
setSelectedDropdownDetail(detail)
8081
}, [])
8182

82-
const handleToggleIncline = useCallback(() => {
83-
setInclineOnMap(prev => !prev)
84-
}, [])
85-
8683
return (
8784
<ElevationWidget
8885
data={chartData}
@@ -93,8 +90,6 @@ export default function ElevationInfoBar({
9390
onToggleExpanded={onToggleExpanded}
9491
onClose={onClose}
9592
alternativeRouteNumbers={alternativeRouteNumbers}
96-
showInclineOnMap={inclineOnMap}
97-
onToggleInclineOnMap={handleToggleIncline}
9893
elevationLabel={tr('elevation')}
9994
/>
10095
)

src/pathDetails/elevationWidget/ElevationWidget.module.css

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -74,29 +74,6 @@
7474
line-height: 1;
7575
}
7676

77-
.inclineButton {
78-
display: flex;
79-
align-items: center;
80-
justify-content: center;
81-
width: 26px;
82-
height: 26px;
83-
border: 1px solid #ccc;
84-
border-radius: 4px;
85-
background: #f8f8f9;
86-
cursor: pointer;
87-
flex-shrink: 0;
88-
padding: 0;
89-
}
90-
91-
.inclineButton:hover {
92-
background: #e8e8e8;
93-
}
94-
95-
.inclineButtonActive {
96-
background: #e0f0e4;
97-
border-color: #2E7D32;
98-
}
99-
10077
.expandButton {
10178
display: flex;
10279
align-items: center;

src/pathDetails/elevationWidget/ElevationWidget.tsx

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ interface ElevationWidgetProps {
2828
onToggleExpanded: () => void
2929
onClose?: () => void
3030
alternativeRouteNumbers: number[]
31-
showInclineOnMap: boolean
32-
onToggleInclineOnMap: () => void
3331
elevationLabel: string
3432
}
3533

@@ -44,8 +42,6 @@ export default function ElevationWidget({
4442
onToggleExpanded,
4543
onClose,
4644
alternativeRouteNumbers,
47-
showInclineOnMap,
48-
onToggleInclineOnMap,
4945
elevationLabel,
5046
}: ElevationWidgetProps) {
5147
const containerRef = useRef<HTMLDivElement>(null)
@@ -204,19 +200,6 @@ export default function ElevationWidget({
204200
}
205201
</button>
206202
)}
207-
{!selectedDetail && (
208-
<button
209-
className={`${styles.inclineButton}${showInclineOnMap ? ' ' + styles.inclineButtonActive : ''}`}
210-
onClick={onToggleInclineOnMap}
211-
title="Show incline on map"
212-
>
213-
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
214-
<line x1="1" y1="10" x2="5" y2="5" stroke="#2E7D32" strokeWidth="2.5" strokeLinecap="round" />
215-
<line x1="5" y1="5" x2="9" y2="3" stroke="#FF9800" strokeWidth="2.5" />
216-
<line x1="9" y1="3" x2="13" y2="10" stroke="#F44336" strokeWidth="2.5" strokeLinecap="round" />
217-
</svg>
218-
</button>
219-
)}
220203
<button
221204
className={styles.expandButton}
222205
onClick={onToggleExpanded}

0 commit comments

Comments
 (0)