auto-sync: 2026-05-03 13:50:01

This commit is contained in:
Stream
2026-05-03 13:50:01 +03:00
parent 6184976174
commit af496380bf
4 changed files with 132 additions and 1 deletions

View File

@@ -332,4 +332,4 @@ if os.path.exists(STATIC_DIR):
if __name__ == "__main__":
print(f"==> Enduro Trails API DB={DATA_PATH} Port={PORT}")
uvicorn.run(app, host="0.0.0.0", port=PORT)
uvicorn.run("app:app", host="0.0.0.0", port=PORT, workers=4)

View File

@@ -211,3 +211,70 @@ body {
font-family: monospace;
color: #333;
}
/* ─── Кастомные кнопки управления ────────────────────────────────────────── */
.custom-map-ctrl {
position: absolute;
right: 10px;
display: flex;
flex-direction: column;
gap: 6px;
z-index: 5;
}
#map-controls-br {
bottom: 40px;
}
.map-ctrl-btn {
width: 36px;
height: 36px;
background: #fff;
border: 1px solid #ccc;
border-radius: 4px;
cursor: pointer;
font-size: 18px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 1px 4px rgba(0,0,0,0.15);
transition: background 0.15s;
user-select: none;
}
.map-ctrl-btn:hover { background: #f5f5f5; }
.map-ctrl-btn.active { background: #ff6600; border-color: #ff6600; }
/* ─── Маркер текущего местоположения ─────────────────────────────────────── */
.my-location-marker {
position: relative;
width: 20px;
height: 20px;
}
.my-location-dot {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 14px; height: 14px;
background: #ff6600;
border: 2px solid #fff;
border-radius: 50%;
box-shadow: 0 0 4px rgba(0,0,0,0.3);
z-index: 2;
}
.my-location-pulse {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 30px; height: 30px;
background: rgba(255, 102, 0, 0.25);
border-radius: 50%;
animation: location-pulse 1.5s ease-out infinite;
}
@keyframes location-pulse {
0% { transform: translate(-50%, -50%) scale(0.5); opacity: 1; }
100% { transform: translate(-50%, -50%) scale(1.5); opacity: 0; }
}

View File

@@ -1,3 +1,62 @@
// ─── Компас ───────────────────────────────────────────────────────────────────
let compassLocked = false;
function toggleCompass() {
const map = window._map;
if (!map) return;
const btn = document.getElementById('btn-compass');
compassLocked = !compassLocked;
if (compassLocked) {
map.rotateTo(0, { duration: 300 });
map.dragRotate.disable();
map.touchZoomRotate.disableRotation();
btn.textContent = '⬆️';
btn.title = 'Север вверху (нажми для свободного вращения)';
btn.classList.add('active');
} else {
map.dragRotate.enable();
map.touchZoomRotate.enableRotation();
btn.textContent = '🧭';
btn.title = 'Свободное вращение';
btn.classList.remove('active');
}
}
// ─── Геолокация ───────────────────────────────────────────────────────────────
let locationMarker = null;
function locateMe() {
if (!navigator.geolocation) {
alert('Геолокация недоступна в этом браузере');
return;
}
const btn = document.getElementById('btn-locate');
btn.textContent = '⏳';
navigator.geolocation.getCurrentPosition(
(pos) => {
const { longitude, latitude } = pos.coords;
const map = window._map;
btn.textContent = '📍';
map.flyTo({ center: [longitude, latitude], zoom: 13, duration: 800 });
if (locationMarker) {
locationMarker.setLngLat([longitude, latitude]);
} else {
const el = document.createElement('div');
el.className = 'my-location-marker';
el.innerHTML = '<div class="my-location-dot"></div><div class="my-location-pulse"></div>';
locationMarker = new maplibregl.Marker({ element: el, anchor: 'center' })
.setLngLat([longitude, latitude])
.addTo(map);
}
},
(err) => {
btn.textContent = '📍';
alert('Не удалось определить местоположение: ' + err.message);
},
{ enableHighAccuracy: true, timeout: 10000 }
);
}
// ─── Layer visibility state ───────────────────────────────────────────────────
const layerState = {
tracks: true,

View File

@@ -93,6 +93,11 @@
</div>
<div id="stats">Zoom: <span id="zoom-val">7</span> | Координаты: <span id="coords-val"></span></div>
<div id="map-controls-br" class="custom-map-ctrl">
<button id="btn-compass" class="map-ctrl-btn" title="Свободное вращение" onclick="toggleCompass()">🧭</button>
<button id="btn-locate" class="map-ctrl-btn" title="Моё местоположение" onclick="locateMe()">📍</button>
</div>
</div>
<script src="/app.js" defer></script>