install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/leaflet" ~/.claude/skills/comeonoliver-skillshub-leaflet && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/leaflet/SKILL.mdsource content
Leaflet — Lightweight Open-Source Maps
Overview
You are an expert in Leaflet, the lightweight open-source JavaScript library for interactive maps. You help developers build map-based applications using OpenStreetMap tiles (free, no API key), custom markers, GeoJSON layers, clustering, and React integration via react-leaflet.
Instructions
React Integration
import { MapContainer, TileLayer, Marker, Popup, GeoJSON, useMap } from "react-leaflet"; import MarkerClusterGroup from "react-leaflet-cluster"; import "leaflet/dist/leaflet.css"; function StoreMap({ stores }) { return ( <MapContainer center={[40.75, -73.98]} zoom={12} style={{ height: "100vh", width: "100%" }}> <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution='© OpenStreetMap contributors' /> {/* Cluster markers when zoomed out */} <MarkerClusterGroup> {stores.map((store) => ( <Marker key={store.id} position={[store.lat, store.lng]}> <Popup> <h3>{store.name}</h3> <p>{store.address}</p> <p>Hours: {store.hours}</p> </Popup> </Marker> ))} </MarkerClusterGroup> </MapContainer> ); } // GeoJSON boundaries (neighborhoods, delivery zones) function DeliveryZones({ zones }) { return ( <MapContainer center={[40.75, -73.98]} zoom={11}> <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <GeoJSON data={zones} style={(feature) => ({ fillColor: feature.properties.active ? "#22c55e" : "#ef4444", weight: 2, opacity: 0.8, fillOpacity: 0.3, })} onEachFeature={(feature, layer) => { layer.bindPopup(` <b>${feature.properties.name}</b><br/> Orders: ${feature.properties.orderCount}<br/> Avg delivery: ${feature.properties.avgDeliveryMin} min `); }} /> </MapContainer> ); }
Custom Icons and Controls
import L from "leaflet"; // Custom marker icon const storeIcon = new L.Icon({ iconUrl: "/icons/store-pin.png", iconSize: [32, 32], iconAnchor: [16, 32], popupAnchor: [0, -32], }); // Custom map control (e.g., "Locate Me" button) function LocateControl() { const map = useMap(); return ( <button className="leaflet-control" onClick={() => map.locate({ setView: true, maxZoom: 16 })} > 📍 My Location </button> ); }
Installation
npm install leaflet react-leaflet npm install react-leaflet-cluster # Marker clustering npm install @types/leaflet # TypeScript types
Examples
Example 1: User asks to set up leaflet
User: "Help me set up leaflet for my project"
The agent should:
- Check system requirements and prerequisites
- Install or configure leaflet
- Set up initial project structure
- Verify the setup works correctly
Example 2: User asks to build a feature with leaflet
User: "Create a dashboard using leaflet"
The agent should:
- Scaffold the component or configuration
- Connect to the appropriate data source
- Implement the requested feature
- Test and validate the output
Guidelines
- Free tiles — Use OpenStreetMap tiles (no API key, no cost); switch to Mapbox/Stadia for custom styling
- Marker clustering — Use
for 100+ markers; prevents visual clutter and improves performancereact-leaflet-cluster - GeoJSON for regions — Use GeoJSON layers for boundaries, zones, and polygons; style dynamically based on data
- Lazy load — Leaflet CSS and JS are ~40KB; lazy load the map component for better initial page load
- SSR compatibility — Leaflet requires
; usewindow
in Next.jsdynamic(() => import("./Map"), { ssr: false }) - Tile caching — Use service workers to cache map tiles for offline support in PWAs
- Event handling — Use
hook for click, zoom, move events; build interactive experiencesuseMapEvents - Lightweight alternative — At 42KB (gzipped), Leaflet is 5x smaller than Mapbox GL JS; choose Leaflet when you don't need 3D or custom styles