feat(geo): real-time attendance map on OpenStreetMap tiles

New GeoAttendance scene plus Attendance Map chip on Landing. Uses
react-leaflet 4 + leaflet 1.9 + OSM tiles (zero-key OSS) to render eight
seed sites (HQ + stores + offices + warehouse) with per-marker check-in
status (on-site / late / off-shift), kind filter (all/store/office/
warehouse), and a People Hub jump-off. Auto-fits to the visible markers.

OSS stack: react-leaflet@4, leaflet@1.9.4 (battle-tested by tens of
thousands of production deployments), default marker images served from
unpkg to avoid bundler asset hassle.
This commit is contained in:
2026-06-14 12:51:36 +04:00
parent c28bd386ad
commit 97f14dd6f7
6 changed files with 193 additions and 0 deletions
+21
View File
@@ -1959,3 +1959,24 @@ select.studio-input { background: var(--bp-paper); }
.hero-hub-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.hub-chip { padding: 8px 14px; background: var(--bp-paper); border: 1px solid var(--bp-navy); color: var(--bp-navy); font-family: var(--bp-mono); font-size: 11px; letter-spacing: 0.04em; cursor: pointer; transition: background 0.1s; }
.hub-chip:hover { background: color-mix(in srgb, var(--bp-amber) 20%, var(--bp-paper)); }
.geo-scene { padding: 24px; max-width: 1400px; margin: 0 auto; background: var(--bp-paper); min-height: calc(100vh - 60px); }
.geo-head { margin-bottom: 20px; }
.geo-intro { font-size: 13px; color: var(--bp-muted); max-width: 720px; line-height: 1.5; margin-top: 6px; }
.geo-stats { display: flex; gap: 8px; margin-top: 12px; }
.geo-stat { font-family: var(--bp-mono); font-size: 11px; padding: 4px 10px; border: 1px solid var(--bp-navy); }
.geo-stat-ok { background: color-mix(in srgb, #4a8a3f 25%, var(--bp-paper)); }
.geo-stat-late { background: color-mix(in srgb, var(--bp-amber) 30%, var(--bp-paper)); }
.geo-stat-off { color: var(--bp-muted); }
.geo-filter-row { display: flex; gap: 6px; margin-top: 12px; flex-wrap: wrap; }
.hub-chip.active { background: var(--bp-amber); color: var(--bp-paper); }
.geo-map-wrap { border: 1px solid var(--bp-navy); height: 560px; overflow: hidden; }
.geo-map { width: 100%; height: 100%; }
.geo-popup-tag { font-family: var(--bp-mono); font-size: 10px; padding: 2px 6px; border: 1px solid currentColor; display: inline-block; margin: 2px 0; }
.geo-popup-checked_in { color: #2e7a25; }
.geo-popup-late { color: #c08020; }
.geo-popup-checked_out { color: #777; }
@media (max-width: 700px) {
.geo-map-wrap { height: 380px; }
}