Skip to content

Commit 34776c3

Browse files
Give an option to append valhalla tiles to style.json file (#312)
1 parent 9bf225e commit 34776c3

File tree

6 files changed

+675
-11
lines changed

6 files changed

+675
-11
lines changed

src/components/tiles/tiles.spec.tsx

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ const createMockLayers = () => [
1616

1717
const createMockMap = (layers = createMockLayers()) => {
1818
const layerVisibility: Record<string, string> = {};
19+
const sources: Record<string, unknown> = {};
20+
const dynamicLayers: Record<string, unknown> = {};
1921

2022
return {
2123
getStyle: vi.fn(() => ({ layers })),
@@ -34,6 +36,20 @@ const createMockMap = (layers = createMockLayers()) => {
3436
),
3537
on: vi.fn(),
3638
off: vi.fn(),
39+
getSource: vi.fn((id: string) => sources[id]),
40+
addSource: vi.fn((id: string, spec: unknown) => {
41+
sources[id] = spec;
42+
}),
43+
removeSource: vi.fn((id: string) => {
44+
delete sources[id];
45+
}),
46+
getLayer: vi.fn((id: string) => dynamicLayers[id]),
47+
addLayer: vi.fn((layer: { id: string }) => {
48+
dynamicLayers[layer.id] = layer;
49+
}),
50+
removeLayer: vi.fn((id: string) => {
51+
delete dynamicLayers[id];
52+
}),
3753
};
3854
};
3955

@@ -360,7 +376,7 @@ describe('TilesControl', () => {
360376
render(<TilesControl />);
361377

362378
const groupSwitches = screen.getAllByRole('switch');
363-
const roadsGroupSwitch = groupSwitches[1]!;
379+
const roadsGroupSwitch = groupSwitches[2]!;
364380

365381
await user.click(roadsGroupSwitch);
366382

@@ -386,7 +402,7 @@ describe('TilesControl', () => {
386402
render(<TilesControl />);
387403

388404
const groupSwitches = screen.getAllByRole('switch');
389-
const waterGroupSwitch = groupSwitches[0]!;
405+
const waterGroupSwitch = groupSwitches[1]!;
390406

391407
await user.click(waterGroupSwitch);
392408
await user.click(waterGroupSwitch);
@@ -431,12 +447,14 @@ describe('TilesControl', () => {
431447
expect(mockMap.getStyle).toHaveBeenCalled();
432448
const initialCallCount = mockMap.getStyle.mock.calls.length;
433449

434-
const styleDataHandler = mockMap.on.mock.calls.find(
435-
(call) => call[0] === 'styledata'
436-
)?.[1];
450+
const styleDataHandlers = mockMap.on.mock.calls
451+
.filter((call) => call[0] === 'styledata')
452+
.map((call) => call[1]);
437453

438454
await act(async () => {
439-
styleDataHandler?.();
455+
for (const handler of styleDataHandlers) {
456+
handler?.();
457+
}
440458
});
441459

442460
await waitFor(() => {
@@ -456,12 +474,14 @@ describe('TilesControl', () => {
456474
expect(screen.getByText('water-fill')).toBeInTheDocument();
457475
});
458476

459-
const styleDataHandler = mockMap.on.mock.calls.find(
460-
(call) => call[0] === 'styledata'
461-
)?.[1];
477+
const styleDataHandlers = mockMap.on.mock.calls
478+
.filter((call) => call[0] === 'styledata')
479+
.map((call) => call[1]);
462480

463481
await act(async () => {
464-
styleDataHandler?.();
482+
for (const handler of styleDataHandlers) {
483+
handler?.();
484+
}
465485
});
466486

467487
await waitFor(() => {

src/components/tiles/tiles.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ import {
1010
CollapsibleTrigger,
1111
} from '@/components/ui/collapsible';
1212
import { ChevronDown, ChevronRight } from 'lucide-react';
13+
import { cn } from '@/lib/utils';
14+
import { ValhallaLayersToggle } from './valhalla-layers-toggle';
15+
import { VALHALLA_SOURCE_ID } from './valhalla-layers';
1316

1417
interface LayerInfo {
1518
id: string;
1619
type: string;
1720
sourceLayer?: string;
21+
source?: string;
1822
}
1923

2024
interface GroupedLayers {
@@ -67,6 +71,7 @@ export const TilesControl = () => {
6771
type: layer.type,
6872
sourceLayer:
6973
'source-layer' in layer ? layer['source-layer'] : undefined,
74+
source: 'source' in layer ? (layer.source as string) : undefined,
7075
}));
7176
// eslint-disable-next-line react-hooks/exhaustive-deps -- styleVersion is used to invalidate cache on style changes
7277
}, [mapReady, mainMap, styleVersion]);
@@ -163,8 +168,15 @@ export const TilesControl = () => {
163168
return visibleCount > 0 && visibleCount < layersInGroup.length;
164169
};
165170

171+
const isValhallaGroup = (sourceLayer: string) => {
172+
const layersInGroup = groupedLayers.grouped[sourceLayer] || [];
173+
return layersInGroup.some((layer) => layer.source === VALHALLA_SOURCE_ID);
174+
};
175+
166176
return (
167177
<div className="flex flex-col gap-3 flex-1 overflow-hidden min-h-0">
178+
<ValhallaLayersToggle />
179+
168180
<Input
169181
type="text"
170182
placeholder="Search layers..."
@@ -180,7 +192,13 @@ export const TilesControl = () => {
180192
open={expandedGroups.has(sourceLayer)}
181193
onOpenChange={() => toggleExpanded(sourceLayer)}
182194
>
183-
<div className="flex items-center gap-2 p-2 bg-muted/50 rounded-md">
195+
<div
196+
className={cn(
197+
'flex items-center gap-2 p-2 bg-muted/50 rounded-md',
198+
isValhallaGroup(sourceLayer) &&
199+
'border-l-2 border-l-green-600'
200+
)}
201+
>
184202
<CollapsibleTrigger className="flex items-center gap-1 flex-1 text-left">
185203
{expandedGroups.has(sourceLayer) ? (
186204
<ChevronDown className="size-4" />
@@ -191,6 +209,11 @@ export const TilesControl = () => {
191209
<span className="text-xs text-muted-foreground ml-1">
192210
({groupLayers.length})
193211
</span>
212+
{isValhallaGroup(sourceLayer) && (
213+
<span className="text-xs bg-green-600 text-white px-1.5 py-0.5 rounded ml-2">
214+
Valhalla
215+
</span>
216+
)}
194217
</CollapsibleTrigger>
195218
<Switch
196219
checked={isGroupVisible(sourceLayer)}

0 commit comments

Comments
 (0)