| Name | Message | Date |
|---|---|---|
| 📄 +page.svelte | 1 month ago |
📄
src/routes/history/map/+page.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<script lang="ts">
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import { get } from "svelte/store";
import { historyStore } from "$lib/history";
import { labelsStore } from "$lib/labels";
function buildMap(node: HTMLElement) {
const entries = get(historyStore).filter((e) => e.coords != null);
const labels = get(labelsStore);
const map = L.map(node, { zoomControl: true });
L.tileLayer(
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
{
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
},
).addTo(map);
const birdIcon = L.divIcon({
html: `<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<polygon points="13,9 20,6 18,13 13,12" fill="#c4253a"/>
<ellipse cx="9" cy="11" rx="6" ry="4.5" fill="#c4253a"/>
<circle cx="5" cy="8" r="4" fill="#c4253a"/>
<polygon points="1,8 5,6.5 5,9.5" fill="#e89a3a"/>
<circle cx="3.5" cy="7.5" r="0.9" fill="#fff4d6"/>
</svg>`,
className: "bird-pin",
iconSize: [20, 20],
iconAnchor: [10, 10],
popupAnchor: [0, -14],
});
if (entries.length > 0) {
const group = L.featureGroup();
for (const entry of entries) {
const name = labels[entry.labelIndex]?.commonName ?? "Unknown bird";
L.marker([entry.coords!.lat, entry.coords!.lng], { icon: birdIcon })
.bindPopup(name)
.addTo(group);
}
group.addTo(map);
map.fitBounds(group.getBounds(), { padding: [40, 40] });
} else {
map.setView([20, 0], 2);
}
return () => map.remove();
}
</script>
<div class="map" {@attach buildMap}></div>
{#if !get(historyStore).some((e) => e.coords != null)}
<p class="empty">No sightings with GPS yet.</p>
{/if}
<style>
.map {
position: fixed;
inset: 0;
bottom: calc(var(--nav-height) + 3rem + env(safe-area-inset-bottom));
}
.empty {
position: fixed;
bottom: calc(var(--nav-height) + 3rem + env(safe-area-inset-bottom) + 1rem);
left: 0;
right: 0;
text-align: center;
color: var(--bg-near-black);
font-weight: 700;
font-size: 0.9rem;
pointer-events: none;
}
:global(.leaflet-popup-content-wrapper) {
background: var(--bg-paper);
border: 2px solid var(--bg-near-black);
border-radius: 8px;
box-shadow: 0 3px 0 var(--bg-near-black);
padding: 0;
}
:global(.leaflet-popup-content) {
margin: 0.4rem 0.75rem;
font-family: system-ui, sans-serif;
font-weight: 700;
font-size: 0.85rem;
color: var(--bg-near-black);
}
:global(.leaflet-popup-tip-container) {
display: none;
}
:global(.bird-pin) {
background: none;
border: none;
}
</style>