Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/lib/components/RegistryActivitiesMap.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@
let map = $state<import('leaflet').Map | null>(null);
/** Each drawn outline by activity id, so the page can zoom to one. Not reactive. */
const outlinesById = new Map<string, import('leaflet').GeoJSON>();
/** Every drawn outline, for zooming back out to them all. Not reactive. */
let allOutlines: import('leaflet').FeatureGroup | null = null;

/** Frames every drawn area again, as the map first opened. */
export function showAll() {
map?.closePopup();
frameAll();
}

function frameAll() {
const bounds = allOutlines?.getBounds();
if (map && bounds?.isValid()) map.fitBounds(bounds, { padding: [32, 32], maxZoom: 14 });
}

/** Zooms to one activity's area and opens its popup. Returns false if it has none drawn. */
export function focusActivity(activityId: string): boolean {
Expand Down Expand Up @@ -109,15 +122,16 @@
};
m.on('zoomend', syncDots);

const bounds = outlines.getBounds();
if (bounds.isValid()) m.fitBounds(bounds, { padding: [32, 32], maxZoom: 14 });
allOutlines = outlines;
frameAll();
syncDots();

return () => {
m.off('zoomend', syncDots);
outlines.remove();
dots.remove();
outlinesById.clear();
allOutlines = null;
};
});

Expand Down
19 changes: 17 additions & 2 deletions src/routes/registry/activities/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import Pill from '$lib/components/Pill.svelte';
import ObpErrorDisplay from '$lib/components/ObpErrorDisplay.svelte';
import ToggleGroup from '$lib/components/ToggleGroup.svelte';
import Button from '$lib/components/Button.svelte';
import RegistryActivitiesMap from '$lib/components/RegistryActivitiesMap.svelte';
import { goto } from '$app/navigation';
import { page } from '$app/state';
Expand All @@ -15,7 +16,7 @@
registryOperatorHref,
type RegistryActivity
} from '$lib/registry/activities';
import { Search, List, Map as MapIcon, Layers } from '@lucide/svelte';
import { Search, List, Map as MapIcon, Layers, Maximize } from '@lucide/svelte';
import { findAreaOverlaps } from '$lib/registry/areaOverlaps';

let { data }: { data: PageData } = $props();
Expand Down Expand Up @@ -91,6 +92,10 @@
function focusOnMap(activityId: string) {
if (activitiesMap?.focusActivity(activityId)) focusedId = activityId;
}
function showAllOnMap() {
activitiesMap?.showAll();
focusedId = null;
}

const filtersApplied = $derived(
search.trim() !== '' || creditType !== 'all' || country !== 'all' || status !== 'all'
Expand Down Expand Up @@ -237,13 +242,18 @@
<div class="ogcr-legend mb-3" aria-label="Map key">
<Pill tone="positive" dot>Verified</Pill>
<Pill tone="warning" dot>Unverified</Pill>
{#if mapped.length > 0}
<Button variant="outlined" size="s" class="ogcr-legend__action" onclick={showAllOnMap}>
{#snippet iconLeft()}<Maximize class="size-4" aria-hidden="true" />{/snippet}
Show all activities
</Button>
{/if}
</div>
{#if overlappingCount > 0}
<p class="ogcr-overlap-note text-body-s mb-2">
<Layers class="size-4" aria-hidden="true" />
{overlappingCount}
{overlappingCount === 1 ? 'activity overlaps' : 'activities overlap'} another activity's area
— possible double counting. Click one to see the overlap.
</p>
{/if}
{#if mapped.length > 0}
Expand Down Expand Up @@ -406,8 +416,13 @@
.ogcr-legend {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-xs);
}
/* Sits at the right, above the map it acts on. */
.ogcr-legend :global(.ogcr-legend__action) {
margin-left: auto;
}

/* Small and capped at a few lines, so the map stays the main thing on the page. */
.ogcr-map-list {
Expand Down
Loading