Something went wrong. Try again.
Central platform for European atproto.<cc> country community websites atproto.eu
community atproto
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697<!doctype html><html> <head> <meta charset="utf-8" /> <title>locality map</title> <!-- Self-hosted (local-first): d3, topojson-client and the Natural Earth data are vendored under /map/vendor rather than fetched from a CDN, so no third-party runtime requests. --> <style> @font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 100 800; font-display: swap; src: url('/map/vendor/jetbrains-mono-latin.woff2') format('woff2'); } /* Opaque, theme-matched from the first paint so the iframe never flashes its default (grey/white) background while d3 + the geometry load. prefers-color-scheme covers the first frame by system; the inline script below corrects to a pinned theme. Values are the gruvbox paper tones, kept in sync with global.css --paper. */ html, body { margin: 0; height: 100%; background: #fbf1c7; } @media (prefers-color-scheme: dark) { html, body { background: #282828; } } svg { display: block; width: 100%; height: 100%; } </style> <script src="/map/vendor/d3.min.js"></script> <script src="/map/vendor/topojson-client.min.js"></script> <!-- Load the renderer with the iframe's ?v= so a deploy busts the cached copy (the vendor libs are stable and stay cached). document.write keeps it synchronous + ordered after d3. --> <script> (function () { var v = new URLSearchParams(location.search).get('v'); document.write('<script src="/map/locality-map.js' + (v ? '?v=' + encodeURIComponent(v) : '') + '"><\/script>'); })(); </script> </head> <body> <script> // Embedded via <iframe> from the site. Query params carry the build-time values // (cc, accent, dots, active); theme is resolved here at runtime so the map follows the // page. Same-origin, so localStorage is shared and a parent theme toggle reaches us as a // `storage` event — no postMessage needed. const opts = {}; for (const [k, v] of new URLSearchParams(location.search)) opts[k] = v;
function currentTheme() { try { const pin = localStorage.getItem('theme'); if (pin === 'dark' || pin === 'light') return pin; } catch {} return matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; }
// Paint the correct paper colour immediately (before the async geometry load finishes), // respecting a pinned theme. This is what stops the grey load-flash; the CSS above covers // the very first frame by system preference, this corrects it to the pin. function applyBg() { document.documentElement.style.background = currentTheme() === 'dark' ? '#282828' : '#fbf1c7'; } applyBg();
let drawing = false; function draw() { if (drawing) return; drawing = true; applyBg(); // keep the paper colour in sync when the theme toggles document.body.replaceChildren(); Promise.resolve(LocalityMap.render(document.body, { ...opts, theme: currentTheme() })).finally( () => { drawing = false; }, ); }
draw(); // Re-render when the theme changes: system preference, or a parent/other-tab toggle. matchMedia('(prefers-color-scheme: dark)').addEventListener('change', draw); window.addEventListener('storage', (e) => { if (e.key === 'theme') draw(); }); </script> </body></html>