12 KiB
BRD: Enduro Trails — Поиск точек маршрута
Версия: 1.1
Дата: 2026-05-05
Автор: Стрим 🌊
Статус: 🔄 В разработке
1. Контекст и проблема
Сейчас добавить точку маршрута можно только тапом на карту. Если нужно попасть в конкретное место (деревня, перекрёсток, POI) — нужно сначала найти его на карте, потом тапнуть. Это неудобно, особенно на мобиле.
Верхний search bar решал задачу навигации по карте, но не интегрирован с маршрутом — найденное место просто центрировало карту, не добавляя точку. Плюс bar занимал место и мешал карте.
2. Цель
Убрать верхний search bar. Добавить поиск прямо в список точек маршрута — inline, для каждой точки отдельно. При первом открытии режима маршрута — онбординг с полями ввода старта и финиша.
3. Что меняется
3.1 Убрать верхний search bar
- Удалить
#search-barи#search-resultsиз HTML - Удалить все CSS стили (
#search-bar,#search-input,#search-results,.search-result-item,.sri-*) - Удалить вызов
initSearch()из JS - Кнопку темы (
#btn-theme) перенести в#map-controls-r(рядом с компасом и геолокацией)
3.2 Онбординг при активации режима маршрута
Когда пользователь тапает «Маршрут» в toolbar и точек ещё нет — показывать вместо пустого списка:
┌─────────────────────────────────┐
│ 🔍 Откуда? │ ← поле поиска старта
│ или тапни на карте │ ← подсказка
└─────────────────────────────────┘
После выбора старта автоматически появляется:
┌─────────────────────────────────┐
│ S Название старта │ ← добавленная точка
├─────────────────────────────────┤
│ 🔍 Куда? │ ← поле поиска финиша
│ или тапни на карте │
└─────────────────────────────────┘
После выбора финиша — поля исчезают, маршрут строится, показывается обычный wl-list.
Детали:
- Поля поиска используют тот же Nominatim что и inline поиск в wl-item
- Подсказка «или тапни на карте» — мелкий текст
var(--text3)под полем - Тап на карте тоже работает — добавляет точку и переходит к следующему полю
- Если точки уже есть — онбординг не показывается, сразу wl-list
3.3 Inline поиск в каждой точке маршрута
В каждом wl-item добавить кнопку-лупу. Тап → разворачивается inline панель поиска прямо под точкой.
UX flow:
- Пользователь видит список точек маршрута (S → 1 → F)
- Тапает иконку 🔍 рядом с нужной точкой
- Под точкой появляется поле ввода с автофокусом
- Вводит название места → через 400ms debounce → Nominatim поиск
- Выбирает результат → точка обновляется, карта летит к ней, маршрут перестраивается
- Панель закрывается
Детали:
- Одновременно открыта только одна панель поиска (остальные закрываются)
- Поиск через Nominatim (
countrycodes=ru,accept-language=ru, limit=5) - Результат: название + подзаголовок (область/район)
- После выбора:
routeWaypoints[idx]обновляется,rebuildWaypointMarkers()+renderWaypointsList()+debounceBuildRoute() map.flyTo()к выбранному месту (zoom 13, duration 600ms)
4. UI компоненты
Кнопка лупы в wl-item
- Иконка: Lucide
searchSVG (15×15) - Цвет:
var(--text3)→ hovervar(--accent) - Позиция: между
.wl-infoи.wl-drag-handle
Inline панель поиска
- Фон:
var(--surface), бордер сверхуvar(--border) - Input:
var(--surface2)фон,var(--border)бордер, focus →var(--accent)бордер - Результаты: max-height 180px, scroll, hover
var(--surface2) - Каждый результат: название (bold) + подзаголовок (мелкий,
var(--text2))
Кнопка темы (перенос)
- Переносится в
#map-controls-rкак.map-btn updateThemeButtonIcon()продолжает работать — находит#btn-themeпо id
5. Технические детали
| Аспект | Решение |
|---|---|
| Поиск API | Nominatim /search (уже используется в проекте) |
| Debounce | 400ms |
| Состояние | wpSearchTimeout — глобальная переменная для debounce |
| Закрытие панели | Тап на лупу повторно — закрывает; открытие другой — закрывает текущую |
| После выбора | routeWaypoints[idx] = {lat, lon}, rebuild + route |
| Кнопка «Добавить точку» | wl-add остаётся без изменений |
6. Баги после редизайна (требуют исправления)
| Баг | Описание | Вероятная причина |
|---|---|---|
| Метки в верхнем левом углу | Попап метки отображается не на позиции маркера, а в углу экрана | CSS position маркера сбивает позиционирование MapLibre |
| Метки линейки в верхнем углу | Попап точки линейки отображается не на треке, а в углу | Та же причина — CSS позиционирование маркера |
| Подсказка «Тапни на карте» пропала | #route-status не виден когда точек нет |
Скрыт или перекрыт после редизайна |
Вероятная причина багов с маркерами: в редизайне изменились глобальные CSS стили для position, transform или z-index — это сбивает позиционирование MapLibre маркеров. Маркер MapLibre должен иметь position: absolute без переопределения в глобальных стилях.
Фикс: проверить CSS для .maplibregl-marker, .marker-flag, .ruler-marker — убрать любой position: fixed/relative/static который может переопределять поведение маркера.
7. Definition of Done
| Критерий | Статус |
|---|---|
| Верхний search bar отсутствует | ⬜ |
| Кнопка темы работает в map-controls-r | ⬜ |
| При активации маршрута без точек — поле поиска старта | ⬜ |
| После старта — поле поиска финиша | ⬜ |
| Подсказка «или тапни на карте» видна | ⬜ |
| Иконка лупы в каждом wl-item | ⬜ |
| Тап на лупу → inline поиск открывается | ⬜ |
| Поиск находит места через Nominatim | ⬜ |
| Выбор результата → waypoint обновляется | ⬜ |
| Маршрут перестраивается после выбора | ⬜ |
| Карта летит к выбранному месту | ⬜ |
| Одновременно открыта только одна панель | ⬜ |
| Метки отображаются на позиции маркера (не в углу) | ⬜ |
| Метки линейки отображаются на треке | ⬜ |
| Деплой + health check OK | ⬜ |
8. Файлы
| Файл | Изменения |
|---|---|
prototype/static/index.html |
Удалить #search-bar, #search-results; перенести #btn-theme в #map-controls-r |
prototype/static/app.css |
Удалить стили search bar; добавить .wl-search-*; исправить позиционирование маркеров |
prototype/static/app.js |
Удалить initSearch(); добавить онбординг, openWaypointSearch(), doWaypointSearch(), selectWaypointSearchResult() |
9. Дополнительные замечания (05.05.2026 — пакет 2)
| # | Замечание | Детали |
|---|---|---|
| 1 | Иконка колеса | Заменить на нормальное мотокросс колесо |
| 2 | Флажок финиша | Чёрно-белая шахматная раскраска как финишный флаг |
| 3 | Спиннер в основном листе | Вращающееся колесо пока строится маршрут (как в мини-баре) |
| 4 | Тёмная карта | При тёмной теме — тёмный стиль карты, при светлой — светлый |
| 5 | Автозум на маршрут | Плавный fitBounds после построения маршрута, маршрут по центру без выхода за границы |
| 6 | Мини-бар перекрывает кнопки справа | Исправить z-index/позиционирование #sheet-route-mini |
Детали по пунктам
П.1 Иконка колеса:
Заменить текущую SVG на нормальное мотокросс колесо — спицы, кноблинг, центральная втулка. Использовать Lucide bike или нарисовать SVG колеса с спицами.
П.2 Флажок финиша:
В waypointPinSvg('F', ...) для финишной точки использовать шахматный узор (SVG pattern чёрные/белые клетки) вместо красного цвета.
П.3 Спиннер в основном листе:
В #route-cards показывать skeleton/спиннер пока идёт запрос к OSRM. Тот же спиннер что в мини-баре.
П.4 Тёмная карта:
map.setStyle() при смене темы. Тёмный стиль: /style-dark.json (или текущий тёмный), светлый: /style-light.json (или текущий светлый). После setStyle пересоздать слои маршрутов через map.on('style.load', onMapStyleLoad).
П.5 Автозум:
После drawRouteResults() вызывать:
const coords = routeResults[0].geometry.coordinates;
const bounds = coords.reduce((b, c) => b.extend(c), new maplibregl.LngLatBounds(coords[0], coords[0]));
map.fitBounds(bounds, { padding: 60, duration: 1000, maxZoom: 14 });
П.6 Мини-бар:
#sheet-route-mini перекрывает #map-controls-r. Исправить right или width мини-бара чтобы не залезал на кнопки справа.