Skip to content

Commit 59ccdab

Browse files
committed
Merge remote-tracking branch 'origin/master' into nn-github-bot
2 parents 669d75b + 1416e91 commit 59ccdab

22 files changed

+511
-270
lines changed

.github/workflows/preview-deploy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ jobs:
9393
- name: 🌐 Comment preview URL
9494
uses: actions/github-script@v7
9595
with:
96+
github-token: ${{ secrets.GITHUB_TOKEN }}
9697
script: |
9798
const prNumber = parseInt('${{ steps.pr.outputs.number }}');
9899
const { data: comments } = await github.rest.issues.listComments({

e2e/map.spec.ts

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { test, expect } from '@playwright/test';
22
import {
33
BERLIN_COORDINATES,
44
setupHeightMock,
5-
setupLocateMock,
65
setupNominatimMock,
76
setupRouteMock,
87
setupSearchMock,
@@ -481,6 +480,9 @@ test.describe('Map interactions with left context menu', () => {
481480
button: 'left',
482481
});
483482

483+
// Wait for popup to appear (has 200ms delay)
484+
await expect(page.getByTestId('map-info-popup')).toBeVisible();
485+
484486
await expect(page.getByTestId('dd-button')).toContainText(
485487
'13.393707, 52.518310'
486488
);
@@ -496,14 +498,9 @@ test.describe('Map interactions with left context menu', () => {
496498
);
497499
await expect(page.getByTestId('dms-copy-button')).toBeVisible();
498500

499-
await expect(
500-
page.getByRole('button', { name: 'Locate Point' })
501-
).toBeVisible();
502-
await expect(page.getByTestId('locate-point-copy-button')).toBeVisible();
503-
504-
await expect(
505-
page.getByRole('button', { name: 'Valhalla Location JSON' })
506-
).toBeVisible();
501+
await expect(page.getByTestId('location-json-button')).toContainText(
502+
'Valhalla Location JSON'
503+
);
507504
await expect(page.getByTestId('location-json-copy-button')).toBeVisible();
508505

509506
await expect(page.getByTestId('elevation-button')).toContainText('34 m');
@@ -516,35 +513,10 @@ test.describe('Map interactions with left context menu', () => {
516513
button: 'left',
517514
});
518515

519-
await expect(page.getByTestId('elevation-button')).toContainText('34 m');
520-
});
521-
522-
test('should call locate', async ({ page }) => {
523-
await setupHeightMock(page);
524-
const locateRequests = await setupLocateMock(page);
516+
// Wait for popup to appear (has 200ms delay)
517+
await expect(page.getByTestId('map-info-popup')).toBeVisible();
525518

526-
await page.getByRole('region', { name: 'Map' }).click({
527-
button: 'left',
528-
});
529-
530-
await expect(
531-
page.getByRole('button', { name: 'Locate Point' })
532-
).toBeVisible();
533-
534-
await page.getByRole('button', { name: 'Locate Point' }).click();
535-
536-
expect(locateRequests.length).toBeGreaterThan(0);
537-
538-
const locateRequest = locateRequests[0] as RouteApiRequest;
539-
expect(locateRequest.method).toBe('POST');
540-
expect(locateRequest.url).toMatch(
541-
/https:\/\/valhalla1\.openstreetmap\.de\/locate/
542-
);
543-
expect(locateRequest.body).toBeDefined();
544-
expect(locateRequest.body?.costing).toBe('bicycle');
545-
expect(locateRequest.body?.locations).toStrictEqual([
546-
{ lat: 52.51830999999976, lon: 13.393706999999239 },
547-
]);
519+
await expect(page.getByTestId('elevation-button')).toContainText('34 m');
548520
});
549521

550522
test('should copy text to clipboard', async ({ page }) => {
@@ -554,6 +526,9 @@ test.describe('Map interactions with left context menu', () => {
554526
button: 'left',
555527
});
556528

529+
// Wait for popup to appear (has 200ms delay)
530+
await expect(page.getByTestId('map-info-popup')).toBeVisible();
531+
557532
await page.getByTestId('dd-copy-button').click();
558533

559534
const clipboardContent = await page.evaluate(() =>

src/components/heightgraph.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ const HeightGraph: React.FC<HeightGraphProps> = ({
239239
return () => {
240240
tooltip.remove();
241241
};
242-
}, [data, dimensions, onHighlight]);
242+
}, [data, dimensions, onHighlight, isExpanded]);
243243

244244
const [prevProps, setPrevProps] = useState({ width, height });
245245
if (prevProps.width !== width || prevProps.height !== height) {

src/components/isochrones/isochrone-card.tsx

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,32 @@ import {
1515
} from '@/components/ui/dropdown-menu';
1616
import { Button } from '@/components/ui/button';
1717
import { MetricItem } from '@/components/ui/metric-item';
18+
import { SelectSetting } from '@/components/ui/select-setting';
19+
import { SliderSetting } from '@/components/ui/slider-setting';
20+
import {
21+
ISOCHRONE_PALETTES,
22+
isPaletteId,
23+
DEFAULT_OPACITY,
24+
} from '@/utils/isochrone-palettes';
1825

1926
interface IsochronesCardProps {
2027
data: ValhallaIsochroneResponse;
2128
showOnMap: boolean;
2229
}
2330

31+
const paletteOptions = ISOCHRONE_PALETTES.map((p) => ({
32+
key: p.id,
33+
value: p.id,
34+
text: p.label,
35+
}));
36+
2437
export const IsochroneCard = ({ data, showOnMap }: IsochronesCardProps) => {
2538
const toggleShowOnMap = useIsochronesStore((state) => state.toggleShowOnMap);
26-
39+
const colorPalette = useIsochronesStore((state) => state.colorPalette);
40+
const opacity = useIsochronesStore((state) => state.opacity);
41+
const updateVisualization = useIsochronesStore(
42+
(state) => state.updateVisualization
43+
);
2744
const handleChange = (checked: boolean) => {
2845
toggleShowOnMap(checked);
2946
};
@@ -48,6 +65,40 @@ export const IsochroneCard = ({ data, showOnMap }: IsochronesCardProps) => {
4865
<Label htmlFor="show-on-map">Show on map</Label>
4966
</div>
5067
</div>
68+
<div className="flex flex-col gap-1">
69+
<SelectSetting
70+
id="colorPalette"
71+
label="Color Palette"
72+
description="Choose a color palette for the isochrone polygons. Viridis is a colorblind-friendly option."
73+
value={colorPalette}
74+
options={paletteOptions}
75+
onValueChange={(value) => {
76+
if (isPaletteId(value)) {
77+
updateVisualization({ colorPalette: value });
78+
}
79+
}}
80+
/>
81+
<SliderSetting
82+
id="opacity"
83+
label="Opacity"
84+
description="Controls the transparency of the isochrone fill. Lower values make the map underneath more visible."
85+
min={0}
86+
max={1}
87+
step={0.05}
88+
value={opacity}
89+
onValueChange={(values) => {
90+
const value = values[0] ?? DEFAULT_OPACITY;
91+
updateVisualization({ opacity: value });
92+
}}
93+
onInputChange={(values) => {
94+
let value = values[0] ?? DEFAULT_OPACITY;
95+
value = isNaN(value)
96+
? DEFAULT_OPACITY
97+
: Math.min(1, Math.max(0, value));
98+
updateVisualization({ opacity: value });
99+
}}
100+
/>
101+
</div>
51102
<div className="flex flex-col justify-between gap-2">
52103
{data.features
53104
.filter((feature) => !feature.properties?.type)

0 commit comments

Comments
 (0)