Skip to content

Commit fda55fc

Browse files
committed
Directions: Add markers to directions
1 parent 7125f59 commit fda55fc

File tree

6 files changed

+257
-43
lines changed

6 files changed

+257
-43
lines changed

src/components/Directions/DirectionsAutocomplete.tsx

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { MapClickOverride, useMapStateContext } from '../utils/MapStateContext';
22
import { useStarsContext } from '../utils/StarsContext';
3-
import React, { useEffect, useRef, useState } from 'react';
3+
import React, { useEffect, useMemo, useRef, useState } from 'react';
44
import { abortFetch } from '../../services/fetch';
55
import {
66
fetchGeocoderOptions,
@@ -13,14 +13,15 @@ import { Autocomplete, InputAdornment, TextField } from '@mui/material';
1313
import { useMapCenter } from '../SearchBox/utils';
1414
import { useUserThemeContext } from '../../helpers/theme';
1515
import { renderOptionFactory } from '../SearchBox/renderOptionFactory';
16-
import PlaceIcon from '@mui/icons-material/Place';
1716
import { Option } from '../SearchBox/types';
1817
import { getOptionLabel } from '../SearchBox/getOptionLabel';
1918
import { useUserSettingsContext } from '../utils/UserSettingsContext';
2019
import { getCoordsOption } from '../SearchBox/options/coords';
2120
import { LonLat } from '../../services/types';
2221
import { getGlobalMap } from '../../services/mapStorage';
23-
import maplibregl, { LngLatLike } from 'maplibre-gl';
22+
import maplibregl, { LngLatLike, PointLike } from 'maplibre-gl';
23+
import ReactDOMServer from 'react-dom/server';
24+
import { AlphabeticalMarker } from './TextMarker';
2425

2526
const StyledTextField = styled(TextField)`
2627
input::placeholder {
@@ -35,6 +36,7 @@ const DirectionsInput = ({
3536
label,
3637
onFocus,
3738
onBlur,
39+
pointIndex,
3840
}) => {
3941
const { InputLabelProps, InputProps, ...restParams } = params;
4042

@@ -59,8 +61,11 @@ const DirectionsInput = ({
5961
fullWidth
6062
InputProps={{
6163
startAdornment: (
62-
<InputAdornment position="start">
63-
<PlaceIcon fontSize="small" />
64+
<InputAdornment
65+
position="start"
66+
sx={{ position: 'relative', top: 5, left: 5 }}
67+
>
68+
<AlphabeticalMarker hasPin={false} index={pointIndex} height={32} />
6469
</InputAdornment>
6570
),
6671
}}
@@ -137,14 +142,15 @@ type Props = {
137142
label: string;
138143
value: Option;
139144
setValue: (value: Option) => void;
145+
pointIndex: number;
140146
};
141147

142-
const PREVIEW_MARKER = {
143-
color: 'salmon',
144-
draggable: false,
145-
};
146-
147-
export const DirectionsAutocomplete = ({ label, value, setValue }: Props) => {
148+
export const DirectionsAutocomplete = ({
149+
label,
150+
value,
151+
setValue,
152+
pointIndex,
153+
}: Props) => {
148154
const autocompleteRef = useRef();
149155
const { inputValue, setInputValue } = useInputValueState();
150156
const selectedOptionInputValue = useRef<string | null>(null);
@@ -153,19 +159,45 @@ export const DirectionsAutocomplete = ({ label, value, setValue }: Props) => {
153159
const { userSettings } = useUserSettingsContext();
154160
const { isImperial } = userSettings;
155161

162+
const ALPHABETICAL_MARKER = useMemo(() => {
163+
let svgElement;
164+
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
165+
svgElement = document.createElement('div');
166+
svgElement.innerHTML = ReactDOMServer.renderToStaticMarkup(
167+
<AlphabeticalMarker index={pointIndex} hasShadow width={27} />,
168+
);
169+
} else svgElement = undefined;
170+
171+
return {
172+
color: 'salmon',
173+
draggable: true,
174+
element: svgElement,
175+
offset: [0, -10] as PointLike,
176+
};
177+
}, [pointIndex]);
178+
156179
const markerRef = useRef<maplibregl.Marker>();
180+
157181
useEffect(() => {
158-
console.log('___', value);
159182
const map = getGlobalMap();
160183
if (value?.type === 'coords') {
161-
markerRef.current = new maplibregl.Marker(PREVIEW_MARKER)
184+
markerRef.current = new maplibregl.Marker(ALPHABETICAL_MARKER)
162185
.setLngLat(value.coords.center as LngLatLike)
163186
.addTo(map);
164187
}
165188
return () => {
166189
markerRef.current?.remove();
167190
};
168-
}, [value]);
191+
}, [ALPHABETICAL_MARKER, value]);
192+
193+
const onDragEnd = () => {
194+
const lngLat = markerRef.current?.getLngLat();
195+
if (lngLat) {
196+
setValue(getCoordsOption([lngLat.lng, lngLat.lat]));
197+
}
198+
};
199+
200+
markerRef.current?.on('dragend', onDragEnd);
169201

170202
const options = useOptions(inputValue);
171203

@@ -224,6 +256,7 @@ export const DirectionsAutocomplete = ({ label, value, setValue }: Props) => {
224256
label={label}
225257
onFocus={onInputFocus}
226258
onBlur={handleBlur}
259+
pointIndex={pointIndex}
227260
/>
228261
)}
229262
renderOption={renderOptionFactory(

src/components/Directions/DirectionsForm.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,13 @@ export const DirectionsForm = ({ setResult, hideForm }: Props) => {
165165
value={from}
166166
setValue={setFrom}
167167
label={t('directions.form.start_or_click')}
168+
pointIndex={0}
168169
/>
169170
<DirectionsAutocomplete
170171
value={to}
171172
setValue={setTo}
172173
label={t('directions.form.destination')}
174+
pointIndex={1}
173175
/>
174176
</Stack>
175177

src/components/Directions/Instructions.tsx

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { icon, Sign } from './routing/instructions';
33
import { RoutingResult } from './routing/types';
44
import { useUserSettingsContext } from '../utils/UserSettingsContext';
55
import { toHumanDistance } from './helpers';
6-
import { Stack, Typography } from '@mui/material';
6+
import { Box, Divider, Grid2, Stack, Typography } from '@mui/material';
7+
import { useTheme } from '@emotion/react';
78

89
type Instruction = RoutingResult['instructions'][number];
910

@@ -25,27 +26,37 @@ const StyledListItem = styled.li`
2526
gap: 0.25rem;
2627
`;
2728

28-
const Instruction = ({ instruction }: { instruction: Instruction }) => (
29-
<StyledListItem>
30-
<Stack direction="row" alignItems="center">
31-
<Icon sign={instruction.sign} />
32-
{instruction.street_name || instruction.text}
33-
</Stack>
34-
{instruction.distance > 0 && (
35-
<Stack direction="row" alignItems="center" spacing={0.5}>
36-
<Typography
37-
noWrap
38-
color="textSecondary"
39-
variant="body1"
40-
style={{ overflow: 'visible' }}
41-
>
42-
<Distance distance={instruction.distance} />
29+
const Instruction = ({ instruction }: { instruction: Instruction }) => {
30+
const theme = useTheme();
31+
32+
return (
33+
<StyledListItem>
34+
<Stack direction="row" alignItems="center">
35+
<Box width={theme.spacing(6)}>
36+
<Icon sign={instruction.sign} />
37+
</Box>
38+
<Typography variant="subtitle1" fontWeight={700}>
39+
{instruction.street_name || instruction.text}
4340
</Typography>
44-
<hr style={{ width: '100%' }} />
4541
</Stack>
46-
)}
47-
</StyledListItem>
48-
);
42+
{instruction.distance > 0 && (
43+
<Stack direction="row" alignItems="center" spacing={2} ml={6}>
44+
<Typography
45+
noWrap
46+
color="textSecondary"
47+
variant="body2"
48+
style={{ overflow: 'visible' }}
49+
>
50+
<Distance distance={instruction.distance} />
51+
</Typography>
52+
<Stack flex={1}>
53+
<Divider />
54+
</Stack>
55+
</Stack>
56+
)}
57+
</StyledListItem>
58+
);
59+
};
4960

5061
const StyledList = styled.ul`
5162
list-style: none;

src/components/Directions/Result.tsx

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useMobileMode } from '../helpers';
2-
import { Button, Paper, Stack, Typography } from '@mui/material';
2+
import { Button, Divider, Paper, Stack, Typography } from '@mui/material';
33
import React from 'react';
44
import styled from '@emotion/styled';
55
import { convertHexToRgba } from '../utils/colorUtils';
@@ -126,13 +126,38 @@ export const Result = ({ result, revealForm }: Props) => {
126126

127127
return (
128128
<StyledPaper elevation={3} $height="100%" $overflow="auto">
129-
{t('directions.result.time')}: <strong>{time}</strong>
130-
<br />
131-
{t('directions.result.distance')}: <strong>{distance}</strong>
132-
<br />
133-
{t('directions.result.ascent')}: <strong>{ascent}</strong>
134-
<br />
135-
<br />
129+
<Stack
130+
direction="row"
131+
spacing={2}
132+
width="100%"
133+
justifyContent="space-between"
134+
>
135+
<div>
136+
<Typography variant="caption">
137+
{t('directions.result.time')}
138+
</Typography>
139+
<Typography fontWeight={900} variant="h6">
140+
{time}
141+
</Typography>
142+
</div>
143+
<div>
144+
<Typography variant="caption">
145+
{t('directions.result.distance')}
146+
</Typography>
147+
<Typography fontWeight={900} variant="h6">
148+
{distance}
149+
</Typography>
150+
</div>
151+
<div>
152+
<Typography variant="caption">
153+
{t('directions.result.ascent')}
154+
</Typography>
155+
<Typography fontWeight={900} variant="h6">
156+
{ascent}
157+
</Typography>
158+
</div>
159+
</Stack>
160+
<Divider sx={{ mt: 2, mb: 3 }} />
136161
{result.instructions && (
137162
<Instructions instructions={result.instructions} />
138163
)}

0 commit comments

Comments
 (0)