Skip to content

Instantly share code, notes, and snippets.

@CaseyRo
Created May 7, 2026 09:09
Show Gist options
  • Select an option

  • Save CaseyRo/af7e9205f407f18aa2257b896b57c235 to your computer and use it in GitHub Desktop.

Select an option

Save CaseyRo/af7e9205f407f18aa2257b896b57c235 to your computer and use it in GitHub Desktop.
Strassenflohmarkt Kiebitz Aue — Druckansicht (klosterdorf.de)
<!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">&nbsp;·&nbsp; Sa. 16. Mai 2025 &nbsp;·&nbsp; 10–16 Uhr</span>
</div>
<div id="main">
<div id="map"></div>
<div class="legend-col">
<div class="col-header">Nr. &nbsp;·&nbsp; Adresse &nbsp;·&nbsp; 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. &nbsp;·&nbsp; Adresse &nbsp;·&nbsp; 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