Created
May 7, 2026 09:09
-
-
Save CaseyRo/af7e9205f407f18aa2257b896b57c235 to your computer and use it in GitHub Desktop.
Strassenflohmarkt Kiebitz Aue — Druckansicht (klosterdorf.de)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="de"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Hofflohmarkt Kiebitz Aue</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css"/> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script> | |
| <style> | |
| * { margin:0; padding:0; box-sizing:border-box; } | |
| @page { size: A4 landscape; margin:0; } | |
| body { | |
| width:297mm; height:210mm; | |
| font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; | |
| background:#fff; overflow:hidden; | |
| display:flex; flex-direction:column; | |
| } | |
| #header { | |
| flex-shrink:0; height:16mm; background:#E8690A; | |
| display:flex; align-items:center; padding:0 6mm; gap: 10px; | |
| } | |
| #header h1 { color:#fff; font-size:15pt; font-weight:800; letter-spacing:.02em; } | |
| #header .sub { color:#fff; font-size:15pt; font-weight:800; letter-spacing:.02em; white-space:nowrap; } | |
| #main { flex:1; display:flex; overflow:hidden; } | |
| #map { width:50%; height:100%; flex-shrink:0; } | |
| .legend-col { | |
| width:25%; height:100%; background:#FAF4EC; | |
| overflow:hidden; display:flex; flex-direction:column; | |
| border-left:2px solid #C8580A; | |
| } | |
| .legend-col:first-of-type { border-left:3px solid #C8580A; } | |
| .col-header { | |
| flex-shrink:0; background:#E8690A; | |
| padding:2.5mm 3mm 2mm; border-bottom:2px solid #C8580A; | |
| font-size:8pt; font-weight:700; color:#fff; | |
| letter-spacing:.03em; text-transform:uppercase; | |
| } | |
| .entries { flex:1; overflow:hidden; } | |
| .entry { | |
| display:flex; align-items:flex-start; gap:4px; | |
| padding:2.2mm 3mm; border-bottom:1px solid #C8580A44; | |
| } | |
| .entry:nth-child(odd) { background:#F5E8D5; } | |
| .entry:nth-child(even) { background:#FDEBD0; } | |
| .badge { | |
| flex-shrink:0; width:20px; height:20px; border-radius:50%; | |
| background:#C8580A; color:#fff; font-size:9pt; font-weight:800; | |
| display:flex; align-items:center; justify-content:center; margin-top:1px; | |
| } | |
| .text { min-width:0; } | |
| .addr { font-size:9pt; font-weight:800; color:#111; line-height:1.2; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; } | |
| .wares { font-size:7.5pt; color:#333; line-height:1.35; word-break:break-word; font-weight:500; } | |
| .num-marker { | |
| background:#fff; border:2.5px solid #111; border-radius:50%; | |
| color:#111; font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; | |
| font-weight:900; display:flex; align-items:center; justify-content:center; | |
| box-shadow:0 1px 5px rgba(0,0,0,.5); | |
| transition: transform .1s; | |
| } | |
| .num-marker.draggable { cursor:grab; border-color:#E8690A; border-width:3px; } | |
| .num-marker.draggable:active { cursor:grabbing; } | |
| .p-marker { | |
| background:#1a6bbf; border:1.5px solid #003d8a; border-radius:3px; | |
| color:#fff; font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; | |
| font-weight:900; font-size:9px; display:flex; align-items:center; justify-content:center; | |
| box-shadow:0 1px 4px rgba(0,0,0,.45); | |
| } | |
| .p-marker.draggable { cursor:grab; border-color:#FFD700; border-width:2px; } | |
| .parking-note { | |
| flex-shrink:0; | |
| background:#1a6bbf; color:#fff; | |
| font-size:8pt; font-weight:600; line-height:1.5; | |
| padding:4mm 3mm; | |
| border-top:2px solid #1255a0; | |
| display:flex; flex-direction:column; justify-content:center; | |
| min-height:18mm; | |
| } | |
| .parking-note strong { display:block; font-size:9pt; margin-bottom:1.5mm; letter-spacing:0.02em; } | |
| #toolbar { | |
| position:fixed; top:8px; left:50%; | |
| transform:translateX(-50%); | |
| background:white; border:2px solid #E8690A; border-radius:8px; | |
| padding:6px 12px; display:flex; align-items:center; gap:10px; | |
| box-shadow:0 2px 12px rgba(0,0,0,.2); z-index:9999; font-size:12px; | |
| } | |
| #toolbar button { | |
| background:#E8690A; color:white; border:none; border-radius:5px; | |
| padding:5px 12px; font-size:12px; font-weight:700; cursor:pointer; | |
| } | |
| #toolbar button.off { background:#888; } | |
| #toolbar button:hover { opacity:.85; } | |
| #info-box { color:#555; font-size:11px; max-width:220px; } | |
| #copy-btn { background:#27AE60 !important; } | |
| @media print { | |
| #toolbar { display:none !important; } | |
| body { -webkit-print-color-adjust:exact; print-color-adjust:exact; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="toolbar"> | |
| <button id="edit-btn" class="off" onclick="toggleEdit()">✏️ Bearbeiten</button> | |
| <button id="park-btn" class="off" style="display:none;background:#1a6bbf" onclick="toggleParkMode()">🅿️ Parkplatz setzen</button> | |
| <span id="info-box">Klick auf „Bearbeiten", dann Marker ziehen oder Parkplätze setzen.</span> | |
| <button id="copy-btn" style="display:none" onclick="copyCoords()">📋 Koordinaten kopieren</button> | |
| </div> | |
| <div id="header"> | |
| <h1>🏡 Strassenflohmarkt – Kiebitz Aue, Klosterdorf</h1> | |
| <span class="sub"> · Sa. 16. Mai 2025 · 10–16 Uhr</span> | |
| </div> | |
| <div id="main"> | |
| <div id="map"></div> | |
| <div class="legend-col"> | |
| <div class="col-header">Nr. · Adresse · Angebot</div> | |
| <div class="entries" id="entries-left"></div> | |
| </div> | |
| <div class="legend-col" style="display:flex;flex-direction:column;"> | |
| <div class="col-header">Nr. · Adresse · Angebot</div> | |
| <div class="entries" id="entries-right" style="flex:1"></div> | |
| <div class="parking-note"> | |
| <strong>🅿️ Parkhinweis</strong> | |
| Bitte nur in den vorgesehenen Parkbuchten parken – und von dort zu Fuß losschlendern! | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Manually verified coordinates | |
| const participants = [ | |
| { n:1, addr:"Schlehenring 7", wares:"Kleidung, Handtaschen, Elektro, Bücher, Hausrat", lat:52.595097, lng:13.948667 }, | |
| { n:2, addr:"Schlehenring 33", wares:"Werkzeug, Elektro, Kleidung", lat:52.595619, lng:13.949912 }, | |
| { n:3, addr:"Schlehenring 20", wares:"Spielzeug, Trödel", lat:52.595918, lng:13.949697 }, | |
| { n:4, addr:"Schlehenring 23", wares:"Spielzeug, Kindersachen", lat:52.596246, lng:13.950243 }, | |
| { n:5, addr:"Schlehenring 21", wares:"Kinderkleidung, Spielzeug, Schuhe", lat:52.596560, lng:13.949780 }, | |
| { n:6, addr:"Kiefernweg 2", wares:"Kinderkleidung, Spielzeug, Bücher", lat:52.596922, lng:13.950314 }, | |
| { n:7, addr:"Kiefernweg 1", wares:"Kinderkleidung, Babysachen, Elektro, Spielzeug", lat:52.596779, lng:13.950625 }, | |
| { n:8, addr:"Fichtenweg 1", wares:"Spielzeug", lat:52.596997, lng:13.951070 }, | |
| { n:9, addr:"Birkenweg 1", wares:"Hausrat, Kleidung, Spielzeug", lat:52.596336, lng:13.951178 }, | |
| { n:10, addr:"Schlehenring 28", wares:"Bücher, Roller, Kleidung", lat:52.595740, lng:13.950968 }, | |
| { n:11, addr:"Lindenplatz 6", wares:"Hausrat", lat:52.596632, lng:13.952256 }, | |
| { n:12, addr:"Lindenallee 12", wares:"Kinderkleidung, Spielzeug, Babysachen", lat:52.595987, lng:13.952787 }, | |
| { n:13, addr:"Jasminweg 11", wares:"Spielzeug, Puzzles", lat:52.595589, lng:13.954160 }, | |
| { n:14, addr:"Fliederweg 14", wares:"Spielzeug, Gartenartikel, Elektro, Kinderkleidung", lat:52.595329, lng:13.954627 }, | |
| { n:15, addr:"Ahornstraße 30", wares:"Pflanzen, Spielzeug, Kinderkleidung", lat:52.594771, lng:13.954501 }, | |
| { n:16, addr:"Ahornstraße 28", wares:"Hausrat, Spielzeug, Puzzles", lat:52.594615, lng:13.953989 }, | |
| { n:17, addr:"Fliederweg 7a", wares:"Spielzeug, Kleidung, Hausrat", lat:52.594902, lng:13.953624 }, | |
| { n:18, addr:"Kirschweg 16", wares:"Bücher, Spiele, Deko, Kleinkram", lat:52.593494, lng:13.952229 }, | |
| { n:19, addr:"Lindenallee 41a", wares:"Trödel, Puzzles, Kleidung", lat:52.593012, lng:13.950169 }, | |
| { n:20, addr:"Ahornstraße 9", wares:"Spielzeug, Bücher, Modeschmuck, Hausrat", lat:52.594354, lng:13.949847 }, | |
| { n:21, addr:"Ahornstraße 7", wares:"Trödel", lat:52.594407, lng:13.950427 }, | |
| { n:22, addr:"Ebereschenweg 1", wares:"Kinderkleidung, Spielzeug", lat:52.597417, lng:13.951902 }, | |
| { n:23, addr:"Eichenweg 6", wares:"Pflanzen, Elektro, Kleidung, Hausrat", lat:52.597642, lng:13.951773 }, | |
| { n:24, addr:"Eibenweg 12", wares:"Kinderkleidung, Spielzeug", lat:52.597760, lng:13.954160 }, | |
| { n:25, addr:"Lindenallee 24", wares:"Werkzeug, Trödel, Spielzeug, Kindersachen", lat:52.597059, lng:13.954080 }, | |
| { n:26, addr:"Fliederweg 41", wares:"Handgemachtes", lat:52.597540, lng:13.955810 }, | |
| { n:27, addr:"Buchenweg 4", wares:"Hausrat, Bücher, CDs/DVDs, Spielzeug, Fahrrad", lat:52.598740, lng:13.954080 }, | |
| ]; | |
| const parkingSpots = [ | |
| { lat:52.597536, lng:13.952346 }, | |
| { lat:52.597074, lng:13.951478 }, | |
| { lat:52.597992, lng:13.953263 }, | |
| { lat:52.594826, lng:13.949199 }, | |
| { lat:52.593920, lng:13.950421 }, | |
| { lat:52.592513, lng:13.950566 }, | |
| { lat:52.594813, lng:13.955097 }, | |
| { lat:52.595158, lng:13.954781 }, | |
| { lat:52.596155, lng:13.954738 }, | |
| { lat:52.595781, lng:13.954545 }, | |
| { lat:52.596768, lng:13.955065 }, | |
| { lat:52.597172, lng:13.955296 }, | |
| { lat:52.599227, lng:13.955923 }, | |
| { lat:52.598989, lng:13.955328 }, | |
| ]; | |
| const pos = participants.map(p => ({ lat: p.lat, lng: p.lng })); | |
| // ── Edit mode state ─────────────────────────────────────────────────────────── | |
| let editMode = false; | |
| let parkMode = false; | |
| const leafletMarkers = []; | |
| const parkingMarkers = []; // { marker, lat, lng } | |
| function toggleEdit() { | |
| editMode = !editMode; | |
| const btn = document.getElementById('edit-btn'); | |
| const parkBtn = document.getElementById('park-btn'); | |
| const copyBtn = document.getElementById('copy-btn'); | |
| const info = document.getElementById('info-box'); | |
| btn.textContent = editMode ? '🔒 Fertig' : '✏️ Bearbeiten'; | |
| btn.className = editMode ? '' : 'off'; | |
| parkBtn.style.display = editMode ? 'inline-block' : 'none'; | |
| copyBtn.style.display = editMode ? 'inline-block' : 'none'; | |
| if (!editMode) { | |
| parkMode = false; | |
| parkBtn.textContent = '🅿️ Parkplatz setzen'; | |
| parkBtn.className = 'off'; | |
| map.dragging.disable(); | |
| map.scrollWheelZoom.disable(); | |
| map.off('click', onMapClick); | |
| } else { | |
| map.dragging.enable(); | |
| map.scrollWheelZoom.enable(); | |
| } | |
| info.textContent = editMode | |
| ? 'Nummern-Marker ziehen · oder 🅿️ aktivieren und auf Karte klicken' | |
| : 'Klick auf „Bearbeiten", dann Marker ziehen oder Parkplätze setzen.'; | |
| leafletMarkers.forEach(m => { | |
| if (editMode) m.dragging.enable(); else m.dragging.disable(); | |
| const el = m.getElement(); | |
| if (el) { | |
| const inner = el.querySelector('.num-marker'); | |
| if (inner) { if (editMode) inner.classList.add('draggable'); else inner.classList.remove('draggable'); } | |
| } | |
| }); | |
| parkingMarkers.forEach(({ marker }) => { | |
| if (editMode) marker.dragging.enable(); else marker.dragging.disable(); | |
| const el = marker.getElement(); | |
| if (el) { | |
| const inner = el.querySelector('.p-marker'); | |
| if (inner) { if (editMode) inner.classList.add('draggable'); else inner.classList.remove('draggable'); } | |
| } | |
| }); | |
| } | |
| function toggleParkMode() { | |
| parkMode = !parkMode; | |
| const btn = document.getElementById('park-btn'); | |
| const info = document.getElementById('info-box'); | |
| if (parkMode) { | |
| btn.textContent = '🅿️ Fertig setzen'; | |
| btn.className = ''; | |
| map.on('click', onMapClick); | |
| info.textContent = 'Klick auf die Karte um einen Parkplatz-Marker zu setzen'; | |
| } else { | |
| btn.textContent = '🅿️ Parkplatz setzen'; | |
| btn.className = 'off'; | |
| map.off('click', onMapClick); | |
| info.textContent = 'Nummern-Marker ziehen · oder 🅿️ aktivieren und auf Karte klicken'; | |
| } | |
| } | |
| function onMapClick(e) { | |
| addParkingMarker(e.latlng.lat, e.latlng.lng, true); | |
| } | |
| function addParkingMarker(lat, lng, draggable) { | |
| const icon = L.divIcon({ | |
| className: '', | |
| html: `<div class="p-marker${draggable ? ' draggable' : ''}" style="width:16px;height:16px">P</div>`, | |
| iconSize: [16, 16], | |
| iconAnchor: [8, 8], | |
| }); | |
| const marker = L.marker([lat, lng], { icon, draggable: draggable || false }).addTo(map); | |
| marker.on('drag', () => { | |
| const ll = marker.getLatLng(); | |
| document.getElementById('info-box').textContent = `Parkplatz: ${ll.lat.toFixed(5)}, ${ll.lng.toFixed(5)}`; | |
| }); | |
| // Right-click to remove | |
| marker.on('contextmenu', () => { | |
| if (editMode) { | |
| map.removeLayer(marker); | |
| const idx = parkingMarkers.findIndex(pm => pm.marker === marker); | |
| if (idx > -1) parkingMarkers.splice(idx, 1); | |
| } | |
| }); | |
| parkingMarkers.push({ marker }); | |
| } | |
| function copyCoords() { | |
| const numLines = leafletMarkers.map((m, i) => { | |
| const ll = m.getLatLng(); | |
| const p = participants[i]; | |
| return ` { n:${p.n}, addr:"${p.addr}", wares:"${p.wares}", lat:${ll.lat.toFixed(6)}, lng:${ll.lng.toFixed(6)} },`; | |
| }); | |
| const parkLines = parkingMarkers.map(({ marker }) => { | |
| const ll = marker.getLatLng(); | |
| return ` { lat:${ll.lat.toFixed(6)}, lng:${ll.lng.toFixed(6)} },`; | |
| }); | |
| const text = | |
| 'const participants = [\n' + numLines.join('\n') + '\n];\n\n' + | |
| 'const parkingSpots = [\n' + parkLines.join('\n') + '\n];'; | |
| navigator.clipboard.writeText(text).then(() => { | |
| document.getElementById('info-box').textContent = '✅ Koordinaten kopiert! Schick sie an Claude.'; | |
| }); | |
| } | |
| // ── Map ─────────────────────────────────────────────────────────────────────── | |
| const map = L.map('map', { | |
| zoomControl: false, scrollWheelZoom: false, dragging: false, | |
| doubleClickZoom: false, touchZoom: false, keyboard: false, | |
| }); | |
| L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
| attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>-Mitwirkende', | |
| maxZoom: 19, | |
| }).addTo(map); | |
| // Fit bounds on true positions | |
| map.fitBounds(L.latLngBounds(participants.map(p => [p.lat, p.lng])).pad(0.13)); | |
| // Draw thin leader lines from nudged → true position if moved significantly | |
| participants.forEach((p, i) => { | |
| const dp = pos[i]; | |
| const dLat = Math.abs(dp.lat - p.lat); | |
| const dLng = Math.abs(dp.lng - p.lng); | |
| if (dLat > 0.00005 || dLng > 0.00005) { | |
| L.polyline([[p.lat, p.lng], [dp.lat, dp.lng]], { | |
| color: '#E8690A', weight: 1, opacity: 0.55, dashArray: '3,3' | |
| }).addTo(map); | |
| // Small dot at true location | |
| L.circleMarker([p.lat, p.lng], { | |
| radius: 3, color: '#E8690A', fillColor: '#E8690A', | |
| fillOpacity: 0.7, weight: 1 | |
| }).addTo(map); | |
| } | |
| }); | |
| // Place numbered markers at nudged positions — store refs for edit mode | |
| participants.forEach((p, i) => { | |
| const size = p.n >= 10 ? 26 : 24; | |
| const fs = p.n >= 10 ? '9px' : '11px'; | |
| const icon = L.divIcon({ | |
| className: '', | |
| html: `<div class="num-marker" style="width:${size}px;height:${size}px;font-size:${fs}">${p.n}</div>`, | |
| iconSize: [size, size], | |
| iconAnchor: [size / 2, size / 2], | |
| }); | |
| const marker = L.marker([pos[i].lat, pos[i].lng], { icon, draggable: false }).addTo(map); | |
| marker.on('drag', () => { | |
| const ll = marker.getLatLng(); | |
| document.getElementById('info-box').textContent = | |
| `Nr. ${p.n} (${p.addr}): ${ll.lat.toFixed(5)}, ${ll.lng.toFixed(5)}`; | |
| }); | |
| leafletMarkers.push(marker); | |
| }); | |
| // Place fixed parking markers | |
| parkingSpots.forEach(sp => addParkingMarker(sp.lat, sp.lng, false)); | |
| // ── Legend ──────────────────────────────────────────────────────────────────── | |
| function makeEntry(p) { | |
| const div = document.createElement('div'); | |
| div.className = 'entry'; | |
| div.innerHTML = ` | |
| <div class="badge">${p.n}</div> | |
| <div class="text"> | |
| <div class="addr">${p.addr}</div> | |
| <div class="wares">${p.wares}</div> | |
| </div>`; | |
| return div; | |
| } | |
| const left = document.getElementById('entries-left'); | |
| const right = document.getElementById('entries-right'); | |
| participants.forEach((p, i) => (i < 14 ? left : right).appendChild(makeEntry(p))); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment