Files
wiki/tasks/enduro-trails/DEV_TASK_PHASE5_UX3.md
2026-05-05 22:30:06 +03:00

134 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dev Task: Enduro Trails — UX маршрута дополнение (drag + дистанции)
**Приоритет:** HIGH
**Проект:** enduro-trails
**Дата:** 2026-05-05
**Дополнение к:** DEV_TASK_PHASE5_UX2.md
---
## Задача 5: Drag точек в основном sheet — не закрывать sheet
### Проблема
Сейчас в `_initWaypointDragHandles` после drop вызывается `debounceBuildRoute()` — это нормально. Но где-то в цепочке sheet закрывается.
### Нужное поведение
При перетаскивании точек в `#waypoints-list` (основной sheet открыт):
- Sheet остаётся открытым
- Маршрут пересчитывается в фоне (колесо в мини-баре)
- После пересчёта — обновить карточки маршрута прямо в открытом sheet
### Изменения
В `endDrag()` внутри `_initWaypointDragHandles`:
```js
function endDrag(finalClientY) {
if (dragIdx < 0) return;
clearHighlights();
const dy = Math.abs(finalClientY - startY);
if (dragging && dy > 30 && lastOverEl !== null) {
const dropIdx = parseInt(lastOverEl.dataset.idx, 10);
let insertAt = lastOverPos === 'top' ? dropIdx : dropIdx + 1;
const moved = routeWaypoints.splice(dragIdx, 1)[0];
if (insertAt > dragIdx) insertAt--;
routeWaypoints.splice(insertAt, 0, moved);
rebuildWaypointMarkers();
renderWaypointsList();
// НЕ закрывать sheet — просто пересчитать маршрут
if (routeWaypoints.length >= 2) {
showMiniRouteLoading(); // колесо в мини-баре
debounceBuildRoute();
}
updateMiniRouteCard();
}
dragIdx = -1;
dragging = false;
lastOverEl = null;
lastOverPos = null;
}
```
В `buildRoute()` — после успешного построения, если основной sheet открыт, обновить карточки без закрытия:
```js
// После drawRouteResults(routeResults, 0):
const sheetOpen = document.getElementById('sheet-route')?.classList.contains('open');
if (sheetOpen) {
renderRouteCards(routeResults); // обновить карточки в открытом sheet
} else {
showMiniRouteSheet(); // показать мини-бар
}
hideMiniRouteLoading();
```
---
## Задача 6: Расстояние между точками в wl-item
### Нужное поведение
В каждом `wl-item` (кроме первой точки) показывать расстояние от предыдущей точки.
Формат:
- < 1 км → "130 м"
- ≥ 1 км → "2,3 км" (запятая как разделитель)
### Реализация
Добавить функцию форматирования дистанции между точками:
```js
function formatSegmentDist(m) {
if (m < 1000) return Math.round(m) + ' м';
return (m / 1000).toFixed(1).replace('.', ',') + ' км';
}
```
Использовать haversine для расчёта расстояния между соседними точками:
```js
function haversineM(a, b) {
const R = 6371000;
const dLat = (b.lat - a.lat) * Math.PI / 180;
const dLon = (b.lon - a.lon) * Math.PI / 180;
const s = Math.sin(dLat/2)**2 + Math.cos(a.lat*Math.PI/180) * Math.cos(b.lat*Math.PI/180) * Math.sin(dLon/2)**2;
return R * 2 * Math.atan2(Math.sqrt(s), Math.sqrt(1-s));
}
```
В `renderWaypointsList()` добавить дистанцию в каждый wl-item (кроме первого):
```js
routeWaypoints.map((wp, i) => {
// ...
const distStr = i > 0 ? formatSegmentDist(haversineM(routeWaypoints[i-1], wp)) : '';
return `<div class="wl-item" id="wl-item-${i}" data-idx="${i}">
<div class="wl-pin">${waypointPinSvg(label, color)}</div>
<div class="wl-info">
<span class="wl-label" id="wl-label-${i}">${coordText}</span>
${distStr ? `<span class="wl-dist">${distStr}</span>` : ''}
</div>
<div class="wl-drag-handle" data-idx="${i}">${gripSvg}</div>
<button class="wl-remove" onclick="removeWaypoint(${i})" ...>...</button>
</div>`;
})
```
CSS для `.wl-dist`:
```css
.wl-info { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.wl-label { font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wl-dist { font-size: 11px; color: var(--text3); margin-top: 1px; }
```
---
## Деплой
```
/tmp/deploy_static.js
SSH: host=82.22.50.71, port=22, user=slin, pass=motoZ@yaz2010
Health: curl -s http://mva154:5558/api/health
```
## Ограничения
- НЕ трогать `app.py`
- Без npm-зависимостей
- Реализовать поверх изменений из DEV_TASK_PHASE5_UX2.md (они уже в коде или деплоятся параллельно)