Skip to content

Instantly share code, notes, and snippets.

@thekonsti1
Created December 25, 2025 20:03
Show Gist options
  • Select an option

  • Save thekonsti1/f8ae1bd210afb0d79f0daa9061bf55b5 to your computer and use it in GitHub Desktop.

Select an option

Save thekonsti1/f8ae1bd210afb0d79f0daa9061bf55b5 to your computer and use it in GitHub Desktop.
Untitled
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Global Price Tracker</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<style>
:root { --primary: #1a73e8; --bg: #f8f9fa; }
body { margin: 0; font-family: 'Segoe UI', sans-serif; display: flex; height: 100vh; overflow: hidden; }
/* Seitenleiste */
#sidebar {
width: 300px; background: white; border-right: 1px solid #ddd;
display: flex; flex-direction: column; z-index: 2000;
}
#sidebar-header { padding: 20px; background: var(--primary); color: white; }
#price-list { flex: 1; overflow-y: auto; padding: 10px; }
.price-item {
padding: 12px; border-bottom: 1px solid #eee; cursor: pointer;
transition: background 0.2s; border-radius: 8px; margin-bottom: 5px;
}
.price-item:hover { background: #eef2ff; }
.price-item b { color: #d93025; font-size: 1.1em; }
.price-item small { display: block; color: #666; margin-top: 4px; }
/* Karte & Suche */
#main { flex: 1; position: relative; }
#map { height: 100%; width: 100%; cursor: crosshair; }
#search-ui {
position: absolute; top: 15px; left: 15px; z-index: 1000;
background: white; padding: 10px; border-radius: 10px;
box-shadow: 0 4px 15px rgba(0,0,0,0.2); width: 280px; display: flex; gap: 5px;
}
input { flex: 1; padding: 10px; border: 1px solid #ccc; border-radius: 6px; outline: none; }
button { padding: 10px; background: var(--primary); color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: bold; }
@media (max-width: 600px) {
body { flex-direction: column; }
#sidebar { width: 100%; height: 30%; border-right: none; border-top: 1px solid #ddd; }
}
</style>
</head>
<body>
<div id="sidebar">
<div id="sidebar-header">
<h3 style="margin:0">đź’° Alle Preise</h3>
</div>
<div id="price-list">
</div>
</div>
<div id="main">
<div id="search-ui">
<input type="text" id="addrInp" placeholder="Adresse suchen...">
<button onclick="searchAddr()">Finden</button>
</div>
<div id="map"></div>
</div>
<script>
const bounds = L.latLngBounds(L.latLng(-85, -180), L.latLng(85, 180));
const map = L.map('map', {
maxBounds: bounds,
maxBoundsViscosity: 1.0,
minZoom: 2,
worldCopyJump: false
}).setView([51.16, 10.45], 5);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
noWrap: true, bounds: bounds
}).addTo(map);
let storageKey = 'price_app_shared_v3';
let data = JSON.parse(localStorage.getItem(storageKey) || '[]');
function updateUI() {
const listContainer = document.getElementById('price-list');
listContainer.innerHTML = '';
// Marker auf Karte löschen und neu zeichnen
map.eachLayer((layer) => {
if (layer instanceof L.Marker) map.removeLayer(layer);
});
data.forEach((item, index) => {
// Marker zur Karte hinzufĂĽgen
const marker = L.marker([item.lat, item.lng]).addTo(map)
.bindPopup(`<b style="font-size:1.4em; color:#d93025;">${item.price} €</b>`);
// Element zur Liste hinzufĂĽgen
const div = document.createElement('div');
div.className = 'price-item';
div.innerHTML = `<b>${item.price} €</b> <small>${item.address || 'Gespeicherter Ort'}</small>`;
div.onclick = () => {
map.setView([item.lat, item.lng], 15);
marker.openPopup();
};
listContainer.prepend(div); // Neueste oben
});
}
map.on('click', async function(e) {
if (e.originalEvent.target.classList.contains('leaflet-marker-icon')) return;
const price = prompt("Welchen Preis möchtest du eintragen? (in €)");
if (!price) return;
// Optional: Adresse fĂĽr die Liste abrufen
let addrName = "Ort auf Karte";
try {
const res = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${e.latlng.lat}&lon=${e.latlng.lng}`);
const resData = await res.json();
addrName = resData.display_name.split(',')[0] + ", " + (resData.address.city || resData.address.town || "");
} catch(err) {}
const entry = { lat: e.latlng.lat, lng: e.latlng.lng, price: price, address: addrName };
data.push(entry);
localStorage.setItem(storageKey, JSON.stringify(data));
updateUI();
});
async function searchAddr() {
const query = document.getElementById('addrInp').value;
const res = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}`);
const results = await res.json();
if (results.length > 0) {
map.setView([results[0].lat, results[0].lon], 16);
}
}
// Initiales Laden
updateUI();
</script>
</body>
</html>
body {
font-family: system-ui;
background: #f06d06;
color: white;
text-align: center;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment