Files
wiki/tasks/enduro-trails/DEV_TASK_DARK_STYLE.md
2026-05-12 23:20:01 +03:00

11 KiB
Raw Permalink Blame History

DEV TASK: Тёмная тема карты (F-18)

Статус: Ready for dev
Проект: enduro-trails
Фаза: 5.1
BRD: нет (простая фича)


Цель

Карта MapLibre переключается между светлым и тёмным стилем синхронно с темой UI (auto/light/dark + SunCalc).

Архитектура

Сейчас style.json — это светлый стиль (фон #f0ede6, OSM raster desaturated). Нужно создать style-dark.json с тёмной палитрой и исправить логику в switchMapStyle(), которая сейчас инвертирована (считает style.json тёмным).

Подход: тёмный стиль = тот же OSM raster, но с brightness-max: 0.3, contrast: -0.2, тёмный background. Цвета треков и POI адаптированы для тёмного фона.

Стек / Зависимости

  • MapLibre GL JS (уже подключён)
  • Никаких новых зависимостей

Инфраструктура

Параметр Значение
Сервер slin@82.22.50.71 (пароль: motoZ@yaz2010)
Рабочая директория /home/slin/enduro-trails/prototype/static/
Workspace /home/node/.openclaw/workspace/tasks/enduro-trails/prototype/static/
Деплой SFTP + docker cp после рестарта
Контейнер prototype-enduro-trails-1
URL https://openclaw.mva154.duckdns.org/enduro/

Файловая карта

Действие Файл Ответственность
Создать static/style-dark.json Тёмный стиль карты
Переименовать static/style.json → оставить как есть Светлый стиль (уже есть)
Изменить static/app.js (строки 86-105) Исправить логику switchMapStyle

Задачи

Task 1: Создать style-dark.json

Файлы:

  • Создать: static/style-dark.json

Шаги:

  • 1.1 Создать style-dark.json на основе style.json со следующими изменениями:
{
  "name": "Enduro Trails Dark",
  "layers": [
    {
      "id": "background",
      "paint": { "background-color": "#1a1a2e" }
    },
    {
      "id": "osm-base",
      "paint": {
        "raster-opacity": 1.0,
        "raster-saturation": -0.6,
        "raster-contrast": -0.1,
        "raster-brightness-min": 0,
        "raster-brightness-max": 0.35
      }
    },
    {
      "id": "trails-track",
      "paint": {
        "line-color": "...",
        "line-opacity": 0.95
      }
      // Цвета треков: grade1/2 → #FFE066, grade3/4/5 → #FF6633, default → #FF6633
    },
    {
      "id": "trails-path-bridleway",
      "paint": {
        "line-color": "#ff4444",
        "line-opacity": 0.9
      }
    },
    {
      "id": "poi-circles",
      "paint": {
        "circle-stroke-color": "#333333"
        // Остальные цвета POI — ярче на 10-15% для контраста на тёмном фоне
      }
    },
    {
      "id": "poi-labels",
      "paint": {
        "text-color": "#e0e0e0",
        "text-halo-color": "#1a1a2e",
        "text-halo-width": 2
      }
    }
  ]
}

Полная спецификация изменений относительно style.json:

Слой Свойство Светлый Тёмный
background background-color #f0ede6 #1a1a2e
osm-base raster-saturation -0.4 -0.6
osm-base raster-contrast 0.25 -0.1
osm-base raster-brightness-max 0.9 0.35
trails-track line-color grade1/2 #FFD700 #FFE066
trails-track line-color grade3/4/5/default #FF4400 #FF6633
trails-path-bridleway line-color #cc0000 #ff4444
poi-circles circle-stroke-color #ffffff #333333
poi-labels text-color #333333 #e0e0e0
poi-labels text-halo-color #ffffff #1a1a2e
poi-labels text-halo-width 1.5 2

Все остальные свойства (sources, glyphs, filters, zoom levels, line-width) — копировать из style.json без изменений.

  • 1.2 Проверить валидность JSON
cat static/style-dark.json | python3 -m json.tool > /dev/null && echo "OK"
# Ожидаемый результат: OK

Критерий готовности: Файл style-dark.json существует, валидный JSON, содержит все слои из style.json с тёмной палитрой.


Task 2: Исправить switchMapStyle() в app.js

Файлы:

  • Изменить: static/app.js (строки 86-105)

Шаги:

  • 2.1 Заменить функцию switchMapStyle() (строки 86-105):

Было:

function switchMapStyle() {
  const map = window._map;
  if (!map) return;
  const dark = isDarkTheme();
  const basePath = window.location.pathname.replace(/\/[^/]*$/, '') || '';
  const styleUrl = dark ? basePath + '/style.json' : basePath + '/style-light.json';

  // Check if style-light.json exists - if not, keep current
  fetch(styleUrl, { method: 'HEAD' }).then(r => {
    if (r.ok) {
      map.setStyle(styleUrl);
    } else {
      // No light style available, keep dark
      if (!dark) {
        console.log('Light map style not available, keeping dark');
      }
    }
  }).catch(() => {
    // Network error, don't switch
  });
}

Стало:

function switchMapStyle() {
  const map = window._map;
  if (!map) return;
  const dark = isDarkTheme();
  const basePath = window.location.pathname.replace(/\/[^/]*$/, '') || '';
  const styleUrl = dark ? basePath + '/style-dark.json' : basePath + '/style.json';

  fetch(styleUrl, { method: 'HEAD' }).then(r => {
    if (r.ok) {
      map.setStyle(styleUrl);
    } else {
      console.log('Map style not available:', styleUrl);
    }
  }).catch(() => {
    // Network error, don't switch
  });
}

Ключевое изменение: dark → style-dark.json, light → style.json (было инвертировано).

  • 2.2 Проверить что switchMapStyle() вызывается в applyTheme() (строка 26) — уже есть, не трогать.

Критерий готовности: При isDarkTheme() === true загружается style-dark.json, при falsestyle.json.


Task 3: Деплой и проверка

Шаги:

  • 3.1 Загрузить файлы на сервер
# Через Node.js ssh2 (deploy_static.js) или напрямую:
scp static/style-dark.json slin@82.22.50.71:/home/slin/enduro-trails/prototype/static/
scp static/app.js slin@82.22.50.71:/home/slin/enduro-trails/prototype/static/
  • 3.2 Docker cp в контейнер
ssh slin@82.22.50.71 << 'EOF'
docker cp /home/slin/enduro-trails/prototype/static/style-dark.json prototype-enduro-trails-1:/app/static/style-dark.json
docker cp /home/slin/enduro-trails/prototype/static/app.js prototype-enduro-trails-1:/app/static/app.js
EOF

⚠️ НЕ рестартовать контейнер! Просто cp — иначе придётся копировать ВСЕ файлы заново.

  • 3.3 Проверить доступность стилей
curl -s -o /dev/null -w "%{http_code}" https://openclaw.mva154.duckdns.org/enduro/style.json
# Ожидаемый результат: 200

curl -s -o /dev/null -w "%{http_code}" https://openclaw.mva154.duckdns.org/enduro/style-dark.json
# Ожидаемый результат: 200
  • 3.4 Проверить содержимое тёмного стиля
curl -s https://openclaw.mva154.duckdns.org/enduro/style-dark.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['name'], d['layers'][0]['paint'])"
# Ожидаемый результат: Enduro Trails Dark {'background-color': '#1a1a2e'}

Критерий готовности: Оба стиля доступны по URL, тёмный стиль содержит правильную палитру.


Проверка (Acceptance)

# Проверка Действие Ожидаемый результат
1 Светлая тема Открыть сайт, выбрать ☀️ Карта светлая (бежевый фон)
2 Тёмная тема Переключить на 🌙 Карта тёмная (тёмно-синий фон, приглушённый OSM)
3 Auto (день) Режим auto днём Карта светлая
4 Auto (ночь) Режим auto ночью Карта тёмная
5 Overlay сохраняется Включить terrain → переключить тему Terrain слой остаётся видимым
6 Маршрут сохраняется Построить маршрут → переключить тему Маршрут остаётся на карте
7 style-dark.json 200 curl HTTP 200

Ограничения и контекст

  • ⚠️ docker cp БЕЗ рестарта контейнера — рестарт перезапишет статику из образа
  • ⚠️ SSH через Node.js ssh2 модуль (бинарный ssh в контейнере OpenClaw не работает — glibc mismatch). Альтернатива: deploy_static.js
  • ⚠️ После map.setStyle() все кастомные слои (terrain, routes, markers) слетают — onMapStyleLoad() + rebuildMapOverlays() уже обрабатывают это через событие style.load
  • 🚫 Не трогать style.json — это рабочий светлый стиль
  • 🚫 Не менять логику SunCalc / applyAutoTheme — она работает корректно

Деплой-чеклист

  • style-dark.json создан и валиден
  • app.js — логика switchMapStyle исправлена
  • Файлы загружены на сервер (/home/slin/enduro-trails/prototype/static/)
  • docker cp выполнен (без рестарта!)
  • style-dark.json доступен по URL (HTTP 200)
  • Переключение темы меняет стиль карты
  • Overlays (terrain, routes) сохраняются при смене стиля

Создано: 2026-05-12 | Автор ТЗ: Стрим | Исполнитель: Dev-агент